Buscar

Linguagem C

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 53 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 53 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 53 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

1. Introdução........................................................................................................................................... 4 
1.1. Características................................................................................................................... 4 
1.2. Histórico ........................................................................................................................... 4 
1.3. Características de um programa........................................................................................ 4 
1.4. Formato de um programa em C ........................................................................................ 4 
1.5. Exemplo de um programa................................................................................................. 5 
2. Identificadores .................................................................................................................................... 6 
3. Tipos de dados para variáveis e funções ............................................................................................ 7 
3.1. Standard (já definidos na linguagem) ............................................................................... 7 
3.2. Modificadores de tipo ....................................................................................................... 7 
4. Declaração de variáveis...................................................................................................................... 8 
4.1. Variáveis locais................................................................................................................. 8 
4.2. Parâmetros formais ........................................................................................................... 9 
4.3. Variáveis globais .............................................................................................................. 9 
4.4. Modificadores de classe de armazenamento..................................................................... 10 
4.4.1. Variáveis automáticas - auto ........................................................................... 10 
4.4.2. Variáveis externas - extern.............................................................................. 10 
4.4.3. Variáveis estáticas - static ............................................................................... 11 
4.4.4. Variáveis register ............................................................................................ 11 
5. Operadores.......................................................................................................................................... 23 
5.1. aritméticos......................................................................................................................... 23 
5.2. lógicos ou boleanos........................................................................................................... 23 
5.3. relacionais ......................................................................................................................... 23 
5.4. outros operadores.............................................................................................................. 24 
5.5. precedência (da maior para a menor)................................................................................ 24 
6. Funções de entrada e saída ................................................................................................................. 12 
6.1. printf()............................................................................................................................... 12 
6.2. putchar()............................................................................................................................ 12 
6.3. puts() ................................................................................................................................. 12 
6.4. scanf() ............................................................................................................................... 12 
6.5. getchar()............................................................................................................................ 12 
6.2. gets() ................................................................................................................................. 12 
7. Instuções de controle .......................................................................................................................... 14 
7.1. while ................................................................................................................................. 14 
7.2. for...................................................................................................................................... 15 
7.3. do while ............................................................................................................................ 15 
7.4. if e derivados..................................................................................................................... 16 
7.5. switch................................................................................................................................ 17 
7.6. continue............................................................................................................................. 18 
7.7. break ................................................................................................................................. 18 
8. Funções............................................................................................................................................... 21 
9. Arrays unidimensionais (vetores)....................................................................................................... 25 
9.1. Strings ............................................................................................................................... 26 
10. Arrays bidimensionais (matrizes bidimensionais) .............................................................................. 31 
11. Pointers (ponteiros) ............................................................................................................................ 33 
11.1. Definição........................................................................................................................... 33 
11.2. Inicialização de pointers na definição............................................................................... 34 
11.3. Passagem de parâmetros por endereço (referência) .......................................................... 34 
12. A relação entre pointers e arrays ........................................................................................................ 36 
13. Pointers e arrays bidimensionais ........................................................................................................ 40 
13.1. Arrays de pointers (ragged arrays).................................................................................... 42 
14. Definição de novos tipo...................................................................................................................... 44 
15. Ponteiro para percorrer array de ponteiros. ........................................................................................ 45 
16. Ponteiros para funções........................................................................................................................ 47 
17. Pré-processador e diretivas................................................................................................................. 49 
17.1 #define .............................................................................................................................. 49 
17.2 #include............................................................................................................................. 5017.3. compilação condicional .................................................................................................... 50 
2 
 
18. Tipos construídos ............................................................................................................................... 53 
18.1. Tipo enumerado ................................................................................................................ 53 
18.2. Estruturas .......................................................................................................................... 54 
18.3. Inicialização de estruturas................................................................................................. 56 
18.4. Campos de bits.................................................................................................................. 56 
18.5. Uniões ............................................................................................................................... 57 
19. Pointer para estruturas ........................................................................................................................ 60 
20. Arquivos ............................................................................................................................................. 61 
20.1. Funções para abertura e fechamento de arquivos ............................................................. 61 
20.2. Principais funções para leitura e gravação sequenciais .................................................... 63 
20.3. Principais funções para leitura e gravação direta (binário)............................................... 65 
21. Alocação dinâmica de memória.......................................................................................................... 71 
3 
1. Introdução 
 
1.1. Características 
 
 • linguagem de médio nível, que foi criada para substituir o ASSEMBLY 
 • linguagem estruturada; 
 • versátil (aplicação em várias áreas); 
 • portável, o mesmo programa funciona em várias plataformas; 
 • código eficiente; 
 • compilação condicional; 
 • compilação separada (funções em vários arquivos); 
 • linguagem para o programador. 
 
1.2. Histórico 
 
 A linguagem C foi desenvolvida em 1971 por Kernighan e Ritchie (K & R), nos Laboratórios 
Bell; 
 A princípio seus nomes foram BCPL, B e posteriormente foi chamada de C, mais 
recentemente, foi criada a sucessora da linguagem C, a linguagem orientada a objetos C++ 
 
1.3. Características de um programa 
 
 • um programa em C é composto por pelo menos uma função, a função "main"; 
 • todo programa em C começa a sua execução a partir da função "main"; 
 • normalmente, um programa em C é uma coleção de chamadas de funções, as quais são de 
pequeno tamanho; 
 • toda função tem um tipo; 
 • as palavras reservadas e funções da biblioteca do C são sempre escritas com letras 
minúsculas. 
 
1.4. Formato de um programa em C 
 
 "definições" 
 função_1 
 função_2 
 ... 
 função_n 
 funcão_main 
 
 A ordem das funções dentro de um programa pode ser qualquer. 
 
1.5. Exemplo de um programa 
 
 #include <stdio.h> /* instrução para o pré-processador */ 
 void main() /* início da função main */ 
 { /* início de bloco */ 
 int i; /* define */ 
 i = 10; /* inicializa */ 
 printf("i = %d\n", i); /* chama função de impressão */ 
 } /* fim de bloco */ 
 • toda instrução termina por ';' 
4 
 • protótipo de printf está em stdio.h (standard IO) 
2. Identificadores 
 
 São usados em nomes de funções e variáveis. 
 
 ANSI: 31 caracteres para variáveis locais 
 6 para funções e variáveis globais 
 
 Nos PC's, a maioria dos compiladores reconhece 31 caracteres tanto para variáveis quanto 
para funções. 
 
 • devem começar por letra ou '_'; 
 • normalmente se usam letras minúsculas; 
 • não podem ser iguais às palavras reservadas; 
 • minúsculas diferentes de maiúsculas: 
 ABC # Abc # ABc # abc 
3. Tipos de dados para variáveis e funções 
 
3.1. Standard (já definidos na linguagem) 
 
 caracter char (1 caracter) 
 inteiro int(2 ou 4 bytes; PC = 2 bytes) 
 real float (4 bytes) 
 double(8 bytes) 
 nada void (0 bytes) 
 
 O tipo inteiro possui o tamanho da palavra da CPU. 
 
 Para o PC temos: 
 
Tipo Tamanho 
em Bits 
Faixa 
char 8 0 a 255 
int 16 -32768 a 32767 
float 32 6 dígitos 
double 64 12 dígitos 
void 0 sem valor 
 
3.2. Modificadores de tipo 
 
 Alteram o significado do tipo standard. 
 • signed (com sinal) 
 • unsigned (sem sinal) 
 • long (passa inteiro de 2 bytes para 4 bytes) 
 • short (passa inteiro de 4 bytes para 2 bytes) 
 No PC: 
5 
 long int = long ⇒ 4 bytes 
 short int = int ⇒ 2 bytes 
 
 Ex.: 
 signed char ⇒ -128 a 127 
 unsigned int ⇒ 0 a 65535 
4. Declaração de variáveis 
 
 Variáveis devem ser declaradas antes de serem usadas. 
 
 Formato: <tipo> <lista de variáveis); 
 
 Ex.: 
 int a, b, c; 
 float soma; 
 double somatorio, raiz_quadrada; 
 char sim, nao; 
 
 As variáveis podem ser definidas dentro de qualquer bloco: 
 { 
 int x, y; 
 comandos; 
 } 
 As variáveis podem ser locais, globais e parâmetros formais 
 
4.1. Variáveis locais 
 
 São as declaradas dentro de blocos e só são reconhecidas dentro do bloco de declaração. 
 
 Ex.: 
 #include <stdio.h> 
 void main() 
 { 
 int i, j; 
 i = 2; 
 j = 2 * i; 
 printf("O dobro de %d = %d\n", i, j); 
 } 
 
 No exemplo acima, 'i' e 'j' são variáveis locais da função "main". 
 
 Ex.: 
 void f1() 
 { 
 int x; 
 x = 5; 
 ... 
 if (a > 10) 
 { 
 int x, y; 
 x = 20; 
 y = 40; 
 ... 
 } 
6 
 } 
 
 No exemplo, a variável 'x' tem o valor 5 quando sair do bloco mais interno. 
 
4.2. Parâmetros formais 
 
 São os parâmetros das funções. 
 
 Obs.: 
O C só passa parâmetros por valor, isto é, o que é passado para a função é uma cópia do 
conteúdo da variável. 
 
 Ex.: 
 int soma(int a, int b) 
 { 
 return (a + b); 
 } 
 No exemplo, 'a' e 'b' são parâmetros formais e a função "soma" poderia ser chamada: 
 j = soma(2, 3); 
 x = soma(a, b); 
 
4.3. Variáveis globais 
 
 São reconhecidas por todas as funções de um programa ou de um arquivo. 
 
 Ex.: 
 #include <stdio.h> 
 int cont; 
 void f(void); 
 void main() 
 { 
 cont = 100; 
 printf("cont em main = %d\n", cont); 
 cont = cont + 1; 
 f(); 
 } 
 
 void f() 
 { 
 printf("cont em f = %d\n", cont); 
 } 
 
 
4.4. Modificadores de classe de armazenamento 
 
 Indicam como as variáveis devem ser armazenadas. 
 Exemplo de mapa da memória de um programa em C em um equipamento genérico: 
 
Área de Código 
Área de Variáveis 
Estáticas e Globais 
Stack 
7 
Heap 
 
 
4.4.1. Variáveis automáticas - auto 
 
 São as variáveis definidas normalmente. 
 
 Ex.: 
 int x; <=> auto int x; 
 A palavra auto não é necessária. 
 
4.4.2. Variáveis externas - extern 
 
 São as variáveis globais definidas em arquivos diferentes. 
 
 Ex.: 
 arquivo 1: 
 int x, y; 
 
 void main() 
 { 
 y = 30; 
 x = 10; 
 f(); 
 ... 
 } 
 
 arquivo 2: 
 ... 
 extern int x, y; 
 void f() 
 { 
 ... 
 printf("%d %d\n", x, y); 
 ... 
 } 
 
4.4.3. Variáveis estáticas - static 
 
 A variável não perde o seu valor dentro da função ou arquivo. 
 Este tipo de variável é mais empregado para definição de strings. 
 
 Quando uma função é definida como static, ela só pode ser ativada por uma função que esteja 
no mesmo arquivo. 
 
 
 
 
4.4.4. Variáveis register 
 
 A variável é colocada em um dos registradores da CPU. 
 Deve ser bem escolhida (PC sópermite duas) 
 
 Ex.: 
8 
 register int i, j; 
 
 Este tipo de varável é mais usada em casos nos quais a velocidade é importante, como por 
exemplo em variáveis que controlam loops. 
5. Operadores 
 
 Um operador é um caracter ou grupo de caracteres que causará uma manipulação matemática 
ou lógica. 
 
 Em C, os operadores podem ser aritméticos, relacionais e lógicos e entre bits. 
 
5.1. aritméticos 
 
 + ⇒ adição 
 - ⇒ subtração e menos unário 
 * ⇒ multiplicação 
 / ⇒ divisão 
 % ⇒ resto divisão 
 -- ⇒ decremento 
 ++ ⇒ incremento 
 += ⇒ soma 
 -= ⇒ subtração 
 *= ⇒ multiplicação 
 /= ⇒ divisão 
 
5.2. lógicos ou boleanos 
 
 && ⇒ e 
 || ⇒ ou 
 ! ⇒ não 
 
5.3. relacionais 
 
 > ⇒ maior 
 < ⇒ menor 
 == ⇒ igual 
 != ⇒ diferente 
 >= ⇒ maior ou igual 
 <= ⇒ menor ou igual 
5.4. Outros operadores 
 
 * ⇒ retorna o valor contido em um endereço 
 & ⇒ retorna o endereço de uma variável 
 sizeof ⇒ retorna o tamanho de uma variável ou tipo 
 ? ⇒ avalia expressão verdadeira 
 , ⇒ equivalente a "faça isto e isto e isto ..." 
 . ⇒ membro de estrutura ou união 
 -> ⇒ pointer para membro de estrutura ou união 
9 
 (type) ⇒ cast (altera tipo do dado) 
 
5.5. precedência (da maior para a menor) 
 
 () [] -> . 
 ! ~ ++ -- (type) * & sizeof 
 * / % 
 + - 
 << >> 
 < <= > >= 
 == != 
 & 
 ^ 
 | 
 && 
 || 
 ? 
 = += -= *= /= 
 , 
 
6. Funções de entrada e saída 
 
 Ao contrário de outras linguagens, no C as operaçães de leitura e impressão, tanto na tela 
quanto em arquivos, é totalmente feita por funções. Os protótipos destas funções se 
encontram no arquivo stdio.h, o qual deve sempre ser incluído quando forem usadas funções 
de IO (entrada e saída). 
 
6.1. printf() 
 
 Principal função de impressão no vídeo. 
 
 Formato: 
 int printf(formato, argumentos); 
 
 A função printf retorna o número de caracteres impressos. 
 
 Obs1.: Em C, o valor de retorno de uma função pode ser ignorado; 
 Obs2.: Em C, as funções podem ter um número variável de parâmetros. 
 
 Ex.: printf("\nFIM\n"); 
 Principais formatos de impressão: 
 
 • %d - inteiro 
 • %c - caracter 
 • %f - float 
 • %ld - long int 
 • %lf - double 
 • %s - string 
 • %e - notação científica 
 
10 
 A saída pode ser formatada através do tamanho do campo: 
 
 Exemplo: 
 • %3d - inteiro com 3 dígitos 
 • %7.2f - float com dois dígitos após o ponto decimal 
 
6.2. putchar() 
 
 Imprime um caracter. 
 
 Formato: 
 int putchar(variável); 
 
 Ex.: putchar(a); ⇒ imprime o conteúdo da variável a. 
 
6.3. puts() 
 
 Imprime um cadeia de caracteres (string). 
 
 Formato: 
 int puts(variável); 
 
 Ex.: puts(st); ⇒ imprime o conteúdo da string st. 
 
6.4. scanf() 
 
 Principal função de leitura do teclado 
 
 Formato: 
 int scanf(formato, parâmetros); 
 
 Retorna o número de variáveis lidas corretamente ou EOF em caso de erro grave. 
 
 Principais formatos: 
 • %d - inteiro 
 • %c - caracter 
 • %f - float 
 • %ld - long int 
 • %lf - double 
 • %s - string 
 
 Para a função scanf, o branco é considerado delimitador. 
 
 Ex.: 
 scanf("%d %d", &a, &b); 1b3 ou 1b...b3 
 scanf("%d , %d", &a, &b); 1 , 3 
 
 Exercício: Ler dois números e imprimir a soma. 
 
 #include <stdio.h> 
 void main() 
11 
 { 
 int a, b, c; 
 printf("Entre 2 numeros: "); 
 scanf("%d %d", &a, &b); 
 c = a + b; 
 printf("soma = %d\n", c); 
 /* printf("soma = %d\n", a + b); */ 
 } 
 
6.5. getchar() 
 
 Lê um caracter do teclado. 
 
 Formato: 
 int getchar(void); 
 
 Ex.: c = getchar(); ⇒ guarda na variável c o caracter lido. 
 
6.6. gets() 
 
 Lê uma cadeia de caracteres (string) do teclado. 
 
 Formato: 
 char gets(variável); 
 
 Ex.: gets(s); ⇒ guarda na variável s a string lida. 
 
7. Instuções de controle 
 
7.1. while 
 
 Estrutura de repetição com teste no início. 
 
 Formato: 
 while (condição) 
 bloco; 
 
 Executa o bloco enquanto a condição for verdadeira. 
 
 Obs.: Em C, verdadeiro é tudo o que for diferente de zero. 
 Ex.: Imprimir a soma dos números de 1 a 5 com while 
 Solução 1: 
 #include <stdio.h> 
 void main() 
 { 
 int i, soma; 
 i = 1; 
 soma = 0; 
 while (i <= 5) 
 { 
 soma = soma + i; 
 i = i + 1; 
 } 
12 
 printf("\nSoma = %d\n", soma); 
 } 
 
 Solução 2: 
 #include <stdio.h> 
 void main() 
 { 
 int i = 1, soma = 0; 
 while (i <= 5) 
 { 
 soma += i; 
 i++; 
 } 
 printf("\nSoma = %d\n", soma); 
 } 
 
 Obs.: 
 i++; ⇔ ++i; 
 
 se a = 1: 
 para b = ++a; ⇒ b = 2 e a = 2 
 para b = a++; ⇒ b = 1 e a = 2 
 
 var = var op exp; ⇔ var op = exp; 
 
 x = x + 5; x += 5; 
 x = x / (a + b); x /= a + b; 
 
7.2. for 
 
 Estrutura de repetição com a quantidade já conhecida. 
 
 Formato: 
 for (inicialização; condição; incremento) 
 bloco; 
 
 Exemplo: Imprimir os números de 1 a 10 
 #include <stdio.h> 
 void main() 
 { 
 int i; 
 for (i = 1; i <= 10; i++) 
 printf("%d\n", i); 
 } 
 
 Obs.: Todos os campos do for são opcionais: 
 
 #include <stdio.h> 
 void main() 
 { 
 int i = 1; 
 for (; i <= 10;) 
 printf("%d\n", i++); 
 } 
 
13 
7.3. do while 
 
 Estrutura de repetição com o teste no final. 
 
 Formato: 
 do 
 bloco; 
 while (condição); 
 
 Repete o bloco enquanto a condição for verdadeira. 
 
 Exemplo.: Imprimir os números de 1 a 10 
 #include <stdio.h> 
 void main() 
 { 
 int i = 1; 
 do 
 { 
 printf("%d\n", i) 
 i++; 
 } 
 while (i <= 10); 
 } 
 
 Exercício: Calcular o fatorial de um número lido. 
 Solução 1: 
 #include <stdio.h> 
 void main() 
 { 
 int n, i, fator = 1; 
 printf("Entre o numero: "); 
 scanf("%d", &n); 
 for (i = 1; i <= n; i++) 
 fator *= i; 
 printf("Fatorial de %d = %d\n", n, fator); 
 } 
 
 Solução 2: 
 #include <stdio.h> 
 void main() 
 { 
 int n, i, fat; 
 printf("Entre o numero: "); 
 scanf("%d", &n); 
 i = n; 
 for (fat = 1; n > 1; n--) 
 fat *= n; 
 printf("Fatorial de %d = %d\n", i, fat); 
 } 
 
7.4. if e derivados 
 
 Estrutura de decisão 
 
 Formato: 
 if (teste) 
14 
 bloco; 
 
 if (teste) 
 bloco1; 
 else 
 bloco2; 
 
 if (teste1) 
 bloco1; 
 else if (teste2) 
 bloco2; 
 else if (teste3) 
 bloco3; 
 else 
 bloco4; 
 
 Obs.: Se bloco possuir mais de uma instrução é necessário {} 
 
 Exercício: ler 2 números e indicar o maior 
 #include <stdio.h> 
 void main() 
 { 
 int a, b; 
 printf("Entre 2 numeros: "); 
 scanf("%d %d", &a, &b); 
 if (a == b) /* teste é com == */ 
 printf("Sao iguais\n"); 
 else if (a > b) 
 printf("O primeiro é maior\n"); 
 else 
 printf("O segundo é maior\n"); 
 } 
 
 Exercício: ler uma série de números reais e indicar o maior e o menor. 
 #include <stdio.h> 
 void main() 
 { 
 float min, max, x; 
 printf("Entre os numeros:\n"); 
 scanf("%f", &x); 
 min = max = x; /* atribuição múltipla */ 
 while (scanf("%f", &x) == 1) 
 if (min > x) 
 min = x; 
 else if (max < x) 
 max = x; 
 printf("O maior é: %f\n", max); 
 printf("O menor é: %f\n", min); 
 } 
 
7.5. switch 
 
 Estrutura de decisão que substitui grandes if's. 
 
 Formato: 
 switch (exp) 
15 
 { 
 case cte1: 
 bloco1; 
 break;case cte2: 
 bloco2; 
 break; 
 case cte3: 
 bloco3; 
 break; 
 ... 
 case cten: 
 blocon; 
 break; 
 default: 
 bloco; 
 break; /* não é necessário break aqui */ 
 } 
 
 Obs.: A expressão 'exp' sempre deverá fornecer um resultado inteiro. 
 
7.6. continue 
 
 Passa para o próximo incremento em um for ignorando as instruções restantes dentro do bloco 
do for. 
 
 Exemplo: 
 ... 
 for (i = 0; i < 10; i++) 
 { 
 if (i == 0) 
 continue; /* evita divisão por zero */ 
 printf("%f\n", (float) 10 / i); 
 } 
 
7.7. break 
 
 Interrompe a execução de um for, while, do ... while ou switch. O fluxo de execução do 
programa é desviado para primeira instução fora do bloco que possui o break. 
 
 Exemplo: 
 while (1) /* loop infinito */ 
 { 
 scanf("%d" , &a); 
 if (a != 0) 
 processa(); 
 else 
 break; 
 } 
 
 Exercício: Fazer um programa que simule uma calculadora, com as quatro operações, teste a 
divisão por zero e sinal inválido. 
 
 Solução: 
 
 #define FALSE 0 /* definição de constantes */ 
 #define TRUE 1 
16 
 
 #include <stdio.h> 
 void main() 
 { 
 float v1, v2, res; 
 char op; 
 int erro = 1; /* usa int como variável lógica */ 
 
 printf("Entre sua expressão:\n"); 
 scanf("%f %c %f", &v1, &op, &v2); 
 
 switch (op) 
 { 
 case '+': 
 res = v1 + v2; 
 break; 
 
 case '-': 
 res = v1 - v2: 
 break; 
 
 case '*': 
 res = v1 * v2; 
 break; 
 
 case '/': 
 if (v2 == 0.0) 
 { 
 printf("\nErro: Divisão por zero\n"); 
 erro = TRUE; 
 } 
 else 
 res = v1 / v2; 
 break; 
 default: 
 erro = TRUE; 
 printf("\nSinal inválido\n"); 
 break; 
 } 
 
 if (erro==1) 
 printf("\nO resultado é: %10.4f\n", res); 
 } 
 
 Exercício: Fazer um programa que leia um valor n e que leia e imprima o quadrado de n 
números. 
 
 #include <stdio.h> 
 void main() 
 { 
 float x; 
 int n; 
 
 printf("Numero de valores a serem lidos: "); 
 scanf("%d", &n); 
 while (n--) 
 { 
 printf("Valor: "); 
 scanf("%f", &x); 
 printf("Quadrado de %f = %f\n", x, x * x); 
17 
 } 
 } 
 
8. Funções 
 
 Pequeno programa que retorna um valor. 
 
 Formato: 
 tipo nome_função (parâmetros) 
 { 
 declaração de variáveis locais; 
 corpo da função; 
 } 
 
 • tipo é o tipo do valor a ser retornado pela função; 
 • se uma função não retorna nada, o seu tipo é void; 
 • os parâmetros são sempre passados por valor, isto é, uma cópia do valor da variável é 
passado para a função; 
 • para arrays (vetores e matrizes) é passado como valor o endereço da primeira posição; 
 • deve-se sempre usar o protótipo da função; 
 • variáveis 'char' são transformadas em 'int' e variáveis 'float' são transformadas em 'double'. 
 
 Notas: 
 O formato da função varia entre o padrão K & R e o ANSI, sendo que o padrão K & R pode 
ser usado no ANSI. 
 
 formato K & R | formato ANSI 
 int soma (a, b) | int soma (int a, int b) 
 int a, b; | { 
 { | return (a+b); 
 return (a+b); | } 
 } | 
 O valor retornado por uma função pode ou não ser utilizado, como por exemplo na função 
printf(). 
 
 Uma função pode retornar de qualquer ponto da função, bastando para isto se usar a instrução 
return. 
 
 Exercício: Fazer um programa para ler um número e imprimir o seu fatorial. 
 
 #include <stdio.h> 
 long fatorial(long); 
 long leval(void); 
 void printfat(long); 
 void main() 
 { 
 long fat, val; 
 val = leval(); 
 fat = fatorial(val); 
 printfat(fat); 
 } 
 
 long leval() 
 { 
18 
 long x; 
 printf("Entre o valor a ser calculado: "); 
 scanf("%ld", &x); 
 return(x); 
 } 
 
 void printfat(long y) 
 { 
 printf("Fatorial = %ld\n", y); 
 } 
 
 long fatorial(long a) 
 { 
 long fator = 1; 
 long i; 
 for (i = 1; i <= a; i++) 
 fator *= i; 
 return(fator); 
 } 
 
9. Arrays unidimensionais (vetores) 
 
 Definição de vetores unidimensionais: 
 
 Formato: 
 <tipo> <nome>[<tam>]; 
 
 Exemplo: 
 int vet[5]; ⇒ define vet como um vetor inteiro de 5 posições 
 
 A posição do primeiro elemento é vet[0] e do último vet[4]. 
 
 Exemplos de acesso: 
 int vet[5]; 
 
 vet[0]=10; 
 vet[1]=20; 
 vet[2]=40; 
 
 for (i = 0; i < 5; i++) /* zera o vetor */ 
 vet [i]=0; 
 
 Inicialização na definição: 
 
 para vetor local: 
 
 static int vet[] = {1, 3, 5}; 
 assume que o vetor 'vet' possui 3 elementos 
 
 static float vet[10]; 
 assume que o vetor 'vet' tem 10 elementos, os quais são inicializados com zero (0) 
 
 static int vet[5] = {1, 2, 3}; 
 assume que o vetor 'vet' tem 5 elementos, sendo que o quarto e o quinto são inicializados com 
zero (0) 
19 
 
 para vetor global: 
 
 int vet[] = {10,20,40,50}; 
 assume que o vetor 'vet' tem 4 elementos 
 
 Quando um vetor 'extern' ou 'static' for inicializado sem dimensão, a dimensão será a do 
número de valores da inicialização. 
 
 Caso seja fornecida a dimensão e faltem elementos na inicialização, os elementos não 
inicializados valer,o zero. 
 
 Exercício: Fazer uma função que retorne o maior número de um vetor double. 
 
 #include <stdio.h> 
 double maxval(double [], int); 
 void levet(double [], int); 
 
 void main() 
 { 
 double vet[100]; 
 int i, n; 
 printf("Numero de elementos do vetor: "); 
 scanf("%d", &n); 
 levet(vet, n); 
 printf("Maior valor = %lf", maxval(vet, n)); 
 } 
 
 void levet(double v[], int n) 
 { /* double v[]; não precisa dar a dimensão */ 
 int i; 
 double aux; 
 printf("Entre os elementos do vetor:"); 
 for (i = 0; i < n; i++) 
 { 
 scanf("%lf", &aux); 
 v[i] = aux; 
 } 
 } 
 
 double maxval(double v[], int n) 
 { 
 int i; 
 double maior; 
 maior = v[0]; /* maior começa como sendo o primeiro */ 
 for (i = 1; i < n; i++) 
 if (v[i] > maior) 
 maior = v[i]; 
 return(maior); 
 } 
 
 
9.1. Strings 
 
 São arrays de caracteres. 
 
 Obs.: Em C, toda string acaba com o caracter '\0'. 
20 
 
 Definição de um vetor de caracteres: 
 char str[7]; 
 
 A definição acima, define str como sendo um vetor de 6 caracteres mais o caracter de final de 
string. 
 
 Exemplo: 
 
 char str[8]; 
 
 str[0] = 'R'; 
 str[1] = 'i'; 
 str[2] = 'n'; 
 str[3] = 'a'; 
 str[4] = 'l'; 
 str[5] = 'd'; 
 str[6] = 'o'; 
 str[7] = '\0'; 
 
 
 
 
 Na memória teríamos: 
 
R 0 
i 1 
n 2 
a 3 
l 4 
d 5 
o 6 
\0 7 
 
 Podemos inicializar uma string de duas formas: 
 
 1. Como um vetor: 
 
 static char str[] = {'R', 'i', 'n', 'a', 'l', 'd', 'o', '\0'}; 
 assume 7 caracteres mais '\0' = 8 
 
 2. Deixar que o compilador inicialize: 
 
 static char str[]="Rinaldo"; 
 assume 7 caracteres mais '\0' = 8 
 
 Obs.: Não é possível a atribuição direta: 
 char str[7]; 
 str = "Rinaldo"; /* Erro: não vale a atribuição */ 
 
 Ex.: Fazer um programa para ler um nome e dar um bom dia para o dono do nome. 
 
21 
 Solução 1: 
 
 #include <stdio.h> 
 #define TAM 100 
 void main() 
 { 
 char linha[TAM]; 
 int c, i; 
 
 printf("\nQual é o seu nome? "); 
 for (i = 0; (c = getchar()) != '\n'; i++) 
 linha[i]=c;linha[i] = '\0'; 
 printf("Tenha um bom dia "); 
 for (i = 0; linha[i] != '\0'; i++) 
 putchar(linha[i]); 
 putchar('\n'); 
 } 
 
 A função getchar retorna um caracter do teclado e a função putchar coloca um caracter no 
vídeo. Estas funções, bem como as outras de IO podem ser redirecionadas. Em caso de erro, a 
função getchar retorna EOF. 
 Solução 2: 
 
 #include <stdio.h> 
 #define TAM 100 
 void main() 
 { 
 char linha[TAM]; 
 
 printf("\nQual é o seu nome? "); 
 gets(linha); 
 printf("\nTenha um bom dia "); 
 puts(linha); 
 } 
 
 A função gets tem por finalidade ler uma string e a puts imprimir uma string. A função puts 
fornece automaticamente uma mudança de linha após a impressão. 
 
 
 Para atribuição de strings, usa-se a função strcpy, que possui o formato: 
 char *strcpy(char *destino, char *origem); 
 
 Exemplo: 
 
 strcpy(str, "casa"); 
 str passa a ter "casa" 
 
 Para se saber o tamanho de uma função, usa-se a função strlen, que possui o formato: 
 int strlen(char *st); 
 
 Exercício: Construir a função strlen. 
 
 Solução 1: 
 
 int strlen(char cadeia[]) 
22 
 { 
 int len=0, i=0; 
 
 while (cadeia[i] != '\0') 
 { 
 ++len; 
 ++i; 
 } 
 return(len); 
 } 
 
 Solução 2: 
 
 int strlen(char cadeia[]) 
 { 
 int i; 
 
 for (i = 0; cadeia[i] != '\0'; i++); /* bloco nulo */ 
 return (i); 
 } 
 Exercício: Construir a função stingcpy 
 
 Solução 1: 
 
 void stringcpy(char[], char[]); 
 
 void stringcpy(char s1[], char s2[]) 
 { 
 int i; 
 for (i = 0; s2[i] != '\0'; i++) 
 s1[i] = s2[i]; 
 s1[i] = '\0'; 
 } 
 
 Solução 2: 
 
 void stringcpy(char s1[], char s2[]) 
 { 
 int i = 0; 
 while ((s1[i] = s2[i]) != '\0') 
 i++; 
 } 
10. Arrays bidimensionais (matrizes bidimensionais) 
 
 Formato: 
 <tipo> <nome>[<d1><d2>]; 
 
 onde: 
 d1 ⇒ número de linhas (varia entre 0 e d1 - 1) 
 d2 ⇒ número de colunas (varia entre 0 e d2 - 1) 
 
 Exemplo: 
 int b[3][5]; ⇒3 linhas e 5 colunas 
 
 Inicialização na declaração: 
23 
 static int b[][3] = | static int b[][3] = 
 { | { 
 1, 1, 1, | {1, 1, 1}, 
 2, 2, 2, | {2, 2, 2}, 
 3, 3, 3 | {3, 3, 3} 
 }; | }; 
 
 A inicialização também pode ser feito de forma esparsa. Por exemplo: 
 
 static int b[3][3] = 
 { 
 {1, 1}, 
 {1} 
 }; 
 
 
 
 
 A matriz gerada pela inicialização acima será: 
 
 1 1 0 
 1 0 0 
 0 0 0 
 
 Note que para este tipo de inicialização é necessário que se forneça o número de linhas e de 
colunas. 
 
 Nota: O armazenamento em C é feito por linhas. 
 
 Passagem de um array bidimensional para uma função: 
 
 Ao se passar uma matriz bidimensional, a única dimensção fixa é o número de colunas (ao 
contrário do Fortran que fixa o número de linhas). 
 
 Exemplo: 
 Dado: 
 void main() 
 { 
 int mat[10][20]; 
 ... 
 f(mat, 10, 20); 
 ... 
 } 
 
 A função f() poderia receber a matriz de duas formas: 
 
 void f(int mat[10][20], int lin, int col) ou 
 void f(int mat[][20], int lin, int col) 
 { 
 
 } 
 
 Exemplo para zerar uma matriz: 
 
 void zera(float mat[][20], int, int); /* protótipo */ 
24 
 
 void main() 
 { 
 float mat[10][20]; 
 zera(mat, 10, 20); 
 } 
 
 void zera(float mat[][20], int lin, int col) 
 { 
 register int i, j; 
 for (i = 0; i < lin; i++) 
 for (j = 0; j < col; j++) 
 mat[i][j] = 0.0; 
 } 
 
 
11. Pointers (ponteiros) 
 
11.1. Definição 
 
 Um pointer é uma variável que contém como valor um endereço. 
 
 Para definirmos uma variável como ponteiro, devemos fornecer o tipo da variável para qual 
apontará e um nome. 
 
 Embora os endereços de variáveis de um tipo, por exemplo int, sejam semelhantes aos de 
outros tipos como float, char ou double, é importante não misturá-los. Para a declaração de 
um ponteiro tem-se que indicar o tipo de variável para o qual ele irá apontar, pois ao serem 
feitas as operações aritméticas com os ponteiros eles irão variar em função do tipo. 
 
 Principais vantagens do uso: 
 • superar as restrições de passagem de argumento, por valor, para funções; 
 • acessar elementos de arrays de modo alternativo ao uso de índices; 
 • permitir a criação de estruturas dinâmicas, como árvores e listas encadeadas bem como 
a sua manipulação. 
 
 Forma de definição: 
 <tipo> *<nome>; 
 
 Exemplos: 
 int *p; ⇒ p é um pointer para inteiro 
 float *pf; ⇒ pf é um pointer para float 
 
 int i, *pt; ⇒ pt é um pointer para inteiro 
 pt = &i; ⇒ pt recebe o endereço de 'i' 
 
25 
 
5 1002
i p
1002 2000
t
 
 
 *pt ⇒ 5 (conteúdo do endereço dado por pt) 
 void *pvoid; ⇒ pointer para qualquer tipo 
 
 Dado: 
 float x, y, *p, *q; 
 
 Temos como operações possíveis: 
 p = &x; ⇒ p aponta para x 
 y = *p; ⇒ y recebe o valor que está no endereço dado por p 
 q = p; ⇒ q e p apontam para o mesmo endereço 
 
 
 Erros comuns: 
 int *p; 
 *p = 10; não apontou para nenhuma variável 
 float val; 
 int *p; 
 p = &val; tipos incompatíveis 
 
11.2. Inicialização de pointers na definição 
 
 int i = 7, *p = &i; 
 a inicialização é de 'p' e não de '*p' 
 
11.3. Passagem de parâmetros por endereço (referência) 
 
 Para que se possa passar uma variável por referência, devemos passar um pointer para esta 
variável ou, em outras palavras, o seu endereço. 
 
 /* 
 ** Exemplo: ler dois valores e trocá-los de ordem 
 */ 
 
 #include <stdio.h> 
 void swap(int *, int *); /* protótipo de swap */ 
 
 void main() 
 { 
 int a, b; 
 
 scanf("%d %d", &a, &b); /* le os dados */ 
 swap(&a, &b); /* chama a função swap */ 
 printf("%d : %d\n", a, b); /* imprime resultado */ 
 } 
 
 void swap(int *x, int *y) 
26 
 { 
 int tmp; 
 tmp = *x; 
 *x = *y; 
 *y = tmp; 
 } 
 
 Exercício: fazer uma função que tenha o seguinte protótipo: 
 
 void soma(int *r, int a, int b); 
 
 #include <stdio.h> 
 void soma(int *r, int a, int b); 
 
 void main() 
 { 
 int x, y, z; 
 printf("\nEntre dois números:\n"); 
 scanf("%d %d", &x, &y); 
 soma(&z, x, y); 
 printf("\nA soma é: %d\n", z); 
 } 
 
 
 void soma(int *r, int a, int b) 
 { 
 *r = a + b; 
 } 
 
12. A relação entre pointers e arrays 
 
 Um nome de array é um endereço ou pointer, que é fixo. 
 
 Exemplo: 
 
 int k, a[100], *p; 
 
 p = a; ⇒ 'p' possui o endereço do primeiro elemento de 'a' 
ou 
 p = &a[0]; ⇒'p' possui o endereço do primeiro elemento de 'a' 
 
 Para que 'p' aponte para o elemento seguinte, basta incrementar o endereço de 1. 
 
 p = a + 1; ⇔ p = &a[1]; 
 
 p++; ⇒ 'p' aponta para o próximo elemento 
 
 k = *p++; ⇒ 'k' recebe o valor do elemento apontado por 
 'p' e 'p'aponta para o próximo elemento 
 
 Exemplo para zerar um vetor: 
 
 for (i = 0; i < 100; i++) /* com índice */ 
 a[i]=0; 
27 
 
 ou 
 
 for (i = 0, p = a; i < 100; i++) /* com ponteiro */ 
 *p++ = 0; 
 
 Exercício: Criar a função strlen usando pointer. 
 Solução 1: 
 #include <stdio.h> 
 int strlen(char* str); 
 void main() 
 { 
 static char str[] = "Esta string tem 30 caracteres."; 
 printf("\nTamanho da string: %d caracteres.\n", 
 strlen(str)); 
 } 
 int strlen(register char *s) 
 { 
 register int n; 
 for (n = 0; *s != '\0'; s++) 
 ++n; 
 return(n); 
 } 
 
 Solução 2: 
 #include <stdio.h>int strlen(char *str); 
 void main() 
 { 
 static char str[] = "Esta string tem 30 caracteres."; 
 printf("\nTamanho da string : %d caracteres.\n", 
strlen(str)); 
 } 
 int strlen(register char *s) 
 { 
 register int n=0; 
 while (*s++) 
 ++n; 
 return(n); 
 } 
 
 Solução 3: 
 #include <stdio.h> 
 int strlen(char *str); 
 void main() 
 { 
 static char str[] = "Esta string tem 30 caracteres."; 
 printf("\nTamanho da string : %d caracteres.\n", 
 strlen(str)); 
 } 
 int strlen(register char *s) 
 { 
 register char *ps; 
 ps = s; /* ps aponta para o inicio da string */ 
 while (*ps) 
 ps++; 
 return(ps - s); 
 } 
 
28 
 Exercício: Criar a função strcpy, que tem como finalidade copiar o conteúdo de uma 
string em outra. 
 
 Solução: 
 
 #include <stdio.h> 
 char *strcpy(char *d, char *o); 
 
 void main() 
 { 
 static char orig[] = "teste", dest[20]; 
 strcpy(dest, orig); 
 printf("origem = %s ; destino = %s\n", dest, orig); 
 } 
 
 char *strcpy (char *dest, char *origem) 
 { 
 char *d = dest; 
 
 /* 
 ** O while a seguir faz a copia e incrementa os 
 ** ponteiros de cada string, até aparecer um caracter 
 ** nulo significando fim de string. 
 ** Alguns compiladores darão um aviso (warning), achando 
 ** que se deseja fazer um teste ao invés de atribuição 
 ** com teste, que é o que se pretende fazer realmente. 
 */ 
 
 while (*d++ = *origem++); /* sem bloco */ 
 return(dest); 
 } 
 
 
 Exercício: Criar a função strcmp que tem como finalidade comparar o conteúdo de 
uma string com o de outra. A função tem o seguinte formato: 
 
 int strcmp(char *s, char *t); 
 Esta função retorna: 
 • 0 ⇒ se as strings forem iguais 
 • < 0 ⇒ se s < t 
 • > 0 ⇒ se s > t 
 
 Solução: 
 
 #include <stdio.h> 
 int strcmp(char *s, char *d); 
 
 void main() 
 { 
 char s1[20], s2[20]; 
 
 printf("Entre a primeira string: "); 
 gets(s1); 
 printf("Entre a segunda string: "); 
 gets(s2); 
 
 if (strcmp (s1, s2)) 
29 
 printf ("\nDiferentes.\n"); /* <> de zero */ 
 else 
 printf ("\nIguais.\n"); 
 } 
 
 int strcmp (char *s1, char *s2) 
 { 
 while (*s1 == *s2) 
 if (*s1++) 
 s2++; 
 else 
 return(0); 
 return(*s1 - *s2); 
 } 
 
 Para definição e inicialização de strings, também é possível o seguinte tipo de instrução: 
 char *mens = "Divisao por zero"; 
 
 A definição acima, define mens como sendo um pointer para a string "Divisao por zero". 
 
 Exercício: Fazer um programa que utilize uma função que retorne o maior elemento de um 
vetor. 
 
13. Pointers e arrays bidimensionais 
 
 Como para vetores unidimensionais, o nome de um array é um pointer fixo. Assim, as 
seguintes instruções são equivalentes e geram o mesmo código: 
 
 b[i][j] *(*(b + i) + j) *(b + i * ncolun + j) 
 
 
 Como para vetores unidimensionais, existem formas de se acessar matrizes de uma forma 
mais eficiente, como veremos a seguir. 
 
 Definição de pointers para matrizes. 
 int mat[10][20], (*plin)[20]; 
 plin = mat; 
 
 Nas instruções acima, definimos plin como sendo um pointer para uma linha de um array com 
20 colunas e mandamos que ele aponte para o primeiro elemento. 
 
 Forma de armazenamento na memória: 
... ... ...
20 elementos 20 elementos 20 elementos 
 
 
 Para acessar um elemento da matriz via ponteiro: 
 (*plin)[j] ou *(*(plin) + j) 
 
 Para se passar para a próxima linha: 
 plin++; 
30 
 
 
20 20 20
plin plin + 1 plin + 10 
 
 Nota: 
 (*plim)[20] define um ponteiro para linha de um vetor com 20 colunas, enquanto que 
*plin[20] define um vetor de 20 elementos do tipo ponteiro. 
 
 Exercício: Calcular a média dos elementos de uma coluna de uma matriz de 3 colunas. 
 Solução: 
 
 #include <stdio.h> 
 double test_avg(int[][3], int, int); 
 void main() 
 { 
 double res; 
 static int board[][3] = 
 { 
 1, 2, 3, 
 4, 5, 6, 
 7, 8, 9, 
 10, 11, 12 
 }; 
 
 res = test_avg(board, 4, 2); 
 printf("%lf\n", res); 
 } 
 
 double test_avg(int tab[][3], int maxlin, int col) 
 { 
 long sum = 0; 
 int i, (*ptr)[3] = tab; 
 
 for (i = 0; i < maxlin; i++) 
 sum += (*ptr++)[col]; 
 return ((double) sum / maxlin); 
 } 
 
 
 Exercício: calcular a média dos elementos de uma linha de uma matriz de 3 colunas. 
 
 Solução: 
 
 #include <stdio.h> 
 double test2_avg(int[][3], int); 
 void main() 
 { 
 static int board[][3] = 
 { 
 1, 2, 3, 
 4, 5, 6, 
 7, 8, 9, 
 10, 11, 12 
 }; 
 double res; 
 res = test2_avg(board,1); /* calcular para linha 1. */ 
31 
 printf("%lf\n", res); 
 } 
 
 
 
 
 
 
 
 double test2_avg(int tab[][3], int linha) 
 { 
 long soma = 0; 
 int i; 
 int *p = &tab[linha][0]; 
 
 for (i = 0; i < 3; i++) 
 soma += *p++; 
 return ((double) soma / 3); 
 } 
 
 Notas: 
 • &tab[n][0] - endereço do elemento (n, 0) em tab 
 • tab[n] - linha n de tab 
 
 O nome de um array bidimensional quando usado com um único índice é um ponteiro para o 
primeiro elemento de uma determinada linha. 
 
 
13.1. Arrays de pointers (ragged arrays) 
 
 São arrays com linhas de tamanho variável. Um array deste tipo é composto por ponteiros 
para outras variáveis e o seu uso mais comum é para acessar tabelas de strings. 
 
 Exemplo: definir um vetor de pointers para uma tabela de dias da semana. 
 
 static char *dias[] = 
 { 
 "segunda", "terça", "quarta", 
 "quinta", "sexta", "sábado", "domingo" 
 }; 
 
 Para esta definição, dias é um array de 7 ponteiros para caracteres. 
 
 O esquema a seguir apresenta a organização interna da tabela de dias da semana. 
 
 
...
dias
0
1
6
s e g u n d a \0
\0
\0
t e r ç a
d o m i n g o 
 
32 
 Os elementos de 'dias' podem ser acessados de duas maneira: 
 
 1. dias[i] 
 printf("%s\n", dias[2]); será impresso "quarta" 
 
 2. dias[i][j] 
 printf("%c\n", dias[1][2]); será impresso 'r' 
 (dias[1] ⇒ "terça" e dias[1][2] ⇒ 'r' de "terça" 
 
 
 Exercício: Fazer uma função para imprimir 'dias'. 
 
 Solução: 
 
 #include <stdio.h> 
 void printab(char*[], int); 
 
 void printab(char *tab[], int n) 
 { 
 int i; 
 for (i = 0; i <= n; i++) 
 printf("%s\n",tab[i]); 
 } 
 
 Nota: 
 Um elemento em um array de pointers pode ser usado como se ele fosse um pointer para o 
primeiro elemento de uma linha de um array bidimensional (tab[i]). 
 
14. Definição de novos tipo 
 
 Para definição de novos tipos, é utilizada a instrução typedef. 
 
 Formato: 
 typedef <tipo existente> <novo tipo>; 
 
 Exemplos: 
 para se definir o tipo 'contador': 
 
 typedef int contador; 
 contador i, j; (int i, j) 
 
 para se definir o tipo 'string': 
 
 typedef char string[81]; 
 string text; (char text[81]) 
 
 para se definir o tipo 'boolean': 
 
 typedef int boolean; 
 #define FALSE 0 
 #define TRUE 1 
 ... 
33 
 boolean ok = TRUE; 
 if (ok) ... 
 
 para se definir o tipo 'ptrchar' (pointer para caracter): 
 
 typedef char *ptrchar; 
 ptrchar pchar; (char *pchar) 
 
15. Ponteiro para percorrer array de ponteiros. 
 
 Como para os outros arrays, o nome de um array de ponteiros é um ponteiro para o primeiro 
elemento do array. Quando se passaum array de ponteiros como parâmetro, o que realmente 
se passa é um pointeiro para o primeiro elemento do array. 
 
 Exemplo: Imprimir tabela 'dias'. 
 
 typedef char *CHARPTR; /* define tipo pointer para char */ 
 
 void print_tab(CHARPTR *tab_ptr, int n) 
 { 
 CHARPTR *end_ptr = tab_ptr + (n - 1); 
 while (tab_ptr <= end_ptr) 
 printf ("%s\n", *tab_ptr++); 
 } 
 
 Esquema dos ponteiros: 
 
 
...
0
1
6
s e g u n d a \0
\0
\0
t e r ç a
d o m i n g o
tab_ptr
end_ptr
 
 
16. Ponteiros para funções 
 
 Permitem passar funções como argumentos. 
 
 Forma de definição: 
 
 <tipo> (*func_ptr)(<tipos dos argumentos>); 
 
 Nota: se não forem colocados os parênteses, estará sendo defininda uma função que 
retorna um pointer para <tipo>. 
 
 Exemplo: 
 
 int soma (int, int); 
 void main() 
 { 
34 
 int (*ptr_soma)(int, int); 
 ptr_soma = soma; /* pointer para função soma */ 
 x = (*ptr_soma)(3,5); /* ⇒ x = soma(3,5); */ 
 } 
 Exercício: Fazer um programa que leia duas strings de dados numéricos ou 
alfanuméricos e as compare conforme o seu tipo. 
 
 #include <stdio.h> 
 #include <stdlib.h> 
 #include <string.h> 
 
 int numcmp(char *, char *); 
 void check(char *, char *, int (*cmp)(char *, char *)); 
 
 void main() 
 { 
 char s1[80], s2[80]; 
 
 gets(s1); /* obtem primeira string */ 
 gets(s2); /* obtem a segunda string */ 
 if (isalpha(*s1)) 
 check(s1 ,s2, strcmp); /* comp. como strings */ 
 else 
 check(s1, s2, numcmp); /* comp. como números */ 
 } 
 
 void check(char *a, char *b, int (*cmp)(char *, char *)) 
 { 
 if (!(*cmp)(a, b)) 
 printf("iguais.\n"); 
 else 
 printf("diferentes.\n"); 
 } 
 
 int numcmp(char *a, char *b) 
 { 
 if (atoi(a) == atoi(b)) 
 return(0); 
 else 
 return(1); 
 } 
 
 
 Observações sobre o exemplo: 
 • a função strcmp compara strings 
 • a função isalpha retorna <> 0 para letra do alfabeto 
 • a função atoi transforma uma string em número inteiro 
 
17. Pré-processador e diretivas 
 
 O pré-processador é um programa que age antes do compilador da linguagem C, aumentando 
sua capacidade e auxiliando a portabilidade. Ele é comandado por diretivas (que começam 
sempre pelo sinal #). As diretivas só valem no arquivo onde estão definidas ou arquivos 
incluídos abaixo destas diretivas As principais diretivas são o #define e o #include. Além 
destas existem diretivas para compilação condicional (#if, #else, #elif, #endif, #ifdef e 
#ifndef) e outras utilizadas apenas por determinados compiladores como por exemplo para 
35 
montagem de trechos de programa em linguagem Assembly (#asm e #endasm). Entretanto, 
estas últimas não são portáveis, pois não são encontradas em todos os compiladores C. 
17.1 #define 
 
 Serve para definir uma constante simbólica. Por exemplo: 
 
 #define TRUE 1 
 #define FALSE 0 
 #define MENS_ERRO "Erro. Divisão por zero.\n" 
 #define MAX_TAM 100 
 
 As constantes assim definidas podem ser usadas para atribuir valores a variáveis, passadas 
como parâmetros e para comparações dentro do programa. 
 
 Exemplo: 
 
 int erro; 
 ... 
 erro = FALSE; 
 if (a == 0) 
 flag = TRUE; 
 ... 
 if (erro) 
 printf (MENS_ERRO); 
 Outra finalidade é definir macros. Por exemplo: 
 #define streq(x, y) (strcmp((x), (y)) == 0) /* iguais */ 
 #define strlt(x, y) (strcmp((x), (y)) < 0) /* x < y */ 
 #define strgt(x, y) (strcmp((x), (y)) > 0) /* x > y */ 
 
 Para que se possa reutilizar uma constante devemos torná-la antes indefinida, usando a 
diretiva #undef e a seguir redefiní-la novamente usando outro #define. Por exemplo: 
 
 a) #define NOME "teste" 
 ... 
 ... 
 #undef NOME 
 #define NOME "teste" 
 
 b) #define TAM 100 
 #define COMP 100 
 char array [TAM][COMP] 
 #undef COMP 
 #define COMP 200 
 char arrayb [TAM][COMP] 
 
17.2 #include 
 
 Permite incluir o conteúdo de um arquivo no programa. Por exemplo: 
 
 #include <stdio.h> procura stdio.h no diretório de arquivos 
 header 
 #include "stdio.h" procura stdio.h no diretório corrente 
 #include "b:auxiliar.h" procura auxiliar.h no drive b 
 
 Esta última forma deve ser evitada, pois gera dependência do sistema operacional. 
36 
 
17.3. Compilação condicional 
 
 Os comandos para compilação condicional são: 
 #if, #else, #elif, #ifdef, #ifndef e #endif #if, #else, #elif e #endif: 
 
 São comandos do tipo 'if then else' que indicarão para o compilador os trechos do programa 
que serão ou não compilados. 
 
 Exemplo de formatos possíveis: 
 
 #if expressão constante 
 sequência de comandos 
 #endif 
 
 #if expressão constante 
 sequência de comandos 1 
 #else 
 sequência de comandos 2 
 #endif 
 
 #if expressão constante 1 
 sequência de comandos 1 
 #elif expressão constante 2 
 sequência de comandos 2 
 #else 
 sequência de comandos 3 
 #endif 
 
 Exemplos de uso: 
 
 a) 
 #define MAX 100 
 ... 
 ... 
 
 void func() 
 { 
 #if MAX > 99 
 printf("Compilado para array > 99.\n"); 
 #endif 
 ... 
 ... 
 } 
 
 b) 
 #if PC == 1 
 #define COMP 1 
 #else 
 #define COMP 2 
 #endif 
 
 
 
 
 #ifdef e #ifndef 
37 
 
 Usados para testar a existência ou não do símbolo que tem como parâmetro. 
 
 Exemplo de formatos possíveis: 
 
 #ifdef símbolo 
 sequência de comandos 
 #endif 
 
 #ifdef símbolo 
 sequência de comandos 1 
 #else 
 sequência de comandos 2 
 #endif 
 
 #ifndef símbolo 
 sequência de comandos 
 #endif 
 
 #ifndef símbolo 
 sequência de comandos 1 
 #else 
 sequência de comandos 2 
 #endif 
 
 Exemplos de uso: 
 
 a) 
 #ifdef DEBUG 
 printf ("O valor de x : %d\n", x); 
 #endif 
 
 b) 
 #ifndef DEBUG 
 printf ("Sem debug.\n"); 
 #endif 
 
18. Tipos construídos 
 
18.1. Tipo enumerado 
 
 Faz com que uma variável possa ter somente um valor dentre um conjunto determinado de 
valores. 
 
 Forma de definição: 
 enum <nome> {<conjunto de valores separados por vírgulas>}; 
 
 Exemplo: 
 enum dia 
 {segunda, terça, quarta, quinta, sexta, sábado, domingo}; 
 0 1 2 3 4 5 6 
 
 Este exemplo define o tipo 'dia'. Uma variável deste tipo somente poderá receber um dos 
valores dados entre parênteses. 
 
38 
 enum dia, dia1, dia2, todos[7]; /* define variáveis */ 
 dia1 = segunda; 
 todos[6] = domingo; 
 
 Note que os valores entre parênteses não são strings. 
 
 Uma outra forma de definição possível é: 
 
 enum {segunda, ..., domingo} dia1, dia2; 
 
 Se usarmos as definições acima, a cada valor do tipo enumerado será associado um valor 
inteiro, a partir de zero (0). Entretanto, podemos indicar os valores inteiros que desejamos 
associar: 
 
 enum frutas {laranja = 7, lim,o = 6, jaca = 0}; 
 enum frutas {pera = 2, laranja, abacate, lim,o = 7}; 
 
 Apesar das definições acima, os valores dos tipos enumerados não são inteiros. 
 
 Erros: 
 
 dia1 = 1.0; 
 dia2 = 2; 
 
 Para usarmos o valor inteiro associado, devemos usar um "cast" para inteiro: 
 
 i = (int) dia1; 
 
18.2. Estruturas 
 
 Estruturas (struct) são usadas quando há necessidade de se combinar dados de um mesmo tipo 
ou de tipos diferentes em um único objeto ou registro. 
 
 Forma de definição: 
 
 struct <nome> 
 { 
 <tipo1> <campo1>; 
 <tipo2> <campo2>; 
 ... 
 <tipon> <campon>; 
 }; 
 
 Exemplos: 
 struct s1 /* Define estruturachamada s1 */ 
 { /* contendo os seguintes campos:*/ 
 int a; /* inteiro - a */ 
 char nome[81]; /* array de caracteres - nome */ 
 char ender[100]; /* array de caracteres - endereço */ 
 }; 
 struct s1 passa a ser um tipo. 
 
 /* 
 ** utiliza a estrutura s1 para definir 
 ** duas variáveis estruturadas: info1 e info2 
39 
 */ 
 struct s1 info1, info2; 
 
 Outra forma de definirmos variáveis é: 
 
 struct 
 { 
 int x; 
 int y; 
 } v1, v2; 
 
 No exemplo acima, não foi criado um tipo. 
 
 Também é possível o uso do typedef em conjunto com as estruturas: 
 
 typedef struct s1 s_s1; 
 s_s1 info1, info2; 
 
 Acesso aos membros de uma estrutura: 
 
 <variável>.<campo>; 
 
 Exemplos: 
 info1.a = 10; 
 strcpy(info1.nome, "teste"); 
 
 struct s2 
 { 
 int a; 
 char *nome; 
 }; 
 
 struct s2 info3; 
 info3.a = 10; 
 info3.nome = "José da Silva"; /* nome é um ponteiro */ 
 
 Operações possíveis entre estruturas: 
 
 A partir da definição: struct s1 v1, v2; temos: 
 
 - atribuição: 
 v1 = v2; 
 
 - comparação: (somente igualdade e desigualdade) 
 if (v1 == v2) 
 { 
 ... 
 } 
 
 É possível perguntarmos se duas estruturas são iguais ou diferentes, mas não se uma é maior 
ou menor do que a outra. No entanto, os campos (membros) de uma estrutura podem ser 
comparados com os de outra. 
 
40 
 Apesar de na versão ANSI podermos passar estruturas por valor para as funções, isto deve ser 
evitado, já que torna a chamada da função mais lenta e aumenta a área ocupada no stack. A 
forma mais indicada para se passar estruturas é utilizar pointers, como será visto mais adiante. 
 
18.3. Inicialização de estruturas 
 
 Para alguns compiladores, é necessário que as variáveis locais sejam estáticas. 
 
 struct s_carta 
 { 
 int carta; 
 char naipe; /* Ouro, Copas, Paus e Espadas */ 
 }; 
 
 struct s_carta c = 
 { 
 12, 
 'O' /* inicializa como dama de ouros */ 
 }; 
 
19. Pointer para estruturas 
 
 Como vimos anteriormente, devemos passar as estruturas através de pointers e não por valor. 
Isto deve ser feito mesmo que não alteremos nenhum dos campos da estrutura. 
 
 Exemplo: 
 
 #include <stdio.h> 
 struct s_data 
 { 
 int dia, mes, ano; 
 }; 
 
 typedef struct s_data sdata; 
 
 void prtdata(sdata *); 
 
 void main() 
 { 
 sdata data; 
 data.dia = 15; 
 data.mes = 3; 
 data.ano = 1988; 
 prtdata(&data); /* passa o endereço da estrutura */ 
 } 
 
 void prtdata(sdata *data) 
 { 
 printf("%d/%d/%d\n", 
 (*data).dia, (*data).mes, (*data).ano); 
 /* também pode usar: data->dia, data->mes, data->ano */ 
 } 
 
 Existem duas formas de se acessar os valores de uma estrutura através de pointers: 
 
41 
 *(pointer).componente; ou 
 pointer->componente; 
 
 Exemplo: 
 
 sdata data, *pdata; 
 pdata = &data; 
 (*pdata).dia = 31; ou pdata->dia = 31; 
 (*pdata).mes = 12; ou pdata->mes = 12; 
 (*pdata).ano = 1989; ou pdata->ano = 1989; 
 
20. Arquivos 
 
 A linguagem C possui alguns arquivos pré-definidos e que são automaticamente abertos 
quando um programa começa a ser executado. 
 
 Eles são: 
 stdin standard input (default = teclado) 
 stdout standard output (default = vídeo) 
 stderr standard error (default = vídeo) 
 stdprn standard printer (somente alguns compiladores) 
 
 Os arquivos pré-definidos stdin, stdout e stderr podem ser redirecionados pelo usuário. 
 O arquivo stdprn é dependente do compilador, podendo existir ou não. 
 
 Para estes arquivo pré-definidos, a leitura e impressão se passam como se estivéssemos 
utilizando um arquivo texto (leitura e gravação sequenciais). 
 
 O conceito de arquivos em C é um pouco diferente do de outras linguagens. Na maioria das 
linguagens, o tipo de acesso (direto ou sequencial) está diretamente ligado à forma de abertura 
do arquivo, o que não acontece em C. 
 
 Em C, o acesso a um arquivo pode ser direto ou sequencial, sendo que esta escolha é feita 
conforme as necessidades do usuário. 
 
 O C possui funções que permitem o acesso tanto direto quanto sequencial e permitem um 
acesso bastante eficiente à arquivos. 
 
 Forma de definição: 
 FILE *fp; 
 
 Para que esta definição esteja correta, é necessário que o arquivo stdio.h tenha sido incluído. 
 
20.1. Funções para abertura e fechamento de arquivos 
 
 Abertura de arquivos: 
 
 FILE *fopen(char *, char *); 
 fp = fopen(nome, modo); 
 
42 
 Esta função abre o arquivo de nome "nome" com o modo "modo"."nome" e "modo" são 
strings de caracteres. 
 
 Os modos de abertura possíveis são apresentados na tabela abaixo: 
 
Modo Tipo Read Write Cria Append 
r t s n n n 
r+ t s s n n 
rb b s n n n 
rb+ b s s n n 
w t n s s n 
w+ t s s s n 
wb b n s s n 
wb+ b s s s n 
a t n s s s 
a+ t s s s s 
ab b n s s s 
ab+ b s s s s 
 
 Onde: 
 • r ⇒ read 
 • w ⇒ write 
 • a ⇒ append 
 • t ⇒ texto 
 • b ⇒ binário 
 • s ⇒ sim 
 • n ⇒ não 
 
 Em caso de sucesso na abertura, a função fopen retorna um ponteiro para o arquivo, o qual 
será utilizado como nome lógico do arquivo dentro do programa e, em caso de erro, retorna 
NULL. 
 É responsabilidade do usuário verificar se o arquivo foi aberto ou não. 
 
 Exemplo: 
 
 fp = fopen("teste.dat", "r"); 
 if (fp == NULL) /* ou if (!fp) */ 
 { 
 printf("\nErro: abertura de arquivo para leitura"); 
 exit(1); /* retorna para o sistema operacional */ 
 } 
 O nome do arquivo pode indicar um nome simples ou um nome com path (caminho). 
 
 Exemplos de nomes: 
 
 "teste.dat" 
43 
 "C:\programas\testes\teste.dat" 
 
 A diferença básica entre os modos texto e binário reside no fato de que quando os arquivos 
são abertos no modo texto para gravação, o caracter NL (New Line) é convertido em dois: CR 
(Carriage Return) e LF (LineFeed) e quando são abertos no modo texto para leitura, ocorre o 
inverso. Para os aquivos abertos no modo binário, esta conversão não existe, havendo, 
portanto, uma correspondência de 1 para 1. 
 
 
 Fechamento de arquivos: 
 
 int fclose(FILE *); 
 fclose(fp); 
 
 Em caso de sucesso, a função retorna NULL e em caso de erro, um valor diferente de zero 
(0). 
 
 Exemplo: 
 
 if ((fp = fopen("teste.dat", "r")) == NULL) 
 { 
 printf("\nErro de abertura para leitura"); 
 exit(1); 
 } 
 ... 
 ... 
 fclose(fp); 
 
20.2. Principais funções para leitura e gravação seqüenciais 
 
 Leitura: 
 
 char *fgets(char *, int, FILE *); 
 pchar = fgets(buffer, num, fp); 
 
 Le caracteres do arquivo dado pof 'fp'. A leitura termina quando forem lidos 'num - 1' 
caracteres, ou quando encontrar o caracter NL (New Line) ou EOF (End Of File). Os 
caracteres lidos são colocados em 'buffer'. Se a leitura foi correta, a função retorna um pointer 
para 'buffer' e em caso de erro retorna NULL. 
 O buffer deve ser grande o suficiente para que sejam colocados os caracteres '\0' e NL. 
 
 Exemplo: 
 
 char *pchar, buffer[100]; 
 FILE *fp; 
 ... 
 pchar = fgets(buffer, 98, fp); 
 ... 
 
 int fgetc(FILE *); 
 v_int = fgetc(fp); 
 
44 
 Le um caracter do arquivo dado por 'fp' e retorna o seu código ASCII. Se a leitura chegar ao 
final do arquivo ou houver erro de leitura, é retornado EOF. Entretanto, deve-se usar esta 
função com certo cuidado, já que EOF pode ser um caracter válido em arquivos abertos no 
modo binário. 
 
 
 int fscanf(FILE *, char *, ...); 
 fscanf(fp, fmt, args); 
 
 Funciona de forma semelhante à função scanf. Le as variáveis em 'args' com o formato 'fmt' 
do arquivo dado por'fp'. Em caso de sucesso, retorna o número de variáveis que foram lidas. 
Caso se chegue ao final do arquivo, é retornado EOF. 
 
 
 Gravação: 
 
 int fputs(char *, FILE *); 
 fputs(str, fp); 
 
 Grava a string 'str' no arquivo dado por 'fp'. A função retorna zero (0) se gravou bem e outro 
valor em caso de erro. 
 
 int fputc(int, FILE *); 
 fputc(carac, fp); 
 
 Grava o caracter 'carac' no arquivo dado por 'fp'. Em caso de erro, retorna EOF, porém se o 
arquivo for aberto em modo binário, EOF poderá ser um caracter válido. 
 
 int fprintf(FILE *, char *, ...); 
 fprintf(fp, fmt, args); 
 
 Funciona de forma semelhante à função printf. Grava as variáveis em 'args' com o formato 
'fmt' no arquivo dado por 'fp'. Em caso de sucesso, retorna o número de caracteres que foram 
gravados e em caso de erro, retorna um número negativo. 
 
 
20.3. Principais funções para leitura e gravação direta (binário) 
 
 Normalmente, para acesso direto se abre o arquivo como binário, para que a correspondência 
de caracteres seja de 1 para 1. 
 
 Funções para posicionamento: 
 
 void rewind(FILE *); 
 rewind(fp); 
 
 Coloca o ponteiro interno de I/O no início do arquivo dado por 'fp'. 
 
 int fseek(FILE *, long, int); 
 fseek(fp, offset, origem); 
 
45 
 Move o ponteiro interno de I/O do arquivo dado por 'fp' conforme 'offset' e 'origem'. 'offset' 
indica o número de bytes , a partir da origem 'origem', que o ponteiro deve se deslocar. Os 
valores possíveis para 'origem' são: 
 
 0 ou SEEK_SET - início do arquivo 
 1 ou SEEK_CUR - posição atual do ponteiro 
 2 ou SEEK_END - final do arquivo 
 
 Note que a variável 'offset' é do tipo long int. 
 
 Por exemplo, a instrução fseek(fp, 0l, 0) é equivalente a rewind(fp). 
 
 A função fseek retorna zero (0) para sucesso e um valor diferente de zero (0) para erro. 
 
 int fread(void *, int, int, FILE *); 
 fread(buf, tam, nblocos, fp); 
 
 Le para 'buf' 'nblocos' de 'tam' bytes do arquivo dado por 'fp'. 
 
 A função fread retorna o número de blocos lidos. 
 
 
 int fwrite(void *, int, int, FILE *); 
 int fwrite(buf, tam, nblocos, fp); 
 
 Funciona como fread, só que para gravação. A função retorna o número de blocos que foram 
gravados. 
 
 Exemplo: 
 Gravar e ler a variável double x de um arquivo. 
 
 ... 
 double x; 
 ... 
 fwrite(&x, sizeof(double), 1, fp); 
 ... 
 fread(&x, sizeof(double), 1, fp); 
 
 Exercício: Fazer um programa inicialize um vetor de 100 elementos com os números de 0 a 
99, o grave em um arquivo e o leia para outro vetor. 
 
 #include <stdio.h> 
 #include <stdlib.h> 
 
 void main() 
 { 
 FILE *fp; 
 int i; 
 float v1[100], v2[100], *pv; 
 
 for (pv = v1, i = 0; i < 100; i++) 
 *pv++ = (float) i; /* inicializa o vetor */ 
 
 /* abre o arquivo */ 
 if ((fp = fopen("teste.dat", "wb")) == NULL) 
46 
 { 
 printf("\nErro de abertura: gravação"); 
 exit(1); 
 } 
 
 fwrite(v1, sizeof(float), 100, fp); /* grava vetor */ 
 fclose(fp); /* fecha o arquivo */ 
 /* reabre o arquivo teste */ 
 if ((fp = fopen("teste.dat", "rb")) == NULL) 
 { 
 printf("\nErro de abertura: leitura"); 
 exit(2); 
 } 
 
 fread(v2, sizeof(float), 100, fp); /* le p/ novo vet */ 
 fclose(fp); /* fecha o arquivo */ 
 
 for(pv = v2, i = 0; i < 100; i++) 
 printf("%.2f\n", *pv++); /* imprime vetor lido */ 
 } 
 
 
 Exercício: Fazer um programa que grave em um arquivo três vetores de 100 elementos cada, 
sendo o primeiro formado pelos números de 0 a 99, o segundo os 100 primeiros números 
pares e o terceiro os 100 primeiros múltiplos de 3. A seguir fechar o arquivo e reabrí-lo lendo 
e imprimindo cada um dos vetores. 
 
 #include <stdio.h> 
 #include <stdlib.h> 
 #define TAM 100 
 
 void main() 
 { 
 FILE *fp; 
 int i; 
 float v1[TAM], *pv; 
 
 /* Abre arquivo testando se houve erro. */ 
 if ((fp = fopen("teste.vet", "wb")) == NULL) 
 { 
 printf("\nErro ao abrir arquivo inicial.\n"); 
 exit(1); 
 } 
 
 for (pv = v1, i = 0; i < TAM; i++) 
 *pv++ = (float)i; /* gera num. de 0 a 99 */ 
 
 /* 
 ** Aqui grava apenas um bloco com o tamanho de v1, 
 ** o que equivale a gravar sizeof(float) x TAM bytes. 
 ** Testa se gravou tudo. 
 */ 
 if (fwrite(v1, sizeof(v1), 1, fp) != 1) 
 { 
 printf ("\nErro ao gravar vetor 1.\n"); 
 exit(2); 
 } 
 
 for (pv = v1, i = 0; i < TAM; i++) 
47 
 *pv++ = (float) i * 2; /* vet: 0,2,4,...,198 */ 
 
 /* 
 ** Aqui grava TAM blocos com o tamanho de float, 
 ** o que equivale a gravar sizeof(float) x TAM bytes. 
 ** Testa se gravou tudo. 
 */ 
 if (fwrite(v1, sizeof(float), TAM, fp) != TAM) 
 { 
 printf ("\nErro ao gravar vetor 2.\n"); 
 exit(3); 
 } 
 
 for (pv = v1, i = 0; i < TAM; i++) 
 *pv++ = (float) i * 3; /* vet: 0,3,6,...,297 */ 
 
 /* 
 ** Aqui grava TAM blocos com o tamanho de float, 
 ** o que equivale a gravar sizeof(float) x TAM bytes. 
 ** Testa se gravou tudo. 
 */ 
 if (fwrite(v1, sizeof(float), TAM, fp) != TAM ) 
 { 
 printf ("\nErro ao gravar vetor 3.\n"); 
 exit(4); 
 }; 
 
 fclose(fp); /* fecha o arquivo */ 
 
 /* Reabre arquivo testando se houve erro.*/ 
 if ((fp = fopen("teste.vet", "rb")) == NULL) 
 { 
 printf("\nErro ao reabrir o arquivo.\n"); 
 exit(5); 
 } 
 
 fread(v1, sizeof(v1), 1, fp); /* le primeiro vetor */ 
 for (pv = v1, i = 0; i < TAM; i++) 
 printf("%f ", *pv++); /* imprime */ 
 
 printf("\n\n"); /* pula 2 linhas */ 
 rewind(fp); /* volta inicio arquivo */ 
 
 /* 
 ** a partir do inicio e com deslocamento v1, aponta 
 ** para o segundo vetor 
 */ 
 fseek(fp, (long) sizeof(v1), 0); 
 fread(v1, sizeof(float), TAM, fp); /* le seg. vetor */ 
 
 for (pv = v1, i = 0; i < TAM; i++) 
 printf("%f ", *pv++); /* imprime */ 
 printf("\n\n"); /* pula 2 linhas */ 
 rewind(fp); /* volta inicio arquivo */ 
 /* 
 ** a partir do início e com deslocamento de 2 x v1, 
 ** aponta para o terceiro vetor 
 */ 
 fseek(fp, (long) sizeof(v1) * 2,0); 
 fread(v1, sizeof(v1), 1, fp); /* le terceiro vetor */ 
48 
 
 for (pv=v1, i=0; i<TAM; i++) 
 printf("%f ", *pv++); /* imprime */ 
 printf("\n\n"); /* pula duas linhas */ 
 fclose(fp); /* fecha arquivo */ 
 } 
 
 
 Exemplo do uso de estruturas em arquivos: 
 
 struct s_prop 
 { 
 char nome[20]; 
 double mod; 
 double coef; 
 }; 
 
 typedef struct s_prop sprop; 
 sprop prop; 
 sprop variasprops[100]; 
 ... 
 /* grava uma propriedade */ 
 fwrite(&prop, sizeof(sprop), 1, fp); 
 /* grava um elemento da estrutura */ 
 
 /* grava vetor com várias propriedades */ 
 fwrite(variasprops, sizeof(sprop), 100, fp); 
 
21. Alocação dinâmica de memória 
 
 A linguagem C possui uma série de funções que permitem alocar e liberar áreas de memória, 
fazendo com que se possa usar a memória gasta por variáveis, vetores, matrizes, listas, pilhas, 
etc. de uma forma mais eficiente. 
 
 Quando necessário, o usuário pede uma área e a utiliza e, quando esta área não for mais 
necessária, ela é devolvida ao sistema operacional, de forma a poder serutilizada em outra 
etapa do programa. 
 
 O esquema abaixo apresenta o mapa da memória de um programa em C. 
 
Área de Código 
Área de Variáveis 
Estáticas e Globais 
Stack 
Heap 
 
 
 A área disponível para alocação dinâmica se encontra na "Heap". 
 
 As principais funções para manipulação de memória estão definidas no header stdlib.h e são: 
 
49 
 • malloc 
 • calloc 
 • realloc 
 • free 
 
 
 void *malloc(unsigned int); 
 ptr = malloc(tam); 
 
 Aloca uma área de 'tam' bytes. Se alocou corretamente, retorna um pointer para o primeiro 
byte da área alocada e em caso de erro retorna NULL. 
 
 Exemplo 1: 
 int *ptr; 
 ... 
 ptr = malloc(sizeof(int)); 
 if (ptr == NULL) 
 { 
 printf("Erro de alocação"); 
 exit(1); 
 } 
 
 *ptr = 10; 
 ... 
 
 Exemplo 2: 
 
 int *ptr, *ptraux, i; 
 ... 
 ptr = malloc(sizeof(int) * 100); 
 if (ptr == NULL) 
 { 
 printf("Erro de alocação"); 
 exit(1); 
 } 
 
 ptraux = ptr; 
 for (i = 0; i < 100; i++) 
 *ptr++ = i; 
 ptr = ptraux; 
 ... 
 
 Exemplo 3: 
 
 /* 
 ** Obtem área para um vetor do tipo float. 
 ** O número de elementos do vetor é pedido pelo programa. 
 ** Após a obtenção da área necessária s,o pedidos dados 
 ** para o seu preenchimento. 
 */ 
 
 #include <stdio.h> 
 #include <stdlib.h> 
 
 void privet(float, int); 
 
 void main() 
50 
 { 
 int num, i; 
 float *pvet, *pinic; 
 
 printf("\nEntre com número de elementos:\n"); 
 scanf("%d", &num); 
 pvet = (float*) malloc(num * sizeof(float)); 
 if (!pvet) 
 { 
 printf("\nErro. Falta de memória.\n"); 
 exit(1); 
 } 
 
 pinic = pvet; 
 for (i = 0; i < num; i++) 
 { 
 printf("\n%d -> ", i + 1); 
 scanf("%f", pvet++); /* não funciona no Turbo C */ 
 } 
 
 
 /* 
 ** para o Turbo C fazer: 
 for (i = 0; i < num; i++) 
 { 
 float aux; 
 printf("\n%d -> ", i + 1); 
 scanf("%f", &aux); 
 *pvet++ = aux; 
 } 
 */ 
 
 pvet = pinic; 
 prtvet(pvet, num); /* imprime o vetor */ 
 free(pvet); 
 } 
 
 void prtvet(float *p, int n) 
 { 
 int i; 
 for (i = 0; i < n; i++) 
 printf("\n\%d -> %f", i + 1, *pv++); 
 } 
 
 
 void *calloc(unsigned int, unsigned int); 
 ptr = calloc(num, size); 
 
 Aloca uma área de 'tam' * 'num' bytes. Se alocou corretamente, retorna um pointer para o 
primeiro byte da área alocada e em caso de erro retorna NULL. A área alocada é 
automaticamente zerada. 
 
 Exemplo 1: 
 
 int *ptr; 
 ... 
 ptr = calloc(1, sizeof(int)); 
 if (ptr == NULL) 
51 
 { 
 printf("Erro de alocação"); 
 exit(1); 
 } 
 *ptr = 10; 
 ... 
 
 Exemplo 2: 
 
 int *ptr, *ptraux, i; 
 ... 
 ptr = calloc(100, sizeof(int)); 
 if (ptr == NULL) 
 { 
 printf("Erro de alocação"); 
 exit(1); 
 } 
 
 ptraux = ptr; 
 for (i = 0; i < 100; i++) 
 *ptr++ = i; 
 ptr = ptraux; 
 ... 
 
 void free(void *); 
 free(ptr); 
 
 Libera a área alocada por malloc, calloc ou realloc. 
 Exemplo: 
 
 int *ptr, *ptraux, i; 
 ... 
 ptr = malloc(sizeof(int) * 100); 
 if (ptr == NULL) 
 { 
 printf("Erro de alocação"); 
 exit(1); 
 } 
 
 ptraux = ptr; 
 for (i = 0; i < 100; i++) 
 *ptr++ = i; 
 ptr = ptraux; 
 ... 
 free(ptr); 
 ... 
 
 void *realloc(void *, unsigned int) 
 nptr = realloc(old, tam); 
 
 A função realloc altera o tamanho da área alocada por malloc ou calloc. O novo tamanho 
pode ser maior ou menor do que o tamanho original. Quando chamada, retorna um pointer 
para a nova área alocada, sendo 'old' um pointer para a área antiga e 'tam' o novo tamanho em 
bytes. Em caso de erro, a função retorna NULL e o programa deve ser interrompido, já que a 
área original poderá estar comprometida. 
 
 Exemplo: 
52 
 
 #include <stdio.h> 
 #include <stdlib.h> 
 
 void prtvet(float*, int); 
 
 void main() 
 { 
 int num, i; 
 char *p; 
 
 p = (char*) malloc(23); 
 strcpy (p, "AQUI TEM 22 CARACTERES"); 
 printf("\n%s\n", p); 
 p = realloc(p, 24); 
 strcat(p, "."); 
 printf("\n%s\n", p); 
 free(p); 
 } 
 
53 
	1. Introdução
	1.1. Características
	1.2. Histórico
	1.3. Características de um programa
	1.4. Formato de um programa em C
	1.5. Exemplo de um programa
	2. Identificadores
	3. Tipos de dados para variáveis e funções
	3.1. Standard (já definidos na linguagem)
	3.2. Modificadores de tipo
	4. Declaração de variáveis
	4.1. Variáveis locais
	4.2. Parâmetros formais
	4.3. Variáveis globais
	4.4. Modificadores de classe de armazenamento
	4.4.1. Variáveis automáticas - auto
	4.4.2. Variáveis externas - extern
	4.4.3. Variáveis estáticas - static
	4.4.4. Variáveis register
	5. Operadores
	5.1. aritméticos
	5.2. lógicos ou boleanos
	5.3. relacionais
	5.4. Outros operadores 
	5.5. precedência (da maior para a menor)
	6. Funções de entrada e saída
	6.1. printf()
	6.2. putchar()
	6.3. puts()
	6.4. scanf()
	6.5. getchar()
	6.6. gets()
	7. Instuções de controle
	7.1. while
	7.2. for
	7.3. do while
	7.4. if e derivados
	7.5. switch
	7.6. continue
	7.7. break
	8. Funções
	9. Arrays unidimensionais (vetores)
	9.1. Strings
	10. Arrays bidimensionais (matrizes bidimensionais)
	11. Pointers (ponteiros)
	11.1. Definição
	11.2. Inicialização de pointers na definição
	11.3. Passagem de parâmetros por endereço (referência)
	12. A relação entre pointers e arrays
	13. Pointers e arrays bidimensionais
	13.1. Arrays de pointers (ragged arrays)
	14. Definição de novos tipo
	15. Ponteiro para percorrer array de ponteiros.
	16. Ponteiros para funções
	17. Pré-processador e diretivas
	17.1 #define
	17.2 #include
	17.3. Compilação condicional
	18. Tipos construídos
	18.1. Tipo enumerado
	18.2. Estruturas
	18.3. Inicialização de estruturas
	19. Pointer para estruturas
	20. Arquivos
	20.1. Funções para abertura e fechamento de arquivos
	20.2. Principais funções para leitura e gravação seqüenciais
	20.3. Principais funções para leitura e gravação direta (binário)
	21. Alocação dinâmica de memória

Outros materiais