Contedo
1
Programar em C/Capa
3.1
Histria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.1.1
Desenvolvimentos iniciais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.1.2
C de K&R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.1.3
3.1.4
C99 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.1.5
Resumo em ingls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Programar em C/Pr-requisitos
4.1
Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2
Compilador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3
Ligador ou linker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.4
Obtendo um compilador
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.5
Links externos
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.1
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2
gcc
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3
Visual C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
6.1
Compilao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
6.2
Etapas da compilao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
11
7.1
Um programa em C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
7.2
Compilando o programa
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
7.2.1
8
13
8.1
13
Estrutura bsica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
i
ii
CONTEDO
8.1.1
Escopo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
8.2
Introduo s funes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
8.3
Expresses
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
8.4
Comentrios
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
Programar em C/Variveis
15
9.1
Variveis
15
9.2
Declarando variveis
9.3
Atribuindo valores
9.4
Exemplo de erro
9.5
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
Nomes de variveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
17
17
17
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
10.0.4 Bool
10.0.5 Endereos
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
19
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
10.0.8 Literais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
11 Programar em C/Constantes
11.1 Constantes
21
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
21
21
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
23
23
12.3 printf()
24
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
24
26
12.4 scanf()
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
29
29
31
31
CONTEDO
iii
31
31
31
31
32
32
32
32
32
32
32
14.5 Funes de Arredondamento para Nmeros Inteiros, Valores Absolutos e Resto da Diviso . . . . .
32
32
32
32
33
15 Programar em C/Operadores
34
34
34
34
15.4 Expoentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
34
34
35
35
35
35
35
15.10Todos os Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
15.11Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
37
37
37
16.3 Testes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
16.3.1 if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
16.3.2 switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
16.4 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
16.4.1 while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
39
16.4.3 for
39
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
iv
CONTEDO
16.4.4 break e continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
40
41
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17 Programar em C/Funes
42
42
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
17.2.2 Parmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
44
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
45
17.7 void . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
17.8 Recursividade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
17.9 inline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
46
18 Programar em C/Pr-processador
18.1 O pr-processador
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
47
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
18.2.2 #dene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
18.2.3 #undef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
48
18.2.5 #if
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
18.2.6 #else
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
18.2.7 #elif
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
18.2.1 #include
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
18.4 Concatenao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
19 Programar em C/Exerccios
19.1 Questes
49
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
19.2.1 Exerccio 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
19.2.2 Exerccio 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
19.2.3 Exerccio 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
19.2.4 Exerccio 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
19.2.5 Exerccio 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
19.2.6 Exerccio 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
19.2.7 Exerccio 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
19.2.8 Exerccio 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
CONTEDO
19.2.9 Exerccio 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
19.2.10 Exerccio 10
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
19.2.11 Exerccio 11
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
20 Programar em C/Vetores
52
20.1 Vetores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
52
52
52
53
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
21 Programar em C/Strings
21.1 Strings
53
54
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
54
21.2.1 strlen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
21.2.2 strcpy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
21.2.3 strcat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
21.2.4 strcmp
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
21.2.5 strrchr
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
21.2.6 memcpy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
21.2.7 memset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
21.2.8 sprintf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
57
57
58
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
58
23.2 Estruturas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
58
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
58
23.2.2 Declarando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
58
59
23.2.4 Acessando
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
59
59
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
59
59
23.3 Unies
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
59
23.4 Enumeraes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
59
23.4.1 Uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
60
60
24 Programar em C/Enumerao
61
vi
CONTEDO
24.1 Enumerations (enum) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
61
25 Programar em C/Unio
25.1 Unions
62
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25.2 Declarao
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26 Programar em C/Estruturas
62
62
62
62
63
26.1 Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
63
63
63
63
64
64
64
64
64
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27 Programar em C/Ponteiros
66
27.1 Bsico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27.1.1 O que um ponteiro?
66
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
66
66
67
67
27.2 Intermedirio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
68
68
68
69
69
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
69
27.3 Avanado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
69
69
. . . . . . . . . . . . . . . . . . . . . . .
70
70
72
28.1 typedef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
28.2 sizeof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
73
73
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
73
CONTEDO
vii
28.4.1 const . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
74
28.4.2 volatile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
74
28.4.3 extern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
74
28.4.4 static . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
74
28.4.5 register . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
74
76
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
76
76
30 Programar em C/Bibliotecas
30.1 Bibliotecas
78
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30.2 O arquivo-cabealho
78
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
79
30.3.1 No GCC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
79
79
80
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
80
80
31.2.1 Exemplo
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
81
81
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
81
31.3.1 fwrite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
81
31.3.2 fputc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
31.4.1 fgetc
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
31.4.2 fgets
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
31.4.3 fscanf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
31.4.4 fscanf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
31.4.5 fread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
31.5.1 fseek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
31.5.2 rewind
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
31.5.3 feof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
83
85
85
85
32.1.2 calloc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
85
viii
CONTEDO
32.1.3 realloc
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
86
86
86
33 Programar em C/Sockets
88
33.1 Abstraes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
88
88
88
88
34 Programar em C/Makeles
89
34.1 Makele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
89
90
93
94
95
96
96
97
97
97
98
99
40.1 Primitivas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
99
99
99
40.4 Insero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
99
99
40.4.2 Insero no m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
99
101
CONTEDO
ix
102
43 Fila
103
104
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
106
46 Insertion sort
107
47 Selection sort
108
48 Bubble sort
109
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
110
111
CONTEDO
50.2.3 Licena . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Captulo 1
Programar em C/Capa
Programar em C
Captulo 2
para desenvolver processadores de texto, jogos, tocadores de mdia, etc. Muitos vo decidir trabalhar com a
mesma linguagem que a biblioteca foi escrita, e assim o
processo continua...
C uma das linguagens de programao mais populares
para se escrever sistemas operacionais, como o Microsoft
Windows, o Mac OS X e o GNU/Linux. Sistemas operacionais comunicam-se diretamente com o hardware; no
h nenhuma camada mais baixa para mediar seus pedidos. Originalmente, os sistemas operacionais eram escritos na linguagem Assembly, o que resultava em um
cdigo muito rpido e eciente. Entretanto, escrever um
sistema operacional em Assembly um processo tedioso
(lento), e produz um cdigo que funcionar somente em
uma arquitetura de CPU, tal como o x86 ou ARM. Escrever um sistema operacional em uma linguagem de alto
nvel, tal como C, possibilita que os programadores readaptem o sistema operacional a vrias arquiteturas sem
precisar reescrever todo o cdigo. O ncleo (kernel) Linux um exemplo de sistema operacional escrito em C,
com apenas algumas sees do cdigo escritas em Assembly, para poder executar instrues que s existem
em uma ou outra arquitetura e para algumas otimizaes.
Mas por que C e no Java ou Basic, ou ainda Perl? Linguagens como o Java ou Perl so linguagens a base de
bytecode interpretado por uma mquina virtual, sendo assim, no um cdigo interpretado diretamente pelo processador. Ao contrrio de muitas linguagens de programao, o C permite ao programador enderear a memria de maneira muito parecida como seria feito em Assembly. Linguagens como o Java ou o Perl fornecem mecanismos que permitem que o programador faa o seu
trabalho sem ter que se preocupar com a atribuio de
memria ou com apontadores. Geralmente isso bom,
uma vez que bastante trabalhoso lidar com a alocao de
memria quando escrevemos aplicaes com algoritmos
de alto nvel. No entanto, quando lidamos com tarefas
de baixo-nvel como aquelas que um ncleo (kernel) tem
obrigao de desempenhar, como a de copiar um conjunto de bytes para uma placa de rede, torna-se altamente
necessrio um acesso direto memria algo que no
possvel fazer com Java. C pode ser diretamente compilado em cdigo de mquina, e por isso rpido e eciente. Alm disso, C permite personalizar como implementar cada coisa ao bsico, como alocao de memria,
permitindo adaptaes para melhorar desempenho.
Vale lembrar que os softwares interpretadores de script ou
bytecode, como Java e Python, so escritos em linguagens
como C e C++.
Ser uma surpresa que C seja uma linguagem to popular?
Como num efeito domin, a prxima gerao de programas segue a tendncia dos seus ancestrais. Sistemas operacionais desenvolvidos em C sempre tm bibliotecas de
sistema desenvolvidas em C. Essas bibliotecas so usadas
para criar bibliotecas de programa (como Xlib, OpenGL
ou GTK), e seus desenvolvedores geralmente decidem
usar a mesma linguagem das bibliotecas de sistema. Desenvolvedores de aplicao usam bibliotecas de programa
2
Captulo 3
conhecido pelos programadores de C como K&R, serviu durante muitos anos como uma especicao informal da linguagem. A verso da linguagem C que ele descreve usualmente referida como C de K&R. (A segunda edio do livro cobre o posterior padro ANSI C,
descrito abaixo.) K&R introduziram as seguintes caractersticas na linguagem:
Desenvolvimentos iniciais
3.1.2
C de K&R
Em 1978, Ritchie e Kernighan publicaram a primeira edio do livro The C Programming Language. Esse livro,
3
3.1.3
Durante os nais da dcada de 1970, a linguagem C comeou a substituir a linguagem BASIC como a linguagem de programao de microcomputadores mais usada.
Durante a dcada de 1980, foi adotada para uso no PC
IBM, e a sua popularidade comeou a aumentar signicativamente. Ao mesmo tempo, Bjarne Stroustrup, juntamente com outros nos laboratrios Bell, comeou a trabalhar num projeto onde se adicionavam construes de
linguagens de programao orientada por objetos linguagem C. A linguagem que eles produziram, chamada
C++, nos dias de hoje a linguagem de programao de
aplicaes mais comum no sistema operativo Windows
da companhia Microsoft; C permanece mais popular no
mundo UNIX.
A portabilidade do UNIX foi a razo principal para a popularidade inicial de ambos, UNIX e C; pois ao invs de
3.1. HISTRIA
criar um novo sistema operacional para cada nova mquina, system programmers could simply write the few
system dependent parts required for the machine, and
write a C compiler for the new system; and since most
of the system utilities were written in C, it simply made
sense to also write new utilities in the language.
Captulo 4
Programar em C/Pr-requisitos
pr-requisito para um bom aprendizado de qualquer lin- separadamente. Em outras palavras ele une os arquivos
guagem de programao conceitos sobre lgica de pro- objetos e as bibliotecas (estticas, dinmicas) para forgramao.
mar uma nova biblioteca ou um executvel.
Alm disso, para programar em C, voc precisa de um
editor de textos e um compilador, discutidos a seguir.
4.1 Editor
Borland C++: a Borland disponibilizou um compilador gratuito que funciona em linha de comando,
como alternativa ao IDE comercial.
4.2 Compilador
Para Linux/Unix-like
gcc: um conjunto de compiladores ociais do projeto GNU, de cdigo aberto. Costumam vir instalados na maioria das distribuies GNU/Linux e
est disponvel para diversas plataformas, principalmente para as baseadas em sistemas do tipo unix.
Captulo 5
Programar em C/Utilizando um
compilador
5.1 Compiladores: viso geral
Para executar o compilador, voc precisa abrir um terminal (ou prompt de comando, como costuma ser chamado no Windows, ou ainda console). lgico que se
voc estiver em um sistema sem ambiente grco (como
o DOS), voc no precisa fazer isso.
O Windows s tem um terminal nativo, que o interpretador de comandos dele (cmd.exe ou command.com).
Pacotes como o Cygwin e o MSys (do mesmo projeto que Para compilar o arquivo programa.c, gerando o cdigoo MinGW) incluem terminais alternativos que funcionam objeto programa.o":
basicamente maneira do Linux.
gcc [OPES] -c programa.c
No Linux, alm dos terminais de modo texto, h vrios Para gerar o executvel programa binario bin ou proemuladores de terminal, entre os quais esto o XTerm, o grama.exe no Windows/DOS a partir do cdigo-objeto:
Konsole (KDE) e o Terminal do Gnome. O uso de todos
gcc [OPES] -o programa[.bin] programa.o
eles idntico.
Para gerar o executvel diretamente a partir do arquivofonte:
5.2 gcc
Resumo:
Captulo 6
Captulo 7
12
acima(ola.c) abra um terminal, entre na pasta onde o arquivo se localiza e digite o seguinte comando:
gcc -o ola ola.c
O compilador ir gerar o arquivo executvel chamado ola
que pode ser executado da seguinte forma:
./ola
[1] Esse comando uma diretiva do pr-processador; voc
aprender mais sobre esses comandos na seo Prprocessador.
Captulo 8
momento. O conceito de escopo est justamente relacionado a isso. Escopo o nvel em que um dado pode
ser acessado; em C h dois nveis: local e global. Uma
varivel global pode ser acessada por qualquer parte do
programa; variveis locais podem ser acessadas apenas
dentro do bloco onde foram declaradas (ou nos seus subblocos), mas no fora dele (ou nos blocos que o contm).
Isso possibilita que voc declare vrias variveis com o
mesmo nome mas em blocos diferentes. Veja um exemplo:
14
uma linha s (iniciados por //) foram incorporados ao padro da linguagem apenas em 1999, e portanto alguns
Se quisermos saber o valor de retorno de uma funo, compiladores podem no os suportar. As verses mais
podemos armazen-lo numa varivel. Variveis sero in- recentes do GCC no tero problema em suportar esse
troduzidas logo adiante, mas a sintaxe muito fcil de tipo de comentrio.
aprender:
valor_de_retorno = funcao(arg1, arg2);
Vejamos um exemplo completo:
//quadrado.c //calcula o quadrado de um nmero
#include<stdio.h> int square( int num1 ) { return
num1 * num1; } int main(){ int number; int result;
printf("\nDigite um numero: "); scanf("%d, &number);
result = square(number); printf(O Quadrado de %d eh:
%d, number, result); return 0; }
Em C, todo o cdigo (exceto as declaraes de variveis
e funes) deve estar dentro de funes. Todo programa
deve ter pelo menos uma funo, a funo main, que
por onde comea a execuo do programa.
8.3 Expresses
Um conceito muito importante em programao o de
expresso. Expresses so conjuntos de valores, variveis, operadores e chamadas de funes que so avaliados ou interpretados para resultar num certo valor, que
chamado o valor da expresso. Por exemplo:
3 * 4 + 9 uma expresso de valor 21;
a + 3 * b uma expresso equivalente expresso
matemtica a + 3b;
foo() uma expresso cujo valor o valor de retorno
da funo foo.
8.4 Comentrios
Muitas vezes bastante til colocar comentrios no cdigo, por exemplo para esclarecer o que uma funo faz,
ou qual a utilidade de um argumento, etc. A maioria das
linguagens de programao permite comentrios; em C,
eles podem aparecer de duas maneiras:
/* Comentrios que podem ocupar vrias linhas. */
e
// Comentrios de uma linha s, que englobam // tudo
desde as duas barras at o nal da linha.
Tudo que estiver entre as marcas /* e */ ou entre // ser
ignorado pelo compilador. Note que os comentrios de
Captulo 9
Programar em C/Variveis
9.3 Atribuindo valores
9.1 Variveis
Em um programa, existe a necessidade de se guardar valores na memria, e isso feito atravs de variveis, que
podem ser denidas simplicadamente como nomes que
se referem a lugares na memria onde so guardados valores. Ao declararmos uma varivel, no apenas estamos
reservando um espao de memria, como tambm estamos associando um nome a ele, o identicador. Ao invs
de utilizarmos o endereo da varivel na memria, que seria geralmente notado na forma hexadecimal, como por
exemplo 0x0012FED4, referimo-nos ao endereo apenas
pelo seu nome. Apenas para deixar claro, a prpria notao em hexadecimal j uma simplicao, pois computadores na verdade trabalham com binrio.
Em C, para utilizar uma varivel, ela deve ser primeiramente declarada, ou seja, devemos requisitar o espao
necessrio para essa varivel. Aps reservar um espao
na memria, o computador ir associar a ele o nome
da varivel. Se voc no declarar uma varivel e tentar
utiliz-la, o compilador ir avis-lo disso e no continuar a compilao.
int a; a = 2; a = 3;
no nal o valor da varivel a ser 3.
Mesmo sabendo que um exemplo de erro, escreva o cdigo acima em um arquivo .c e tente compilar para se
sempre necessrio indicar o tipo da varivel, pois cada familiarizar com as mensagens de erro do compilador,
tipo tem um tamanho diferente, ou seja, ocupa mais ou assim voc saber o que fazer quando elas ocorrerem.
menos espao na memria do computador. Mais adiante No exemplo acima no foi declarada a varivel a, ao tenintroduziremos os tipos de varivel.
tar compilar o compilador informa que o smbolo a no
15
16
foi denido.
Captulo 10
'
10.0.1
00000000 1 Combinao
00000001 2 Combinao
00000010 3 Combinao
00000011 4 Combinao
00000100 5 Combinao
00000101 6 Combinao
00000110 7 Combinao
18
Se quisermos ter nmeros negativos e positivos podemos
dividir esse valor a meio e d 32768 para cada lado positivo e negativo, mas como temos de ter o zero vamos
roubar um valor ao lado positivo e ento camos com o
intervalo [32768, 32767]. E camos com as mesmas
65 536 combinaes.
Apresentamos inteiro com 2 bytes, mas eles podem ter
4 bytes, isso vai depender do processador do computador, ie, com quantos bytes consegue ele lidar ao mesmo
tempo.
19
Os tipos oat e double servem para guardar nmeros de
ponto utuante. A diferena entre os dois , alm do intervalo de dados, a preciso. Geralmente, o tipo oat
guarda dados (com sinal positivo ou negativo) de 3,4E38 a 3,4E+38 (alm do zero). J double suporta nmeros
to pequenos quanto 1,7E-308 e no mximo 1,7E+308.
oat 32 %f 3,4E-38 3.4E+38 double 64 %lf 1,7E308 1,7E+308 long double 80/128 %Lf 3,4E-4932
3,4E+4932
Nota: O tipo long double trabalha em mquinas x64 no
padro LP64 (Mac OS X e Unix)
10.0.4
Bool
10.0.5
Endereos
Os vrios locais na memria so identicados por um address, que tem uma lgica sequencial numerada. So necessrios 16 bits para guardar o endereo de um byte.
dito de outra forma so necessrios 2 bytes para guardar
a morada de um byte. ser isto verdade?!! isso quer dizer que se guardarmos os endereos de todos os bytes, s
temos 1/3 da memria disponvel para guardar valores.
Bem isto um pouco estranho, mas repare-se que apenas vamos guardar os addresses das variveis reservadas.
Depois as variveis nem sempre so de 1 byte, por isso
apenas iremos guardar o endereo do primeiro byte e no
de todos. por m faz sentido guardar o endereo de outro endereo? Os endereos de memria (addresses) so
normalmente expressos em linguagem hexadecimal (base
16, utilizam os 10 algarismos mais as 6 primeiras letras
de a a f - do alfabeto para fazerem as 16).
10.0.6
20
10.0.7
10.0.8
Literais
Em programao, um literal uma notao que representa um valor constante. Exemplos de literais em C so
415, 19.52, 'C', Joo. Esses exemplos representam os
quatro tipos de literais em C: literais de inteiros, literais
de reais, literais de caracteres e literais de strings. S
com esses exemplos j possvel deduzir como se usam
os literais; mas importante fazer algumas observaes:
Literais de inteiros podem ser especicados nas bases decimal, octal ou hexadecimal. Se o literal for
prexado com 0x ou 0X, ele ser interpretado
como hexadecimal; se o prexo for apenas 0, ser
interpretado como octal; ou se no houver prexo,
ser interpretado como decimal.
Literais de reais podem ser especicados na
forma decimal (144.57) ou em notao cientca
(1.4457e+2). Lembre-se que o separador decimal
o ponto e no a vrgula, como seria usual.
Literais de caracteres devem vir entre aspas simples
(') e conter a representao de apenas um caractere1 .
Usos vlidos seriam: 'c', '\n', '\x1b', '\033'. Se voc
quiser usar a aspa simples como caractere, precedaa com uma barra invertida: '\''.
Captulo 11
Programar em C/Constantes
11.1 Constantes
Em um captulo anterior abordamos as variveis e agora
vamos abordar constantes. A razo que as coisas esto
mais maduras e uma pessoa sabe muito bem o que uma
constante. Que simplesmente um valor que no se altera durante a execuo do programa. A questo de no
se alterar durante a escrita do programa realmente a razo deste captulo. Devemos separar as guas entre uma
constante e um literal. O literal o prprio valor.
E se necessitarmos de alterar o valor, alteramos apenas 1 vez, em vez de todas as vezes onde apareceria
o valor.
O formato geral :
#dene identicador valor
Repare que a diretiva de preprocessador no tem o ;ponto e vrgula no m! O que normal para diretivas
de Preprocessador.
O que que acontece se tivermos o ; no m? Ser
que encontrei um bug? se eu colocar o ; no #dene NEWLINE '\n'; no acontece nada.
11.2 DEFINED
(#DEFINE)
CONSTANTS
21
22
e o valor do a cava com o valor de 6;
Agora com o prexo const eu no poderei alterar o valor,
porque constante constante, no pode mudar o valor.
Esta maneira bem melhor do que a anterior para declarar constantes, primeiro porque aqui temos a informao
do tipo de varivel, em segundo porque podemos fazer
este const int a; como uma funo local e no global.
Captulo 12
So as funes mais simples do cabealho stdio.h. Ambas enviam (ou imprimem) sada padro os caracteres
fornecidos a elas; putchar() manda apenas um caractere,
e puts() manda uma sequncia de caracteres (ou string).
Exemplo:
puts (Esta uma demonstrao da funo puts.); putchar ('Z');
23
24
O valor de pi 3.1415.
Note que o argumento deve ser uma sequncia de carac- Voc pode imprimir quantos valores quiser, bastando
teres. Se voc tentar, por exemplo, imprimir o nmero para isso colocar mais argumentos e mais especicaes
42 desta maneira:
de formato, lembrando de colocar na ordem certa. Alguns compiladores, como o gcc, mostram um aviso caso
puts(42);
o nmero de argumentos seja diferente do nmero de esNa verdade o que o compilador tentar fazer imprimir a pecicaes de formato, o que provavelmente causaria
sequncia de caracteres que comea na posio 42 da me- resultados indesejados. A sintaxe geral da funo printf()
mria (provavelmente ele ir alert-lo sobre isso se voc :
tentar compilar esse cdigo). Se voc tentar executar esse
cdigo, provavelmente ocorrer uma falha de segmenta- printf (string de formatao, arg1, arg2, ...);
o (erro que ocorre quando um programa tenta acessar Suponha que voc tem um programa que soma dois valomemria que no lhe pertence). A maneira correta de res. Para mostrar o resultado da conta, voc poderia fazer
imprimir o nmero 42 seria coloc-lo entre aspas duplas: isso:
puts(42);
12.3 printf()
printf vem de print formatted (imprimir formatado).
primeira vista, a funo printf() pode parecer idntica
puts(). No entanto, ela muito mais poderosa. Ela permite facilmente imprimir valores que no so sequncias
de caracteres, alm de poder formatar os dados e juntar vrias sequncias de caracteres. Por isso, a funo
printf() muito mais usada que a puts().
5 + 9 = 14
A seguir mostramos os especicadores de formato para
vrios tipos de dados.
A documentao mais tcnica os chama de especicadores de converso, pois o que ocorre na maioria das
vezes , de fato, a converso de um valor numrico em
uma sequncia de caracteres que representa aquele valor.
Ela pode ser usada exatamente como a funo puts(), se Mas o nome formato no deixa de estar correto, pois
fornecermos a ela apenas uma sequncia de caracteres:
eles especicam em que formato (inteiro, real etc.) est
o argumento correspondente.
printf(Este um programa em C);
Ela tambm pode ser escrita da seguinte forma:
printf(Ola " mundo "!!!" );
Mas e se precisarmos imprimir o contedo de uma varivel? A funo printf tambm pode fazer isso! Voc deve,
obviamente, especicar onde o valor da varivel deve ser
impresso. Isso feito atravs da especicao de formato
%d, caso a varivel seja do tipo int (sequncias para outros tipos sero dadas adiante). Voc tambm precisar,
logicamente, especicar qual varivel imprimir. Isso
feito dando-se mais um argumento funo printf(). O
cdigo dever car assim:
12.3. PRINTF()
25
' (aspa simples/apstrofe): nmeros decimais devem ser exibidos com separador de milhares caso as
conguraes regionais o especiquem. Essa opo
normalmente s funciona nos sistemas Unix.
Largura do campo
Como o prprio nome j diz, especica qual a largura
mnima do campo. Se o valor no ocupar toda a largura
do campo, este ser preenchido com espaos ou zeros.
Por exemplo, podemos imprimir um cdigo de at 5 dgitos preenchido com zeros, de maneira que os valores 1,
27, 409 e 55192 apaream como 00001, 00027, 00409 e
55192.
A largura deve ser especicada logo aps as opes, se
presentes, e pode ser um nmero que especica a largura ou um asterisco, que diz que a largura ser especicada pelo prximo argumento (ou seja, o argumento anterior ao valor a ser impresso). Neste exemplo, o campo
ter largura igual ao valor de num e o valor impresso ser
300:
printf ("%*d, num, 300);
O campo impresso de acordo com as seguintes regras:
Se o valor for mais largo que o campo, este ser ex- " 3.4500
pandido para poder conter o valor. O valor nunca
ser cortado.
Tamanho da varivel
Se o valor for menor que o campo, a largura do
campo ser preenchida com espaos ou zeros. Os importante ressaltar que quando so usados modicazeros so especicados pela opo 0, que precede a dores de tamanho de tipos, a maneira como os dados so
armazenados pode tornar-se diferente. Assim, devemos
largura.
informar funo printf() precisamente qual o tipo da
O alinhamento padro direita. Para se alinhar varivel cujo valor desejamos exibir. A funo printf()
um nmero esquerda usa-se a opo - (hfen ou admite cinco principais modicadores de tamanho de vasinal de menos) antes da largura do campo.
rivel:
Por exemplo, compare as trs maneiras de exibir o nmero 15:
printf ("%5d, 15); // exibe " 15 printf ("%05d, 15); //
exibe 00015 printf ("%5d, 15); // exibe 15 "
E alguns outros exemplos:
printf ("%10s, Jos"); // exibe Jos " printf ("%10s,
Jos"); // exibe " Jos" printf ("%4s, Jos"); // exibe
Jos"
26
ll: indica que a converso inteira corresponde a uma Isso necessrio pois a funo scanf() deve modicar as
varivel long long.
variveis, e quando no usamos o operador de endereo,
passamos apenas o valor de uma varivel para a funo.
L: indica que a converso de nmero real corres- Isso ser explicado melhor no captulo sobre ponteiros.
ponde a uma varivel long double.
O fato de scanf receber endereos de variveis (em vez
de seus valores) tambm explica por que ele precisa ser
Quando o tipo da varivel no tem modicadores de ta- informado da diferena entre %f (oat) e %lf (double)
manho (long ou short), no se usa nenhum modicador enquanto que o printf no precisa.
de tamanho da varivel na funo printf().
Um exemplo bsico da utilizao de scanf() este:
int a; scanf ("%d, &a);
12.3.2
Sequncias de escape
O que este exemplo faz declarar uma varivel e aguardar o usurio digitar algo. Os dados s sero processados
quando o usurio apertar Enter. Depois disso, os caracteres digitados pelo usurio sero convertidos para um valor inteiro e esse inteiro ser guardado no endereo que
corresponde varivel a. Se o valor digitado no puder
ser convertido (porque o usurio no digitou nenhum algarismo vlido), a varivel no ser modicada.
Assim como na funo printf(), podemos receber quantos
valores quisermos, bastando usar vrios especicadores
de converso:
int a; char b; oat c; scanf ("%d %c %f, &a,&b,&c);
12.4 scanf()
A funo scanf() l dados da entrada padro (teclado) e
os guarda em variveis do programa. Assim como para
printf(), usamos uma string de formatao para especicar como sero lidos os dados. A sintaxe de scanf()
esta:
scanf (string de formatao, &arg1, &arg2, ...);
Como voc pode ver, a sintaxe quase igual de printf(),
com exceo do E comercial (&). Voc entender melhor
o seu uso nas sees seguintes, mas adiantamos que ele
um operador que retorna o endereo de uma varivel.
27
%c l uma sequncia de caracteres, sem ignorar int a, b; int num; num = scanf("%d%d, &a, &b);
espaos. O padro ler um caractere, se no for Este exemplo l dois nmeros inteiros e os guarda nas vaespecicada a largura do campo.
riveis a e b. O nmero de converses realizadas guardado na varivel num. Se aps o scanf, num for diferente
%[...] l uma sequncia de caracteres, sem ignorar de 2, sinal de que o usurio digitou algo incompatvel
espaos, especicando entre colchetes quais carac- com o formato desejado.
teres devem ser aceitos, ou, se o primeiro caractere
Note que aqui introduzimos um conceito novo: o valor
dentro dos colchetes for um acento circunexo (^),
de retorno de uma funo. Ele pode ser obtido simplesquais no devem ser aceitos. Alm disso, se colomente associando o valor de uma varivel chamada da
carmos um trao entre dois caracteres, todos os cafuno. Ele ser detalhado na seo Funes, mas j
racteres entre os dois sero includos no padro. Por
possvel compreender um pouco sua utilizao.
exemplo, se quisermos incluir qualquer letra minscula, poderimos escrever %[a-z]; se quisssemos
tambm incluir as maisculas, colocaramos %[azA-Z]. A leitura pra quando for encontrado um caractere que no coincide com o padro especicado. 12.5 gets() e getchar()
J os modicadores funcionam de maneira bastante dife- gets() e getchar(), assim como scanf(), lem da entrada
padro. Assim como puts() e putchar(), no suportam
rente:
formatao. Como o nome sugere, getchar() l apenas um
caractere, e gets() l uma string at o nal da linha ou at
O modicador * (asterisco) especica que o valor
que no haja mais dados para ler, e adiciona o terminador
atual deve ser lido da maneira especicada, mas no
de string "\0.
ser guardado em nenhuma varivel, e portanto no
deve haver um ponteiro correspondente a esse va- A sintaxe das funes :
lor. Por exemplo, poderimos ter um programa que gets(ponteiro_para_string); char c; c = getchar();
espera ler uma palavra e depois um nmero, mas
no importa qual palavra . Nesse caso usaramos No entanto, existe um problema com a funo gets().
o modicador *: scanf ("%*s %d, &numero). O Veja o exemplo a seguir:
programa leria a palavra e guardaria o nmero na #include <stdio.h> int main() { char buer[10];
varivel numero.
printf(Entre com o seu nome: "); gets(buer); printf(O
nome : %s, buer); return 0; }
Como na funo printf(), existe o especicador de A notao char buer[10], que ainda no foi introduzida
largura do campo, que deve aparecer antes do es- (e ser detalhada na seo Vetores (arrays)), pede que seja
pecicador de converso, mas em scanf() ele es- reservado um espao para 10 caracteres para a string bufpecica a largura mxima. Se a largura mxima fer. Portanto, se usurio digitar mais de 9 caracteres (pois
foi denida como n, scanf() pular para o prximo o terminador de string adicionado ao que o usurio digicampo se j tiver lido n caracteres. Por exemplo, tou), os caracteres excedentes adicionais sero colocados
scanf ("%4d, &num) ler um nmero de at quatro na rea de memria subsequente ocupada pela varivel,
algarismos. Se o usurio digitar mais, o excedente escrevendo uma regio de memria que no est reserser no ser lido por essa chamada, mas poder ser vada string. Este efeito conhecido como estouro de
lido por uma prxima chamada a scanf.
buer e pode causar problemas imprevisveis. Por isso,
no se deve usar a funo gets(); mais tarde introduziMais detalhes sobre os especicadores de converso e os remos a funo fgets(), que no apresenta esse problema
modicadores podem ser encontrados na documentao e que deve ser usada no lugar de gets().
da biblioteca padro.
12.4.1
Valor de retorno
A funco scanf() retorna o nmero de converses realizadas com sucesso. Isso til pois, se o valor contido
numa varivel aps a chamada de scanf() for igual ao valor anterior, no possvel saber se o valor digitado foi o
mesmo que j havia ou se no foi feita a converso. Para
obter esse nmero de converses realizadas, voc deve
guardar o resultado numa varivel do tipo int. Veja como
proceder:
28
Captulo 13
0; }
Abreviaes
Outro exemplo:
Genericamente, para qualquer dos cinco operadores aritSe quisermos um resultado no-inteiro, um dos operandos mticos op, vale a abreviao:
deve ser no-inteiro. Nesse exemplo, poderamos usar
3.0/2 ou 3/2.0, ou mesmo 3./2 ou (1.0 * 3)/2, pois, em C, var = var op num; var op= num;
uma operao envolvendo um nmero no-inteiro sempre Ou seja, os seguintes pares so equivalentes:
ter como resultado um nmero real.
x *= 12; x = x * 12; x /= 10; x = x / 10; x -= 2; x = x - 2;
Note que em C o separador decimal o ponto e no a x %= 11; x = x % 11;
vrgula.
Este exemplo clarica o uso dos operadores de increO seguinte exemplo poderia surpreender, pois o pro- mento:
grama dir que o valor de f continua sendo 3.
#include <stdio.h> int main() { int a, b; a = b
#include <stdio.h> int main() { int i = 5; int j = 2; oat f = 5; printf("%d\n, ++a + 5); printf("%d\n, a);
= 3.0; f = f + j / i; printf(O valor de f %f, f); return printf("%d\n, b++ + 5); printf("%d\n, b); return 0; }
29
30
Captulo 14
no intervalo porque os valores decimais pode representar o innito, e atan() = /2); as funes atan2 retornam o valor no intervalo [-,+]. Para a funo atan2,
um domain error pode ocorrer se os dois argumentos
forem zero.
As funes podem ser agrupadas nas seguintes categorias: #include <math.h> oat atanf(oat x); /* C99 */ oat
atan2f(oat y, oat x); /* C99 */ double atan(double x);
double atan2(double y, double x); long double atanl(long
1. Funes Trigonomtricas
double x); /* C99 */ long double atan2l(long double y,
long double x); /* C99 */
2. Funes Hiperblicas
3. Funes Exponencial e Logaritmo
4. Funes pow e sqrt
As funes cos, sin, e tan retornam o coseno, seno, e tangente do argumento, expresso em radianos.
14.1.2
31
32
14.3.1
A funo exp
14.3.2
As funes frexp dividem um nmero real numa frao As funes sqrt computam a raiz positiva de x e retornam
normalizada e um nmero inteiro mltiplo de 2. As fun- o resultado. Um domain error ocorre se o argumento
es guardam o nmero inteiro no objeto apontado por for negativo.
ex.
#include <math.h> oat sqrtf(oat x); /* C99 */ double
As funes frexp retornam o valor x de forma que x tem o sqrt(double x); long double sqrtl(long double x); /* C99
valor [1/2, 1) ou zero, e value igual a x vezes 2 elevado a */
*ex. Se value for zero, as duas partes do resultado seram
zero.
As funes ldexp multiplicam um nmero real por um
nmero inteiro mltiplo de 2 e retornam o resultado. Um
range error pode ocorrer.
As funes modf divide o argumento value entre um parte
inteira e uma frao, cada uma tem o mesmo sinal do
argumento. As funes guardam o parte inteira no objeto
apontado por *iptr e retornam o frao.
#include <math.h> oat frexpf(oat value, int *ex); /*
C99 */ double frexp(double value, int *ex); long double frexpl(long double value, int *ex); /* C99 */ oat
ldexpf(oat x, int ex); /* C99 */ double ldexp(double
x, int ex); long double ldexpl(long double x, int ex); /*
C99 */ oat mod(oat value, oat *iptr); /* C99 */
double modf(double value, double *iptr); long double
mod(long double value, long double *iptr); /* C99 */
14.3.3
As funes log computam o logaritmo natural do argumento e retornam o resultado. Um domain error ocorre As funes fabs computam o valor absoluto do nmero
se o argumento for negativo. Um range error pode real x e retornam o resultado.
ocorrer se o argumento for zero.
#include <math.h> oat fabsf(oat x); /* C99 */ double
As funs log10 computam o logaritmo comum (base- fabs(double x); long double fabsl(long double x); /* C99
10) do argumento e retornam o resultado. Um domain */
error ocorre se o argumento for negativo. Um range
error ocorre se o argumento for zero.
33
Captulo 15
Programar em C/Operadores
15.1 Operadores Aritmticos
Notar igualmente overow de que j falamos (antes e depois de compilar). ou seja pego no valor de uma varivel
adiciono o valor de uma segunda varivel e dou esse resulTabela: Operadores aritmeticos
tado a uma terceira varivel. Isto pode resultar em overNotar o ltimo operador. Notar que so operadores que ow. Ser trabalho do programador em controlar isto.
operam apenas com 2 operandos (operadores binrios).
O que que resulta se adicionarmos um int por um oat e
Na diviso euclidiana temos 30 dividido 7 tem por quoesse oat com casas decimais e colocarmos esse resultado
ciente 4 e como resto 2.
num int? o que resulta que o resultado ca truncado.
30 / 7 = 4 30 = 7 x 4 + 2 30 % 7 = 2
a mesma situao de declarar um int e colocar um oat.
como foi visto no capitulo das variveis.
Existe uma maneira de fazer abreviaturas:
Isto mais uma abreviatura para os programadores escreverem menos. H quem ache isto muito estpido pois
um esforo de assimilao desnecessrio em troca a escrever uma letra.
15.4 Expoentes
Precedncia de operadores aritmticos (o operador aritmtico tem maior precedncia do que o operador de
O C e o C++ no tm o operador expoente, no entanto,
asignment)
tem a funo pow (de power) que est no cabealho da
Table 4-3: Prioridade dos operadores aritmticos
biblioteca padro <math.h>. a funo pow() tem 2 arguNo caso de termos na mesma instruo operadores com mentos, o primeiro para a base e o 2 para o expoente. o
o mesmo nvel de precedncia (prioridade) fazer a regra 1 argumento tem de ser oat ou double.
da esquerda para a direita. eg. a=8/2*4 seria 16 e no 1,
porque temos a diviso est no lado esquerdo.
35
Vo poderia se perguntar: Como que o computador operadores relacionais (comparao) pois davam valores
faz essa comparao ? de onde que ele sabe que um boolean.
nmero A maior que outro B?
Para o operador and (&&) basta uma das compaResposta: Considere que voc quisesse comparar dois
raes ser falsa paro resultado ser falso
dados tipo char, lembrando que um char na verdade
um nmero inteiro na tabela ASCII. Sendo assim supo Para o operador or (||) basta uma das comparaes
nha que gostarias de comparar o caractere 'a' que igual a
dos operandos ser verdadeira para se tornar verda97 na tabela ascii com o caractere 't' que 116 na tabela;
deira
assim, ao comparar 97 com 116 o que acontee na memria a comparao de 01100001 (97) com 01110100
Por m o operador not um operador unrio
(116) em um registrador especco, vo sendo somadas
apenas para um valor boolean que pode ser resultado
as potncias de 2 da esquerda para a direita de forma que
de comparao
ca evidente para ele (o registrador) quem maior. Isso
o que acontee quando comparamos duas strings com a
Exemplo:
funo strcmp e ela retorna um nmero para a diferena
entre elas. Esse nmero justamente a diferena entre if (age <= 12 || age >= 65) printf(Admission is free);
os valores da tabela ASCII entre o primeiro caractere das else printf(You have to pay);
duas.
notar o operador == que a comparao de igualdade. o
operador = de atribuio.
Novamente existe a regra da esquerda para a direita caso Comparaes de precedncia entre Operadores aritmtihaja igualdade de precedncia
cos, relacionais e lgicos
15.11 Exerccios
(7 == 5) // evaluates to false.
(5 > 4) // evaluates to true.
(3 != 2) // evaluates to true.
36
(6 >= 6) // evaluates to true.
(5 < 5) // evaluates to false
(a == 5) // evaluates to false since a is not equal to 5.
(a*b >= c) // evaluates to true since (2*3 >= 6) is
true.
(b+4 > a*c) // evaluates to false since (3+4 > 2*6) is
false.
((b=2) == a) // evaluates to true.
!(5 == 5) // evaluates to false because the expression
at its right (5 == 5) is true.
!(6 <= 4) // evaluates to true because (6 <= 4) would
be false.
!true // evaluates to false
!false // evaluates to true.
( (5 == 5) && (3 > 6) ) // evaluates to false ( true
&& false ).
( (5 == 5) || (3 > 6) ) // evaluates to true ( true || false
).
Captulo 16
Geralmente em expresses condicionais usamos os operadores relacionais, ou seja, que avaliam a relao entre
seus dois operandos. Existem seis deles:
Todos esses operadores so binrios, ou seja, trabalham
com dois valores ou operandos. Esses operadores sempre
comparam o valor da esquerda com o da direita, ou seja,
a expresso a > b signica "a maior que b".
if (x == 1) ...
while, que executa um bloco enquanto uma condiTambm comum que combinemos condies. Por
o for verdadeira;
exemplo, podemos querer que um nmero seja menor que
do, semelhante ao while, mas a condio avaliada 10 ou maior que 50. Como o operador ou "||", escreaps a execuo (e no antes);
veramos: n < 10 || n > 50. A seguir voc v os operadores
lgicos:
goto, que simplesmente pula para um lugar prAlgumas explicaes sobre os operadores lgicos:
denido.
O operador no unrio, ou seja, uma operao que envolve apenas um valor. O que ele faz
inverter o valor de seu operando: retorna falso se a
expresso for verdadeira e vice-versa. Deve-se usar
parnteses ao negar uma expresso: !(x > 6), por
exemplo.
37
38
tando para isso colocar um novo teste no bloco else. Tambm possvel aninhar blocos if, ou seja, colocar um dentro de outro:
Observao Se voc quer saber se um nmero est entre outros dois, a sintaxe matemtica (10 < n < 50) no
funcionar. Se voc usar esse cdigo, na verdade primeiramente ser avaliada a expresso 10 < n, que poder
resultar em 0 ou 1. Portanto, a expresso equivale a (0 ou
1) < 50, o que sempre verdadeiro.
switch
16.3 Testes
Testes so estruturas de controle que executam certos Note que no teste switch no precisamos usar chaves em
blocos de cdigo apenas se uma certa condio for ver- volta dos blocos, a menos que declaremos variveis neles.
dadeira. Existem trs estruturas desse tipo em C:
Um exemplo da utilizao de switch seria a criao de
um menu:
int opcao; printf ("[1] Cadastrar cliente\n "[2] Procurar cliente\n "[3] Inserir pedido\n "[0] Sair\n\n
O teste if avalia uma condio e, se ela for verdadeira, Digite sua escolha: "); scanf ("%d, &opcao); switch
executa um bloco de cdigo. A sintaxe correspondente a (opcao) { case 1: cadastra_cliente(); break; case 2:
procura_cliente(); break; case 3: insere_pedido(); break;
isso :
case 0: return 0; default: printf (Opo invlida!\n); }
if (condio) { ... /* bloco a ser executado se a condio
for verdadeira */ }
A instruo break indica que deve-se continuar a execuo aps o nal do bloco switch (pulando o que estiver
Mas tambm podemos especicar um bloco a ser execu- no meio). Se ela no fosse usada, para um certo valor
tado caso a condio for falsa. Nesse caso, escrevemos: encontrado, seriam executadas tambm as instrues de
if (condio) { ... /* bloco a ser executado se a condio todos os valores abaixo dele. Em alguns casos, podemos
for verdadeira */ } else { ... /* bloco a ser executado se a omitir intencionalmente a instruo break. Por exemplo,
no exemplo acima, no colocamos uma instruo break
condio for falsa */ }
para o valor zero, pois quando retornamos de uma funo (return 0) o bloco switch j abandonado.
As chaves podem ser omitidas caso haja apenas uma
Tambm podemos querer que uma instruo seja execuinstruo no bloco. Por exemplo:
tada para mais de um valor. Vamos supor que no nosso
if (x == 5) printf (x igual a 5.\n);
menu as duas primeiras opes fossem Cadastrar pessoa
fsica e Cadastrar pessoa jurdica, e tvessemos uma
Perceba que, se esquecermos as chaves, o compilador no funo que faz o cadastro diferentemente dependendo do
dever dar nenhum erro; no entanto, tudo que exceder valor da varivel pessoa_sica. Poderamos fazer um ca primeira instruo ser executado incondicionalmente, digo assim:
mesmo que esteja na mesma linha! No exemplo a se- switch (opcao) { case 1: /* pessoa fsica */ pessoa_sica
guir, a frase x igual a 5 seria exibida mesmo que o = 1; case 2: cadastra(); break; ... }
nmero no fosse 5!
16.3.1
if
Nesse caso, para qualquer uma das duas opes seria executada a funo cadastra, mas se selecionarmos pessoa
Podemos avaliar diversas condies com os testes if, bas- fsica a varivel ser atribuda antes.
16.4. LOOPS
16.3.3
39
Note que, ao contrrio de if, ao usarmos o operador condicional ?: precisamos sempre prover tanto o valor para Loops innitos
o caso de a condio ser falsa quanto o valor para o caso
de ela ser verdadeira.
Voc pode fazer loops innitos com while, usando uma
O operador condicional pode ser usado em situaes condio que sempre verdadeira, como 1 == 1 ou simplesmente 1 (que, como qualquer valor no-nulo, concomo essa:
siderado verdadeiro):
int horaAbertura = (diaSemana == DOMINGO) ? 11 :
while (1) { ... }
9; printf (Abrimos s %d horas, horaAbertura);
Ou seja, se o dia da semana for domingo, a varivel hora- Voc pode sair de um loop innito ou no com a
Abertura ser denida para 11; caso contrrio, ser de- instruo break, que voc j viu no teste switch e ser
explicada mais abaixo.
nida para 9.
Outro exemplo:
if (numMensagens > 0) { printf (Voc tem %d men- 16.4.2 do ... while
sage%s, numMensagens, (numMensagens > 1) ? ns :
O loop do ... while exatamente igual ao while
m); }
exceto por um aspecto: a condio testada depois do
bloco, o que signica que o bloco executado pelo menos
Neste caso, o programa utilizaria mensagens caso hou- uma vez. A estrutura do ... while executa o bloco, testa a
vesse mais de uma mensagem, e mensagem caso hou- condio e, se esta for verdadeira, volta para o bloco de
vesse apenas uma mensagem.
cdigo. Sua sintaxe :
do { ... } while (condio);
16.4 Loops
16.4.1
while
Por exemplo:
while (a < b) { printf ("%d menor que %d, a, b); a++; }
16.4.3 for
Este cdigo seria executado at que a fosse igual a b; se
a fosse igual ou maior que b, nada seria executado. Por O loop for nada mais que uma abreviao do loop while,
exemplo, para b = 10 e a < 10, a ltima mensagem que o que permite que alguma inicializao seja feita antes do
loop e que um incremento (ou alguma outra ao) seja
usurio veria 9 menor que 10.
40
Podemos tambm omitir o bloco de cdigo, se nos interessar apenas fazer incrementos ou se quisermos esperar
por alguma situao que estabelecida por uma funo
externa; nesse caso, usamos o ponto-e-vrgula aps os parnteses de for. Isso tambm valido para o loop while:
for (inicializao; condio; incremento) ; while (condiOs nomes de rtulo so identicadores suxados por doiso) ;
pontos (:), no comeo de uma linha (podendo ser prece-
41
Captulo 17
Programar em C/Funes
17.1 O que funo
Exemplo:
#include <stdio.h> int main(void) { imprime_par(3,4); [tipo de retorno da funo] [nome da funo] (1 parimprime_par(2,8); return 0; }
metro, 2 parmetro, ) { //cdigo }
42
43
Para o nome da funo e dos parmetros valem as int funcao (int a, int b) oat funcao (oat preco, int
mesmas regras que foram dadas para os nomes de quantidade) double funcao (double angulo)
variveis. No podemos usar o mesmo nome para
funes diferentes em um programa.
Para especicar que a funo no usa nenhum parmetro,
a lista de parmetros deve conter apenas a palavra-chave
Todas as funes devem ser denidas antes da funvoid. No entanto, ela freqentemente omitida nesses
o main, ou deve ser feito o prottipo da funo,
casos. Portanto, voc poderia escrever qualquer uma desque veremos mais adiante.
tas duas linhas:
O cdigo deve estar obrigatoriamente dentro das
chaves e funciona como qualquer outro bloco.
17.2.1
Valor de retorno
Freqentemente, uma funo faz algum tipo de processamento ou clculo e precisa retornar o resultado desse
procedimento. Em C, isso se chama valor de retorno e
pode ser feito com a instruo return. Para poder retornar um valor, precisamos especicar seu tipo (char, int,
oat, double e variaes). Para efetivamente retornar um
valor, usamos a instruo return seguida do valor de retorno, que pode ou no vir entre parnteses. Um exemplo
bem simples de funo que retorna um valor inteiro:
44
(Digite um nmero inteiro: "); scanf ("%d, &numero); parmetros, j que estes so ignorados por quem chama
resultado = quadrado (numero); printf (O quadrado de a funo:
%d %d.\n, numero, resultado); despedida (); return 0; int quadrado (int);
}
Poderamos, por exemplo, reorganizar o incio do
programa-exemplo dado um pouco acima, o que permiOl! Digite um nmero inteiro: 42 O quadrado de 42 tiria colocar as funes em qualquer ordem mesmo que
1764. Fim do programa.
houvesse interdependncia entre elas:
Voc veria na tela, ao executar o programa:
Repare que, ao chegar na chamada de uma funo, o pro- #include <stdio.h> int quadrado (int x); void saudacao
grama passa o controle para essa funo e, aps seu tr- (void); void despedida (void); // seguem as funes do
mino, devolve o controle para a instruo seguinte na fun- programa
o original.
Mais um exemplo, com uma funo de 3 argumentos:
Quando um programa C est sendo compilado e uma chamada de funo encontrada, o compilador precisa saber
o tipo de retorno e os parmetros da funo, para que
ele possa manipul-los corretamente. O compilador s
tem como saber isso se a funo j tiver sido denida.
Portanto, se tentarmos chamar uma funo que est denida abaixo da linha onde estamos fazendo a chamada, ou
mesmo em outro arquivo, o compilador dar uma mensagem de erro, pois no conseguiu reconhecer a funo.
As primeiras so as designadas como locais: s tm validade dentro do bloco no qual so declaradas. As ltimas
so as globais, elas esto vigentes em qualquer uma das
funes.
E no podemos usar os valores denido dentro da minhaFuncion, pois no h nenhuma instruo que dena
que valor usar. Lembre-se: O computador no vai adiviNuma declarao, tambm podemos omitir os nomes dos nhar qual valor usar. Deve-se denir cada instruo.
int quadrado (int x);
17.7. VOID
45
void calcular() /*No houve denio de valor entre o num, vai car com o dobro do valor. Esse valor do
parenteses*/ { long supercie = largo * alto; /*Error bip main() vai entrar novamente no main(). E associado
bip valor nao denido*/ return(supercie); }
varivel res. Depois temos a impresso da varivel
num e res. Ora o que acontece que o valor do num
Nesse exemplo abaixo, poderemos usar o valor das vari- ca igual ao valor antes de entrar na funo. Fazemos a
mesma coisa agora com a varivel a e b, e vemos que
veis externas dentro de todas as funes. Exemplo:
agora a funo a alterada. Resumindo, o valor vari#include <stdio.h> /* Variaveis externas */ long largo vel quando entra numa outra funo no alterado (na
= 10; long alto = 20; void F_soma () { /*soma uma passagem por valor).
variavel interna e largo e alto sao variaveis externas */
long soma = largo + alto ; printf(largo + alto = %i Quando o valor do parmetro alterado denominamos
\n, soma); } long calcular() { long supercie = largo * chamada (ou passagem) por referncia. O C no faz
alto; return supercie; } int main(void) { F_somma (); chamadas por referncia. Mas podemos simular isto com
outra arma do C que so os ponteiros, que sero melhor
printf(Supercie : %ld \n, calcular() ); return 0 ; }
explicados mais adiante.
Curiosidade A palavra reservada auto serve para dizer
que uma varivel local, mas a utilizao de auto no
mais necessria pois as variveis declaradas dentro de um
bloco j so consideradas locais.
17.7 void
Como dissemos, uma funo retorna um valor. E pode
receber parmetros. O void utilizado da seguinte forma:
void funo(void) { //codigo }
No exemplo acima, a palavra void dene que:
no vai receber parmetros; e
no vai retornar qualquer valor.
Ou melhor, void uma explicitao do programador que
aquela funo no vai receber ou retornar nenhum valor.
O valor da funo ignorado, mas a funo realmente
retorna um valor, por isso para que o resultado no seja
interpretado como um erro e bom declarar void.
Nota
No se pode utilizar void na funo principal
main, apesar de existirem exemplos com void
em algumas bibliograas. Infelizmente, alguns
compiladores aceitam void main(). O main()
especial e tem de retornar um int. Uma execuo bem sucedida do programa costuma retornar 0 (zero) e, em caso de erro, retorna 1
(um).
46
(l-se cinco fatorial) igual a 54321 . Ateno
conveno 0! = 1 .
Uma maneira de denir o algoritmo de fatorial :
{
1,
se n = 0 ou n = 1
n! =
n(n 1)!, se n 2
E a implementao correspondente seria esta:
#include <stdio.h> #include <stdlib.h> int fat(int n) { if
(n) return n*fat(n-1); else return 1; } int main() { int n;
printf("\n\nDigite um valor para n: "); scanf("%d, &n);
printf("\nO fatorial de %d e' %d, n, fat(n)); return 0; }
Exemplo 2 :
#include <stdio.h> #include <stdlib.h> unsigned long
b(unsigned int n){ if (n == 0 || n == 1) return n;
else return b(n - 1) + b(n - 2); } int main(){ int n;
printf("\n\nDigite um valor para n: "); scanf("%d, &n);
printf("\n F(%d) = %d \n ",n, b(n)); return 0; }
Vamos introduzir o valor 5 para este programa.
So feitas as seguintes chamadas recursivas. Observe a
estrutura upside-down (rvore de cabea para baixo) criada pelas chamadas recursivas.
Fibonacci(5) / \ / \ / \ / \ / \ F(4) + F(3) / \ / \ / \ / \ / \ / \ /
\ / \ / \ / \ F(3) + F(2) F(2) + F(1) /\ /\ | \ \ / \ / \ | \ \ / \ / \
| \ \ / \ / \ | \ \ F(2) + F(1) F(1) + F(0) F(1) + F(0) 1 /\ | | |
| | / \ | | | | | / \ | | | | | / \ | | | | | F(1) + F(0) 1 1 0 1 0 | | | | | | |
|10
Cada vez que a sub-rotina chama a si mesmo, ela deve
armazenar o estado atual da sub-rotina (linha atual que
est sendo executada, os valores de todas as variveis, etc)
em uma estrutura de dados chamada de pilha.
Se voc usar a recursividade durante um longo perodo de
tempo, a pilha vai car muito grande e o programa dar
uma mensagem de aviso.
17.9 inline
Uma funo inline, em vez de ser chamada, ser movida
para o local de chamada no momento da compilao.
Se zermos um paralelismo com as diretivas de compilao, como #dene, ela vai substituir cada chamada da
funo pela prpria funo, como fosse uma macro.
Mas isto s tem vantagens para cdigos pequenos e para
quem necessite muito da velocidade no processamento.
Alguns compiladores j fazem isto automaticamente.
Para tornar uma funo inline basta preceder a declarao da funo com o nome inline.
inline [tipo_de_retorno] [nome_da_funo] (argumentos) { //cdigo }
Captulo 18
Programar em C/Pr-processador
18.1 O pr-processador
O pr-processador C um programa que examina o programa fonte escrito em C e executa certas modicaes
nele, baseado nas diretivas de compilao (ou diretivas
do pr-processador). As diretivas de compilao so comandos que no so compilados, sendo dirigidos ao prprocessador, executado pelo compilador antes da execuo do processo de compilao propriamente dito.
18.2.2 #dene
#dene
nome_do_smbolo
nome_da_constante
valor_da_constante
ne
nome_da_macro(parmetros)
so_de_substituio
#include
#dene
A diretiva #dene tem duas utilidades. Uma delas apenas denir um smbolo que pode ser testado mais tarde.
Outra denir uma constante ou ainda uma macro com
parmetros. As trs maneiras de usar a diretiva so:
#undef
#dene
#deexpres-
#ifdef
#ifndef
#if
#else
#elif
#endif
Exemplo 1:
#include
Exemplo 2:
A diretiva #include diz ao pr-processador para incluir
#dene max(A, B) ((A > B) ? (A) : (B)) #dene min(A,
naquele ponto um arquivo especicado. Sua sintaxe :
B) ((A < B) ? (A) : (B)) ... x = max(i, j); y = min(t, r);
#include "nome_do_arquivo"
Aqui, a linha de cdigo: x = max(i, j); ser substituda
ou
pela linha: x = ((i) > (j) ? (i) : (j));. Ou seja, atribuiremos
#include <nome_do_arquivo>
a x o maior valor entre i ou j.
47
48
18.2.3
#undef
18.2.4
#ifdef e #ifndef
18.2.7 #elif
A diretiva #elif serve para implementar uma estrutura do
tipo if (condio) {...} else if (condio) {...}. Sua forma
geral :
#if expresso_1 cdigo #elif expresso_2 cdigo #elif expresso_3 cdigo . . . #elif expresso_n cdigo #endif
Podemos tambm misturar diretivas #elif com #else; obviamente, s devemos usar uma diretiva #else e ela deve
ser a ltima (antes de #endif).
O cdigo entre as duas diretivas s ser compilado se o #ifndef CABECALHO_H #dene CABECALHO_H . .
smbolo (ou constante) nome_do_smbolo j tiver sido de- . #endif
nido. H tambm a estrutura ifndef, que executa o cSe o arquivo ainda no tiver sido includo, ao chegar na
digo se o smbolo no tiver sido denido.
primeira linha do arquivo, o pr-processador no enconLembre que o smbolo deve ter sido denido atravs da trar o smbolo CABECALHO_H, e continuar a ler o
diretiva #dene.
arquivo, o que lhe far denir o smbolo. Se tentarmos incluir novamente o arquivo, o pr-processador pular todo
o contedo pois o smbolo j foi denido.
18.2.5
#if
18.2.6
#else
18.4 Concatenao
O preprocessador C oferece duas possibilidades para manipular uma cadeia de caracteres .
A primeira usando o operador # que permite substituir
a graa de um parmetro .
#include<stdio.h> int main (void) { /* mad equivale
a mad */ #dene String(mad) #mad printf ( String(
Estou aqui ) "\n ); }
A diretiva #else funciona como na estrutura de bloco if A segunda usando o operador ## que serve para conca(condio) {...} else {...}:
tenar vrios parmetros .
#if expresso /* ou #ifndef expresso */ cdigo /* ser Ex: ban##ana igual a banana .
executado se a expresso for verdadeira */ #else cdigo /* #include<stdio.h> int main (void) { int teste = 1000 ;
ser executado se a expresso for falsa */ #endif
#dene CONCAT(x, y) x##y /* igual a tes + te */
printf (" %i \n, CONCAT ( tes, te ) ); }
Um exemplo:
#dene WINDOWS ... /* cdigo */ ... #ifdef WINDOWS #dene CABECALHO windows_io.h #else
#dene CABECALHO unix_io.h #endif #include CABECALHO
Captulo 19
Programar em C/Exerccios
i, var_long, var_double, var_long_double); i = i+1; }
return 0; }
19.2.3 Exerccio 3
Faa um programa que vai lendo cada caractere que o
usurio digitar. Quando o usurio digitar o caractere 'x',
o programa deve exibir todos os caracteres que foram digitados antes do 'x'.
Exerccios
19.1 Questes
O que faz o seguinte programa?
Exerccio 1
19.2.2
Exerccio 4
Exerccio 2
#include <stdio.h> #include <stdlib.h> #dene ARSIZE 10 int main(){ int m_carac[ARSIZE],qtd1; int
qtd2, pare, ultcar; ultcar = 0; pare = 0; /* * Le os
caracteres para uma matriz. * Para se for o m da
linha ou a matriz estiver cheia. */ while(pare != 1)
{ m_carac[ultcar] = getchar(); if(m_carac[ultcar] ==
'\n') pare = 1; else ultcar = ultcar + 1; if(ultcar ==
ARSIZE) pare = 1; } ultcar = ultcar-1; /* * Agora
executa a ordenao bolha tradicional. */ qtd1 = 0;
while(qtd1 < ultcar) { qtd2 = qtd1 + 1; while(qtd2 <=
ultcar) { if(m_carac[qtd1] > m_carac[qtd2]) { /* troca
*/ int temp; temp = m_carac[qtd1]; m_carac[qtd1] =
m_carac[qtd2]; m_carac[qtd2] = temp; } qtd2 = qtd2 +
1; } qtd1 = qtd1 + 1; } qtd1 = 0; while(qtd1 <= ultcar)
{ printf("%c\n, m_carac[qtd1]); qtd1 = qtd1 + 1; }
exit(EXIT_SUCCESS); }
49
50
19.2.5
Exerccio 5
19.2.7 Exerccio 7
19.2.6
Exerccio 6
19.2.9 Exerccio 9
#include <stdio.h> #include <stdlib.h> void
exibe_maior(int a1, int a2); /* declarao */ int
main() { int i,j; for(i = 10; i <= 10; i++) { for(j =
10; j <= 10; j++) { exibe_maior(i,j); } } return 0; }
/* * Funo exibe_maior. * Retorna: void * Imprime
na tela o maior de seus dois argumentos. */ void
exibe_maior(int a1, int a2){ /* denio */ int maior;
if(a1 > a2) { maior = a1; } else { maior = a2; } printf(O
maior entre %d e %d e' %d\n, a1, a2, maior); }
19.2.10 Exerccio 10
Faa uma calculadora:
19.2.11
Exerccio 11
51
Captulo 20
Programar em C/Vetores
20.1 Vetores
Ao inicializar um vetor com vrios valores, pode ser trabalhoso contar todos os valores para colocar o tamanho
do vetor na declarao. Por isso, em C podemos omitir o nmero de elementos quando os valores so iniciVetores, tambm chamados arrays (do ingls) ou arranjo alizados; o tamanho do vetor ser o nmero de valores
ou ainda matrizes, so uma maneira de armazenar vrios inicializados. Por exemplo, as duas notaes abaixo so
dados num mesmo nome de varivel atravs do uso de equivalentes:
ndices numricos. Em C, vetores devem sempre conter
int valores[5] = {1, 2, 3, 4, 5}; int valores[] = {1, 2, 3, 4,
dados do mesmo tipo de varivel.
5};
Declaramos vetores de maneira muito semelhante declarao de variveis normais. A nica diferena que
depois do nome da varivel deve ser informada a quantidade de elementos do vetor. Para declarar um vetor
20.1.2 Exemplo de Aplicao de Vetores
chamado vetor, com cinco elementos inteiros, escrevemos:
O cdigo abaixo de um programa que recebe 5 nmeros
int vetor[5];
inteiros e informa qual destes maior.
#include <stdio.h> #include <stdlib.h> #include <conio.h> int main(void) { int vetor[5]; int x, i; printf
(digite 5 numeros\n); for (i = 0; i < 5; i++) /*Este laco
faz o scan de cada elemento do vetor*/ { scanf("%d,
&vetor[i] ); } i = 1; x = vetor[0]; while (i < 5) /*Este
Da mesma maneira que podemos inicializar uma varivel laco compara cada elemento do vetor*/ { if (vetor[i] >
junto com sua declarao, podemos usar as chaves ({}) x) { x = vetor[i]; } i++; } printf("\n O maior numero que
voce digitou foi %d .\n,x); getch (); return 0; }
para inicializar um array.
Note que a quantidade de elementos de um vetor no pode
ser alterada depois que o vetor for declarado. Para criar
vetores de tamanho dinmico, podemos usar ponteiros,
que sero abordados mais adiante.
53
Podemos ter ainda conjunto de variveis multidimensio- soma de %s e %s eh: %d\n, argv[1], argv[2], result); }
nais.
tipo_da_varivel nome_da_varivel [tam1][tam2] ...
[tamN];
onde a iniciao :
tipo_da_varivel nome_da_varivel [tam1][tam2] ...
[tamN] = {lista_de_valores}; oat vect [6] = { 1.3, 4.5,
2.7, 4.1, 0.0, 100.1 }; 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 str [10] = Joao"; char str_vect [3][10] = {
Joao, Maria, Jose }; int matrx[2][4]= { { 1,2,3,4
}, { 5,6,7,8 } };
Podemos, em alguns casos, inicializar matrizes das quais
no sabemos o tamanho a priori. O compilador C vai,
neste caso vericar o tamanho do que voc declarou e
considerar como sendo o tamanho da matriz. Isto ocorre
na hora da compilao e no poder mais ser mudado
durante o programa
Uma tabela de inteiros positivos de duas dimenso (3 linhas, 4 colunas ) se deniria da seguinte forma:
int Tabela [3][4]
Suponha que o primeiro ndice o ndice da linha e o
segundo da coluna .
Ento teramos:
Exemplo da inicializao de um vetor multidimensional usando loops.
int i,j;
for (i=0; i<=2; i++){
for (j=0; j<=3; j++){
Tabela[i][j] = 0;
}
}
20.3.1
Captulo 21
Programar em C/Strings
21.1 Strings
21.2.1 strlen
54
55
strncat, onde o nmero mximo de caracteres a serem #include <string.h> void *memcpy (void *dest, const
copiados o terceiro argumento.
void *srce, size_t n);
21.2.4
strcmp
21.2.7 memset
Sintaxe:
#include <string.h> void *memset (void *buer, int c,
size_t n);
Descrio: memset inicializa n octetos do buer com o
inteiro c.
21.2.6
Sintaxe:
memcpy
56
%s\n, var); return 0; }
Captulo 22
$./Calcular restar
gcc
Captulo 23
Ou, mais amplamente, uma estrutura seria uma representao de qualquer tipo de dado denido por mais de uma
varivel. Por exemplo, o tipo FILE* na verdade um
ponteiro para uma estrutura que contm alguns dados que
Muitas vezes necessrio manipular dados complexos o sistema usa para controlar o acesso ao uxo/arquivo.
que seriam difceis de representar usando apenas os tipos No necessrio, para a maioria dos programadores, coprimitivos (char, int, double, oat). Para isso, h, em C, nhecer a estrutura do tipo FILE.
trs tipos de dados que podem ser denidos pelo usurio:
estruturas (struct);
unies (union);
A denio de um tipo de estrutura feita com a palavrachave struct, seguida do nome a ser dado ao tipo e de
um bloco contendo as declaraes dos elementos da estrutura:
enumeraes (enum).
As estruturas e unies so compostas por vrias variveis struct nome_do_tipo { tipo_elem a; tipo_elem b, c; ... };
(escolhidas pelo programador), por isso so ditos deni- muito importante incluir o ponto-e-vrgula ao nal
dos pelo usurio. J as enumeraes so, resumidamente, do bloco!
tipos cujos valores devem pertencer a um conjunto denido pelo programador.
23.2.2 Declarando
23.2 Estruturas
Uma estrutura (ou struct) um tipo de dados resultante
do agrupamento de vrias variveis nomeadas, no necessariamente similares, numa s; essas variveis so chamadas membros da estrutura. Para declarar uma estrutura,
usamos a palavra-chave struct, seguida do nome que se
deseja dar estrutura (ao tipo de dados) e de um bloco
contendo as declaraes dos membros. Veja um exemplo:
Para declarar uma varivel de um tipo j denido, fornecemos o nome do tipo, incluindo a palavra-chave
struct:
struct nome_do_tipo variavel;
Tambm possvel condensar a denio do tipo e a declarao em um passo, substituindo o nome do tipo pela
denio, sem o ponto-e-vrgula:
struct mystruct { int a, b, c; double d, e, f; char string[25];
} variavel;
struct mystruct { int a, b, c; double d, e, f; char string[25]; Tambm possvel inicializar uma estrutura usando as
};
chaves {} para envolver os elementos da estrutura, sepaEste exemplo cria um tipo de dados denominado mystruct, rados por vrgulas. Os elementos devem estar na ordem
contendo sete membros (a, b, c, d, e, f, string). Note que em que foram declarados, mas no obrigatrio inicialio nome mystruct o nome do tipo de dados, no de uma zar todos; no entanto, para inicializar um elemento, todos
varivel desse tipo.
os anteriores devem ser inicializados tambm. Por exemUm exemplo simples de aplicao de estruturas seria uma plo, poderamos declarar valores iniciais para a varivel
cha pessoal que tenha nome, telefone e endereo; a cha acima da seguinte maneira:
seria uma estrutura.
23.3. UNIES
Teste"}; struct mystruct v2 = {9, 5, 7};
59
J vimos acima que podemos normalmente passar membros de uma estrutura como argumentos de funes.
Tambm possvel passar estruturas inteiras como arguPara quem usa o C99 com o compilador GNU. Durante mentos:
a inicializao de um estrutura possvel especicar o
nome do campo com '.nome_do_campo =' antes do valor. #include <stdio.h> struct ponto { int x; int y; }; void
imprime_ponto (struct ponto p) { printf ("(%d, %d)\n,
Exemplo:
p.x, p.y); } int main () { struct ponto a = {3, 7}; imstruct mystruct v2 = {.a=9,.b=5,.c=7};
prime_ponto (a); return 0; }
23.2.3
Inicializador designado
23.2.4
Acessando
23.2.5
Vetores de estruturas
23.3 Unies
Unies so parecidas com estruturas, mas h uma diferena fundamental: nas unies, todos os elementos ocupam o mesmo espao de memria. Por isso, s possvel
acessar um elemento por vez, j que uma mudana em um
elemento causar mudana em todos os outros. A denio e a declarao de unies igual das estruturas,
trocando a palavra struct por union.
struct info_usuario { int id; char nome[20]; long endereco_ip; time_t hora_conexao; }; struct info_usuario usu- H principalmente dois usos para as unies:
arios[10];
economia de espao, j que guardam-se vrias vaE, por exemplo, para obter o horrio em que o 2
riveis no mesmo espao;
usurio usurio se conectou, poderamos escrever usuarios[1].hora_conexao.
representao de uma informao de mais de
uma maneira. Um exemplo disso so os endereos IP, que na biblioteca de sockets podem ser re23.2.6 Atribuio e cpia
presentados como um grupo de 4 octetos (char) ou
como um nico valor inteiro (int). Isso feito com
Podemos facilmente copiar todos os campos de uma esuma unio parecida com esta: union ip_address {
trutura para outra, fazendo uma atribuio simples como
int s_long; char s_byte[4]; }; Dessa maneira, o ena de inteiros:
dereo pode ser facilmente representado de maneira
humanamente legvel (com 4 octetos), sem diculstruct ponto { int x; int y; }; ... struct ponto a = {2, 3};
tar o processamento interno (com o valor inteiro).
struct ponto b = {5, 8}; b = a; // agora o ponto b tambm
tem coordenadas (2, 3)
No entanto, devemos ter cuidado se a estrutura contiver
campos ponteiros, pois, nesses casos, o que ser copiado o endereo de memria (e no o contedo daquele
endereo). Por exemplo, se tivermos uma estrutura que
comporta um inteiro e uma string, uma cpia sua conter
o mesmo inteiro e um ponteiro para a mesma string,
o que signica que alteraes na string da cpia sero reetidas tambm no original!
23.4 Enumeraes
Enumerao (enum) ou tipo enumerado um tipo de
dados que tem como conjunto de valores possveis um
conjunto nito de identicadores (nomes) determinados
pelo programador. Em C, cada identicador em uma
enumerao corresponde a um inteiro.
60
Enumeraes so denidas de maneira similar s estru- Essa estrutura esta formada por um tipo que tem o tamaturas e unies, com algumas diferenas. A palavra chave nho de um short esse mesmo tipo ser divido em pores
usada enum.
menores. No exemplo acima os campos tem os tamanhos
enum nome_enumerao { IDENTIFICADOR_1, 6,6,1,1,2 igual a 16 bits que o tamanho de um unsigned
short . Para acessar os campos usamos o mesmo mtodo
IDENTIFICADOR_2, ... IDENTIFICADOR_n };
que usamos com estruturas normais .
Note as diferenas: no h ponto-e-vrgula no nal ou no
BIT_FIELD_1 meu_campo; meu_campo.campo_1 =
meio das declaraes (mas ainda h no nal do bloco), e
16; meu_campo.campo_4 = 0;
no h declarao de tipos.
Com essa declarao, ao IDENTIFICADOR_1 ser atribuido o valor 0, ao IDENTIFICADOR_2 ser atribudo
o valor 1, e assim por diante. Podemos tambm explicitar os valores que quisermos colocando um sinal de igual
e o valor desejado aps o identicador.
Caso no haja valor determinado para o primeiro
identicador, ele ser zero. Para os demais identicadores, o padro seguir a ordem dos nmeros,
a partir do valor do identicador anterior.
Podemos misturar identicadores de valor determinado com identicadores de valor implcito, bastando seguir a regra acima.
Por exemplo:
enum cores { VERMELHO, /* 0 */ AZUL = 5, /* 5 */
VERDE, /* 6 */ AMARELO, /* 7 */ MARROM = 10
/* 10 */ };
23.4.1
Uso
Captulo 24
Programar em C/Enumerao
24.1 Enumerations (enum)
#include <stdio.h> #include <stdlib.h> void mostrarAs enumerations denem um nova tipo de varivel e li- Res(int quem); /*Aqui os valores Italia = 4 e Brasil
mita desde logo os valores.
= 5 so incrementados automaticamente*/ enum {
enum colors {black, blue, green, cyan, red, purple, ARGENTINA = 3, ITALIA, BRASIL }; int main(void)
{ /*Colocamos 5 se voc for Argentino coloque 3 */
yellow, white};
int n = BRASIL ; mostrarRes(n); } void mostrarRes(int
quem) { switch(quem) { case BRASIL : printf( Brasil
A maneira mais simples de interpretar uma enumeration
invencvel como de costume\n ); break; case ARGEN imagina-la como uma matriz de apenas uma linha. TeTINA : printf(Argentina um dia quem sabe\n) ; break;
mos o nome da linha de temos as vrias clulas na licase ITALIA : printf(Foi sorte\n) ; break; default :
nha. Cada constante enumerada (muitas vezes chamado
printf(Se estou vivo teve erro do sistema xx \n) ; }
de enumerator) tem um valor inteiro (caso no seja esprintf(The end , hasta la vista\n \n); /*De um enter
pecicado ele comea em zero)
depois de } para evitar warning */ }
Exemplo:
Mas podemos denir o valor tipo
enum forma {quadrado=5, rectangulo,triangulo=27,
circulo, elipse}
caramos com a nossa linha do tipo:
reparem nos valores dos nmeros.
A vantagem em termos enumeraes que se uma varivel declarada tipo enumerao, tem um tipo nico e
os seus valores esto limitados e podero ser vericados
durante a compilao.
tal como as estruturas criar tipos de variveis.
61
Captulo 25
Programar em C/Unio
25.1 Unions
25.2 Declarao
union mytypes_t { int i; oat f; } mytypes;
Captulo 26
Programar em C/Estruturas
26.1 Structures
ponto).
nova_estrutura.fruta[0];
As stuctures permitem com que possamos ter variveis
Nos d o primeiro caracter da palavra contida dentro do
de vrios tipos aglomerados sob o mesmo nome. E esse
membro fruta.
mesmo nome vai passar a ser um novo tipo de dados tal
Para inicializar um campo da estrutura o processo o
como o int ou oat.
mesmo que usamos com as variveis.
Mas o uso disto que podemos ter valores que tenham
alguma relao lgica, por exemplo guardar um int de nova_estrutura.campo_dois = 100;
idade e um string de nome. Isto pode ser atributos de uma
pessoa. Ou seja podemos empacotar vrias variveis de
vrios tipos com o objetivo de representar o mundo real 26.3 Matrizes de estruturas
e dar um nome a essas variveis todas.
Ao fazer isto crimos um tipo de dados da mesma forma Uma estrutura como qualquer outro tipo de dado no C.
como fazemos em relao ao int ou ao oat.
Podemos, portanto, criar matrizes de estruturas. Vamos
ver como caria a declarao de um vetor de 100 chas
pessoais:
A sintaxe :
Primeiro mtodo:
struct minha_estrutura { int
campo_dois; char fruta[40]; } ;
variavel_um;
Agora podemos usar esse tipo struct para denir vari- struct product { .. } int main() { struct product apple,
banana, melon; }
veis.
E at podemos declarar um array delas
struct minha_estrutura nova_estructura;
Para ter acesso aos membros denidos dentro da estrutura Person p[20];
utilizamos um operador de seleao de membro "."(um Pergunta: como que feito exatamente os objetos?
63
64
Se tivermos apenas um objeto (ou varivel da estrutura) // pointers to structures #include <stdio.h> struct mono necessrio darmos o nome da estrutura
vies_t { char title[100]; int year; }; int main () { string
struct { char item[40]; // name of item double cost; // mystr; movies_t amovie; movies_t *pmovie; pmovie =
cost double retail; // retail price int on_hand; // amount &amovie; //atribumos valor ao ponteiro printf(Enter
on hand int lead_time; // number of days before resupply title: "); fgets(pmovie->title, 100, stdin); //operador > printf(Enter year: "; scanf("%d, &pmovie->year);
} temp;
printf("\nYou have entered:\n); printf("%s (%d)\n,
pmovie->title, pmovie->year); //operador -> return 0; }
Agora queremos dar valores a cada uma das pessoas, queremos dar o nome e a altura, para isso faramos;
A forma genrica :
structure-varname.member-name
ou seja
[objecto_estrutura][member_estrutura]
Exemplo
#include <stdio.h> const int MAX = 3; struct Person { char name[100]; int height; }; int main () {
Person p[MAX]; for (int x = 0; x < MAX; x++) {
printf(Enter persons name: "); getline(cin, p[x].name);
printf(Enter height in meters: "); scanf("%d\n,
&p[x].height); } printf(Outputting person data\n);
printf("======================\n); for (int x =
0; x < MAX; x++){ printf(Person #%ds name is %s
and height is %d.\n, x + 1, p[x].name, p[x].height); }
return 0; }
65
Captulo 27
Programar em C/Ponteiros
Poderamos escrever um livro inteiro sobre ponteiros, *q, *r; // agora sim temos trs ponteiros Para acessar o
pois o contedo demasiadamente extenso. Por esse motivo este assunto foi dividido em bsico, intermedirio
e avanado, assim o leitor poder fazer seus estudos conforme suas necessidades.
recomendvel para quem est vendo programao pela
primeira vez aqui que no se preocupe com o avanado
sobre ponteiros por enquanto.
27.1 Bsico
Esquema de um ponteiro
27.1.1
O que um ponteiro?
27.1.2
int *p = &a;
27.1. BSICO
inicializ-lo; esse um erro comum. Inicialmente, um
ponteiro pode apontar para qualquer lugar da memria
do computador. Ou seja, ao tentar ler ou gravar o valor
apontado por ele, voc estar manipulando um lugar desconhecido na memria!
int *p; *p = 9;
67
NULL est denido dentro do cabealho stddef.h . Aqui
voc no espera que o programa acabe com algum tipo
de mgica, se NULL igual ao valor do ponteiro isso
signica que no foi encontrado nem um endereo acessvel, ento voc para. Caso contrario voc estar executando uma operao que no permitida. Ou colocar 5
em (0x00000000) .
Nesse exemplo, estamos a manipular um lugar desconhecido da memria! Se voc tentar compilar esse cdigo,
o compilador dever dar uma mensagem de aviso; du- 27.1.4 Mais operaes com ponteiros
rante a execuo, provavelmente ocorrer uma falha de
segmentao (erro que ocorre quando um programa tenta
Suponhamos dois ponteiros inicializados p1 e p2. Podeacessar a memria alheia).
mos fazer dois tipos de atribuio entre eles:
Um exemplo mais elaborado:
p1 = p2;
#include <stdio.h> int main() { int i = 10 ; int *p ; p =
Esse primeiro exemplo far com que p1 aponte para o
&i ; *p = 5 ; printf ("%d\t%d\t%p\n, i, *p, p); return 0; }
mesmo lugar que p2. Ou seja, usar p1 ser equivalente a
usar p2 aps essa atribuio.
Primeiramente declaramos a varivel i, com valor 10, e
*p1 = *p2;
o ponteiro p, que apontar para o endereo de i. Depois,
guardamos o valor 5 no endereo apontado por p. Se voc Nesse segundo caso, estamos a igualar os valores apontados pelos dois ponteiros: alteraremos o valor apontado
executar esse exemplo, ver algo parecido com:
por p1 para o valor apontado por p2.
5 5 0022FF74
Agora vamos dar mais alguns exemplos com o ponteiro
claro que os valores de i e de *p sero iguais, j que p
p:
aponta para i. O terceiro valor o endereo de memria
onde est i (e, consequentemente, o prprio valor de p), p++;
e ser diferente em cada sistema.
Aqui estamos a incrementar o ponteiro. Quando increCuidado! Os operadores unrios & e * no podem ser mentamos um ponteiro ele passa a apontar para o prconfundidos com os operadores binrios AND bit a bit e ximo valor do mesmo tipo em relao ao valor para o
qual o ponteiro aponta. Isto , se temos um ponteiro para
multiplicao, respectivamente.
um inteiro e o incrementamos, ele passa a apontar para
o prximo inteiro. Note que o incremento no ocorre
byte-a-byte!
27.1.3 Ponteiro e NULL
Uma falha de segmentao ou em ingls (segmentation fault) ocorre quando um programa tenta acessar um
endereo na memria que est reservado ou que no
existe.Nos sistemas Unix quando acontece este tipo de
erro o sinal SIGSEGV enviado ao programa indicando
uma falha de segmentao.
(*p)++;
Aqui, colocamos *p entre parnteses para especicar que
queremos alterar o valor apontado por p. Ou seja, aqui
iremos incrementar o contedo da varivel apontada pelo
ponteiro p.
*p++
Aqui o ponteiro contem null, denido com o endereo Neste caso, o efeito no to claro quanto nos outros
exemplos. A precedncia do operador ++ sobre o opera(0x00000000) que causa uma falha de segmentao .
/*Endereo invalido*/ #dene null ( (char*) 0 ) int dor * faz com que a expresso seja equivalente a (*p)++.
O valor atual de p retornado ao operador *, e o valor
main(void){ int a = 5; int *p = null; *p = a; }
de p incrementado. Ou seja, obtemos o valor atual do
ponteiro e j o fazemos apontar para o prximo valor.
Esse programa termina anormalmente. Voc esta tenx = *(p + 15);
tando colocar o valor 5 em um endereo invlido.
Para que isso no acontea o ponteiro deve ser iniciali- Esta linha atribui a uma varivel x o contedo do dcimoquinto inteiro adiante daquele apontado por p. Por exemzado com um endereo valido. Exemplo :
plo, suponhamos que tivssemos uma srie de variveis
#include <stdio.h> #include <errno.h> #include <std- i0, i1, i2, i15 e que p apontasse para i0. Nossa varidef.h> int main(void){ int a = 5; int *p = NULL; p = &a; vel x receberia o valor de i15.
/* A operao no permitida */ if(p == NULL) return
-EPERM ; else{ printf(Endereo a disposio:%p\n, p Tente acompanhar este exemplo dos dois tipos de atribuio de ponteiros:
); *p = a; /* Pode colocar 5 */ } }
int *a, *b, c = 4, d = 2; a = &c; // a apontar para c b =
68
27.2 Intermedirio
27.2.1
Ponteiro de estrutura
27.2.2
Ponteiros como parmetros de fun- Quando uma funo recebe como parmetros os enderees
os e no os valores das variveis, dizemos que estamos
a fazer uma chamada por referncia; o caso desse lComecemos por uma situao-problema: eu tenho 2 va- timo exemplo. Quando passamos diretamente os valores
riveis e quero trocar o valor delas. Vamos comear com das variveis para uma funo, dizemos que uma chaum algoritmo simples, dentro da funo main():
mada por valor; foi o caso do segundo exemplo. Veja
#include <stdio.h> int main() { int a = 5, b = 10, temp; mais um exemplo abaixo:
printf ("%d %d\n, a, b); temp = a; a = b; b = temp; // passagem_valor_referencia.c #include<stdio.h> int
printf ("%d %d\n, a, b); return 0; }
cubo_valor( int ); int cubo_referencia( int * ); int
main(){ int number = 5; printf("\nO valor original
Esse exemplo funcionar exatamente como esperado: eh: %d, number ); number = cubo_valor( number );
primeiramente ele imprimir 5 10 e depois ele impri- printf("\nO novo valor de number eh: %d, number);
mir 10 5. Mas e se quisermos trocar vrias vezes o printf("\n---------------"); number = 5; printf("\nO valor
valor de duas variveis? muito mais conveniente criar original eh: %d, number ); cubo_referencia( &number
uma funo que faa isso. Vamos fazer uma tentativa de ); printf("\nO novo valor de number eh: %d, number);
return 0; } int cubo_valor( int a){ return a * a * a; } int
implementao da funo swap (troca, em ingls):
cubo_referencia( int *aPtr ){ *aPtr = *aPtr * *aPtr *
#include <stdio.h> void swap(int i, int j) { int temp;
27.3. AVANADO
*aPtr; }
27.2.3
Ponteiros e vetores
69
#include <stdio.h> int main () { int i; int vetor[10]; for
(i = 0; i < 10; i++) { printf (Digite um valor para a
posicao %d do vetor: ", i + 1); scanf ("%d, &vetor[i]);
//isso equivalente a fazer *(x + i) } for (i = 0; i < 10;
i++) printf ("%d\n, vetor[i]); return (0); }
Essa indexao, apesar de estranha, funciona corretamente e sem aviso na compilao. Ela prtica, mas,
para os iniciantes, pode parecer complicada. s treinar
para entender.
Avanado
Ponteiros para ponteiros
Note que um ponteiro uma varivel como outra qualquer, e por isso tambm ocupa espao em memria. Para
obtermos o endereo que um ponteiro ocupa em e memria, usamos o operador &, assim como fazemos nas
variveis comuns.
Mas e se estivssemos interessados em guardar o endereo de um ponteiro, que tipo de vriavel deveria recebe#include <stdio.h> int main() { int numbers[5]; int lo? A resposta : um ponteiro, isto , um ponteiro para
*p; int n; p = numbers; *p = 10; p++; *p = 20; p = outro ponteiro.
&numbers[2]; *p = 30; p = numbers + 3; *p = 40; p = Considere a seguinte declarao:
numbers; *(p + 4) = 50; for (n = 0; n < 5; n++) cout <<
int x = 1;
numbers[n] << ", "; return 0; }
Declaramos uma varivel chamada x com o valor 1.
Veja mais este exemplo:
Ele resume as vrias formas de acessar elementos de um Como j sabemos, para declarar um ponteiro, deve-se vericar o tipo da varivel que ele ir apontar (neste caso
vetor usando ponteiros.
int) e colocar um asterisco entre o tipo da varivel e o
nome do ponteiro:
27.2.4
o C permite fazer um tipo indexao de um vetor quando Declaramos um ponteiro apontado para x.
uma varivel controla seu ndice. O seguinte cdigo Agora, para se guardar o endereo de um ponteiro, os
mesmos passos devem ser seguidos. Primeiramente vevlido e funciona: Observe a indexao vetor[i].
70
ricamos os tipo da varivel que ser apontada (int *) e ferncia), pois os seus valores so alterados pela funo
colocamos um asterisco entre o tipo e nome do ponteiro: atribuiValores. De nada adiantaria passar o vetor por valor, pois o valor s seria alterado localmente na funo
int ** p_p_x = &p_x;
(como j vimos no caso de troca do valor de duas variDeclaramos um ponteiro que ir apontar para o ponteiro veis).
p_x, ou seja, um ponteiro para ponteiro. Note que C no
impe limites para o nmero de asteriscos em uma vari- Por causa dessa equivalncia entre vetores e ponteiros,
podemos fazer uma pequena alterao no prottipo (tanto
vel.
na declarao quanto na denio) das funes atribuiVaNo exemplo a seguir, todos os printf iro escrever a lores e mostraValores, sem precisar alterar o cdigo inmesma coisa na tela.
terno dessas funes ou a chamada a elas dentro da funo
#include <stdio.h> int main(void) { int x = 1; int *p_x = main ? trocando
&x; // p_x aponta para x int **p_p_x = &p_x; // p_p_x void atribuiValores(int[], int); void mostraValores(int[],
aponta para o ponteiro p_x printf("%d\n, x); // Valor int);
da varivel printf("%d\n, *p_x); // Valor da varivel
por
apontada por p_x printf("%d\n, **p_p_x); // Valor da
varivel apontada pelo endereo apontado por p_p_x void atribuiValores(int*, int); void mostraValores(int*,
return 0; }
int);
Para o compilador, voc no fez mudana alguma, justaPercebe que **p_p_x consiste no valor da varivel apon- mente por conta dessa equivalncia. Em ambos os casos,
tada pelo endereo apontado por p_p_x.
foi passado o endereo do vetor para as funes.
Uma aplicao de ponteiros para ponteiros est nas
strings, j que strings so vetores, que por sua vez so
ponteiros. Um vetor de strings seria justamente um pon- 27.3.3 Ponteiros para funes
teiro para um ponteiro.
Os ponteiros para funes servem, geralmente, para passar uma funo como argumento de uma outra funo.
27.3.2 Passando vetores como argumentos Neste exemplo
de funes
27.3. AVANADO
Se ptr um ponteiro para uma funo, faz bastante sentido que a funo em si seja chamada por *ptr. No entanto, a sintaxe mais moderna permite que ponteiros para
funes sejam chamados exatamente da mesma maneira
que funes:
nome_do_ponteiro(argumentos);
Por m, para inicializar um ponteiro para funo, no
precisamos usar o operador de endereo (ele j est implcito). Por isso, quando chamamos a funo operacao,
no precisamos escrever &soma.
Veja mais um exemplo na verdade, uma extenso do
exemplo anterior:
#include <stdio.h> int soma(int a, int b) { return (a+b);
} int subtracao(int a, int b) { return (a-b); } int (*menos)(int, int) = subtracao; int operacao(int x, int y, int
(*func)(int,int)) { int g; g = func(x, y); return (g); }
int main() { int m, n; m = operacao(7, 5, soma); n =
operacao(20, m, menos); printf("%d\n, n); return 0; }
Aqui, criamos mais uma funo, subtracao, alm de criar
um outro ponteiro para ela (uma espcie de atalho), menos. Na funo main, referimo-nos funo de subtrao
atravs desse atalho.
Veja tambm que aqui usamos a sintaxe moderna para a
chamada de ponteiros de funes, ao contrrio do exemplo anterior.
71
Captulo 28
28.2 sizeof
poderamos declarar variveis inteiras sem sinal (unsigned int) da seguinte maneira:
73
Nesse caso, o 10 ou o 3 convertido para oat. O outro nmero continua como inteiro, mas ao entrar na diviso com um oat, ele convertido automaticamente para
oat. A diviso feita e depois atribuda varivel a.
destino=origem;
Em poucas palavras, casting colocar um tipo entre paSe o destino e a origem so de tipos diferentes o compi- rnteses antes da atribuio de uma varivel. A forma
lador faz uma converso entre os tipos. Mas nem todas geral para cast :
as converses so possveis. O primeiro ponto a ser res- (tipo)varivel (tipo)(expresso) variavel_destino =
saltado que o valor de origem convertido para o valor (tipo)variavel_origem;
de destino antes de ser atribudo e no o contrrio.
Mas existem umas converses automticas:
Em C, cada tipo bsico ocupa uma determinada poro
int f(void) { oat f_var; double d_var; long double
de bits na memria, logo, a converso entre tipos nem
l_d_var; f_var = 1; d_var = 1; l_d_var = 1; d_var = d_var
sempre algo nativo da linguagem, por assim dizer. H
+ f_var; /*o oat convertido em double*/ l_d_var =
funes como atol e atof que convertem string em inteiro
d_var + f_var; /*o oat e o double convertidos em long
longo (long int) e string em double, respectivamente. Mas
double*/ return l_d_var; }
em muitos casos possvel usar o casting.
importante lembrar que quando convertemos um tipo
numrico para outro, ns nunca ganhamos preciso. Ns
podemos perder preciso ou no mximo manter a preciso anterior. Isto pode ser entendido de uma outra forma.
Quando convertemos um nmero no estamos introduzindo no sistema nenhuma informao adicional. Isto implica que nunca vamos ganhar preciso.
28.3.1
74
28.4.1
const
Podemos ver pelo exemplo que as variveis com o modicador const podem ser inicializadas. Mas PI no poderia
ser alterado em qualquer outra parte do programa. Se o
programador tentar modicar PI o compilador gerar um
erro de compilao.
<
28.4.4 static
nclude <stdio.h>
28.4.3
extern
28.4.5 register
75
Captulo 29
argc (argument count) um inteiro e possui o nmero de argumentos com os quais o programa foi 29.2 Lista de argumentos
chamado na linha de comando. Ele no mnimo 1,
pois o nome do programa contado como sendo o
Na linguagem C possvel funes como printf onde
primeiro argumento.
o nmero de argumentos podem variar. As reticncias
( ... ) indicam um numero varivel de argumentos ou
argv (argument values) um ponteiro para uma ma- argumentos com tipos varivel. Ex:
triz de strings (conceitos que sero abordados mais
frente). Cada string desta matriz um dos par- void f_erro(int n, char *fmt, ...);
metros da linha de comando. argv[0] sempre aponta Essa declarao indica que se deve fornecer pelo menos
para o nome do programa (que, como j foi dito, dois argumentos, um do tipo int e um do tipo char mais
considerado o primeiro argumento). para saber pode se fornecer argumentos suplementares. Ou seja,
quantos elementos temos em argv que temos argc.
no h limites para sua criatividade"! Ex:
f_erro( 3, Erro: misso impossvel "); f_erro( valor, "%s
Como pode se imaginar, os nomes dos parmetros argc %d\n, mensagem, errno);
e argv podem ser mudados, mas por questo de padroE necessrio ter pelo menos um argumento antes dos ponnizao no se costuma modic-los.
tos. Veja um exemplo incorreto.
Exemplo: Escreva um programa que faa uso dos parmetros argv e argc. O programa dever receber da linha void erreur(...);
de comando o dia, ms e ano correntes, e imprimir a data O arquivo de cabealho stdarg.h declara um tipo va_list
em formato apropriado. Veja o exemplo, supondo que o e dene trs macros para manipular uma lista de arguexecutvel se chame data:
mentos cuja quantidade e tipos so desconhecidos pela
funo.
data 19 04 99
O programa dever imprimir: 19 de abril de 1999
Sintaxe:
#include <stdarg.h> void va_start(va_list ap, last); type
va_arg(va_list ap, type); void va_end(va_list ap); void
va_copy(va_list dest, va_list src);
Descrio:
va_start:
76
Exemplo 1
/* Calcula a soma de n inteiros */ /* o ultimo argumento
deve ser 0 */ #include <stdio.h> #include <stdarg.h>
int soma(int n1, ...) { va_list pa; int som, n; som = n1;
va_start(pa, n1); while( (n = va_arg(pa, int)) != 0) som
= som + n; va_end(pa); return som; } main() { printf(1
+ 3 + 5 + 7 + 9 = %d\n, soma(1,3,5,7,9,0)); printf(1
+ 1 = %d\n, soma(1,1,0)); return 0; } /*-- resultado
---------------------------- 1 + 3 + 5 + 7 + 9 = 25 1 + 1 = 2
---------------------------------------------------------*/
Exemplo 2
#include <stdio.h> #include <stdarg.h> void
meu_printf(char *fmt, ...) { va_list pa; int n; char
77
*s, c; oat f; va_start(pa, fmt); while (*fmt != '\0') { if (
*fmt == '%' ) { /* (*++fmt) equivale a (*fmt = *fmt +
1 )*/ switch (*++fmt) { case '%' : putchar('%'); break;
case 'c' : /* char*/ c = va_arg(pa, int); putchar(c); break;
case 'd' : /* int */ n = va_arg(pa, int); printf("%d, n);
break; case 'f' : /* oat */ f = va_arg(pa, double); /*
!!!!! */ printf("%f, f); break; case 's : /* string */ s
= va_arg(pa, char *); for ( ; *s != '\0'; s++ ) putchar(
*s ); break; } /* end switch */ } else putchar( *fmt );
/*incrementa o ponteiro*/ fmt++; } va_end(pa); } int
main() { meu_printf(oat = %f\n, (oat) 1.2345);
meu_printf(int = %d char = %c String = %s\n, 123,
'A', C is beautiful !" ); return 0; }
Captulo 30
Programar em C/Bibliotecas
30.1 Bibliotecas
Bibliotecas so conjuntos de funes que foram feitas
por algum e que podem ser usadas por outros programas
sem que nos preocupemos com o cdigo dessas funes.
30.2 O arquivo-cabealho
Arquivos-cabealho so arquivos que contm informaes que servem para o compilador reconhecer funes
(VER: convenes para chamadas a funes ou calling
convention), macros, tipos de dados e variveis que no
esto no arquivo sendo compilado. Esses arquivos costumam ter a extenso ".h o caso, por exemplo, dos
As linhas acima so o arquivo do cdigo da nossa bibli- cabealhos padro stdio.h e math.h. A letra H usada
oteca. Abaixo est o cdigo de um programa que testar pois a inicial de header (cabealho em ingls).
essa biblioteca. Lembre-se de que os dois trechos devem
Em uma biblioteca, os cabealhos contm, os prottipos
estar em arquivos separados.
das funes disponibilizadas pela biblioteca e, quando
#include <stdio.h> int main() { int r1, r2, n_pgtos; necessrio, sobre os tipos de estruturas usados. Bibliotedouble a_vista, juros, v_pgto; r1 = rand (); r2 = rand cas mais complexas costumam dividir essas funes entre
(); printf (Nmeros aleatrios: %d, %d\n\n, r1, r2); vrios arquivos.
printf (" Valor vista: "); scanf ("%lf, &a_vista); printf
(Nmero de pagamentos: "); scanf ("%d, &n_pgtos); Para fazer nosso prprio cabealho, precisamos colocar
printf (" Taxa de juros: "); scanf ("%lf, &juros); juros as declaraes das funes disponveis na biblioteca:
/= 100; /* converte a porcentagem em nmero */ v_pgto int rand (); void init_seed (); double vf (double, int,
= vf (a_vista, n_pgtos, juros); printf (Valor de cada double);
pagamento: %lf\n, v_pgto); return 0; }
78
79
No GCC:
#ifndef _TESTE1_H #dene _TESTE1_H int rand (); gcc main.c -L. -l libteste1.a -o main.bin -lm
void init_seed (); double vf (double, int, double); #endif Note as opes que voc no conhecia: -L e -l . A primeira indica em que diretrio deve ser procurada a biAgora, sempre que precisarmos usar a biblioteca teste1, blioteca; o ponto indica o diretrio atual. Se essa opo
basta incluir o arquivo teste1.h no incio do nosso pro- for omitida, o compilador procurar apenas nos diretrios
padro. A segunda uma opo do editor de links indigrama:
cando uma biblioteca a ser includa; o compilador procu#include teste1.h
rar pelo arquivo adicionando o prexo lib e a extenso
.a, da a necessidade de dar o nome libteste1.a bibliNote que se o cabealho estiver instalado nos diretrios oteca. Mais bibliotecas podem ser includas como a -lm
padro do compilador ou do sistema, voc deve trocar as que neste caso serve para chamar a biblioteca math do
aspas pelos sinais de menor/maior (< ... >).
math.h, sem este comando ele poder apresentar um erro
na hora da compilao.
No Visual C++:
Tendo salvo o cdigo da biblioteca no arquivo teste1.c, link /out:main.exe main.obj teste1.lib
voc deve compilar a biblioteca.
Note que nesse caso simplesmente especicamos os arquivos que devem ser montados. O diretrio de procura
pode ser especicado pela opo /libpath:diretrio.
30.3.1
No GCC
30.3.2
No MS Visual C++
Captulo 31
*nome_do_arquivo,
char
80
81
stdaux: dispositivo de sada auxiliar (em muitos sistemas, associado porta serial)
O nico argumento o identicador do uxo (retornado por fopen). O valor de retorno indica o sucesso
da operao com o valor zero.
Fechar um arquivo faz com que qualquer caractere
que tenha permanecido no buer associado ao
uxo de sada seja gravado. Mas, o que este buffer"? Quando voc envia caracteres para serem gravados em um arquivo, estes caracteres so armazenados temporariamente em uma rea de memria (o
buer) em vez de serem escritos em disco imediatamente. Quando o buer estiver cheio, seu
contedo escrito no disco de uma vez. A razo
para se fazer isto tem a ver com a ecincia nas leituras e gravaes de arquivos. Se, para cada caractere que fssemos gravar, tivssemos que posicionar a cabea de gravao em um ponto especco do
disco, apenas para gravar aquele caractere, as gravaes seriam muito lentas. Assim estas gravaes s
sero efetuadas quando houver um volume razovel
de informaes a serem gravadas ou quando o arquivo for fechado.
A funo exit() fecha todos os arquivos que um programa tiver aberto.
31.3.1 fwrite
Esta funo envolve os conceitos de ponteiro e vetor,
que s sero abordados mais tarde.
A funo ush() fora a gravao de todos os caA funo fwrite() funciona como a sua companheira
racteres que esto no buer para o arquivo.
fread(), porm escreve no arquivo. Seu prottipo :
31.2.1
Exemplo
A funo retorna o nmero de itens escritos. Este vaUm pequeno exemplo apenas para ilustrar a abertura e lor ser igual a count a menos que ocorra algum erro. O
fechamento de arquivos:
exemplo abaixo ilustra o uso de fwrite e fread para gravar
#include <stdio.h> int main() { FILE *fp; fp = fopen e posteriormente ler uma varivel oat em um arquivo
(README, w); if (fp == NULL) { printf (Houve binrio.
um erro ao abrir o arquivo.\n); return 1; } printf #include <stdio.h> #include <stdlib.h> int main() {
(Arquivo README criado com sucesso.\n); fclose FILE *pf; oat pi = 3.1415; oat pilido; if((pf =
(fp); return 0; }
fopen(arquivo.bin, wb)) == NULL) /* Abre arquivo
binrio para escrita */ { printf(Erro na abertura do
arquivo); exit(1); } if(fwrite(&pi, sizeof(oat), 1,pf)
!= 1) /* Escreve a varivel pi */ printf(Erro na escrita
31.2.2 Arquivos pr-denidos
do arquivo); fclose(pf); /* Fecha o arquivo */ if((pf =
fopen(arquivo.bin, rb)) == NULL) /* Abre o arquivo
Na biblioteca padro do C, existem alguns uxos pr- novamente para leitura */ { printf(Erro na abertura do
denidos que no precisam (nem devem) ser abertos nem arquivo); exit(1); } if(fread(&pilido, sizeof(oat), 1,pf)
fechados:
!= 1) /* Le em pilido o valor da varivel armazenada
82
31.4.2 fgets
31.3.2
fputc
Novamente, h quatro funes, das quais trs se asseme- fgets (str, tamanho, stdin);
lham s usadas para a sada padro:
int fgetc (FILE *uxo);
31.4.3 fscanf
void fgets (char *string, int tamanho, FILE *uxo);
void fscanf (FILE *uxo, char *formatao, ...);
Sintaxe quase igual de scanf(); s necessrio adiint fread (void *dados, int tamanho_do_elemento, int
cionar o identicador de uxo no incio.
num_elementos, FILE *uxo);
31.4.4 fscanf
31.4.1
fgetc
83
31.4.5
fread
Essa funo envolve os conceitos de ponteiro e vetor, Outra forma de se vericar se o nal do arquivo foi atingido comparar o caractere lido por getc com EOF. O
que s sero abordados mais tarde.
programa a seguir abre um arquivo j existente e o l,
caracter por caracter, at que o nal do arquivo seja atinPodemos escrever e ler blocos de dados. Para tanto, te- gido. Os caracteres lidos so apresentados na tela:
mos as funes fread() e fwrite(). O prottipo de fread()
#include <stdio.h> #include <stdlib.h> int main() { FILE
:
*fp; char c; fp = fopen(arquivo.txt,"r); /* Arquivo
unsigned fread (void *buer, int numero_de_bytes, int ASCII, para leitura */ if(!fp) { printf( Erro na abertura
count, FILE *fp);
do arquivo); exit(0); } while((c = getc(fp) ) != EOF) /*
O buer a regio de memria na qual sero armazena- Enquanto no chegar ao nal do arquivo */ printf("%c,
dos os dados lidos. O nmero de bytes o tamanho da c); /* imprime o caracter lido */ fclose(fp); return 0; }
unidade a ser lida. count indica quantas unidades devem
ser lidas. Isto signica que o nmero total de bytes lidos Verique o exemplo.
:
#include <stdio.h> #include <stdlib.h> #include
numero_de_bytes*count
<string.h> int main() { FILE *p; char c, str[30],
A funo retorna o nmero de unidades efetivamente li- frase[80] = Este e um arquivo chamado: "; int i;
das. Este nmero pode ser menor que count quando o m printf("\n\n Entre com um nome para o arquivo:\n);
gets(str); /* Le um nome para o arquivo a ser aberto: */
do arquivo for encontrado ou ocorrer algum erro.
if (!(p = fopen(str,"w))) /* Caso ocorra algum erro na
Quando o arquivo for aberto para dados binrios, fread
abertura do arquivo..*/ { printf(Erro! Impossivel abrir
pode ler qualquer tipo de dados.
o arquivo!\n); exit(1); /* o programa aborta automaticamente */ } strcat(frase, str); for (i=0; frase[i]; i++)
putc(frase[i],p); fclose(p); /* Se nao houve erro,imprime
no arquivo e o fecha ...*/ p = fopen(str,"r); /* Abre
31.5 Movendo pelo arquivo
novamente para leitura */ c = getc(p); /* Le o primeiro
caracter */ while (!feof(p)) /* Enquanto no se chegar
31.5.1 fseek
no nal do arquivo */ { printf("%c,c); /* Imprime o
caracter na tela */ c = getc(p); /* Le um novo caracter
Para se fazer procuras e acessos randmicos em arquivos no arquivo */ } fclose(p); /* Fecha o arquivo */ }
usa-se a funo fseek(). Esta move a posio corrente de
leitura ou escrita no arquivo de um valor especicado, a
partir de um ponto especicado. Seu prottipo :
int fseek (FILE *fp, long numbytes, int origem);
ferror e perror
84
exemplo, pode acabar o espao em disco enquanto gravamos, ou o disco pode estar com problemas e no conseguimos ler, etc. Uma funo que pode ser usada em
conjunto com ferror() a funo perror() (print error),
cujo argumento uma string que normalmente indica em
que parte do programa o problema ocorreu.
#include <stdio.h> #include <stdlib.h> int main() { FILE
*pf; char string[100]; if((pf = fopen(arquivo.txt,"w))
==NULL) { printf("\nNao consigo abrir o arquivo ! ");
exit(1); } do { printf("\nDigite uma nova string. Para
terminar, digite <enter>: "); gets(string); fputs(string,
pf); putc('\n', pf); if(ferror(pf)) { perror(Erro na
gravacao); fclose(pf); exit(1); } }while (strlen(string) >
0); fclose(pf); }
Captulo 32
Programar em C/Gerenciamento de
memria
32.1 Alocao dinmica
Todos os dados de um programa so armazenados na memria do computador; muito comum necessitar reservar
um certo espao na memria para poder guardar dados
mais tarde. Por exemplo, poderamos reservar um espao
de 1000 bytes para guardar uma string que o usurio viesse a digitar, declarando um vetor de 1000 caracteres.
E se quisssemos reservar um espao que s conhecido no tempo de execuo do programa? E se o espao Outros exemplos:
fosse muito grande, de modo que declarar vetores de tal
int main() { int *p, *q; p = malloc(sizeof(int)); q = p; *p
tamanho seria inconveniente (pois, entre outras coisas,
= 10; printf("%d\n, *q); *q = 20; printf("%d\n, *q); }
aumenta sem necessidade o tamanho do executvel)?
int main() { int *p, *q; p = malloc(sizeof(int)); q
Para solucionar esse problema, existe a alocao din- = malloc(sizeof(int)); *p = 10; *q = 20; *p = *q;
mica de memria, que como o nome sugere, uma ma- printf("%d\n, *p); }
neira de alocar memria medida que o programa vai
sendo executado. As quatro funes relacionadas com a
alocao dinmica sero descritas a seguir.
O compilador aceita *p=*q porque so ambos int.
32.1.1
malloc e free
Essas duas funes so as mais bsicas para o gerenciamento de memria. malloc responsvel pela alocao
de um pedao de memria, e free responsvel por liberar esse pedao de memria.
A funo malloc() serve para alocar memria e tem o seguinte prottipo:
void *malloc (unsigned int num); void free (void * ptr);
Para alocar um espao na memria, precisamos fornecer
funo malloc o nmero de bytes desejados. Ela aloca
na memria e retorna um ponteiro void * para o primeiro
byte alocado. O ponteiro void* pode ser atribudo a qualquer tipo de ponteiro. Se no houver memria suciente
para alocar a memria requisitada a funo malloc() retorna um ponteiro nulo.
32.1.2 calloc
A funo calloc() tambm serve para alocar memria,
mas possui um prottipo um pouco diferente:
void *calloc(size_t nelem, size_t elsize);
86
para alocar a memria requisitada a funo calloc() re- printf(Conteudo de str1 : %s\n, str1); free(str1);
torna um ponteiro nulo.
free(str2); return 0; }
Exemplo:
#include <stdio.h> #include <stdlib.h> /* Para usar calloc() */ int main (){ int *p; int n; int i; ... /* Determina o
valor de n em algum lugar */ p = calloc(n, sizeof(int)); /*
Aloca n nmeros inteiros p pode agora ser tratado como
um vetor com n posicoes */ //p = malloc(n*sizeof(int));
/* Maneira equivalente usando malloc. */ if (!p) { printf
("** Erro: Memoria Insuciente **"); exit(0); } for (i=0;
i<n; i++) /* p pode ser tratado como um vetor com n
posicoes */ p[i] = i*i; ... return 0; }
#include <stdio.h> #include <stdlib.h> oat *Alocar_vetor_real (int n) { oat *v; /* ponteiro para o vetor
*/ if (n < 1) { /* verica parametros recebidos */ printf
("** Erro: Parametro invalido **\n); return (NULL); }
v = calloc (n, sizeof(oat)); /* aloca o vetor */ if (v ==
NULL) { printf ("** Erro: Memoria Insuciente **");
return (NULL); } return (v); /* retorna o ponteiro para
o vetor */ } oat *Liberar_vetor_real (oat *v) { if (v
== NULL) return (NULL); free(v); /* libera o vetor
*/ return (NULL); /* retorna o ponteiro */ } int main
(void) { oat *p; int a; ... /* outros comandos, inclusive
a inicializacao de a */ p = Alocar_vetor_real (a); ... /*
outros comandos, utilizando p[] normalmente */ p =
Liberar_vetor_real (p); }
32.1.3
realloc
A funo realloc() serve para realocar memria e tem o A alocao dinmica de memria para matrizes realiseguinte prottipo:
zada da mesma forma que para vetores, com a diferena
que teremos um ponteiro apontando para outro ponteiro
void *realloc(void *ptr, size_t size);
que aponta para o valor nal, ou seja um ponteiro para
ponteiro, o que denominado indireo mltipla. A inA funo realloc ajusta o tamanho de um bloco a size oc- direo mltipla pode ser levada a qualquer dimenso detetos consecutivos. A funo modica o tamanho da me- sejada, mas raramente necessrio mais de um ponteiro
mria previamente alocada com malloc, calloc ou realloc
para um ponteiro. Um exemplo de implementao para
e apontada por ptr para o tamanho especicado por size. matriz real bidimensional fornecido a seguir. A estruO valor de size pode ser maior ou menor que o original.
tura de dados utilizada neste exemplo composta por um
Um ponteiro para o bloco devolvido porque realloc() vetor de ponteiros (correspondendo ao primeiro ndice da
pode precisar mover o bloco para aumentar seu tamanho.
matriz), sendo que cada ponteiro aponta para o incio de
Se isso ocorrer, o contedo do bloco antigo copiado no uma linha da matriz. Em cada linha existe um vetor alonovo bloco, o bloco antigo liberado e nenhuma informacado dinamicamente, como descrito anteriormente (como perdida. Se no precisar mover, o valor retornado pondo o segundo ndice da matriz).
igual a ptr. Se ptr for nulo, a funo aloca size bytes e
devolve um ponteiro, funcionando como malloc(); se size #include <stdio.h> #include <stdlib.h> oat **Alo zero, a memria apontada por ptr liberada. Se no car_matriz_real (int m, int n) { oat **v; /* ponteiro
houver memria suciente para a alocao, um ponteiro para a matriz */ int i; /* variavel auxiliar */ if (m < 1 ||
nulo devolvido e o bloco original deixado inalterado. n < 1) { /* verica parametros recebidos */ printf ("**
Erro: Parametro invalido **\n); return (NULL); } /*
Exemplo:
aloca as linhas da matriz */ v = calloc (m, sizeof(oat
#include <stdio.h> #include <string.h> #include <st- *)); /*Um vetor de m ponteiros para oat */ if (v ==
dlib.h> int main() { char *str1=NULL, *str2=NULL; NULL) { printf ("** Erro: Memoria Insuciente **");
str1 = (char *) malloc(11); strcpy(str1, ABC- return (NULL); } for ( i = 0; i < m; i++ ) /* aloca as
DEFGHIJ); str2 = (char *) realloc(str2, 20); colunas da matriz */ { v[i] = calloc (n, sizeof(oat)); /*
printf(Endereo de str1 : %p\n, str1); printf(Endereo m vetores de n oats */ if (v[i] == NULL) { printf ("**
de str2 : %p\n, str2); str1 = (char *) realloc(str1, Erro: Memoria Insuciente **"); return (NULL); } }
100); printf(Novo endereo de str1 : %p\n, str1); return (v); /* retorna o ponteiro para a matriz */ } oat
87
Captulo 33
Programar em C/Sockets
33.1 Abstraes
int accept(int, struct sockaddr *restrict, socklen_t *restrict); int bind(int, const struct sockaddr *, socklen_t);
int connect(int, const struct sockaddr *, socklen_t); int
getpeername(int, struct sockaddr *restrict, socklen_t
*restrict); int getsockname(int, struct sockaddr *restrict, socklen_t *restrict); int getsockopt(int, int, int,
void *restrict, socklen_t *restrict); int listen(int, int);
ssize_t recv(int, void *, size_t, int); ssize_t recvfrom(int,
void *restrict, size_t, int, struct sockaddr *restrict,
socklen_t *restrict); ssize_t recvmsg(int, struct msghdr
*, int); ssize_t send(int, const void *, size_t, int);
ssize_t sendmsg(int, const struct msghdr *, int); ssize_t
sendto(int, const void *, size_t, int, const struct sockaddr
*, socklen_t); int setsockopt(int, int, int, const void *,
socklen_t); int shutdown(int, int); int socket(int, int, int);
int sockatmark(int); int socketpair(int, int, int, int[2]);
88
Captulo 34
Programar em C/Makeles
34.1 Makele
/*================
teste.c
======================*/ #include <stdio.h>
#include <stdlib.h> /*Uma funao makeTeste()*/ void
makeTeste(void){ printf(O Makele super Legal\n);
}
Aqui escrevemos o header :
/*=======================
teste.h
===============*/
/*==================
O texto contido em um Makele usado para a com- Cabealho ou header ========*/ #ifndef _H_TESTE
pilao, ligao(linking), montagem de arquivos de #dene _H_TESTE /* A nossa funo */ void makeprojeto entre outras tarefas como limpeza de arquivos Teste(void); /* De um enter depois de endif*/ /*Para
evitar warning*/ #endif
temporrios, execuo de comandos, etc.
Agora a funo main :
Vantagens do uso do Makele:
/*======================
main.c
=================*/ #include <stdio.h> #in Evita a compilao de arquivos desnecessrios. Por clude <stdlib.h> #include teste.h /* Aqui main ;( */ int
exemplo, se seu programa utiliza 120 bibliotecas e main(void){ makeTeste(); return (0); }
voc altera apenas uma, o make descobre (compaPara compilar fazemos um arquivo Makele minimal.
rando as datas de alterao dos arquivos fontes com
escrever
comentrios
##
as dos arquivos anteriormente compilados) qual #Para
#############################
Makele
arquivo foi alterado e compila apenas a biblioteca
########################## all:
teste teste:
necessria.
teste.o main.o # O compilador faz a ligao entre os dois
objetos gcc -o teste teste.o main.o #-----> Distancia com
Automatiza tarefas rotineiras como limpeza de v- o boto TAB ### e no com espaos teste.o: teste.c gcc
rios arquivos criados temporariamente na compila- -o teste.o -c teste.c -W -Wall -ansi -pedantic main.o:
o
main.c teste.h gcc -o main.o -c main.c -W -Wall -ansi
Pode ser usado como linguagem geral de script em- -pedantic clean: rm -rf *.o mrproper: clean rm -rf teste
bora seja mais usado para compilao
Para no ter erros os espaos devem ser feito com a tecla
TAB.
As explicaes a seguir so para o utilitrio GNU make E compilar s ir dentro da pasta Projeto apertar F4
(gmake) que similar ao make.
escrever make e apertar enter.
Ento vamos para a apresentao do Makele atravs da Uma vez compilado podemos modicar teste.c . Se
compilao de um pequeno projeto em linguagem C.
teste.c foi modicado ento make modica teste.o e se
no deixa teste.o como esta.
Criar uma pasta com esses 4 arquivos :
89
90
clean: Apaga os arquivos intermedirios.Se voc es- Todos os lugares do cdigo que contem o CONTEDO
crever no console make clean
da varivel so modicados colocando no lugar respectivo
o NOME da
varivel.
ele apaga os arquivos objeto da pasta.
mrproper: Apaga tudo o que deve ser modi- Variveis Personalizadas
cado.No console escreva make mrproper
CC=gcc .Denimos CC para nomes de compiladores de C ou C++ .Aqui o gcc.
34.1.1
CFLAGS=-W -Wall -ansi -pedantic .Serve para denir opes passadas ao compilador.
regra: dependncias Apertar o boto TAB comando co- Para o c++ o NOME e CXXFLAGS .
mando ...
LDFLAGS e utilizado para editar as opes de
links.
Regras complementares
EXEC=teste .EXEC dene o NOME do futuro pro all : o nome das regras a serem executadas.
grama executvel.
clean: Apaga os arquivos intermedirios.
mrproper: Apaga tudo o que deve ser modicado.
Denir Variveis
As variveis servem para facilitar o trabalho.
Em vez de mudar varias linhas mudamos s o contedo
da varivel.
Deve ser por isso que se chama varivel, no?
Denimos da forma seguinte.
OBJ=teste.o main.o . Para cada arquivo.c um arquivo OBJETO e criado com a extenso ".o arquivo.o .
Ento e s olhar na sua pasta todos os arquivos com a extenso ".c e colocar na varivel OBJ com a extenso.o
.
Outra maneira e mesma coisa. OBJ agora e igual a
main.o teste.o
#Para
escrever
comentrios
##
#############################
Makele
########################## #Denimos a va- SRC= $(wildcard *.c) OBJ= $(SRC:.c=.o)
rivel SRC=main.c all: teste teste: teste.o main.o gcc -o
teste teste.o main.o #-----> Distancia com o botao TAB
Observao se quiser fazer aparecer uma mensagem
### e nao com espaos teste.o: teste.c gcc -o teste.o -c
durante a compilao escreva @echo Minha menteste.c -W -Wall -ansi -pedantic # #Coloquei $(SRC) em
sagem .
todos os lugares aonde estava main.c main.o: $(SRC)
E mais tem um monte de mensagens e ca muito
teste.h gcc -o main.o -c $(SRC) -W -Wall -ansi -pedantic
feio
clean: rm -rf *.o mrproper: clean rm -rf teste
34.1. MAKEFILE
91
Tem outra idia??.. O pessoal vamos parando ;) no teste.o main.o teste: teste.o main.o # $@ = teste: # $^
sou uma maquina de idias.
= teste.o main.o $(CC) -o $@ $^ # teste.o:teste.c %.o:
%.c $(CC) -o $@ -c $< $(CFLAGS) main.o: main.c
Para deixar as mensagens em modo silencioso colo- teste.h $(CC) -o $@ -c $< $(CFLAGS) .PHONY:
que "@" no comeo do comando.
clean mrproper clean: rm -rf *.o @echo Compilaao
prontinha mrproper: clean rm -rf $(EXEC)
Fica assim
@$(CC) -o $@ $^
Variveis internas
$@ Nome da regra. $< Nome da primeira dependncia Ler tudo isso s para compilar um programa??
$^ Lista de dependncias $? Lista de dependncias mais O sub-makele e lanado por meio de um Makele
recentes que a regra. $* Nome do arquivo sem suxo
principal vamos simplicar para o Patro Makele.
Aonde estvamos??...Ah sim, para que serve??
O Makele Principal executa os sub-makesles de outras
As regras de interferncia
pastas.
Como ele faz??
No disse nada antes porque estvamos no estado principiantes noob.
Usamos uma varivel pre-denida $(MAKE).
So regras genricas chamadas por default.
.c.o : .Ela signica fazer um arquivo.o a partir de um
arquivo.c .
#Para
escrever
comentrios
##
Vamos fazer a mesma coisa para clean:" e mrpro#############################
Makele
per:" ento ao executar make clean no console ele
########################## #Denimos a vavai executar o mesmo comando no sub-makele.
rivel CC=gcc CFLAGS=-W -Wall -ansi -pedantic
EXEC=teste OBJ=teste.o main.o all: $(EXEC) @echo
Vou comear a compilao #No coloquei a varivel ########################## O Makele principal
OBJ para que possam entender as variveis internas. ##########################" CC=gcc CFLAGS=#Se entenderam podem colocar $(OBJ) no lugar de W -Wall -ansi -pedantic EXEC=teste SRC= $(wildcard
92
*.c) OBJ= $(SRC:.c=.o) all: $(EXEC) @echo Compilando Projeto @echo O patro foi compilado #A
linha que vai compilar sub-make @cd sub-make &&
$(MAKE) teste: $(OBJ) @$(CC) -o $@ $^ %.o: %.c
@$(CC) -o $@ -c $< $(CFLAGS) main.o: main.c teste.h
@$(CC) -o $@ -c $< $(CFLAGS) .PHONY: clean mrproper clean: @rm -rf *.o *~ # E a mesma coisa que dar
um F4 dentro da pasta sub-make # e escrever make clean
@cd sub-make && $(MAKE) $@ mrproper: clean @rm
-rf $(EXEC) #modicamos aqui tambm @cd sub-make
&& $(MAKE) $@
E no Makele principal em baixo de install:" coloque esta linha @cd sub-make && $(MAKE) $@
Aqui eu modiquei o mrproper porque agora os
binarios que devem ser apagados com make mrproper esto em bin.
Vou deixar voces modicarem o mrproper do
sub-makele como pessoas adultas e responsaveis
;) Valeu galera.
Os comandos no console so:
install: .Coloca o binrio ou executvel em uma determinada pasta, como por exemplo /bin ou /usr/bin
no Linux. Pode ser em qualquer outra, utilizando o
comando mv ou cp para mover ou copiar.
Crie uma pasta bin dentro de Projetos. Devem saber que no devem colocar nada intil que venha da
internet na pasta raiz do linux.
Vamos fazer duas variveis:
prex=/caminho/ate onde/esta/Projetos
bindir=$(prex)/bin .Igual a /caminho
ate/Projetos/dentro de Projetos a pasta bin .
E adicionarmos a regra install:all com seus comandos.
Modicando o make principal.
########################## O Makele principal
##########################" #Coloque o caminho at Projeto aqui prex=/home/USER/Projeto bindir=$(prex)/bin CC=gcc CFLAGS=-W -Wall -ansi pedantic EXEC=teste SRC= $(wildcard *.c) OBJ=
$(SRC:.c=.o) all: $(EXEC) @echo Compilando Projeto @echo O patrao foi compilado #A linha que vai
compilar sub-make @cd sub-make && $(MAKE) teste:
$(OBJ) @$(CC) -o $@ $^ %.o: %.c @$(CC) -o $@ -c
$< $(CFLAGS) main.o: main.c teste.h @$(CC) -o $@
make
make install
make clean
make mrproper .Para apagar os binarios.
Captulo 35
93
Captulo 36
94
Captulo 37
strchr
strrev
signal.h
stdio.h
printf
iso10646.h
scanf
time.h
vsnprintf
math.h
sprintf
tan
vprintf
sin
fprintf
cos
fscanf
atan
feof
asin
ush
acos
calloc
pow
malloc
sqrt
system
abs
gets
fgets
puts
fputs
stdlib.h
atoi
atof
atol
itoa
string.h
strcmp
stricmp
strlen
strstr
strcat
strcpy
strncpy
strncat
95
Captulo 38
96
Captulo 39
Um programador novato tende a ver apenas duas aplicaA impresso que se repetir eternamente aquela dentro
es para o printf:
do lao problemtico.
Um ltimo exemplo de deteco de problemas por meio
do printf. Suponha que a resposta dada por um programa
2. Imprimir o resultado do programa.
no a esperada, que a resposta consiste na impresso
de uma varivel x, a qual recebe diversas atribuies ao
O fato que um programador pode aplicar o printf a m
longo do programa. Podemos identicar o erro dando um
de saber o que ocorre durante a execuo de programa.
printf em x aps cada uma de suas atribuies:
Isto permite, dentre outras coisas, detectar erros.
x=... printf(primeira atribuicao de x eh %tipo, x); ...
Por exemplo, suponha um programa no qual vrias funx=... printf(segunda atribuicao de x eh %tipo, x); ...
es e rotinas so executadas. Algo como:
x=... printf(terceira atribuicao de x eh %tipo, x); ...
int main(int argc, char *argv[]) { ... funcao1(...); printf(A resposta eh %tipo, x);
funcao2(...); funcao3(...); funcao4(...); ... return 0; }
1. Solicitar entrada para o usurio do programa.
98
Captulo 40
40.1 Primitivas
No existe nenhuma normalizao quanto as primitivas 40.3 Iniciar uma lista
usadas para a manipulao de uma lista.
A funo abaixo demonstra como iniciar uma lista criAbaixo voc pode ver uma lista com algumas delas .
ando o espao da raiz na memria.
Colocar o ndice sobre o primeiro elemento da lista.
void criar_Lista(struct No **p_Raiz){ *p_Raiz =
Colocar o ndice sobre o ltimo elemento da lista . NULL; }
Colocar o ndice sobre o elemento que segue o elemento atual .
40.4 Insero
Vericar se a lista est vazia : Se a lista estiver vazia Existem 3 tipos de insero em uma lista, pode-se inserir
no comeo, no nal ou entre dois elementos da lista.
retorna verdadeiro, se no, falso.
Vericar se o primeiro elemento : Retorna verdadeiro se o elemento atual o primeiro, se no, falso. 40.4.1 Insero no incio
Vericar se o ltimo elemento : Retorna verdaint inserir_No_Inicio(struct No **p_Raiz, char
deiro se o elemento atual o ltimo, se no, falso.
*p_String){ struct No *p_Novo; /** Alocao di Vericar o nmero de elementos da lista : Retorna nmica da memoria */ if((p_Novo = (struct No *)
o nmero de elementos da lista.
malloc(sizeof(struct No))) == NULL ){ puts( Falta Me Adicionar um elemento no incio : Adicionar um moria\n); return 1 ; } p_Novo->p_dados = p_String;
p_Novo->p_prox = *p_Raiz; *p_Raiz = p_Novo; }
elemento antes do primeiro elemento da lista .
Adicionar um elemento no m : Adicionar um elemento depois do ltimo elemento da lista .
Insero : Inserir um elemento antes do elemento 40.4.2 Insero no m
atual .
int inserir_No_Fim(struct No **p_Raiz,
char
Troca : Trocar o elemento atual .
*p_String){ struct No *p_Novo; if(( p_Novo = (struct
No *) malloc(sizeof(struct No))) == NULL ){ puts(
Remoo : Remover o elemento atual .
Falta Memoria\n); return 1 ; } p_Novo->p_dados
Listar todos os elementos da lista .
= p_String; p_Novo->p_prox = NULL; if(*p_Raiz ==
99
100
40.5 Remoo
Assim como na insero tambm existem 3 tipos de remoo, no incio, no m ou entre dois elementos da lista.
40.5.1
Remoo no incio
40.5.2
Remoo no m
40.6 Exibio
40.6.1
Do m para a raiz
40.6.2
Da raiz para o m
Captulo 41
Programar em C/Pilha
41.1 Pilha
>tamanho++; }
Pilha ou stack uma lista linear em que todas as inseres e remoes de elemento s podem ser feitos em uma
extremidade chamada topo.As pilhas tambm so chamadas de estruturas LIFO (Last In First Out) ou seja o
ltimo elemento inserido o primeiro removido.
41.3 Inicializao
Captulo 42
102
Captulo 43
Fila
Uma la ou queue em ingls uma estrutura de dados
que usa o mtodo FIFO(acrnimo para First In, First
Out, que em portugus signica primeiro a entrar,
primeiro a sair).
A idia fundamental da la que s podemos inserir um
novo elemento no nal da la e s podemos retirar o
elemento do incio.
Exemplo de la em C:
#include <stdio.h> #include <string.h> #include
<stdlib.h> void q_enter(void); void q_list(void); int
q_store(char *ptr); int q_delete(void); int count = 0;
//contador int store = 0; // proxima posio na la
int retrieve = 0; // recupera a posio da la char
*queue[100]; // vetor da la int main() { int i = 0; for (
i = 0; i < 100; i++ ) { queue[i] = NULL; } q_enter(); //
entra os dados na la printf("\n\nTodos os dados da la
(FIFO):\n); q_list(); q_delete(); // Apaga a primeira entrada da la printf("\n\nA la depois delete(FIFO):\n);
q_list(); printf("\n\nNumero de elementos restantes na
la: %i \n, count); getchar(); // espera return 0; } void
q_enter(void) { static char str[100], *ptr; puts(Pressione
a tecla ENTER sem nome pra sair\n); do { printf(Entre
o nome:"); gets(str); ptr = (char *) malloc(strlen(str));
//alocar um espao na memria strcpy(ptr,str); if (*str) {
count++; q_store(ptr); // Guarda o endereo da seqncia de caracteres } } while (*str); //Sair se no houver
uma entrada } // listar a la void q_list(void) { int k; for
(k = retrieve; k < store; k++) { printf(Elemento %d :
%s \n,k+1,queue[k]); } } // Guarda os itens na la int
q_store(char *ptr) { if (store == 100) { printf("\nA lista
esta cheia!\n); return 0 ; } queue[store] = ptr; store++;
// prximo ndice da la } // Apaga um item da la int
q_delete(void) { if (store == retrieve) { printf("\nA la
esta vazia!"); return 0 ; } count--; retrieve++; }
103
Captulo 44
44.2 Struct
typedef struct No{ int numero; struct No *esquerda;
struct No *direita; }No;
44.3 Iniciar
void criarArvore(No **pRaiz){ *pRaiz = NULL; }
44.4 Insero
void inserir(No **pRaiz, int numero){ if(*pRaiz
== NULL){ *pRaiz = (No *) malloc(sizeof(No));
(*pRaiz)->esquerda = NULL; (*pRaiz)->direita
= NULL; (*pRaiz)->numero = numero; }else{
if(numero < (*pRaiz)->numero) inserir(&(*pRaiz)>esquerda, numero); if(numero > (*pRaiz)->numero)
inserir(&(*pRaiz)->direita, numero); } }
104
44.5.1
Em ordem
44.5.2
Pr-ordem
44.5.3
Ps-ordem
44.6 Contar ns
int contarNos(No *pRaiz){ if(pRaiz == NULL) return 0; else return 1 + contarNos(pRaiz->esquerda) +
contarNos(pRaiz->direita); }
105
Captulo 45
106
Captulo 46
Insertion sort
void insertion_sort(int tabela[], int largura) { int i,
memoria, contador; bool marcador; for(i=1; i<largura;
i++) { memoria = tabela[i]; contador = i-1; do {
marcador = false; if(tabela[contador] > memoria) {
tabela[contador+1] = tabela[contador]; contador--;
marcador = true; } if(contador < 0) marcador = false; }
while(marcador); } tabela[contador+1] = memoria;
107
Captulo 47
Selection sort
void selectionSort( int vetorDesordenado[], int tamanhoVetor ) //Funao selection recebendo vetor e
tamanho { int i, j, posicaoValorMinimo; for (i = 0; i
< ( tamanhoVetor - 1 ); i++) //Loop para percorrer o
vetor { posicaoValorMinimo = i; //O valor minimo de
posiao do vetor a ser percorrido e 0 for (j = ( i + 1 ); j <
tamanhoVetor; j++)//Percorreremos o vetor da posiao
1 ate o tamanho estimado { if( vetorDesordenado[j]
< vetorDesordenado[posicaoValorMinimo] ) //Se a
posiao que vamos vericar for menos que a posiao que
temos em maos { posicaoValorMinimo = j;//A variavel
'j' recebe esse valor } } if ( i != posicaoValorMinimo )
{ trocarPosicaoValores( &vetorDesordenado[i], &vetorDesordenado[posicaoValorMinimo] );//vamos chamar
uma outra funao para trocar as posioes de lugares } } }
void trocarPosicaoValores( int *posicaoA, int *posicaoB
)//Funao para trocar as posioes que estamos olhando {
int temporario; temporario = *posicaoA; *posicaoA =
*posicaoB; *posicaoB = temporario; }
108
Captulo 48
Bubble sort
O bubble sort, ou ordenao por utuao (literalmente
por bolha), um algoritmo de ordenao dos mais simples. A ideia percorrer o vetor diversas vezes, a cada
passagem fazendo utuar para o topo o maior elemento
da sequncia. Essa movimentao lembra a forma como
as bolhas em um tanque de gua procuram seu prprio
nvel, e disso vem o nome do algoritmo.
No melhor caso, o algoritmo executa n2 operaes relevantes, onde n representa o nmero de elementos do
vetor. No pior caso, so feitas n2 operaes. A complexidade desse algoritmo de Ordem quadrtica. Por isso,
ele no recomendado para programas que precisem de
velocidade e operem com quantidade elevada de dados.
48.0.1
Cdigo da Funo
48.0.2
109
Captulo 49
49.2 best t
49.3 worst t
O algoritmo worst t aloca o bloco de memria na regio
que tem o maior espao livre.
Est tcnica por procurar ocupar primeiro as parties
maiores termina por deixar espaos livres que poderiam
ser utilizados para que outros blocos de outros programas
as utilizassem, diminuindo e/ou retardando a fragmentao.
110
Captulo 50
111
112
Texto
113
50.2.2
Imagens
114
50.2.3
Licena