Apostila Linguagem C

62
PROGRAMAÇÃO EM C

Transcript of Apostila Linguagem C

Page 1: Apostila Linguagem C

P R O G R A M A Ç Ã O E M C

Page 2: Apostila Linguagem C

SUMÁRIO

1 A LINGUAGEM C - PRIMEIROS PASSOS . . . . . . . . . . . . . . . . 51.1 Introdução ao Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51.1.1 O Linux é igual ao Unix? . . . . . . . . . . . . . . . . . . . . . . . . . . 51.1.2 Comandos Básicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51.1.3 Estrutura de diretórios do Linux . . . . . . . . . . . . . . . . . . . . . . 51.1.4 Como acessar um disquete (floppy) no Linux? . . . . . . . . . . . . . . . 51.1.5 Compilando um programa . . . . . . . . . . . . . . . . . . . . . . . . . 71.1.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71.2 Introdução à Linguagem C . . . . . . . . . . . . . . . . . . . . . . . . . 81.2.1 Características Básicas . . . . . . . . . . . . . . . . . . . . . . . . . . . 81.2.2 Estruturas dos programas em C . . . . . . . . . . . . . . . . . . . . . . . 81.2.3 Primeiro exemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91.2.4 Identação de programas . . . . . . . . . . . . . . . . . . . . . . . . . . . 111.2.5 Revisão de termos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111.2.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2 INTRODUÇÃO AO TRATAMENTO DE VARIÁVEIS . . . . . . . . . . . 122.1 Identificadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.2 Variáveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.3 Tipos de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132.4 Operador de Atribuição . . . . . . . . . . . . . . . . . . . . . . . . . . . 142.5 Variáveis Locais x Variáveis Globais . . . . . . . . . . . . . . . . . . . . 142.5.1 Variáveis Locais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142.5.2 Variáveis Globais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142.6 Constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152.7 Operadores Aritméticos . . . . . . . . . . . . . . . . . . . . . . . . . . . 152.8 Operadores Relacionais e Lógicos . . . . . . . . . . . . . . . . . . . . . . 162.9 Operadores Bit a Bit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172.10 Prioridade das Operações . . . . . . . . . . . . . . . . . . . . . . . . . . 182.11 Operações de entrada e saída . . . . . . . . . . . . . . . . . . . . . . . . 192.11.1 printf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192.11.2 scanf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202.11.3 sprintf e sscanf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212.12 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

Page 3: Apostila Linguagem C

3 COMANDOS DE CONTROLE E REPETIÇÃO . . . . . . . . . . . . . . 233.1 if/else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233.2 while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253.3 for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253.4 do/while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263.5 Break e Continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263.6 switch/case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263.7 Expressões Condicionais . . . . . . . . . . . . . . . . . . . . . . . . . . . 273.8 Exercícios: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

4 MATRIZES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294.1 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304.2 Matrizes Bidimensionais . . . . . . . . . . . . . . . . . . . . . . . . . . . 324.3 Matrizes de Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334.4 Matrizes Multidimensionais . . . . . . . . . . . . . . . . . . . . . . . . . 334.5 Inicialização de Matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . 344.6 Exercícios: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

5 ESTRUTURAS DEFINIDAS PELO USUÁRIO . . . . . . . . . . . . . . 365.1 Estruturas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365.1.1 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385.2 Uniões . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385.3 Enumerações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

6 FUNÇÕES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416.1 Modularidade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416.2 Forma de uma Função . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416.3 Regras de Escopo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426.4 Argumentos de Funções . . . . . . . . . . . . . . . . . . . . . . . . . . . 426.5 O Comando return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436.6 Funções do Tipo void . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436.7 Passagem por Parâmetros . . . . . . . . . . . . . . . . . . . . . . . . . . 446.7.1 Chamada por Valor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446.7.2 Chamada por Referência . . . . . . . . . . . . . . . . . . . . . . . . . . 456.7.3 Matrizes como Argumentos de Funções . . . . . . . . . . . . . . . . . . 466.8 Protótipos de Funções . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466.9 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

7 APONTADORES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487.1 Apontadores: passagem de parâmetros por referência . . . . . . . . . . 507.2 Alocação Dinâmica de ponteiros . . . . . . . . . . . . . . . . . . . . . . 527.3 Exercícios: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

8 ARQUIVOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558.2 Arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558.3 Funções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558.3.1 Ponteiro de Arquivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558.3.2 Abrindo um arquivo (fopen) . . . . . . . . . . . . . . . . . . . . . . . . . 55

Page 4: Apostila Linguagem C

8.3.3 Fechando um arquivo (fclose) . . . . . . . . . . . . . . . . . . . . . . . . 578.3.4 Escrevendo e Lendo um caractere . . . . . . . . . . . . . . . . . . . . . . 578.3.5 Lidando com Strings (fputs e fgets) . . . . . . . . . . . . . . . . . . . . . 588.3.6 Lidando com blocos de dados binários(fread e fwrite) . . . . . . . . . . . 598.3.7 Realizando Procuras (fseek) . . . . . . . . . . . . . . . . . . . . . . . . . 608.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

9 BIBLIOGRAFIA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

Page 5: Apostila Linguagem C

5

1 A LINGUAGEM C - PRIMEIROS PASSOS

Esse capítulo apresenta uma breve introducão ao Sistema Operacional Linux, suas ca-racterísticas básicas e seus principais comandos. O objetivo é dar suporte para o alunodesenvolver seus programas no ambiente Linux, utilizando o compilador gcc. Uma in-trodução a Linguagem de Programação C também é apresentada, através do histórico dalinguagem e da descrição da estrutura básica de um programa escrito com ela.

1.1 Introdução ao Linux

Linux é um Sistema Operacional que foi inicialmente criado por um estudante, LinusTorvalds, na Universidade de Helsinki na Finlândia. Linus era interessado pelo Minix,um pequeno sistema UNIX, e decidiu desenvolver um sistema que excedesse os padrõesMinix.

Ele iniciou seu trabalho em 1991 e sua versão 1.0 surgiu em 1994. O kernel, o coraçãodos sistemas Linux, é desenvolvido sob o GNU General Public License e seu código fonteé disponível para todos, gratuitamente.

1.1.1 O Linux é igual ao Unix?

O Linux foi escrito desde o inicio pelo Linus Torvalds e não contêm nenhuma linha decódigo do UNIX. Mas o Linux foi escrito para ser conforme o padrão POSIX, que deveser o padrão da API (Application Programming Interface) Unix.

1.1.2 Comandos Básicos

Na Tabela 1.1 estão relacionados os principais comandos do Linux:

1.1.3 Estrutura de diretórios do Linux

Na Tabela 1.2 estão relacionados os principais diretórios do Linux. Essa estrutura seráencontrada na maioria das distribuições disponíveis.

1.1.4 Como acessar um disquete (floppy) no Linux?� Para montar: �������

����

� ������ ���

� Para desmontar: �������������

� ����������

Obs.: Para acessar o conteúdo do disquete, copiar, deletar, mover ou qualquer outratarefa relativa aos arquivos, use os comandos do Linux no diretório /mnt/floppy,esse diretório é o disquete!

Page 6: Apostila Linguagem C

6

Comando Funçãoman <comando> Manual de usuário Linux para os comandosls Lista arquivos do diretóriols -la Lista arquivos no diretório com detalhescd <nome-dir> Muda para o diretóriomkdir <nome-dir> Cria o novo diretóriotouch <nome-arquivo> Cria ou atualiza data, se o arquivo já existermdir <nome-dir> Deleta diretório (deve estar vazio)cp <origem> <destino> Copia arquivomv <origem><destino> Move dado da origem para o destinomv <nome1> <nome2> Renomeia diretório ou arquivo 1 para 2rm file Remove arquivo (cuidado!)ps Imprime o numero dos processos ativoskill -9 nro Mata processo nropwd Imprime diretório correntecat f Mostra conteúdo do arquivo fmore f Mostra conteúdo do arquivo f tela a telafree Exibe memória livrepasswd Altera senha do usuário

Tabela 1.1: Comandos básicos do Linux

Diretório Conteúdo/ Diretório raiz do sistema

bin Arquivos executáveis(binários)boot Arquivos estáticos de boot de inicialização(boot-loader)dev Arquivos de dispositivos de entrada/saídaetc Configuração do sistema da máquina local

home Diretório local (home) dos usuárioslib Arquivos das bibliotecas compartilhadas usados freqüentemente

mnt Ponto de montagem de partição temporários (floppy, cdrom, etc)root Diretório local do superusuário (root)sbin Arquivos de sistema essenciaistmp Arquivos temporários gerados por alguns utilitáriosusr Todos os arqs dos diversos aplicativos devem estar aqui

Tabela 1.2: Principais diretórios do Linux

Page 7: Apostila Linguagem C

7

1.1.5 Compilando um programa

Para compilar um programa e transformá-lo em executável, através de linha de co-mando digite:

����� ��������� ������ � �� ��� �� �� ����������� ������� � � � ���� ���

onde gcc é o comando que dispara o compilador, � � é o argumento, não obrigatório,para entrar com o nome do executável. Caso seja omitido � � , o compilador retornaráum nome padrão para o executável igual a � � ��� � . Dúvidas sobre o comando podem serresolvidas digitando � �� � ����� .

Obs.: Para executar o programa digite � antes do nome do executável. Isso é neces-sário porque o executável não está no Path do Sistema Operacional.

1.1.6 Exercícios

1. Logue-se no Linux

2. Abra um Terminal

3. Crie um diretório aluno

4. Entre neste diretório aluno

5. Crie, dentro do diretório aluno, outro diretório chamado teste e entre nele

6. Crie um arquivo chamado linux.arq

7. Faça uma cópia deste arquivo para linux2.arq

8. Liste os arquivos do diretório com detalhes

9. Mova estes dois arquivos para o diretório aluno

10. Volte para o diretório aluno

11. Apague o diretório teste

Page 8: Apostila Linguagem C

8

1.2 Introdução à Linguagem C

A linguagem "C"foi criada nos laboratórios Bell por Brian W. Kernighan e Dennis Rit-chie em 1972. Esta linguagem, teve suas idéias iniciais originadas da linguagem BCPL(Basic Combined Programming Language), desenvolvida por Martin Richards. Esta in-fluência do BCPL se deu através de outra linguagem, chamada "B"e criada por Thompsonem 1970 para o primeiro sistema operacional UNIX no PDP-11.

A partir de sua criação a linguagem "C" sofreu uma longa evolução sendo que uma desuas primeiras utilizações foi a de reescrever o sistema operacional UNIX (1973) que es-tava escrito em linguagem assembly do PDP-11. Por este motivo é que se tem associado alinguagem ao S.O. UNIX, visto que o UNIX é composto, quase na sua totalidade, de pro-gramas escritos em "C" (Sistema Operacional, utilitários, compiladores, ...). Entretantoisto não implica que o "C" seja uma linguagem "amarrada"a um sistema operacional oumáquina.

Devido à evolução do "C" que seguia apenas o padrão descrito por Kernighan e Rit-chie, tornou-se necessária uma padronização mais rígida para a linguagem, permitindo aportabilidade dos softwares escritos nesta linguagem. Isto foi feito pelo ANSI (AmericanNational Standard Institute), criando assim o padrão C ANSI.

1.2.1 Características Básicas

O "C"é uma linguagem de propósitos gerais e que tem como características principais:

� Controle de fluxo e estrutura de dados adotando conceitos modernos de linguagensde programação;

� Poderoso conjunto de operadores e tipos de dados;

� Permite a geração de um código bem otimizado e compacto (quase tão otimizadoquanto o assembly);

� Grande portabilidade de programas (a maioria dos computadores suportam "C");

� É uma linguagem de nível "relativamente baixo", mas com recursos de alto nível;

� Apresenta facilidade de manipulação direta do hardware da máquina;

� Uso de bibliotecas de funções, expandindo as potencialidades da linguagem;

� Grande "liberdade"para o programador.

1.2.2 Estruturas dos programas em C

Todo programa C deve ter ao menos uma função, denominada main(), a qual é aprimeira função a ser chamada quando o programa é executado. Geralmente, a funçãomain() contém um esboço do que o programa faz, ou a estrutura geral de controle doprograma. Embora main não seja uma palavra reservada da linguagem, não se pode usa-la para outros fins que não seja o nome da função principal do programa.

Page 9: Apostila Linguagem C

9

/*No início do programa, declara-se as bibliotecas usadas*/#include <stdio.h>

/* Declarações globais *//* Declaração de funções do programador, se for o caso *//* Declaração da função principal. Sempre necessária */

tipo_devolvido main (lista de parâmetros){

/* variaveis locais ao main, se existirem */// Isto também é comentário até o final da linha/* seqüência de comandos... */

}

A linguagem C é formada por pouco mais de 30 palavras-chave, por isso, normal-mente é necessária a declaração das bibliotecas que contem funções não nativas na lin-guagem. Como exemplo podemos citar as funções de entrada e saída de dados presentesna biblioteca padrão.

Em C, maiúsculas e minúsculas são diferentes por isso preste atenção na hora dedigitar o programa fonte. Essa característica é chamada de case sensitive. Os símbolos /*(inicio de comentário) e */ (final do comentário) indicam comentários de código e podemabranger uma ou mais linhas do programa. Para comentar somente uma linha, pode-seutilizar //.

Todo programa em C consiste em uma ou mais funções. A única função que neces-sariamente precisa estar presente é a denominada main(), que é a primeira função a serchamada quando a execução do programa começa. Embora main() não seja tecnicamenteparte da linguagem C, é tratada como se fosse. Não pode ser usada como nome de variá-vel, porque pode confundir o compilador.

1.2.3 Primeiro exemplo

O único caminho para aprender uma nova linguagem de programação é escrever pro-gramas nesta linguagem, Normalmente os autores utilizam um exemplo clássico no pri-meiro programa, o famoso - Oi Mundo!

Esse será o seu primeiro programa, para cria-lo, utilize algum editor de textos paradigitar os fontes e um compilador para gerar o executável.

#include<stdio.h>main(){

printf(“Oi mundo! � n");}

��� Obs.: Editar esse programa, salvá-lo como oi.c,compilá-lo (gcc oi.c) e executálo (./a.out).

Exercício: Edite este programa, experimente deixar fora do fonte partes como ”;” porexemplo, para verificar as mensagens de erro.

Page 10: Apostila Linguagem C

10

Um programa C, independentemente de seu tamanho, consiste de uma ou mais "fun-ções que especificam as operações computacionais que devem ser feita. Funções C sãosimilares aos procedimentos em Pascal. No nosso exemplo main() é uma função. Nor-malmente você pode escolher o nome que quiser, menos para main.

Um método de comunicação de dados entre funções é por argumentos. Os parêntesesseguindo o nome da função envolvem a lista de argumentos, sendo que nesse exemplo,main é uma função sem argumentos. As chaves envolvem os comandos que formama função, elas são análogas ao BEGIN-END do Pascal. Uma função é ativada por seunome, seguido de uma lista de argumentos entre parênteses. Os parênteses devem estarpresentes mesmo quando não há argumentos.

A linha:printf (“Oi mundo! � n“);É uma chamada de função, que chama a função printf, com o argumento “Oi mundo! � n“.

printf é uma função de biblioteca que imprime no terminal (a menos que outro destinoseja especificado). Nesse caso ela imprime a cadeia de caracteres que compõem seu ar-gumento.

Uma seqüência de qualquer número de caracteres entre aspas “...“ é chamada cadeiade caracteres. A seqüência � n na cadeia é a notação C para o caractere nova linha, que,quando impresso provoca o avanço do cursor do terminal para o inicio da próxima linha.Se você omitir o � n, você encontrará sua saída não terminada por uma alimentação delinha.

printf nunca fornece uma nova linha automaticamente, de forma que múltiplas ati-vações pode ser usadas para construir uma linha de saída passo a passo. Nosso primeiroprograma poderia ter sido escrito como:

#include<stdio.h>main(){

printf(“Oi");printf(“mundo!");printf(“ � n");

}

O código acima produziria uma saída idêntica ao anterior.O � n, apresentado no código anterior, representa um único caractere. Uma seqüência

de escape tal como � n provê um mecanismo geral e extensível para a representação decaracteres difíceis de obter ou invisíveis. Entre outros que C prove, estão:

� n para quebra de linha,

� t para tabulação,

� b para retrocesso,

� " para a aspa,

��� para a contra-barra propriamente dita,

� 0 Nulo,

� a Alerta (beep).

Page 11: Apostila Linguagem C

11

1.2.4 Identação de programas

Os comandos de "C"devem ser escritos em minúsculas e devem ser seguidos de um";", podendo haver mais de um comando na mesma linha, desde que separados por pontoe vírgula (não abuse disto pois torna o código difícil de compreender). A identação doprograma não é obrigatória, mas aconselhada para deixar código-fonte legível para outrosprogramadores ou mesmo para o próprio criador.

Os blocos são definidos de uma { até a outra } e equivalem aos blocos de Pascaldefinidos pelo "BEGIN"e "END". Dentro de cada bloco pode-se definir um conjuntode comandos como se fossem um só, sendo que no C pode-se declarar novas variáveis(variáveis locais ao bloco) independentemente da posição deste bloco no programa.

{ /* inicio de bloco */� � �� � ��� � � ��� � � ������ � ��� ����� � � ��� ���<Comandos>

} /* fim de bloco */

1.2.5 Revisão de termos

Os termos a seguir serão usados freqüentemente nessa apostila.

Código-Fonte: o texto é um programa que um usuário pode ler; normalmente interpre-tado como o programa. O código-fonte é a entrada para o compilador C.

Compilador: programa que lê o código-fonte de uma determinada linguagem de progra-mação e converte-o em código objeto.

Código-Objeto: tradução do código fonte de um programa em código de máquina queo computador pode ler e executar diretamente. O código objeto é a entrada para olinkeditor.

Linkeditor: um programa que une funções compiladas separadamente em um programa.Ele combina as funções da biblioteca C padrão com o código que você escreveu. Asaída do linkeditor é um programa executável.

Biblioteca: o arquivo contendo as funções padrão que seu programa pode usar. Essasfunções incluem todas as operações de E/S como também outras rotinas úteis.

1.2.6 Exercícios

a. Crie um código fonte, que imprime seu nome, idade, endereço e telefone em linhasseparadas na tela.Compile e Execute

b. Altere o código anterior para deixar uma linha em branco entre as linhas e colocar umtab a frente das palavras:Compile e Execute

c. Crie um código fonte para imprimir :"exemplo de utilização de aspas"dia 02 � 03 � 2004Compile e execute

Page 12: Apostila Linguagem C

12

2 INTRODUÇÃO AO TRATAMENTO DE VARIÁVEIS

Nesta aula o aluno receberá noções do tratamento de variáveis em C. Essas noçõesiniciam pela descrição dos tipos de dados disponiveis em C, variáveis locais, globais econstantes.

2.1 Identificadores

Os nomes das variáveis, funções, rótulos e outros objetos definidos pelo usuário, sãochamados de identificadores. Algumas observações sobre os identificadores são impor-tantes, como:

� O primeiro caractere deve ser uma letra ou um sublinhado. Os caracteres sub-seqüentes devem ser letras, números ou sublinhados. Por exemplo: count, total23 epeso.

� Podem ter qualquer tamanho, mas os seis primeiros caracteres devem ser significa-tivos.

� Em C, letras minúsculas e maiúsculas são tratadas diferentemente, portanto "Aula"édiferente de "aula". Case sensitive

� Um identificador não pode ser igual a uma palavra chave do C.

2.2 Variáveis

Uma variável é uma possição de memória que pode ser identificada através de umnome. Estas podem ter seu conteúdo alterado por um comando de atribuição e após aatribuição mudam de valor.

Toda variável tem:

� um nome (identificador)

� um tipo de dado

� um valor

Page 13: Apostila Linguagem C

13

//...int a,b,c;a = 3; // a recebe o valor 3b = a * 2; // b recebe o dobro do valor de ac = a + b + 2; // c recebe 11

//...

2.3 Tipos de dados

O C tem 5 tipos básicos - char, int, float, void e double:

char serve para se guardar caracteres;

int serve para se guardar valores inteiros;

float serve para se guardar valores reais de baixa precisão;

double é o ponto flutuante duplo com muito mais precisão;

void é o tipo vazio, ou um "tipo sem tipo".

Para cada um dos tipos de variáveis existem os modificadores de tipo, que são quatro:signed, unsigned, long e short. Ao float não se pode aplicar nenhum e ao double pode-seaplicar apenas o long. Os quatro modificadores podem ser aplicados a inteiros. A intençãoé que short e long devam prover tamanhos diferentes de inteiros onde isto for prático.

int normalmente terá o tamanho natural para uma determinada máquina. Assim, numamáquina de 16 bits, int provavelmente terá 16 bits. Numa máquina de 32, int deverá ter32 bits. Na verdade, cada compilador é livre para escolher tamanhos adequados para oseu próprio hardware, com a única restrição de que tipos short int e int devem ocupar pelomenos 16 bits, tipos long int pelo menos 32 bits, e short int não pode ser maior que int,que não pode ser maior que long int.

O modificador unsigned serve para especificar variáveis sem sinal. Um unsigned intserá um inteiro que assumirá apenas valores positivos. A seguir são relacionados os tiposde dados permitidos e seus valores máximos e mínimos em um compilador típico paraum hardware de 16 bits. Também nesta tabela está especificado o formato (máscara) quedeve ser utilizado para leitura e impressão dos tipos de dados.

Tipo mascara para e/s Tamanho aproximado(bits) faixa mínimahline char %c 8 -127 a 127int %d ou %i 16 -32.767 a 32.767unsigned int %u 16 0 a 65.535long int %ld 32 -2.147.483.647 a 2.147.483.647unsigned long int %ld 32 0 a 4.294.967.295float %f 32 Seis dígitos de precisãodouble %lf 64 Dez dígitos de precisãolong double %lf 128 Dez dígitos de precisão

O tipo long double é o tipo de ponto flutuante com maior precisão.

Page 14: Apostila Linguagem C

14

2.4 Operador de Atribuição

Em C, você pode utilizar o operador de atribuição dentro de qualquer expressão válidade C. O simbolo utilizado para atribuição é o =. A forma geral do operador de atribuiçãoé:

nome_da_variável = expressão;

2.5 Variáveis Locais x Variáveis Globais

Todas as variáveis devem ser declaradas. Estas podem ser declaradas em três lugaresbásicos: dentro de funções, na definição dos parâmetros das funções e fora de todas asfunções. Estas são chamadas de variáveis locais, parâmetros ou variáveis globais, respec-tivamente.

2.5.1 Variáveis Locais

As variáveis locais devem ser declaradas dentro das funções nas quais serão utiliza-das, ou seja, estas não são acessíveis a outras funções do programa. Portanto, só podemser referenciadas por comandos que estão dentro do bloco no qual as variáveis foramdeclaradas.

func1(void) func2(void){ {

int x; int x;x = 10; x = -199;

} }

No exemplo, pode-se verificar que existem duas funções (fun1 e func2). Estas pos-suem variáveis locais com o mesmo nome, x. Dentro da func1, o valor acessível de xserá 10. Em func2, o valor será -199. Ou seja, nenhuma função tem acesso ao valor dasvariáveis locais de outras funções.

Ressalva-se que todas as variáveis devem ser declaradas no início das funções, e seforem declaradas no meio do programa/função, ocorrerá um erro no processo de compi-lação. Outro fator importante é que as variáveis locais só "existem"ou estão disponíveisquando a função está sendo executada, após a finalização da execução da função, esta áreade memória é liberada e o valor se perde.

2.5.2 Variáveis Globais

As variáveis globais são reconhecidas por todo o programa, e podem ser utilizadas emqualquer trecho de código. O valor destas permanece disponível por toda a execução doprograma.

Page 15: Apostila Linguagem C

15

#include<stdio.h>int total;void contas(){

total = total + 3;}main(){

int i;total = 0;for(i=0;i<10;i++)

contas();printf(“Total = %d � n",total);

}

Pode-se verificar no código exemplo que a variável total foi declarada no início doprograma e esta será acessível a todo o programa. Tanto que o seu valor é inicializadocom zero na função principal e que seu valor também pode ser alterado pela função contas.No final o programa imprimirá na tela: "Total: 27".

2.6 Constantes

Constantes são valores declarados que não podem ser alterados durante a execução doprograma. Portanto, em C as constantes referem-se a valores fixos que o programa nãopode alterar. Esta podem aparecer dentro das expressões ou podem ser declaradas, comopor exemplo:

const valor = 10;const taxa = 1.5;const letra = ’S’;DefineA diretiva define atribui a um identifcador uma string que o substituirá toda a vez que

for encontrador no arquivo-fonte. Esta associa um identificador a um valor. O padrão CANSI refere-se ao identificador como um nome de macro e ao processo de substituiçãocomo substituição de macro (geralmente declarado com letra maiúscula, sempre após adeclaração das bibliotecas). O formato utilizado é:

#define nome_da_macro valor.Veja os exemplos:

#define VERDADEIRO 1#define FALSO 0#define MSG "Digite S para Sair"

2.7 Operadores Aritméticos

A lista dos operadores aritméticos de C estão relacionados na tabela abaixo, visto queestes operadores trabalham da mesma forma que na maioria das outras linguagens.

Page 16: Apostila Linguagem C

16

Operador Aritmético Ação- Subtração+ Adição* Multiplicação/ Divisão

% Módulo da divisão (resto)- - Decremento++ Inremento

A sequir, é apresentado um código fonte comentado, com operações aritméticas.

#include<stdio.h>main(){

int x,y;x = 5;y = 2;printf(“%d � n",x/y); //mostra 2 (truncado)printf(“%d � n",x%y); // mostra 1, o resto da divisãox ++; // x foi incrementado em 1printf(“%d � n",x); // mostra 6, pois x foi incrementado

}

2.8 Operadores Relacionais e Lógicos

No termo operador relacional, relacional refere-se as relações que os valores podemter uns com os outros. Os operadores relacionais retornam verdadeiro (1) ou falso (0).Para verificar o funcionamento dos operadores relacionais, execute o programa abaixo:

Operador relacional Ação== Igual!= Diferente<= Menor ou igual>= Maior ou igual< Menor> Maior

/* O próximo programa ilustra o funcionamento dos operadores relacionais. */

Page 17: Apostila Linguagem C

17

#include<stdio.h>main(){

int i,j;printf(“ � nEntre com 2 nros inteiros:”);scanf(“%d %d”, &i, &j);printf(“ � n%d == %d e %d � n", i, j, i==j);printf(“ � n%d != %d e %d � n", i, j, i!=j);printf(“ � n%d <= %d e %d � n", i, j, i<=j);printf(“ � n%d >= %d e %d � n", i, j, i>=j);printf(“ � n%d < %d e %d � n", i, j, i < j);printf(“ � n%d > %d e %d � n", i, j, i > j);

}

Para fazer operações com valores lógicos (verdadeiro e falso) temos os operadoreslógicos:

Operador lógico Ação&& AND

|| (pipes) OR! (exclamação) NOT

O programa a seguir ilustra o funcionamento dos operadores lógicos. Compile-o efaça testes com vários valores para i e j:

#include<stdio.h>main(){

int i,j;printf(“ � nEntre com 2 nros inteiros (0 ou 1):”);scanf(“%d %d”, &i, &j);printf(“ � n%d AND %d é %d � n", i, j, i && j);printf(“ � n%d OR %d é %d � n", i, j, i || j);printf(“ � n NOT %d é %d � n", i,!i);

}

2.9 Operadores Bit a Bit

C suporta um conjunto de operações bit a bit. Operações bit a bit refere-se a testar,atribuir ou deslocar os bits efetivos em um byte ou uma palavra, que correspondem aostipos de dados char, int e variantes do padrão C. Estas operações são aplicadas bit a bit.Abaixo estão relacionados estas operações.

Page 18: Apostila Linguagem C

18

Operador binário Ação!(exclamação) NOT

& AND| (pipe) OR

ˆ XOR˜ Complemento de 1» Desloca p/direita« Desloca pra esquerda

“Imagine um número inteiro de 16 bits, a variável i, armazenando o valor 2. A repre-sentação binária de i, será: 0000000000000010 (quinze zeros e um único 1 na segundaposição da direita para a esquerda). Pode-se fazer operações em cada um dos bits destenúmero. Por exemplo, se fizermos a negação do número (operação binária NOT, ou ope-rador binário ! em C), isto é, i, o número se transformará em 1111111111111101. Asoperações binárias ajudam programadores que queiram trabalhar com o computador em“baixo nível.

O uso de operações de deslocamento de bits podem ser úteis quando se decodificaa entrada de um dispositivo externo. Estes podem realizar operações de multiplicação edivisão rapidamente. Um deslocamento à direita efetivamente multiplica um número pordois e um à esqueda multiplica. Observe o exemplo de funcionamento na Tabela abaixo:

unsigned char x; x a cada execução da sentença Valor de xx = 7; 00000111 7

x = x « 1; 00001110 14x = x « 3; 01110000 112x = x « 2; 11000000 192x = x » 1; 01100000 96x = x » 2 00011000 24

2.10 Prioridade das Operações

As operações demonstradas possuem prioridades de execução quando são agrupadas.Abaixo segue a ordem de prioridade das operações (iniciam pelas maiores prioridades).

() []! ˜ ++ – ++ (tipo) * &

* / %+ -« »

< <= > >=== !=

&ˆ!

&&!!

= += -= *= /=

Page 19: Apostila Linguagem C

19

2.11 Operações de entrada e saída

printfscanfsprintf e sscanfAs funções que resumem todas as funções de entrada e saída formatada no C são as

funções printf() e scanf(). Um domínio destas funções é fundamental ao programador.

2.11.1 printf

Protótipo:int printf (char *str,...);As reticências no protótipo da função indicam que esta função tem um número de

argumentos variável. Este número está diretamente relacionado com a string de controlestr, que deve ser fornecida como primeiro argumento. A string de controle tem doiscomponentes. O primeiro são caracteres a serem impressos na tela. O segundo são oscomandos de formato. Como já vimos, os últimos determinam uma exibição de variáveisna saída. Os comandos de formato são precedidos de %. A cada comando de formatodeve corresponder um argumento na função printf(). Se isto não ocorrer podem acontecererros imprevisíveis no programa. Abaixo apresentamos a tabela de códigos de formato:

Código Formato%c Um caracter (char)

%d e %i Um número inteiro decimal (int)%e Número em notação científica com o "e"minúsculo%E Número em notação científica com o "e"maiúsculo%f Ponto flutuante decimal%g Escolhe automaticamente o melhor entre %f e %e%G Escolhe automaticamente o melhor entre %f e %E%o Número octal%s String%u Decimal "unsigned"(sem sinal)%x Hexadecimal com letras minúsculas%X Hexadecimal com letras maiúsculas%% Imprime um %%p Ponteiro

Exemplo:

Código Imprimeprintf ("Um %%%c %s",’c’,"char"); Um %c charprintf ("%X %f %e",107,49.67,49.67); 6B 49.67 4.967e1printf ("%d %o",10,10); 10 12

É possível também indicar o tamanho do campo, justificação e o número de casasdecimais. Para isto usa-se códigos colocados entre o % e a letra que indica o tipo deformato.

Um inteiro indica o tamanho mínimo, em caracteres, que deve ser reservado para asaída. Se colocarmos então %5d estamos indicando que o campo terá cinco caracteres decomprimento no mínimo. Se o inteiro precisar de mais de cinco caracteres para ser exibido

Page 20: Apostila Linguagem C

20

então o campo terá o comprimento necessário para exibi-lo. Se o comprimento do inteirofor menor que cinco então o campo terá cinco de comprimento e será preenchido comespaços em branco. Se se quiser um preenchimento com zeros pode-se colocar um zeroantes do número. Temos então que %05d reservará cinco casas para o número e se estefor menor então se fará o preenchimento com zeros.

O alinhamento padrão é à direita. Para se alinhar um número à esquerda usa-se umsinal - antes do número de casas. Então %-5d será o nosso inteiro com o número mínimode cinco casas, só que justificado a esquerda.

Pode-se indicar o número de casas decimais de um número de ponto flutuante. Porexemplo, a notação %10.4f indica um ponto flutuante de comprimento total dez e com 4casas decimais. Entretanto, esta mesma notação, quando aplicada a tipos como inteirose strings indica o número mínimo e máximo de casas. Então %5.8d é um inteiro comcomprimento mínimo de cinco e máximo de oito.

Exemplo:

Código Imprimeprintf("%-5.2f",456.671); |456.67 |printf ("%5.2f",2.671); | 2.67|printf ("%-10s","Ola"); |Ola |

Obs.: O "pipe"( | ) indica o início e o fimdo campo mas não serão escritos na tela.

2.11.2 scanf

Protótipo:int scanf (char *str,...);A string de controle str determina, assim como com a função printf(), quantos parâ-

metros a função vai necessitar. Devemos sempre nos lembrar que a função scanf() devereceber ponteiros como parâmetros. Isto significa que as variáveis que não sejam pornatureza ponteiros devem ser passadas precedidas do operador &. Os especificadores deformato de entrada são muito parecidos com os de printf(). Os caracteres de conversãod, i, u e x podem ser precedidos por h para indicarem que um apontador para short aoinvés de int aparece na lista de argumento, ou pela letra l (letra ele) para indicar que queum apontador para long aparece na lista de argumento. Semelhantemente, os caracteresde conversão e, f e g podem ser precedidos por l para indicarem que um apontador paradouble ao invés de float está na lista de argumento.

Código Formato%c Um caracter (char)

%d e %i Um número inteiro decimal (int)%hi Um short it%li Um long int%e Número em notação científica%f Ponto flutuante decimal%lf Um double%s String%h Inteiro curto%x Hexadecimal com letras minúsculas%p Ponteiro

Page 21: Apostila Linguagem C

21

2.11.3 sprintf e sscanf

sprintf e sscanf são semelhantes a printf e scanf. Porém, ao invés de escreverem nasaída padrão ou lerem da entrada padrão, escrevem ou leem em uma string. Os protótipossão:

int sprintf (char *destino, char *controle, ...);int sscanf (char *destino, char *controle, ...);Estas funções são muito utilizadas para fazer a conversão entre dados na forma numé-

rica e sua representação na forma de strings. No programa abaixo, por exemplo, a variáveli é "impressa"em string1. Além da representação de i como uma string, string1 tambémconterá "Valor de i=".

#include<stdio.h>main(){int i;char string1[20];

printf(“ � nEntre com 1 nros inteiros:”);scanf(“%d”, &i);sprintf(string1,“ Valor de i = %d", i);puts(string1);

}

Já no programa abaixo, foi utilizada a função sscanf para converter a informação ar-mazenada em string1 em seu valor numérico:

#include<stdio.h>main(){int i,j,k;char string1[]=”10 20 30”;

sscanf(string1,"%d %d %d", &i, &j, &k);printf("Valores lidos: %d, %d, %d", i, j, k);

}

2.12 Exercícios

1. Faça um programa que receba dois valores do tipo inteiro e efetue as quatro operaçõesbásicas, mostrando o resultado no final das quatro.

2. Faça um programa que receba o nome do usuário, quatro notas e calcule a média doaluno. A fórmula da média final é: (nota1+2*nota2+3*nota3+4*nota4)/10.

3. Faça um programa que solicite o tamanho do lado de um quadrado e calcule a área domesmo, mostrando o resultado.

Page 22: Apostila Linguagem C

22

4. Programa para calcular a área de um triângulo. Receber a informação da base e daaltura em centímetros. Ao final do programa além de mostrar o resultado da áreacalculada, listar também o calculo para 5 figuras maiores cujas dimensões são odobro da anterior e 5 figuras menores cujas dimensões são a metade da anterior,partindo da base e altura informadas.

5. Faça um programa que solicite a data atual e a data de nascimento do usuário e cal-cule a sua idade em dias. Obs.: Para saber se um ano é bissexto (366 dias),use a segunte formula: � � _ � � � � ��� � ��� ����� ��������� � ���� ����� � ���������� ����������� ������������� �����

6. Programa para conversão de moedas. Inicialmente ler o valor da cotação de 1 dolarpara Real. A seguir pedir o valor em dolar e responder o valor convertido para Real.

Page 23: Apostila Linguagem C

23

3 COMANDOS DE CONTROLE E REPETIÇÃO

3.1 if/else

Execução condicional de comandos. A instrução if causa a execução de uma ou deum conjunto de instruções, dependendo do valor resultante de uma expressão avaliada.

Sintaxe:if (expressão)

comando1;[else][comando2; ]Se a expressão for verdadeira, executa o comando1, caso contrário executa o co-

mando2. Se comando1 ou comando2 tiverem mais de uma instrução deve-se criar blocosusando e .

Exemplo:

if (n != 0)x = a*b/n;

else {n = x*x;x = a*b/n;

}

As instruções de execução condicional dependem da avaliação de uma expressão con-dicional. Esta expressão é composta por várias operações, que são efetuadas através dosoperadores lógicos e relacionais (ou mesmo atribuições e operações matemáticas), devol-vendo um valor booleano TRUE ou FALSE. O C não possui o tipo boolean e não atribuiconceito abstrato para VERDADEIRO e FALSO. Para o C V ou F é representado por umvalor inteiro, com o seguinte significado:

0 - FALSO (FALSE),Não Zero - VERDADEIRO (TRUE).Ou seja, para o C, o valor 0 é considerado FALSO, enquanto que todos os demais va-

lores (-1, 1, 2, 1000, -1000, etc) são considerados VERDADEIROS. Quando o C precisaCALCULAR uma expressão, atribuindo o conceito de V ou F, ele usará SEMPRE o valor1 para Verdadeiro e o valor 0 para FALSO. Assim fica fácil entender o que ocorre nestesexemplos:

Page 24: Apostila Linguagem C

24

main(){int x, y, r;x = 20;y = 10;r = x > y; /* Sim, o x é maior que y. Então esta sentença

é considerada como VERDADEIRA. O C irá avaliar ela comotendo resultado 1 (VERDADEIRO). r recebe 1, portanto */

if (x){ // x vale 20. 20 para o C é conceito de VERDADEIRO.

r = 0;}r = y + ((x>y) && (y > 0));

/* complicou, não? Temos uma sentença AND que serácalculada como sendo VERDADEIRA (1) ou FALSA (0).Como x é maior que y (V, 1) e y é maior que 0 (V),a sentença (x>y) && (y > 0) é VERDADEIRA,valendo 1. y + 1 = 11. r receberá 11.*/

}

Devido à clausula else ser opcional, pode existir uma ambigüidade no uso de ifelseaninhado. O compilador resolve isto associando o else ao último if sem else. Por exemplo:

if (n>0)if (a>b)

z=a;else

z=b;

Se a>b, então z=a, quando n>0. Se a<=b, então z=b, quando n>0. Se n<=0, o valor dez não será alterado nesta porção de código.

Entretanto se tivermos:

if (n>0){

if (a>b)z=a;

}else

z=b;

Se a>b, então z=a, quando n>0. Se n<=0, então z=b. Se n>0 e a<=b, o valor de z nãoserá alterado nesta porção de código.

Page 25: Apostila Linguagem C

25

3.2 while

Enquanto a condição descrita pela expressão for satisfeita (ou seja, verdadeira), ocomando será repetido. O comando somente será executado se a expressão condicionalfor verdadeira. A avaliação da expressão é realizada da mesma forma que no comandoif. O comando while é o único e o principal comando de repetição realmente necessário,sendo que pode substituir qualquer outra construção do tipo: for, repeat/until, do/while,goto ...).

Sintaxe:while (expressão)

comando1;Exemplo: contagem de bits setados na variável n.

bits = 0;while (n != 0){

if (n & 1)bits++;

n »= 1; }

Exemplo: imprimir os números impares de 3 até 21 (inclusive).

i = 3;while ( i <= 21 ){

printf(“%d � n”, i);i = i + 2; }

3.3 for

O comando for serve para a execução de um número fixo de vezes (ou não), enquantouma variável percorre uma determinada faixa de valores. Esta variável é chamada devariável de índice.

Sintaxe:for (inicio; condição; modific)

comando;Onde temos "início"como sendo uma expressão que irá gerar o valor inicial da va-

riável de índice utilizada pelo comando. A "condição"irá indicar uma condição para oprosseguimento do laço (enquanto tal condição for verdadeira irá repetir o laço). E final-mente "modific"será o comando dado a cada execução do laço, sendo este realizado aofinal de um laço do for, modificando o valor da variável de índice, antes de um novo testeda condição. Cada um destes elementos (início, condição e comando) pode ainda estardividido em séries de comandos, como nas expressões do if.

Exemplo: números ímpares de 3 a 21, com for:

for (i = 3; i <= 21; i = i+2)printf("%d � n", i);

Page 26: Apostila Linguagem C

26

Para criarmos um laço infinito (sem fim) podemos fazer um comando da seguinteforma: for(;;) - comando sem expressões de controle. O comando for é equivalente aseguinte estrutura:

while (condição){

comando;modific;

}

3.4 do/while

O comando do/while é o inverso do comando while, ou seja, o teste é executado aofinal deste ao invés de ser no início. Este comando também é equivalente ao comandorepeat/until (Pascal) só que a expressão avaliada em um estaria negada em relação aooutro.

Sintaxe:do comando; } while (expressão);O comando será executado e depois será testada a condição dada pela expressão, e

caso esta seja verdadeira (TRUE) será novamente executado o comando.

3.5 Break e Continue

Break causa a saída no meio de um laço (para comandos: for, while, do/while, switch).Provoca a antecipação do fim do laço. É muito usado com o comando case como será vistomais adiante. Continue serve para a re-execução do laço, a partir do teste. Irá causar areinicialização do laço (não funciona com o switch). Um exemplo prático do seu uso podeser visto no exemplo a seguir:

while ( x <= valmax){

printf ("Entre com um valor:");scanf ("%d",&val);if (val < 0)continue;

}

3.6 switch/case

Faz uma associação de valores com comandos a executar. Conforme o valor dado,executa um certo número de instruções. Serve como uma estrutura mais sofisticada queos if’s encadeados.

Sintaxe:switch (variável)

{case <valor1> : <comando1>;case <valor2> : <comando2>;

Page 27: Apostila Linguagem C

27

<comando3>;...

[ default : comando4; ]}

No comando switch não é possível definir intervalos para os quais o comando seráexecutado, temos que definir os valores textualmente, um a um. Os valores utilizados nocase devem ser do tipo inteiro ou char.

O uso do comando break é muito importante quando associado ao switch, pois casoeste não seja usado a cada case, será feita a execução de todos os comandos até encontraro fim do switch, sendo executado inclusive o default, se houver. Por isso a estruturacomumente usada em um comando case é:

case ’A’:x++;break;

case ’b’:case ’B’:

y++;break;

...

3.7 Expressões Condicionais

As expressões condicionais se apresentam da seguinte forma:expr1 ? expr2 : expr3Esta expressão é equivalente a:se expr1 // Onde: expr1 -> Condição de teste expr2 // expr2/expr3 -> Valor

retornado senão expr3Portanto expr2 será o valor calculado se expr1 for verdadeiro e expr3 será o valor

calculado se expr1 for falso.Exemplo:b = ((x == y)?x:y);

3.8 Exercícios:

1. Escrever um programa que solicite dois numeros ao usuário. O programa deve compa-rar os valores e imprimir na tela os dois números digitados, a soma deles, o maior eo menor deles.

2. Escrever um programa que recebe três numeros inteiros (a, b e cod) e imprima na tela:

a+b, se cod >= 0;

a-b, se cod < 0.

3. Fazer uma função que receba um número (do teclado) e retorne o fatorial deste número(exemplo 5!= 5*4*3*2*1;), usando comandos de repetição (Lembre que os fatoriaisde 0 e de 1 são iguais a 1). Deve pedir para o usuário repetir a entrada se o númeroque ele digitou for negativo. Deve ser capaz de calcular fatoriais maiores que 65535,limite para um inteiro.

Page 28: Apostila Linguagem C

28

4. Faça um programa completo que leia do teclado 10 números inteiros e depois imprima:

a) A soma de todos os elementos

b) O maior e o menor elemento

5. Escrever um trecho de código, usando atribuição condicional, que teste o conteúdo deduas variáveis e atribua o maior valor a uma terceira variável.

6. Faça um programa para calcular o valor de � , dado por:

��� � ����� � � � ������ � � � ���� � � ����� � � �� �� � ��

onde n é fornecido pelo usuário;

7. Escreva um programa que lê um valor � inteiro e positivo, logo em seguida, calcule eescreve o valor de � , dado por:

� � � � � ����� � ����� � ����� � � ��� � ���8. O valor aproximado de � pode ser calculado usando a série:

� � � � � ����� �� � ����� � � ����� �� � ����� �� � � �Sendo � � � � � �!��#"�$ � , implemente um programa que calcule o valor de � , baseadonos n primeiros elementos dessa série. O n deve ser informado pelo usuário, quantomaior esse numero, mais preciso será o valor de � .

9. Escreva um programa que apresente a série de Fibonacci até o n-ésimo elemento, esselimite deve ser informado pelo usuário. A série de Fibonacci é formada pela sequên-cia: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

10. O que faz o trecho de código a seguir?

int a,b,c;

...

c = (a>=0)?(b>=0):(b<0);

Page 29: Apostila Linguagem C

29

4 MATRIZES

Uma matriz é uma coleção de variáveis do mesmo tipo, e esta é referenciada por umnome comum. Cada elemento de uma matriz é acessado através de um índice. O índice0 corresponde ao primeiro elemento de uma matriz, e o índice mais alto, representa oúltimo elemento de uma matriz.

Basicamente existem alguns tipos de matrizes:

� Matrizes Unidimensionais: São matrizes de apenas uma dimensão, e são geral-mente chamadas de vetores ou listas (estáticas).

� Matrizes Bidimensionais: São matrizes de duas dimensões.

� Matrizes Multidimensionais: São matrizes de n dimensões.

A forma geral de se declarar uma matriz unidimensional é:tipo nomevar [tamanho];

Por exemplo, se quisermos declarar um vetor (matriz unidimensional) com o nometeste que armazena 10 número inteiros, teríamos que definir o tipo (int) e o tamanho dovetor (10). Ressalva-se que o primeiro índice de um vetor em C sempre será o 0. Ou seja,os índices deste vetor iriam de 0 a 9, onde têm-se 10 posições. A declaração do vetorficaria assim: int teste[10];

Criando um vetor de 3 posições do tipo double, pode-se analisar como fazer o acessoa cada índice. Vejamos:

Exemplo 1:

main(){double vetor[3];vetor[0]=3.9;vetor[1]=4.9;vetor[2]=0.7;printf("O valor do primeiro elemento eh:%lf � n",vetor[0]); /*Sera impresso 3.9*/printf("O valor do ultimo elemento eh:%lf � n",vetor[2]); /*Sera impresso 0.7*/

}

Quando o C vê uma declaração como esta ele reserva um espaço na memória sufi-cientemente grande para armazenar o número de células especificadas em tamanho. Porexemplo, se declararmos:

Page 30: Apostila Linguagem C

30

float exemplo [20];O compilador C reservará 4x20=80 bytes. Estes bytes são reservados de maneira

contígua. Além disso, C não verifica se o índice que você usou está dentro dos limitesválidos. Este é um cuidado que você deve tomar.

Se o programador não tiver atenção com os limites de validade para os índices elecorre o risco de ter variáveis sobrescritas ou de ver o computador travar. Logo, o programairá compilar e executar se você programou algo, como: exemplo[400]=32;.

Para verificarmos a funcionalidade dos vetores, vamos analisar mais um exemplo.Exemplo 2:

#include <stdio.h>main (){int num[100]; /* Declara um vetor de inteiros de 100 posicoes */int count=0;int totalnums;do{printf (" � nEntre com um numero (-999 p/ terminar):");scanf ("%d",&num[count]);count++;

} while (num[count-1]!=-999);totalnums=count-1;printf (" � n Os números que você digitou foram: � n");for (count=0;count<totalnums;count++)printf ("%d � n",num[count]);

}

No exemplo acima, o inteiro count é inicializado em 0. O programa pede pela entradade números até que o usuário entre com o Flag -999. Os números são armazenados novetor num. A cada número armazenado, o contador do vetor é incrementado para napróxima iteração escrever na próxima posição do vetor. Quando o usuário digita o flag,o programa abandona o primeiro loop e armazena o total de números gravados. Por fim,todos os números são impressos. É bom lembrar aqui que nenhuma restrição é feitaquanto a quantidade de números digitados. Se o usuário digitar mais de 100 números,o programa tentará ler normalmente, mas o programa os escreverá em uma parte nãoalocada de memória, pois o espaço alocado foi para somente 100 inteiros. Isto poderesultar nos mais variados erros no instante da execução do programa.

4.1 Strings

Strings são vetores de caracteres, chars. As strings são o uso mais comum para osvetores. As strings têm o seu último elemento como um ’ � 0’. A declaração geral parauma string é: char nome-da-string [tamanho];

Uma constante string é uma lista de caracteres entre aspas. Por exemplo: ”Oi Mundo”.Neste caso, não é necessário adicionar o nulo no final das constantes strings manualmente

Page 31: Apostila Linguagem C

31

(o compilador faz isso para você).É possível solicitar ao usuário uma determinada string e sua leitura pode ser feita de

duas formas: utilizando a função scanf ou utilizando a função gets. Porém, a função scanftem alguma dificuldade em lidar com os espaços no meio de uma string, por isso vamosutilizar a função gets. Abaixo segue um exemplo para entrada de strings.

Exemplo 3:

#include <stdio.h>main (){char string1[100], string2[100];printf (" � n Digite o seu nome: ");gets (string1);printf (" � n Digite o seu sobrenome: ");gets (string2);printf (" � n Seu nome completo eh: %s %s � n",string1,string2);

}

Existem diversas funções para trabalharmos com strings, estas necessitam que no ca-beçalho seja declarada a biblioteca <string.h>.

A tabela 4.1 apresenta as principais funções de manipulação e tratamento de strings:

Nome Funçãostrcpy(s1,s2) Copia s2 em s1.strcat(s1,s2) Concatena s2 ao final de s1.strlen(s1) Retorna o tamanho de s1.strcmp(s1,s2) Retorna 0 se s1=s2; menor que 0 se s1<s2; maior que 0 se s1>s2.strchr(s1,ch) Retorna um ponteiro para a primeira ocorrência de ch em s1.strstr(s1,s2) Retorna um ponteiro para a primeira ocorrência de s2 em s1.

Tabela 4.1: Manipulação de Strings

Abaixo segue um exemplo de utilização de algumas funções, as quais utilizam a bi-blioteca string.h. Cabe ressaltar que existem ainda diversas funções já desenvolvidas asquais fazem parte da biblioteca. No exemplo, o conteúdo da string s1 é lido do usuário,e o conteúdo de s2 é atribuído através da função strcpy. A função strlen irá imprimir otamanho de cada string, e a função strcmp irá comparar se os conteúdos de s1 e s2 estãoiguais.

Page 32: Apostila Linguagem C

32

Exemplo 4:

#include<stdio.h>#include<string.h>main(){char s1[80],s2[80];printf (" � n Digite uma string qualquer: ");gets(s1);strcpy(s2,"Programa Exemplo");printf(s2);printf(" � n Tamanho: %d %d",strlen(s1),strlen(s2));if (!strcmp(s1,s2))printf(" � n As strings são iguais � n");

else printf (" � n As strings são diferentes! � n");}

4.2 Matrizes Bidimensionais

Quando trabalha-se com C sabe-se que este suporta matrizes multidimensionais. Asmatrizes bidimensionais são a forma mais simples das matrizes multidimensionais.

A forma geral de se declarar uma matriz unidimensional é:tipo nomevar [linha][coluna];É muito importante ressaltar que, nesta estrutura, o índice da esquerda indexa as linhas

e o da direita indexa as colunas.Quando vamos preencher ou ler uma matriz no C o índice mais à direita varia mais

rapidamente que o índice à esquerda.Mais uma vez é bom lembrar que, na linguagem C, os índices variam de zero ao valor

declarado, menos um; mas o C não vai verificar isto para o usuário. Manter os índices nafaixa permitida é tarefa do programador.

Se declararmos int num[4][3], e inicializarmos toda a matriz com o conteúdo zero eapenas a posição 1,2 recebesse um valor diferente (num[1][2]=9;), a matriz poderia sermostrada assim:

0 0 00 0 90 0 00 0 0

Abaixo damos um exemplo do uso de uma matriz, onde a matriz mtrx é preenchida,seqüencialmente por linhas, com os números de 1 a 200.

Page 33: Apostila Linguagem C

33

Exemplo 5:

#include <stdio.h>main (){int mtrx [20][10];int i,j,count;count=1;for (i=0;i<20;i++)for (j=0;j<10;j++){mtrx[i][j]=count;count++;printf(" � n Linha:%d Col:%d INT:%d � n",i,j,mtrx[i][j]);

}}

4.3 Matrizes de Strings

Matrizes de strings são matrizes bidimensionais. Se fizermos um vetor de stringsestaremos fazendo uma lista de vetores.

Esta estrutura é uma matriz bidimensional de chars. Podemos ver a forma geral deuma matriz de strings como sendo:

char nome [nrodestrings][compr-das-strings];Para acessar cada string basta usar apenas o primeiro índice. Então, para acessar uma

determinada string faça:nome [índice]Aqui está um exemplo de um programa que lê 5 strings e as exibe na tela:Exemplo 6:

#include <stdio.h>main (){char strings [5][100];int count;for (count=0;count<5;count++){printf (" � n Digite uma string: ");gets (strings[count]);

}printf (" � n As strings que voce digitou foram: � n");for (count=0;count<5;count++)printf ("%s � n",strings[count]);

}

4.4 Matrizes Multidimensionais

O uso de matrizes multidimensionais na linguagem C é simples. Sua forma geral é:

Page 34: Apostila Linguagem C

34

tipo nome [tam1][tam2] ... [tamN];Uma matriz N-dimensional funciona basicamente como outros tipos de matrizes. Basta

lembrar que o índice que varia mais rapidamente é o índice mais à direita.

4.5 Inicialização de Matrizes

Podemos inicializar matrizes, assim como podemos inicializar variáveis. A formageral de uma matriz como inicialização é:

tipo nome [tam1][tam2] ... [tamN] = {lista-de-valores};A lista de valores é composta por valores (do mesmo tipo da variável) separados por

vírgula. Os valores devem ser dados na ordem em que serão colocados na matriz. Abaixovemos alguns exemplos de inicializações de matrizes:

int matrx [3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };char str [10] = { ’J’, ’o’, ’a’, ’o’, ’ � 0’};char strvect [3][10] = { "Joao", "Maria", "Jose"};

4.6 Exercícios:

1. A avaliação em um colégio é feita através de 3 notas. Como a turma é pequena, existemapenas 4 alunos inscritos. Faça um programa que receba as notas dos 4 alunos eindique a média de cada um deles, mostrando as suas notas individualmente. Depoisdisso, o programa ainda deve indicar a maior média.

2. Faça um programa que tenha um vetor de 20 posições de inteiros positivos. Este devereceber do usuário os valores, validá-los e armazená-los. O programa deve apenasimprimir na tela os números inseridos em posições de índices ímpares do vetor.

3. Faça um programa que recebe 8 números e o armazene em um vetor (entrada). Apósa leitura dos números, deve ser armazenado em outro vetor a raiz quadrada de cadanúmero do vetor de entrada. Imprima as raizes na tela.

4. Fazer o programa que leia o nome do usuário e diga quantas letras este nome tem.

5. Fazer um programa que recebe duas palavras e diz se estas strings são iguais.

6. Fazer um programa que recebe quatro nomes e diz quantos deles começam com a letra’L’ e quantos com a letra ’T’.

7. Fazer um programa que recebe separadamente o primeiro nome, o segundo nome e oúltimo nome de uma pessoa. O programa deve concatenar estes nomes e imprimi-lono final.

8. Fazer o programa que leia uma matriz 4x4 e imprima a média dos elementos.

9. Fazer o programa que leia uma matriz 6x6 e imprima a média dos elementos da diago-nal principal (linha=coluna) e também a média dos elementos da diagonal secundá-ria (linha + coluna == nro_de_linha ).

10. Fazer um programa que recebe uma matriz A 2x2 e uma matriz B 2x2, e crie umaterceira matriz C 2x2, a qual é composta pelos elementos multiplicados de AB.

Page 35: Apostila Linguagem C

35

11. Fazer uma programa que gere (sem o usuário digitá-la) e imprima na tela a seguintematriz:

1 1 1 1 1 11 2 2 2 2 11 2 3 3 2 11 2 3 3 2 11 2 2 2 2 11 1 1 1 1 1

Page 36: Apostila Linguagem C

36

5 ESTRUTURAS DEFINIDAS PELO USUÁRIO

5.1 Estruturas

Matrizes são estruturas de dados homogêneos, isto é, podem conter coleções de dadosdo mesmo tipo (todos int, todos float, todos char). Na vida real encontramos muitassituações onde temos coleções de dados que são de tipos diferentes. Como exemplotemos uma ficha de cadastro de funcionário, uma cédula de identidade, uma inscrição emuma concurso, uma cadastro de usuário em um site, etc.

Num cadastro de usuário temos dados como nome, endereço, telefone, e-mail, datade nascimento, entre outros. Pode-se notar que esses dados são de tipos diferentes. Paraagrupar esses dados não nos serve uma matriz. Há necessidade de uma estrutura de dadosheterogêneos, definida pelo usuário.

As estruturas (struct) são agrupamentos de dados, que definem um novo tipo de dadomais complexo, formado por tipos de dados mais simples.

struct nome_do_tipo_da_estrutura {tipo-var nome-var;tipo-var nome-var2;

...}variáveis_estrutura;

O nome_do_tipo_da_estrutura é o nome para a estrutura. As variáveis_estrutura sãoOPCIONAIS e seriam nomes de variáveis que o usuário já estaria declarando e que seriamdo tipo nome_do_tipo_da_estrutura.

Exemplo:

struct data {int dia;int mes;int ano;int dia_ano;char nome-mes[10];

};

struct data hoje;

A utilização de estruturas no C é semelhante ao record do pascal.Referência a um elemento da estrutura:

Page 37: Apostila Linguagem C

37

nome_estrut.elemento —> hoje.dia = 23;

Exemplo 2:

#include <stdio.h>#include <string.h>

��� _____estrutura de endereço:struct tipo_endereco {char rua [50];int numero;char bairro [20];char cidade [30];char sigla_estado [3];long int CEP;

};

� *Estrutura ficha_pessoalpara adicionar os dados pessoais de alguém:* �struct ficha_pessoal {char nome [50];long int telefone;struct tipo_endereco endereco;};

��� _____Programa Principal____void main (void){struct ficha_pessoal ficha;strcpy(ficha.nome,"Luiz Osvaldo Silva");ficha.telefone=33332234;strcpy(ficha.endereco.rua,"Rua dos Flores");ficha.endereco.numero=10;strcpy(ficha.endereco.bairro,"Menino Deus");strcpy(ficha.endereco.cidade,"Porto Alegre");strcpy(ficha.endereco.sigla_estado,"RS");ficha.endereco.CEP=90000000;

}

Esse programa declara uma variável ficha do tipo ficha_pessoal e preenche os seus da-dos. O exemplo mostra como podemos acessar um elemento de uma estrutura: basta usaro ponto (.). Assim, para acessar o campo telefone de ficha, escrevemos: ficha.telefone= 33332234; Como a struct ficha pessoal possui um campo, endereço, que também éuma struct, podemos fazer acesso aos campos desta struct interna da seguinte maneira:ficha.endereco.numero = 10; ficha.endereco.CEP=90000000; Desta forma, estamos aces-sando, primeiramente, o campo endereco da struct ficha e, dentro deste campo, estamosacessando o campo numero e o campo CEP.

Características das estruturas:

Page 38: Apostila Linguagem C

38

� Não podem ser inicializadas na declaração ou copiadas através de atribuição;

� Podem ser acessadas com o auxílio de pointers. Permitem a criação de listas enca-deadas.

Também podem ser declarados matrizes de estruturas, da mesma forma que uma ma-triz de inteiros ou caracteres. A forma de acesso é semelhante:

struct data st[10]; /*um vetor da estrutura de 10 elementos */

st[0].dia=2;sprintf(st[0].nome_mês, "Janeiro");...

5.1.1 Exercícios

a) Faça um programa que define um tipo para alunos com os seguintes campos: nome(20 caracteres), código (10 caracteres), notas de 3 provas e média final. O programadeverá ler da entrada padrão os dados de 4 alunos, calcular a média individual decada aluno e a média geral dos alunos.

b) Modifique o exercício anterior, mas permita que o usuário forneça antes o númerototal de alunos que deseja digitar.

c) Considere uma bilhete de passagem de ônibbus, conforme mostrado na tabela 5.1. Pri-meiro - Defina uma estrutura de dados de nome Passagem. Segundo - Considerandouma onibus de 48 lugares, defina um vetor de Passagens.

VIAÇÃO MONTENEGRO S/A

Número:______ Nome da Empresa:___________Origem:___________________ Destino:___________________Data: __ � __ � ____ Horário:____:____Assento:______ Distância: ____kmValor da Passagem: R$____________

Tabela 5.1: Bilhete de passagem

5.2 Uniões

Uma declaração union determina uma única localização de memória onde podemestar armazenadas várias variáveis diferentes. A declaração de uma union é semelhante àdeclaração de uma estrutura:

Page 39: Apostila Linguagem C

39

union nome_do_tipo_da_union {tipo_1 nome_1;tipo_2 nome_2;...tipo_n nome_n;

} variaveis_union;

Como exemplo, vamos considerar a seguinte união:

union angulo {float graus;float radianos;

};

Nela, temos duas variáveis (graus e radianos) que, apesar de terem nomes diferentes,ocupam o MESMO local da memória. Isto quer dizer que só gastamos o espaço equiva-lente a um único float. Uniões podem ser feitas também com variáveis de diferentes tipos.Neste caso, a memória alocada corresponde ao tamanho da maior variável no union. Vejao exemplo:

#include <stdio.h>#define GRAUS ’G’#define RAD ’R’union angulo {int graus;float radianos;

};

main(){union angulo ang;char op;printf(" � n Numeros em graus ou radianos? (G/R):");scanf("%c",&op);if (op == GRAUS) {

ang.graus = 180;printf(" � nAngulo: %d � n",ang.graus);

}else if (op == RAD){

ang.radianos = 3.1415;printf(" � nAngulo: %f � n",ang.radianos);

}else printf(" � nEntrada invalida!! � n");

}

Page 40: Apostila Linguagem C

40

5.3 Enumerações

Numa enumeração podemos dizer ao compilador quais os valores que uma determi-nada variável pode assumir. Sua forma geral é:

enum nome_do_tipo_da_enumeração{lista_de_valores

} lista_de_variáveis

Exemplo:

#include <stdio.h>

enum dias_da_semana {segunda,terca,quarta,quinta,sexta,sabado,domingo};

main(){enum dias_da_semana d1,d2;d1=segunda;d2=sexta;if (d1==d2)

printf (“O dia é o mesmo”);else printf (“São dias diferentes”);

}

Você deve estar se perguntando como é que a enumeração funciona. Simples, o com-pilador pega a lista que você fez de valores e associa, a cada um, um número inteiro.Então, ao primeiro da lista, é associado zero, ao segundo 1 e assim por diante. As variá-veis declaradas são então variáveis inteiras.

Page 41: Apostila Linguagem C

41

6 FUNÇÕES

6.1 Modularidade

Modularidade é a técnica de programar, desenvolvendo um programa a partir de pe-quenas partes ou módulos. Em C, construir um módulo significa construir uma função.

Inicialmente, modularizar um programa parece dificultar a programação. Mas o queacontece no desenvolver de qualquer programa é o contrário. As vantagens de se modula-rizar são: economia de tempo de criação do programa, economia de tempo de manutençãodo programa, reutilização de módulos, organização do código e construção de bibliotecas.

6.2 Forma de uma Função

Funções são blocos de construção de C e o local onde toda atividade ou tarefa doprograma se realiza. A forma geral de uma função é:

especificador_do_tipo nome_da_função (lista de parâmetros){corpo da função

}

O especificador_de_tipo especifica o tipo de valor que o comando return da funçãoirá devolver. Se nenhum tipo é especificado, o compilador assume que a função devolveum inteiro. A lista de parâmetros indica o nome das variáveis e seus tipos associados.Estas são separadas por vírgula e e indicam os argumentos da função. A declaração deparâmetros é uma lista com a seguinte forma geral:

tipo nome1, tipo nome2, ... , tipo nomeN

No corpo da função as entradas são processadas, saídas são geradas, ou seja, toda atarefa corresponde desta função.

Abaixo segue um exemplo de criação de uma função em C. Neste exemplo, a funçãorecebe um número x e imprime a raiz quadrada do mesmo.

Page 42: Apostila Linguagem C

42

#include<stdio.h>#include<math.h>void raiz(double x){printf("%lf",sqrt(x));

}main(){double nro;printf("Digite um numero");scanf("%lf",&nro);raiz(nro);

}

6.3 Regras de Escopo

As regras de escopo de uma linguagem são as regras que governam se uma porção decódigo conhece ou tem acesso a outra porção de código ou dados. Ou seja, o escopo é oconjunto de regras que determinam o uso e a validade de variáveis nas diversas partes doprograma.

Para trabalharmos corretamente com as regras de escopo, cabe lembrar o conceito devariáveis locais e variáveis globais. Variáveis locais são aquelas têm validade dentro dobloco no qual são declaradas, ou seja, só existem enquanto o bloco está sendo executado.No caso de criarmos uma variáveil dentro de uma função, esta só será acessível dentrodesta função e poderemos chamar ela de variável local a função. Já as variáveis globaissão aquelas declaradas fora das funções do programa, e são acessíveis através de todos osmódulos do programa. Estas são alocadas no início do programa, e só são desalocadas notérmino do mesmo.

6.4 Argumentos de Funções

Se uma função utiliza argumentos, é necessário declarar as variáveis que aceitem osvalores dos argumentos. Estas variáveis são chamadas de parâmetros formais da função,se comportando como variáveis locais dentro da mesma. Estas são alocadas no início deuma função, e desalocadas na sua saída.

É importante salientar que os parâmentros devem ser passados na ordem respectivae compatibilidade. Foi implementado um exemplo simples, para verificarmos a impor-tância da passagem de parâmetros. Temos uma função que calcula a diferenca entre doisnúmeros, e imprime na tela. Vejamos o exemplo:

Page 43: Apostila Linguagem C

43

#include<stdio.h>void diferenca(int x, int y){printf("%d",x-y);

}main(){diferenca(10,0); /*Imprimirá 10 na Tela*/diferenca(0,10); /* Imprimirá -10 na Tela*/

}

6.5 O Comando return

O comando return é utilizado dentro das funções visando devolver um determinadovalor para a outra função que chamou a função corrente. Quando se chega a uma decla-ração return a função é encerrada imediatamente e, se o valor de retorno é informado, afunção retorna este valor.

É importante lembrar que o valor de retorno fornecido tem que ser compatível com otipo de retorno declarado para a função. Uma função pode ter mais de uma declaraçãoreturn. Isto se torna claro quando pensamos que a função é terminada quando o programachega à primeira declaração return. Abaixo está um exemplo de uso do return:

#include <stdio.h>int Square (int a){return (a*a);

}main (){int num;printf ("Entre com um numero: ");scanf ("%d",&num);num=Square(num);printf ("O seu quadrado vale: %d",num);

}

6.6 Funções do Tipo void

Um dos usos de void é declarar explicitamente funções que não devolvem valores.Podemos analisar a funcionalidade do void observando o programa abaixo:

Page 44: Apostila Linguagem C

44

#include <stdio.h>void Mensagem (void){printf ("Ola! Eu estou vivo.");

}int main (){Mensagem();printf ("Diga de novo:");Mensagem();return 0;

}

No exemplo acima, chama-se duas vezes a função Mensagem. Esta é declarada pararetornar um tipo void, ou seja, não retornar valor nenhum, apenas imprimir uma mensa-gem. Além disso, dentro da lista de parâmetros passamos ainda o tipo void, que siginificaque nenhum valor será passado por parâmetro também.

6.7 Passagem por Parâmetros

Sabemos que as funções em C recebem variáveis por parâmetros. Existem basica-mente duas maneiras de passarmos estes argumentos para as sub-rotinas.

6.7.1 Chamada por Valor

Portanto, quando chamamos uma função os parâmetros formais da função copiam osvalores dos parâmetros que são passados para a função. Estes viram variáveis locais,assim quaisquer alterações feitas nestas variáveis não têm nenhum efeito nas variáveisusadas para chamá-la. Isto ocorre porque são passados para a função apenas os valoresdos parâmetros e não os próprios parâmetros. Vamos analisar o exemplo abaixo:

#include <stdio.h>float sqr (float num){num=num*num;return num;

}void main (){float num,sq;printf ("Entre com um numero: ");scanf ("%f",&num);sq=sqr(num);printf ("O numero original e: %f",num);printf ("O seu quadrado vale: %f",sq);

}

Neste exemplo, a função sqr eleva ao quadrado o float num passado por parâmetro. Afunção utiliza o próprio num (parâmetro) para realizar o cálculo. Como a passagem por

Page 45: Apostila Linguagem C

45

parâmetro foi feita por valor, o valor de num não será alterado quando voltar a funçãomain. Logo, este parâmetro funciona como uma variável local dentro da função, pois ovalor num da função principal foi copiado para a variável num da função sqr.

6.7.2 Chamada por Referência

Neste tipo de chamado os parâmetros podem ser alterados dentro da função, mantendoeste valor para a função que o chamou. Este nome vem do fato de que, neste tipo dechamada, não se passa para a função os valores das variáveis, mas sim suas referências (afunção usa as referências para alterar os valores das variáveis fora da função).

O C só faz chamadas por valor. Isto é bom quando queremos usar os parâmetros for-mais à vontade dentro da função, sem termos que nos preocupar em estar alterando osvalores dos parâmetros que foram passados para a função. Mas isto também pode serruim às vezes, porque podemos querer mudar os valores dos parâmetros fora da funçãotambém. O C++ tem um recurso que permite ao programador fazer chamadas por refe-rência (deve-se utilizar o compilador g++ para isto). Há entretanto, no C, um recurso deprogramação que podemos usar para simular uma chamada por referência.

Quando queremos alterar as variáveis que são passadas para uma função, nós pode-mos declarar seus parâmetros formais como sendo ponteiros. Os ponteiros são a "referên-cia"que precisamos para poder alterar a variável fora da função. O único inconveniente éque, quando usarmos a função, teremos de lembrar de colocar um & na frente das variá-veis que estivermos passando para a função.

O que são ponteiros? "Ponteiro é uma variável que contém um endereço de memória.Esse endereço é normalmente a posição de uma outra variável na memória. Se umavariável contém o endereço de memória da outra, então a primeira variável é dita apontarpara a segunda. "

Veja um exemplo:

#include <stdio.h>void Swap (int *a,int *b){int temp;temp=*a;*a=*b;*b=temp;

}void main (void){int num1,num2;num1=100;num2=200;Swap (&num1,&num2);printf ("Eles agora valem %d %d",num1,num2);

}

O que está acontecendo é que passamos para a função Swap o endereço das variáveisnum1 e num2. Estes endereços são copiados nos ponteiros a e b. Através do operador* estamos acessando o conteúdo apontado pelos ponteiros e modificando-o. O conteúdo

Page 46: Apostila Linguagem C

46

nada mais é do que os valores armazenados em num1 e num2, que, portanto, estão sendomodificados!

6.7.3 Matrizes como Argumentos de Funções

Se declaramos uma matriz de 50 posições, existem basicamente três maneiras de pas-sarmos ela por parâmetro para uma função, são elas:

void func (int matrx[50]);void func (int matrx[]);void func (int *matrx);Nos três casos, teremos dentro de func() um int* chamado matrx. Ao passarmos um

vetor para uma função, na realidade estamos passando um ponteiro. Neste ponteiro éarmazenado o endereço do primeiro elemento do vetor. Isto significa que não é feitauma cópia, elemento a elemento do vetor. Isto faz com que possamos alterar o valor doselementos do vetor dentro da função.

Para chamarmos a função func passando a matriz mt2 de 50 posições, podemos seguiro seguinte exemplo:

func(mt2);Muito embora o parâmetro mt2 seja declarado como uma matriz de inteiros, o com-

pilador C converte-o para um ponteiro de inteiros. Portanto, seu endereço é passado paraa função. Neste caso, o código dentro da função estará operando com, e potencialmentealterando, o conteúdo real da matriz usada para chamar a função.

6.8 Protótipos de Funções

Os protótipos permitem indicar ao compilador indicar a existência de funções duranteo código, e quais os tipos dos argumentos que devem se passados. Até agora, nossasfunções sempre foram declaradas antes do main , não necessitando a indicação do seuprotótipo. A sintaxe de um protótipo de função é:

tipo_de_retorno nome_da_função (declaração_de_parâmetros);Vejamos o seguinte exemplo:

#include <stdio.h>float Square (float a);int main (){float num;printf ("Entre com um numero: ");scanf ("%f",&num);num=Square(num);printf ("O seu quadrado vale: %f",num);return 0;

}float Square (float a){return (a*a);

}

Page 47: Apostila Linguagem C

47

6.9 Exercícios

1. Desenvolva uma função, que receba três notas e devolva a sua média.

2. Desenvolva uma função que receba três notas (p1, p2 e p3) e devolva a média noargumento p3.

3. Construa uma função C que recebe, por parâmetro, um valor n, inteiro e positivo, eescreve os seus divisores.

4. Contrua uma função que recebe um vetor de x elementos preenchidos, e ordene ovetor.

5. Desenvolva uma função em C que recebe o gabarito da LOTO e uma aposta (nomáximo 10 dezenas) e devolve o número de pontos da aposta.

6. Desenvolver um algoritmo com uma função que recebe um vetor e sua dimensiãoe devolve o percentual de valores do vetor que são menores do que a média dosvalores deste vetor.

7. Dado a função abaixo, responda:

int func(int n){if (n)return n*func(n-1);

else return 1;}

� O que esta função faz?� O que é recursividade?

Page 48: Apostila Linguagem C

48

7 APONTADORES

Antes de vermos o que são apontadores e como podem ser utilizados no C, vamosfazer uma rápida revisão sobre o conceito de variáveis. Uma variável é mostrada nasdisciplinas de algoritmos como se fosse uma caixa com um nome e esta caixa possui umvalor qualquer.

Teste cont texto209 34 "exemplo"

Bem, esta é uma analogia fácil de entender quando lidamos com algoritmos, masagora devemos entender como as varáveis são realmente implementadas pelas lingua-gens.

Uma variável é nada mais que um nome (label) que referencia (aponta) uma posiçãode memória. A memória pode ser considerada como um array de bytes, sendo que cadapalavra tem um endereço único. Considerando que teste seja do tipo int, cont do tipochar e texto uma string de 10 posições, podemos admitir que os mesmos poderiam estardispostos da seguinte forma em um trecho de memória hipotético que começa no endereço200:

Endereço Valor Nome200 209 teste201 000202 34 cont203 ’e’ texto204 ’x’205 ’e’206 ’m’207 ’p’208 ’l’209 ’o’210 0211 ?212 ?213 ... xx

Temos, então, que um label, ou seja, um nome de variável que aponta para o início deuma área de memória reservada para si, cujo tamanho depende do tipo. Ou seja, para otipo int, são reservados 2 bytes (em algumas arquiteturas são 4 ou mesmo 8 bytes), parao tipo char apenas um e para a string texto, são reservados tantos bytes quantos forem

Page 49: Apostila Linguagem C

49

necessários para satisfazer o tamanho requerido. No momento o texto de exemplo nãoutiliza todos os 10 bytes, sendo que a próxima variável declarada (xx) ocupará a posiçãode memória 213 mesmo assim. No desenho também está representado o uso do 0 comoterminador de uma cadeia de caracteres no C.

Anteriormente, no Capítulo 6, falamos dos operadores "&"e "*"para manipulação deendereços. Agora podemos entender melhor seu funcionamento. Quando referenciamos avariável pelo nome, o que nos é retornado será simplesmente o valor contido na memóriareferenciada pela variável, ou seja, ao referenciarmos a variável teste, nos será retornadoo valor 209, ao referenciarmos a variável cont, nos será retornado o valor 34. Quando,entretanto, referenciarmos a variável teste com a seguinte sintaxe:

&testeEstamos agora pedindo o endereço ocupado pela variável, ou seja, receberemos o

valor 200 (posição da memória onde a mesma começa). De forma análoga, se usarmos anotação:

testeserá retornado o valor contido na memória cujo endereço está na posição de memória

apontada por teste! Complicado? Vejamos no exemplo:A posição de memória apontada pela variável teste contem o valor 209. Quando

usamos *teste, queremos o valor da posição 209, ou seja, nos será retornado ’o’!! Este é oconceito de apontadores: variáveis cujo valor é o endereço de uma outra variável ou umaárea de memória reservada para tal. Estes exemplos são hipotéticos, pois o C não permiteusar o operador "*"para variáveis que não sejam do tipo pointer.

Os apontadores ou pointers são tipos de dados que tem por função "apontar"(referenciar)variáveis através de seus endereços físicos (posição da variável na memória), permitindouma maior flexibilidade em nossos programas como: acesso indireto por ponteiros, simu-lação de passagem de parâmetros por referência, alocação dinâmica de memória, criaçãode listas encadeadas e outras estruturas de dados mais complexas. São declarados daseguinte forma:

int x,y; // Declaração de dois inteirosint *px; // Declaração de um ponteiro para inteirosdouble vard, *pd; // um double e um ponteiro para double

Os ponteiros são definidos em função do tipo de variável ao qual ele será ligado, sãodo tipo "aponta para um determinado tipo de dado". Como se usa um apontador:

pt = &x; // pt recebe o endereço de x, aponta para xy = *pt; //y recebe o valor apontado por pt

�pt = 12; //O endereço dado por pt recebe o valor 12

//Se pt = &x então *pt = 12 é igual a x = 12

É impossível apontar para registradores e constantes definidas através do comando#define do processador de macros. Um uso muito prático de ponteiros é com os arrays,pois este tipo de dado tem características que se comportam de maneira muito parecidaa eles. Na realidade, um array pode ser visto, na maioria das vezes, como sendo umapontador para uma posição onde se encontram alocados os dados. Por isso temos:

Page 50: Apostila Linguagem C

50

char car,a[10],*ptr;ptr = a; //ptr aponta para o endereço de a[0]ptr = &(a[0]); //igual ao exemplo anterior a = &a[0]car = *(ptr); //car recebe o conteúdo de a[0]

int var[5],*pint;pint = var; //pint aponta para var[0]pint = (var+2); //pint aponta para var[2]

Como já pode ser visto, a indexação dos arrays é feita na mesma maneira em que setrata com ponteiros. Então, incrementar um ponteiro significa somar ao endereço atualtantas unidades quanto for o tamanho do tipo de dado apontado, assim como o endereçode um elemento de um array pode ser obtido apenas somando-se tantas unidades quantofor o tamanho do elemento do array.

Portanto podemos fazer somas e incrementos com ponteiros operando-os como sefossem meros endereços. Sendo que no caso de incrementos, o acréscimo será feito deacordo com tipo de dado ao qual o ponteiro atua (soma tantos bytes quanto for o tamanhodo tipo).

Como foi visto, apontadores acessam diretamente a memória do micro, por isso cons-tituem uma ferramenta poderosa mas ao mesmo tempo perigosa, pois um descuido qual-quer pode causar sérios danos. Sempre que formos usar um ponteiro ele já deverá ter sidoinicializado, ou seja, já deve ter sido atribuído algum endereço a ele.

Arrays, algumas informações extras ...

� A diferença entre um array e um ponteiro é que quando definimos um array, umaárea de memória é reservada para ele e quando definimos um apontador, não háalocação de memória. Exemplo:

char *string -> reserva área somente para o pointer (2/4 bytes)char string[10] -> reserva área para 10 caracteres (10 bytes)

� Arrays são passados como parâmetros para funções como sendo um ponteiro parao início do array.

� Como conseqüência do modo de alocação de arrays de mais de uma dimensão,quando for passado como parâmetro o array, temos que indicar as outras dimensões,exceto a principal. Isto se dá pelo fato de que é passado apenas o endereço inicialdo array, que é tratado como um vetor linear. Sem a indicação das outras dimensõesnão conseguimos distinguir os elementos de uma ou de outra dimensão. Exemplo:

função (a)int a[ ][10]; ��� o primeiro valor é opcional

��� o segundo valor é obrigatório

7.1 Apontadores: passagem de parâmetros por referência

Como visto anteriormente, o C só possui passagem de parâmetros por valor, atravésda pilha do sistema e não possui passagem por referência. Esta regra continua sendoverdadeira, mas pode-se simular a passagem por referência através de ponteiros.

Page 51: Apostila Linguagem C

51

int quadrado ( int *a){�

a=(�a)�(�a);

return(1);}

main (){int a=8;quadrado(&a);printf("A resposta foi %d � n", a);}

Observe que a passagem continua sendo por valor porque o que foi passado não é ovalor inteiro, mas sim o seu endereço, e este endereço não pode ser mudado dentro dafunção. Veja pelo exemplo a seguir:

int x=34; //variável globalint quadrado (int

�a)

{�a=(

�a)�(�a);

a=&x;printf("A tem o valor %d � n",

�a);

return(1);}

main (){int a=8;quadrado(&a);printf("A resposta foi %d � n", a);}

No exemplo acima, o endereço da variável "a", passada por parâmetro, é trocado e aimpressão dentro da função gerará o valor 34 (valor de x), mas quando a função retornar,o valor do endereço de ’a’ (passado por parâmetro) é restaurado, portanto continua sendopor valor, mas o valor absoluto de "a"foi alterado.

Outra observação importante é que a manipulação de valores dentro de uma funçãodeverá ser feita sempre com o operador "*". Outro exemplo:

Page 52: Apostila Linguagem C

52

int x=34; //variável globalint quadrado ( int

�a)

{�a=(

�a)�(�a);

a=&x;printf("A tem o valor %d � n",

�a);

return(1);}

main (){int a=8,

�b;

b=&a;quadrado(b);printf("A resposta foi %d � n", a);printf("A resposta foi %d � n",

�b);

}

No exemplo acima, criou-se uma variável do tipo apontador para inteiros e fez-se comque ela recebesse o endereço de a. A variável b já contem o endereço de uma área dememória e portando a passagem de parâmetro é feita simplesmente pelo seu nome. Porfim, imprimir o valor de a ou o valor da posição apontada por b resultará no mesmo valor,pois b aponta para a.

Portanto, sempre que desejar passar algum valor por referência, deve-se passar o en-dereço deste valor, se desejar-se passar o próprio endereço por referência, deve-se passaro endereço do endereço. Mais adiante serão vistos outras utilidades para ponteiros.

7.2 Alocação Dinâmica de ponteiros

Um apontador pode referenciar uma área de memória já alocada, como por exemplo,um inteiro, char ou mesmo um vetor declarado de forma estática. Entretanto, pode-sereservar uma nova área de memória e fazê-lo apontar para lá. Considere um exemploem que tenhamos que guardar os inteiros digitados pelo usuário para depois imprimi-lostodos. Precisamos de um vetor de inteiros para isso, certo? De quantos elementos?

Talvez soubéssemos de antemão que o usuário irá digitar apenas 20 números, então,podemos fazer a seguinte declaração:

int vetor[20];

Mas se o usuário quiser digitar mais que 20, não será possível ao passo que se eledigitar, digamos, apenas cinco, estamos desperdiçando espaço (15). E se tivermos umaforma de alocar espaço quando tivermos certeza qual o tamanho dele? É possível com ouso de apontadores.

Page 53: Apostila Linguagem C

53

#include <stdio.h>main(){int *vet;int tamanho,i;printf("Quantos elementos vc vai digitar? � n ");scanf("%d", &tamanho);vet = (int *)malloc (tamanho * sizeof(int));if (!vet) { ��� se vetor vazio (not vetor)...

printf("Erro na reserva de memória � n");return(0);

}/* usa-se vet como vet[0], vet[1], ... vet[tamanho-1] */}

Vetores estáticos e dinâmicos, como já dito, são praticamente o mesmo para o C,e podem ser manipulados de forma semelhante. Vamos analisar por partes o exemploacima.

Ao criarmos o apontador vet, ele terá algum endereço de memória e podería-mos usá-lo. Mas, este espaço em memória pode estar sendo usado por outro, pois não o reservamospara nosso uso exclusivo (que é o que fazemos com int vet[20]). Poderia ser desastrosa autilização nestes termos.

Reservar um espaço em memória de uso exclusivo nosso é o que tenta fazer o comandomalloc. Digo tenta, porque ele pode não conseguir, por exemplo, caso não haja memóriasuficiente. O malloc só reserva espaço em bytes e retorna um apontador para este endereçodo tipo void. Por isso que para o compilador aceitar, devemos usar um cast no início parao tipo que estamos usando (no caso, int). Como a reserva é em bytes, devemos reservar aquantidade de bytes que reflita a nossa necessidade. No exemplo, temos uma necessidadede tamanho elementos, sendo que cada elemento é do tipo int, o espaço que precisamos éde tamanho

�sizeof(int).

O malloc retorna o endereço reservado se conseguiu ou ’ � 0’, (NULL) se falhou. Éextremamente recomendável testar seu retorno antes de usar.

Não é correto afirmar que o malloc cria variáveis dinâmicas, pois ele apenas reservaespaço deixando sobre a inteira responsabilidade do programador o gerenciamento destaárea Logo, se o programador fizer mal uso, azar o dele!!! Podemos considerar um péssimouso o exemplo a seguir:

#include <stdio.h>main(){int *vet;int tamanho=20,i;vet = (int *)malloc (tamanho * sizeof(int));if (!vet) {

printf("Erro na reserva de memória � n");return(0);

}vet = &i;}

Page 54: Apostila Linguagem C

54

Na linha em destaque, vet recebe o endereço da variável i. Então, o que aconteceucom a área anteriormente reservada? Continua reservada para nós, mas já não temoscomo usá-la pois não sabemos onde está.

Para liberar-mos um espaço anteriormente alocado, usamos o comando free():free(vet);Não precisamos, neste caso, indicar o tamanho de memória liberada, pois isso o C

controla.

7.3 Exercícios:

1) Implemente a função my_strcmp(), semelhante a strcmp() mas apenas retornando 0 seforem iguais e diferente de zero se não.

2) Faça uma função para somar dois vetores. A função deve receber 3 vetores (os 2vetores a serem somados e o vetor que receberá a soma) e o tamanho dos vetores edeve retornar a média dos valores somados (int).

3) Faça uma função que copie X caracteres para uma outra cadeia de caracteres. A funçãodeverá retornar o número de caracteres efetivamente copiados (pode ser <que x quea string origem terminar antes). Chamada:

char a[50], b[50], tam;

/* atribua um texto qualquer a a */

tam=copia(b,a,10);

/* copia no maximo 10 caracteres de a para b.

Se a string de a tiver só 5, copia apenas os cinco */

4) Faça um programa que crie dois vetores dinâmicos de mesmo tamanho. O tamanhodeve ser passado por parâmetro na execução do programa. O usuário, ao executaro programa, deve digitar todos os elementos de um dos vetores. Depois que todosos elementos foram digitados, os elementos do segundo vetor deve ser calculadoda seguinte forma vet2[0]=tamanho-vet1[0], vet2[n]=tamanho-vet1[n]. Finalmenteimprima ambos os vetores.

Page 55: Apostila Linguagem C

55

8 ARQUIVOS

8.1 Introdução

O padrão C ANSI define um conjunto completo de funções de E/S que pode ser utili-zado para ler e escrever qualque tipo de dado.

O sistema de arquivos em C é projetado para trabalhar com diversos tipos de disposi-tivos. O sistema de arquivo com buffer transforma-se em um dispositivo lógico chamadode stream. Existem dois tipos de streams: texto e binária. Uma stream de texto é umasequência de caracteres. Já uma stream binária é uma sequência de bytes com algumacorrespondência.

8.2 Arquivos

Deve-se associar uma stream com um arquivo específico e para isso também precisa-mos realizar uma operação de abertura. Depois do arquivo aberto, troca-se informaçõesentre ele e o programa. Cada stream associada a um arquivo tem uma estrutura de con-trole do tipo FILE (stdio.h). Além disso, cada vez que o arquivo é aberto, também éinicializado o indicador de posição no arquivo. Quando um caractere é lido ou escrito noarquivo, o indicador de posição é incrementado.

8.3 Funções

O sistema de arquivos C ANSI é composto de diversas funções inter-relacionadas. Asmais comuns são mostradas na Tabela 8.1:

8.3.1 Ponteiro de Arquivo

O ponteiro de arquivo é um ponteiro para informações que definem coisas sobre oarquivo (nome, status e posição atual do arquivo). Este indentifica um arquivo específicoem disco e é usado pela stream associada para direcionar as operações de E/S. Para obteruma variável ponteiro de arquivo, a sintaxe é a seguinte:

FILE *fp;

8.3.2 Abrindo um arquivo (fopen)

A função fopen( ) abre uma stream para uso e associa um arquivo a ela, retornandoum ponteiro associada ao arquivo. A sintaxe da função é:

FILE *fopen(const char* nomearq, const char* modo);Em modo devemos indicar como o arquivo deverá ser aberto. Um arquivo pode ser

Page 56: Apostila Linguagem C

56

Nome Funçãofopen( ) Abre um arquivofclose( ) Fecha um arquivoputc( ) Escrever um caractere em um arquivofputc( ) O mesmo que putc( )getc( ) Lê um caractere de um arquivofgetc( ) O mesmo que getc( )fseek( ) Posiciona o arquivo em um byte específicofprintf( ) É para um arquivo o que um printf( )fscanf( ) É para um arquivo o que o scanf( ) é para o consolefeof( ) Devolve verdadeiro se o fim de arquivo for atingidoferror( ) Devolve verdadeiro se ocorreu um errorewind( ) Recoloca o indicador de posição de arquivo no início do arquivoremove( ) Apaga um arquivofflush( ) Descarrega um arquivo

Tabela 8.1: Funções para Arquivos

aberto em modo texto ou binário. A tabela 8.2 mostra os modos os quais podemos abriros arquivos.

Modo Significador Abre um arquivo-texto para leituraw Cria um arquivo-texto para escritaa Anexa a um arquivo-textorb Abre um arquivo binário para leiturawb Cria um arquivo binário para escritaab Anexa a um arquivo binárior+ Abre um arquivo-texto para leitura/escritaw+ Cria um arquivo-texto para leitura/escritaa+ Anexa/cria um arquivo texto para leitura/escritar+b Abre um arquivo binário para leitura/escritaw+b Cria um arquivo binário para leitura/escritaa+b Anexa a um arquivo binário para leitura/escrita

Tabela 8.2: Modos de Abertura para Arquivos

Para abrir um arquivo chamado prog4all, pode-se desenvolver o seguinte trecho decódigo:

. . .FILE *fp;fp = fopen("prog4all","w");. . .

Se quiseres sempre testar se a operação foi realizada com sucesso, é mais comum seprograma como:

Page 57: Apostila Linguagem C

57

. . .FILE *fp;if((fp=fopen("prog4all","w"))==NULL) {printf("O arquivo não pode ser criado � n");exit(1);

}. . .

8.3.3 Fechando um arquivo (fclose)

A função fclose( ) fecha uma stream que foi aberta por meio de uma chamada fopen( ).Portanto, lembre-se sempre que um arquivo for aberto, você deve fechá-lo antes do finaldo programa. A sintaxe do fclose ( ) é:

int fclose(FILE *fp);

8.3.4 Escrevendo e Lendo um caractere

O padrão C ANSI define duas funções para escrever caracteres: putc( ) e fputc( ). Afunção putc( ) escreve caracteres em um arquivo que foi aberto, tendo o seguinte protótipo:

int putc(int ch, FILE *fp);

Onde ch é o caracter e o fp é o ponteiro para o arquivo. Para ler caracteres de umdeterminado arquivo podemos usar as funções getc( ) e fgetc( ). A função getc( ) lê carac-teres de um arquivo aberto no modo leitura e seu protótipo é:

int getc(FILE *fp);

A função getc( ) irá retornar EOF quando o final do arquivo for alcançado. Paraentendermos melhor o funcionamento destas funções, vamos analisar o seguinte exemplo:

Page 58: Apostila Linguagem C

58

#include <stdio.h>#include <stdlib.h>#include <string.h>void main(){FILE *p;char c, str[30], frase[80] = "Este e um arquivo chamado: ";int i;/* Le um nome para o arquivo a ser aberto: */printf("Entre com um nome para o arquivo: � n");gets(str);if (!(p = fopen(str,"w"))) /* Caso ocorra algum erro na abertura do arquivo..*/{printf("Erro! Impossivel abrir o arquivo! � n");exit(1); /* o programa aborta automaticamente */

}/* Se nao houve erro, imprime no arquivo e o fecha ...*/strcat(frase, str);for (i=0; frase[i]; i++)putc(frase[i],p);

fclose(p);/* Abre novamente para leitura */p = fopen(str,"r");c = getc(p); /* Le o primeiro caracter */while (!feof(p)) /* Enquanto não se chegar no final do arquivo */{printf("%c � n",c); /* Imprime o caracter na tela */c = getc(p); /* Le um novo caracter no arquivo */

}fclose(p); /* Fecha o arquivo */

}

No exemplo, primeiro o arquivo é aberto para a escrita, e imprime-se algo nele. Emseguida, o arquivo é fechado e novamente aberto para a leitura.

8.3.5 Lidando com Strings (fputs e fgets)

C suporta funções fputs( ) e fgets( ) que efetuam operações de leitura e gravação destrings de caracteres para um arquivo em disco. Abaixo estão os protótipos destas fun-ções:

int fputs(const char *str, FILE *fp);

char *fgets(char *str, int length, FILE *fp);

Estas duas funções estão na biblioteca stdio.h. A função fgets( ) lê uma string dastream especificada até que um caractere de nova linha seja lido ou que lenght-1 caracterestenham sido lidos. Pode-se observar um exemplo que irá inserindo strings num arquivoaté a tecla ENTER ser digitada:

Page 59: Apostila Linguagem C

59

#include <stdio.h>#include <stdlib.h>int main(){FILE *pf;char string[100];if((pf = fopen("arquivo.txt","w")) ==NULL){printf("Nao consigo abrir o arquivo ! � n");exit(1);

}do{printf("Digite uma nova string. Para terminar, digite <enter>: � n ");gets(string);fputs(string, pf);putc(’ � n’, pf);

}while (strlen(string) > 0);fclose(pf);

}

8.3.6 Lidando com blocos de dados binários(fread e fwrite)

Podemos escrever e ler blocos de dados. Para tanto, temos as funções fread() efwrite(). O protótipo de fread() é:

unsigned fread (void *buffer, int numerodebytes, int count, FILE *fp);

O buffer é a região de memória na qual serão armazenados os dados lidos. O númerode bytes é o tamanho da unidade a ser lida. Count indica quantas unidades devem serlidas. Isto significa que o número total de bytes lidos é: numerodebytes*count.

A função retorna o número de unidades efetivamente lidas. Este número pode sermenor que count quando o fim do arquivo for encontrado ou ocorrer algum erro. Quandoo arquivo for aberto para dados binários, fread pode ler qualquer tipo de dados.

A função fwrite() funciona como a sua companheira fread(), porém escrevendo noarquivo. Seu protótipo é:

unsigned fwrite(void *buffer, int numerodebytes, int count, FILE *fp);

A função retorna o número de itens escritos. Este valor será igual a count a menosque ocorra algum erro. O exemplo abaixo ilustra o uso de fwrite e fread para gravar eposteriormente ler uma variável float em um arquivo binário.

Page 60: Apostila Linguagem C

60

#include <stdio.h>#include <stdlib.h>int main(){FILE *pf;float pi = 3.1415;float pilido;if((pf = fopen("arquivo.bin", "wb")) == NULL)/* Abre arquivo binário para escrita */{printf("Erro na abertura do arquivo � n");exit(1);

}if(fwrite(&pi, sizeof(float), 1,pf) != 1) /* Escreve a variável pi */printf("Erro na escrita do arquivo � n");

fclose(pf); /* Fecha o arquivo */if((pf = fopen("arquivo.bin", "rb")) == NULL)/* Abre o arquivo novamente para leitura */{printf("Erro na abertura do arquivo � n");exit(1);

}if(fread(&pilido, sizeof(float), 1,pf) != 1)/* Le em pilido o valor da variável armazenada anteriormente */printf("Erro na leitura do arquivo � n");

printf("O valor de PI, lido do arquivo e’: %f � n", pilido);fclose(pf);return(0);

}

Note-se o uso do operador sizeof, que retorna o tamanho em bytes da variável ou dotipo de dados.

8.3.7 Realizando Procuras (fseek)

Para se fazer procuras e acessos randômicos em arquivos usa-se a função fseek(). Estamove a posição corrente de leitura ou escrita no arquivo de um valor especificado, a partirde um ponto especificado. Seu protótipo é:

int fseek (FILE *fp, long numbytes, int origem);O parâmetro origem determina a partir de onde os numbytes de movimentação serão con-tados. Os valores possíveis são definidos por macros em stdio.h. Estes estão apresentadosna Tabela 8.3.

Tendo-se definido a partir de onde irá se contar, numbytes determina quantos bytes dedeslocamento serão dados na posição atual.

Page 61: Apostila Linguagem C

61

Nome Valor SignificadoSEEK_SET 0 Início do arquivoSEEK_CUR 1 Ponto corrente no arquivoSEEK_END 2 Fim do arquivo

Tabela 8.3: Valores do fseek

8.4 Exercícios

1) Fazer um programa que leia do usuário um determinado número de caracteres e armazene-os em um arquivo, chamado de "teste.txt". O programa deve parar de ler quando ousuário digitar a letra ’A’.

2) Fazer um programa que simule uma lista telefônica. O usuário poderá incluir novosregistros (nome + telefone) ou apenas consultá-los. É importante ressaltar que aoreiniciar o programa, o usuário deve poder visualizar telefones pré-cadastrados.

3) Fazer um programa que solicite ao usuário o nome de um arquivo de entrada. Apósabrir este arquivo o programa deve criar outro arquivo que é uma cópia do arquivode origem. O arquivo destino deve ser uma cópia, com algumas alterações, são elas:letras ’a’ são substituídas por ’G’, letras ’c’ são substituídas por ’H’ e letras ’e’ sãosubstituídas pela palavra ’lp’.

4) Faça uma rotina que recebe uma matriz A(4,4) de inteiros e retorna um vetor apenascom os elementos cuja soma dos índices é par. Faça uma rotina que recebe o vetorgerado na rotina anterior e armazena o vetor em um arquivo binário. Faça umarotina para ler o arquivo binário gravado e imprima as informações na tela.

5) Faça um programa que permita inserir e visualizar o cadastro dos alunos de uma acade-mia. As informações a serem armazenada são: nome, idade e peso. As informaçõesdevem ser armazenadas em um arquivo binário.

Page 62: Apostila Linguagem C

62

9 BIBLIOGRAFIA

KRNIGHAN, B.; RITCHIE, D. A Linguagem de Programação C. Campus, PortoAlegre, 1986.

SCHILDT, E. C Completo e Total. Makron Books, São Paulo, 1990;http://linux.orghttp://tlm.conectiva.com.br/http://www.indiana.edu/ uitspubs/b017/http://www.labbas.eng.uerj.br/linux/linuxman.htmlhttp://www.inf.ufrgs.br/ elgios/http://www.inf.pucrs.br/ pinhohttp://www.inf.pucrs.br/ silvia/laprohttp://www.inf.unilasalle.edu.br/ barreto/http://www.cp.cefetpr.br/pessoal/mauricio