Вы находитесь на странице: 1из 125

Programar em C

Contedo
1

Programar em C/Capa

Programar em C/Por que aprender a linguagem C

Programar em C/Histria da linguagem C

3.1

Histria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3.1.1

Desenvolvimentos iniciais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3.1.2

C de K&R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3.1.3

Os Padres C ANSI e C ISO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Programar em C/Utilizando um compilador

5.1

Compiladores: viso geral

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5.2

gcc

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5.3

Visual C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Programar em C/Noes de compilao

10

6.1

Compilao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

6.2

Etapas da compilao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

Programar em C/Um programa em C

11

7.1

Um programa em C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

7.2

Compilando o programa

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

7.2.1
8

Programar em C/Conceitos bsicos

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

10 Programar em C/Tipos de dados

17

10.0.1 Explicando bits e bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17

10.0.2 Nmeros inteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17

10.0.3 Nmeros de ponto utuante

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

19

10.0.4 Bool

10.0.5 Endereos

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

19

10.0.6 Compatibilidade de dados na atribuio de valor . . . . . . . . . . . . . . . . . . . . . . .

19

10.0.7 Converter um tipo de varivel

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

20

10.0.8 Literais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

20

11 Programar em C/Constantes
11.1 Constantes

21

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

21

11.2 DEFINED CONSTANTS (#DEFINE) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

21

11.3 Declared constants (const)

21

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

12 Programar em C/Entrada e sada simples

23

12.1 Entrada e sada simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

23

12.2 puts() e putchar() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

23

12.3 printf()

24

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

12.3.1 Especicaes de formato

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

24

12.3.2 Sequncias de escape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

26

12.4 scanf()

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

12.4.1 Valor de retorno


12.5 gets() e getchar()

26

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

27

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

27

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

27

12.6 sprintf() e sscanf()

13 Programar em C/Operaes matemticas (Bsico)


13.1 Operaes matemticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13.1.1 Abreviaes

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14 Programar em C/Operaes matemticas (Avanado)


14.1 Funes Trigonomtricas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29
29
29
31
31

CONTEDO

iii

14.1.1 As funes acos e asin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31

14.1.2 As funes atan e atan2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31

14.1.3 As funes cos, sin e tan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31

14.2 Funes Hiperblicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31

14.3 Funes Exponencial e Logaritmo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

14.3.1 A funo exp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

14.3.2 As funes frexp, ldexp e modf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

14.3.3 As funes log e log10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

14.4 Funes pow e sqrt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

14.4.1 As funes pow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

14.4.2 As funes sqrt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

14.5 Funes de Arredondamento para Nmeros Inteiros, Valores Absolutos e Resto da Diviso . . . . .

32

14.5.1 As funes ceil e oor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

14.5.2 As funes fabs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

14.5.3 As funes fmod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

14.6 Ligaes externas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

33

15 Programar em C/Operadores

34

15.1 Operadores Aritmticos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34

15.2 Precedncia de Operadores aritmticos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34

15.3 type casting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34

15.4 Expoentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34

15.5 Operadores relacionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34

15.6 Precedncia dos operadores relacionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

35

15.7 Operadores lgicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

35

15.8 Precedncia Operadores lgicos e Relacionais . . . . . . . . . . . . . . . . . . . . . . . . . . . .

35

15.9 Operadores Lgicos Bit a Bit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

35

15.9.1 Deslocamento de bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

35

15.10Todos os Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

35

15.11Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

35

16 Programar em C/Controle de uxo

37

16.1 Controle de uxo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

37

16.2 Expresses de condio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

37

16.3 Testes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38

16.3.1 if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38

16.3.2 switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38

16.3.3 Operador ternrio "?:"

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39

16.4 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39

16.4.1 while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39

16.4.2 do ... while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39

16.4.3 for

39

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

iv

CONTEDO
16.4.4 break e continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

16.5 Saltos incondicionais: goto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

16.6 Terminando o programa

41

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17 Programar em C/Funes

42

17.1 O que funo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

42

17.2 Denindo uma funo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

42

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

43

17.2.2 Parmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

43

17.2.3 Chamadas de funes

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

43

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

43

17.4 Prottipo ou Declarao de funo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

44

17.5 Variveis locais versus globais

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

44

17.6 Passagem de parmetros por valor e por referncia . . . . . . . . . . . . . . . . . . . . . . . . . .

45

17.7 void . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

45

17.8 Recursividade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

45

17.9 inline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

46

17.2.1 Valor de retorno

17.3 Dois exemplos

18 Programar em C/Pr-processador
18.1 O pr-processador

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18.2 Diretivas de compilao

47
47

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

47

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

47

18.2.2 #dene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

47

18.2.3 #undef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

48

18.2.4 #ifdef e #ifndef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

48

18.2.5 #if

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

48

18.2.6 #else

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

48

18.2.7 #elif

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

48

18.2.1 #include

18.3 Usos comuns das diretivas

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

48

18.4 Concatenao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

48

19 Programar em C/Exerccios
19.1 Questes

49

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

19.2 Escrevendo programas

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

20.1.1 Abreviando as declaraes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

52

20.1.2 Exemplo de Aplicao de Vetores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

52

20.2 Vetores multidimensionais (matrizes) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

52

20.3 Argumentos na funo main

53

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

20.3.1 Exemplo de uso de parmetros na funo main

. . . . . . . . . . . . . . . . . . . . . . .

21 Programar em C/Strings
21.1 Strings

53
54

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

54

21.2 Funes da biblioteca padro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

22 Programar em C/Passagem de parmetros

57

22.1 Passagem de Parmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


23 Programar em C/Tipos de dados denidos pelo usurio
23.1 Tipos de dados denidos pelo usurio

57
58

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

58

23.2 Estruturas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

58

23.2.1 Denindo o tipo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

58

23.2.2 Declarando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

58

23.2.3 Inicializador designado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59

23.2.4 Acessando

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59

23.2.5 Vetores de estruturas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59

23.2.6 Atribuio e cpia

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59

23.2.7 Passando para funes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59

23.3 Unies

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59

23.4 Enumeraes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59

23.4.1 Uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

60

23.5 Campo de bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

60

24 Programar em C/Enumerao

61

vi

CONTEDO
24.1 Enumerations (enum) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

61

24.2 Criando um novo tipo de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

61

25 Programar em C/Unio
25.1 Unions

62

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

25.2 Declarao

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

25.3 Unions com estruturas

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

25.4 Anonymous unions estruturas com unions

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

26 Programar em C/Estruturas

62
62
62
62
63

26.1 Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

63

26.2 Declarar uma estrutura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

63

26.3 Matrizes de estruturas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

63

26.4 Declarar instncias (objetos) da estrutura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

63

26.5 Acessar as variveis membro das estruturas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

64

26.6 Iniciar uma estrutura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

64

26.7 Ponteiros para estruturas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

64

26.8 Passando estruturas como argumento de funes . . . . . . . . . . . . . . . . . . . . . . . . . . .

64

26.9 Estruturas aninhadas

64

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

27 Programar em C/Ponteiros

66

27.1 Bsico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27.1.1 O que um ponteiro?

66

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

66

27.1.2 Declarando e acessando ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

66

27.1.3 Ponteiro e NULL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

67

27.1.4 Mais operaes com ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

67

27.2 Intermedirio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

68

27.2.1 Ponteiro de estrutura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

68

27.2.2 Ponteiros como parmetros de funes . . . . . . . . . . . . . . . . . . . . . . . . . . . .

68

27.2.3 Ponteiros e vetores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

69

27.2.4 Indexao estranha de ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

69

27.2.5 Comparando endereos

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

69

27.3 Avanado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

69

27.3.1 Ponteiros para ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

69

27.3.2 Passando vetores como argumentos de funes

. . . . . . . . . . . . . . . . . . . . . . .

70

27.3.3 Ponteiros para funes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

70

28 Programar em C/Mais sobre variveis

72

28.1 typedef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

72

28.2 sizeof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

72

28.3 Converso de tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

73

28.3.1 Casting: converso manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

73

28.4 Atributos das variveis

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

29 Programar em C/Mais sobre funes


29.1 Os argumentos argc e argv

76

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

76

29.2 Lista de argumentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

76

30 Programar em C/Bibliotecas
30.1 Bibliotecas

78

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

30.2 O arquivo-cabealho

78

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

78

30.3 Compilao da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

79

30.3.1 No GCC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

79

30.3.2 No MS Visual C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

79

30.4 Compilao do programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

79

31 Programar em C/Entrada e sada em arquivos


31.1 Trabalhando com arquivos

80

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

80

31.2 Abrindo e fechando um arquivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

80

31.2.1 Exemplo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

81

31.2.2 Arquivos pr-denidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

81

31.3 Escrevendo em arquivos

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

81

31.3.1 fwrite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

81

31.3.2 fputc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

82

31.4 Lendo de arquivos

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

31.5 Movendo pelo arquivo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

83

31.5.1 fseek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

83

31.5.2 rewind

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

83

31.5.3 feof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

83

31.6 Outras funes

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31.6.1 ferror e perror

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32 Programar em C/Gerenciamento de memria

83
83
85

32.1 Alocao dinmica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

85

32.1.1 malloc e free . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

85

32.1.2 calloc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

85

viii

CONTEDO
32.1.3 realloc

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

86

32.1.4 Alocao Dinmica de Vetores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

86

32.1.5 Alocao Dinmica de Matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

86

33 Programar em C/Sockets

88

33.1 Abstraes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

88

33.2 Funes da biblioteca padro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

88

33.3 Famlias de endereo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

88

33.4 Estruturas de endereo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

88

34 Programar em C/Makeles

89

34.1 Makele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

89

34.1.1 Sintaxe de criao do arquivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

90

35 Programar em C/Lista de palavras reservadas

93

36 Programar em C/Seqncias de escape

94

37 Programar em C/Lista de funes

95

38 Programar em C/Lista de bibliotecas

96

38.1 Ligaes externas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


39 Programar em C/Dicas de programao em C

96
97

39.1 Convenes tipogrcas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

97

39.2 A funo printf a melhor amiga de um programador . . . . . . . . . . . . . . . . . . . . . . . .

97

39.3 Tecle 1 para rodar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

98

40 Programar em C/Listas encadeadas

99

40.1 Primitivas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

99

40.2 Lista encadeada linear . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

99

40.3 Iniciar uma lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

99

40.4 Insero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

99

40.4.1 Insero no incio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

99

40.4.2 Insero no m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

99

40.5 Remoo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100


40.5.1 Remoo no incio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
40.5.2 Remoo no m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
40.6 Exibio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
40.6.1 Do m para a raiz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
40.6.2 Da raiz para o m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
41 Programar em C/Pilha

101

41.1 Pilha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101


41.2 Construo do prottipo de um elemento da lista. . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

CONTEDO

ix

41.3 Inicializao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101


41.4 Inserir um elemento na pilha(push) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
41.5 Retirar um elemento da pilha (pop) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
41.6 Imprimir os elementos da pilha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
42 Programar em C/Fila ou Queue

102

43 Fila

103

44 Programar em C/rvores binrias

104

44.1 Arvore binria

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

44.2 Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104


44.3 Iniciar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
44.4 Insero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
44.5 Remoo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
44.5.1 Em ordem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
44.5.2 Pr-ordem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
44.5.3 Ps-ordem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
44.6 Contar ns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
44.7 Contar folhas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
44.8 Altura da rvore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
44.9 Estrutura Completa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
45 Programar em C/Algoritmos de ordenao

106

46 Insertion sort

107

47 Selection sort

108

48 Bubble sort

109

48.0.1 Cdigo da Funo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

48.0.2 Cdigo da Funo Melhorado


49 Programar em C/Algoritmo de alocao

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
110

49.1 rst st . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110


49.2 best t . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
49.3 worst t . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
49.4 Next Fit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
49.5 Buddy System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
50 Programar em C/Lista de autores

111

50.1 Lista de autores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111


50.2 Fontes, contribuidores e licenas de texto e imagem . . . . . . . . . . . . . . . . . . . . . . . . . 112
50.2.1 Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
50.2.2 Imagens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113

CONTEDO
50.2.3 Licena . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

Captulo 1

Programar em C/Capa

Programar em C

ndice>> Ir para o ndice >>

Captulo 2

Programar em C/Por que aprender a


linguagem C
Em uma era onde o software est cada vez mais presente
no nosso dia a dia importante ter algumas bases de programao, e para tanto importante ter um bom material
com explicaes claras e exemplos; e o livro Programar
em C se presta bem ao exerccio.

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

Programar em C/Histria da linguagem C


3.1 Histria
3.1.1

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

Tipos de dados struct


Tipos de dados long int
Tipos de dados unsigned int
O operador =+ foi alterado para +=, e assim sucessivamente (a anlise lxica do compilador confundia
o operador =+. Por exemplo, i =+ 10 e i = +10).
C de K&R frequentemente considerado a parte mais bsica da linguagem cujo suporte deve ser assegurado por
um compilador C. Durante muitos anos, mesmo aps a
introduo do padro C ANSI, ele era considerado o menor denominador comum em que programadores de C
se apoiavam quando uma portabilidade mxima era desejada, j que nem todos os compiladores eram atualizados
para suportar na ntegra o padro C ANSI, e o cdigo C
de K&R razoavelmente bem escrito tambm vlido em
relao ao C ANSI.

Kenneth Thompson ( esquerda) e Dennis Ritchie ( direita), os


criadores da linguagem C

O desenvolvimento inicial da linguagem C ocorreu nos


laboratrios Bell da AT&T entre 1969 e 1973. Segundo
Ritchie, o perodo mais criativo ocorreu em 1972. Deuse o nome C linguagem porque muitas das suas caractersticas derivaram de uma linguagem de programao anterior chamada "B". H vrios relatos que se referem origem do nome B": Ken Thompson d crdito
linguagem de programao BCPL, mas ele tambm criou Nos anos que se seguiram publicao do C K&R, aluma outra linguagem de programao chamada 'Bon, em gumas caractersticas no-ociais foram adicionadas
honra da sua mulher Bonnie.
linguagem, suportadas por compiladores da AT&T e de
Por volta de 1973, a linguagem C tinha se tornado su- outros vendedores. Estas incluam:
cientemente poderosa para que grande parte do ncleo
Funes void e tipos de dados void *
de UNIX, originalmente escrito na linguagem de programao PDP-11/20 Assembly, fosse reescrito em C,
Funes que retornam tipos struct ou union
tornando-se um dos primeiros ncleos de sistema opera Campos de nome struct num espao de nome sepacional implementado em uma linguagem sem ser o Asrado para cada tipo struct
sembly. Como exemplos anteriores pode-se citar o sistema Multics (escrito em PL/I) e TRIPOS (escrito em
Atribuio a tipos de dados struct
BCPL).
Qualicadores const para criar um objeto s de leitura

3.1.2

C de K&R

Uma biblioteca-padro que incorpora grande parte


da funcionalidade implementada por vrios vendedores

Em 1978, Ritchie e Kernighan publicaram a primeira edio do livro The C Programming Language. Esse livro,
3

CAPTULO 3. PROGRAMAR EM C/HISTRIA DA LINGUAGEM C


Enumeraes
O tipo de ponto-utuante de preciso simples

3.1.3

Os Padres C ANSI e C ISO

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.

Adio de vrios tipos de dados novos, incluindo o


long long int (para minimizar a dor da transio de
32-bits para 64-bits), um tipo de dados boolean explicito e um tipo complex que representa nmeros
complexos
Disposies de dados de comprimento varivel
Suporte ocial para comentrios de uma linha iniciados por //, emprestados da linguagem C++
Vrias funes de biblioteca novas, tais como snprintf()
Vrios arquivos-cabealho novos, tais como stdint.h

O interesse em suportar as caractersticas novas de C99


parece depender muito das entidades. Apesar do GCC e
vrios outros compiladores suportarem grande parte das
novas caractersticas do C99, os compiladores mantidos
pela Microsoft e pela Borland no, e estas duas compaEm 1983, o Instituto Norte-Americano de Padres nhias no parecem estar muito interessadas adicionar tais
(ANSI) formou um comit, X3j11, para estabelecer uma funcionalidades, ignorando por completo as normas inespecicao do padro da linguagem C. Aps um pro- ternacionais.
cesso longo e rduo, o padro foi completo em 1989 e
raticado como ANSI X3.159-1989 Programming Language C. Esta verso da linguagem frequentemente re- 3.1.5 Resumo em ingls
ferida como C ANSI. Em 1990, o padro C ANSI, aps
sofrer umas modicaes menores, foi adotado pela Or- Em 1947, trs cientistas do Laboratrio Telefonia Bell,
ganizao Internacional de Padres (ISO) como ISO/IEC William Shockley, Walter Brattain, e John Bardeen cria9899:1990. Um dos objetivos do processo de padroni- ram o transistor. A computao moderna teve incio. Em
zao C ANSI foi o de produzir um sobreconjunto do 1956 no MIT o primeiro computador completamente baC K&R, incorporando muitas das caractersticas no- seado em transistores foi concludo, the TX-0. Em 1958
ociais subsequentemente introduzidas. Entretanto, mui- na Texas Instruments, Jack Kilby construiu o primeiro
tos programas tinham sido escritos e que no compilavam circuito integrado. Mas mesmo antes do primeiro cirem certas plataformas, ou com um certo compilador, de- cuito integrado existir, a primeira linguagem de alto nvel
vido ao uso de bibliotecas de funes no-padro e ao j tinha sido escrita.
fato de alguns compiladores no aderirem ao C ANSI.
Em 1954 Fortran, a Formula Translator, foi escrito. Comeou como Fortran I em 1956. Fortran veio a ser Algol
58, o Algorithmic Language, em 1958. Algol 58 tornou3.1.4 C99
se Algol 60 em 1960. Algol 60 gerou CPL, o CombiAps o processo ANSI de padronizao, as especica- ned Programming Language, em 1963. CPL passou a
es da linguagem C permaneceram relativamente est- ser BCPL, Basic CPL, em 1967. BCPL engendrou B em
ticas por algum tempo, enquanto que a linguagem C++ 1969. E de B surgiu C em 1971.
continuou a evoluir. (Em 1995, a Normative Ammend- B foi a primeira lngua da linhagem C diretamente, tendo
ment 1 criou uma verso nova da linguagem C mas esta sido criado no Bell Labs por Ken Thompson. B era
verso raramente tida em conta.) Contudo, o padro foi uma linguagem interpretada, utilizada no incio, em versubmetido a uma reviso nos nais da dcada de 1990, le- ses internas do sistema operacional UNIX. Thompson
vando publicao da norma ISO 9899:1999 em 1999. e Dennis Ritchie, tambm da Bell Labs, melhorou B,
Este padro geralmente referido como C99. O pa- chamando-NB; novas prorrogaes para NB criaram C,
dro foi adotado como um padro ANSI em Maro de uma linguagem compilada. A maioria dos UNIX foi re2000.
escrito em NB e C, o que levou a um sistema operacional
mais porttil.
As novas caractersticas do C99 incluem:
Funes em linha

B foi, naturalmente, o nome de BCPL e C foi o seu sucessor lgico.

Levantamento de restries sobre a localizao da


declarao de variveis (como em C++)

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.4 Obtendo um compilador

4.1 Editor

Existem diversos compiladores disponveis:

Para editar o cdigo de um programa, apenas necessrio Para Windows ou DOS


um editor de textos, qualquer um, at mesmo o Bloco de
Notas do Windows.
MinGW (antigo mingw32): uma espcie de gcc
para Windows. o compilador includo com o DevNo entanto, h diversos editores que apresentam recurC++, da Bloodshed. O Dev-C++ um IDE (sigla
sos que facilitam a edio de programas, como: desem ingls para Ambiente Integrado de Desenvolvitaque/colorao de sintaxe, complementao de cdigo,
mento) que facilita a edio e compilao de proformatao (indentao) automtica, ajuda integrada, cogramas. Tem traduo para Portugus do Brasil.
mandos integrados para compilar etc. Entre todos eles
podemos destacar o Vim e o Emacs, ambos com verses
para Windows, Linux e Mac OS.

Borland C++: a Borland disponibilizou um compilador gratuito que funciona em linha de comando,
como alternativa ao IDE comercial.

Em sistemas GNU/Linux, a maioria dos editores de texto


j possui recursos para facilitar a edio de programas em
C. Principalmente, devido ao fato da maioria destes e boa
parte do sistema terem sido programadas utilizando C ou
C++.

DJGPP: porte do gcc para DOS. Tambm funciona


no Windows, mas se o objetivo for rodar no Windows, recomenda-se o uso do mingw, que pode usufruir de todos os recursos do Windows.

Entretanto, o editor apenas edita o cdigo. Para


transforma-lo em linguagem de mquina e o executar,
precisaremos de um compilador.

Microsoft Visual C++: compilador comercial da


Microsoft, que tambm tem um IDE. O Framework
.NET, gratuito, tambm inclui o compilador (em linha de comando) do Visual C++.

4.2 Compilador

Bloodshed DEV-C++: ambiente de desenvolvimento integrado livre que utiliza os compiladores


do projeto GNU para compilar programas para o
sistema operacional Microsoft Windows.

O cdigo em linguagem C consiste em instrues que o


computador dever seguir. O compilador realiza o trabalho de traduzir essas instrues para linguagem de mquina, de forma a poderem ser executadas pelo computador.

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.

4.3 Ligador ou linker


A ligao de arquivos consiste na construo de uma imagem memria que contm partes de cdigo compilados
6

4.5. LINKS EXTERNOS


GNU linker: o ligador do projeto GNU o nome do
programa ld e faz parte do pacote GNU Binary
Utilities.

4.5 Links externos


CodeBlocks: pgina para download do CodeBlocks,
uma IDE para C ao estilo do Dev-C++, porm, mais
nova.
Dev-C++: pgina para download do Dev-C++.
DJGPP: pgina ocial, com informaes e links
para download.
GCC: pgina ocial do compilador para diversas
plataformas.

Captulo 5

Programar em C/Utilizando um
compilador
5.1 Compiladores: viso geral

gcc [OPES] nome_do_arquivo


Aqui so listadas algumas das opes do gcc:

Um compilador , geralmente, um programa de modo


texto, que deve ser operado diretamente da linha de comando, sem nenhuma interface grca. Essa uma das
razes pelas quais muitas pessoas preferem usar IDEs.
No entanto, saber um pouco sobre como usar o compilador pela linha de comando pode vir a ser til, por exemplo
quando voc no tiver um IDE disposio. No nenhum bicho-de-sete-cabeas, e a sintaxe da maioria dos
compiladores semelhante.

-c: Compila o cdigo fonte mas no faz as ligaes.


A sada um arquivo objeto.
-o: serve para dar um nome ao arquivo de sada.
-O2: ativa otimizao no nvel 2
-g: salva os smbolos de depurao (o que permite
usar um depurador)

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.

-Wall: ativa todos os avisos do compilador


-pedantic: ativa os avisos necessrios para que o
cdigo esteja estritamente de acordo com os padres

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

gcc [OPES] -o programa[.bin] programa.c

Com o gcc, compilador da GNU utilizado principalmente


no sistema operacional linux ou de tipo unix, voc pode
executar a compilao e a montagem separadamente ou
com um nico comando. Se voc tem vrios arquivosfonte, mais recomendvel executar as duas etapas separadamente: se voc atualizar apenas um arquivo, s precisar recompilar o que atualizou e depois remontar. No
entanto, se voc est desenvolvendo um projeto grande,
recomendvel usar ferramentas de automao do processo de compilao, como o make.

5.3 Visual C++


Em alguma verso no especicada do Visual C++, para
compilar o arquivo programa.c, gerando o cdigoobjeto programa.obj":
cl /c programa.c
Para gerar o executvel programa.exe a partir do
cdigo-objeto:

Resumo:

link /out:programa.exe programa.obj


8

5.3. VISUAL C++


Para gerar o executvel a partir do arquivo-fonte:
cl programa.c

Captulo 6

Programar em C/Noes de compilao


6.1 Compilao
Todo o cdigo em linguagem C que escrevermos deve
ser salvo em um arquivo, em formato texto, com a extenso ".c. Esse cdigo no tem signicado nenhum para a
unidade de processamento; para que o processador possa
executar nosso programa, este deve ser traduzido para a
linguagem de mquina. Essa traduo se chama compilao e feita pelo programa denominado compilador.
O compilador l todo o cdigo e cria um arquivo executvel, em linguagem de mquina, especca para uma
arquitetura de processadores e para um tipo de sistema
operacional, o que signica que um programa compilado
no Windows, por exemplo, no rodar nativamente no Linux se simplesmente copiarmos o executvel. Devemos,
para isso, recompilar o cdigo-fonte do programa.
No Windows, os arquivos executveis so aqueles com
extenso ".exe. No Linux, os executveis so simplesmente arquivos com o atributo executvel.

6.2 Etapas da compilao


O processo que chamamos corriqueiramente de compilao na verdade um conjunto de etapas:
o preprocessamento, etapa em que o prprocessador (programa s vezes acoplado ao
compilador) l o cdigo-fonte e faz algumas
substituies para que o programa possa ser compilado. Em C, o preprocessador tem diversos usos:
compilao condicional (por exemplo, usar trechos
diferentes do cdigo para sistemas operacionais
diferentes), macros, substituio de smbolos e
incluso de arquivos externos que declaram funes
e variveis.
a vericao sinttica, que procura por eventuais
erros nos cdigos dos programas: parnteses no
fechados, falta de ponto-e-vrgula no nal da instruo, etc. Todos esses problemas so alertados e
causam a interrupo da compilao.
10

a compilao propriamente dita, que transforma o


cdigo preprocessado em um programa-objeto, que
est em linguagem de mquina porm no pronto
para ser executado.
a linkedio (linking, em ingls) dos programasobjeto e bibliotecas necessrias em um nico executvel, feita pelo linkeditor (linker). Em C, pode-se
distribuir um programa em vrios arquivos-fonte, o
que ajuda na organizao e permite compilar apenas
a parte do programa correspondente quando necessrio realizar alguma mudana. Na montagem,
todas as partes constituintes do programa so deslocadas e/ou cortadas conforme necessrio para que
tenhamos um programa executvel.

Captulo 7

Programar em C/Um programa em C


7.1 Um programa em C

modo que voc precisar dele em praticamente todos os


programas ele o meio de quase toda comunicao
[1]
comum que o primeiro programa escrito em uma lin- com o teclado, com a tela e com arquivos.
guagem de programao seja um programa que escreve Os programas em C so organizados em funes todo
Hello world!" (Ol mundo!"). Apresentamos o cdigo cdigo em C deve fazer parte de uma funo. Em particue, a seguir, analisaremos cada uma de suas linhas. No lar, todo programa deve ter uma funo chamada main,
se preocupe se no entender ainda alguns aspectos, tudo pela qual ser iniciada a execuo do programa. A funser abordado detalhadamente mais adiante.
o denida, no nosso exemplo, na linha 3, e delimitada
Note que o nmero das linhas dado apenas para facilitar pelas chaves { }.
a referncia; se for copiar o cdigo, lembre-se de tirar os A palavra-chave int signica que a funo devolve um
nmeros de linha.
valor inteiro (voc pode pensar nesse valor exatamente
1. /* o meu primeiro programa */ 2. #include <stdio.h> como o valor de uma funo em matemtica).
3. int main() 4. { 5. printf (Ol, mundo!"); 6. return Na linha 5, executamos a funo printf, que imprime
(0); 7. }
na tela os parmetros que lhe foram passados no
nosso exemplo, passamos a seqncia de caracteres Ol,
O texto do programa tambm conhecido como cdigo mundo!" como parmetro. Essa uma das funes dedo programa ou simplesmente cdigo fonte. O cdigo nidas em um cabealho da biblioteca C, o arquivo stdio.h.
fonte o programa escrito na linguagem de programa- Note o ponto-e-vrgula no nal da linha: todas as inso. Em nosso caso acima, chamamos cdigo C ou sim- trues em C devem terminar com um ponto-e-vrgula.
plesmente cdigo.
(Essa uma causa muito comum de erros de compilao).
Voc deve copiar o cdigo acima em um editor de
texto como notepad e salv-lo como ola.c (sem acento).
Lembre-se de remover os nmeros das linhas. Caso contrrio o cdigo no ir compilar. Esse arquivo agora representa o cdigo fonte do programa escrito em C.
Salvando o cdigo acima em um arquivo com a extenso
".c e seguindo as instrues de compilao do do captulo de utilizao de compilador, voc dever ver como
resultado um Ol, mundo!" na tela. A seguir vamos a
anlise do cdigo.
A primeira linha um comentrio, que para o compilador no tem nenhum signicado. Qualquer texto que esteja entre as marcaes /* e */, podendo inclusive ocupar
vrias linhas, ser considerado como comentrio e ser
completamente ignorado pelo compilador. muito til
como documentao, explicando o que as prximas linhas de cdigo fazem.

Na linha 6, dizemos que a funo main deve devolver (ou


retornar) o valor 0 e terminar sua execuo. (Esse o
valor inteiro que dissemos que amos retornar na linha
3.)
O padro da linguagem C diz que a funo main deve devolver um valor inteiro, e esse valor diz se o programa foi
executado com sucesso ou no. O valor zero indica que o
programa foi nalizado sem nenhum erro, e valores diferentes de zero podem indicar diferentes erros. Voc no
precisar se preocupar com isso no incio do seu estudo
em C o valor devolvido por um programa geralmente
usado em scripts, quando (por exemplo) um comando s
pode ser executado se o anterior tiver ocorrido com sucesso.

7.2 Compilando o programa

A linha 2 pede que seja inserido o contedo do arquivo


stdio.h (que est num lugar j conhecido pelo compila- 7.2.1 Linux
dor). Esse arquivo contm referncias a diversas funes
de entrada e sada de dados (stdio abreviao de Stan- A maioria das distribuies linux j possuem compiladard Input/Output, ou Entrada e Sada Padronizadas), de dor C na instalao padro. Para compilar o programa
11

12

CAPTULO 7. PROGRAMAR EM C/UM PROGRAMA EM C

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

Programar em C/Conceitos bsicos


Voc j viu um programa bsico em C. Antes de comear
a se dedicar ao estudo de C, bom que voc compreenda
alguns termos e alguns aspectos da linguagem, o que facilitar sua compreenso dos captulos seguintes. A seguir, formalizaremos alguns aspectos da estrutura bsica
da linguagem.

8.1 Estrutura bsica

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:

Um programa em C basicamente estruturado em int a; { int a; int b; } { int b; }


blocos de cdigo. Blocos nada mais so que conjuntos de instrues, e devem ser delimitados com
As duas variveis chamadas b so diferentes e s podem
chaves ({ ... }). Um bloco tambm pode conter ouser acessadas dentro do prprio bloco. A primeira varitros blocos.
vel a global, mas s pode ser acessada no segundo bloco,
Uma instruo geralmente corresponde a uma ao pois a varivel local a no primeiro bloco oculta a varivel
executada, e deve sempre terminar com ponto-e- global de mesmo nome. Note que isso possvel em C, e
tome cuidado para no cometer erros por causa disso.
vrgula (;).
O compilador ignora espaos, tabulaes e quebras
de linha no meio do cdigo; esses caracteres so chamados genericamente de espao em branco (whi- 8.2 Introduo s funes
tespace). Ou seja, os trs trechos a seguir so equivalentes:
Funes so muito usadas, no s em C, mas em linguagens de programao em geral. Uma funo basiprintf(Ol mundo);return 0;
camente um bloco de cdigo que realiza uma certa taprintf (Ol mundo); return 0;
refa. Quando queremos realizar aquela tarefa, simplesprintf( Ol mundo ); return 0 ;
mente fazemos uma chamada de funo para a funo
correspondente.
No entanto, voc achar muito mais fcil de ler um es- Uma funo pode precisar que o programador d certos
tilo de cdigo mais parecido com o segundo exemplo. dados para realizar a tarefa; esses dados so chamados
Costuma-se usar (mas no abusar de) espaos e tabula- argumentos. A funo tambm pode retornar um valor,
es para organizar o cdigo.
que pode indicar se a tarefa foi realizada com sucesso, por
exemplo; esse valor o valor de retorno. Podemos fazer
A linguagem sensvel utilizao de maisculas e uma analogia com as funes matemticas: as variveis
minsculas. Por exemplo, se voc escrevesse Printf independentes so os argumentos e o valor numrico da
no lugar de printf, ocorreria um erro, pois o nome funo o valor de retorno.
da funo totalmente em minsculas.
Em C, para chamar uma funo, devemos escrever o seu
nome, seguido da lista de argumentos (separados por vrgula) entre parnteses, mesmo que no haja nenhum argu8.1.1 Escopo
mento. Lembre que a chamada de funo tambm uma
Geralmente, em programao, no queremos que outras instruo, portanto devemos escrever o ponto-e-vrgula
funes usem as variveis que estamos manipulando no no nal. Alguns exemplos de chamadas de funes:
13

14

CAPTULO 8. PROGRAMAR EM C/CONCEITOS BSICOS

funcao(arg1, arg2, arg3); funcao();

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.

Se quisermos associar um valor a uma varivel, usamos o


operador = (igual):
a = 5;
Nesse caso, estamos pedindo que o computador guarde o
valor 5 no espao alocado varivel a.
Observao: Apesar de este operador se assemelhar ao
igual da matemtica, sua funo diferente. Para vericar a igualdade de dois valores, usamos o operador de
comparao "==" (dois iguais).
possvel tambm atribuir um valor a uma varivel ao
mesmo tempo que ela declarada, o que chamado de
inicializar a varivel. Por exemplo:
int a = 5;
possvel tambm declarar mais de uma varivel de um
mesmo tipo em uma nica instruo, separando os nomes
por vrgulas. Tambm possvel inicializar as variveis
dessa maneira:
int a, b, c, d; int e = 5, f = 6; int g, h = 2, i = 7, j;
Como o prprio nome j diz, o valor existente numa varivel pode ser mudado, da mesma maneira que ele normalmente atribudo. Se tivermos:

9.2 Declarando variveis

int a; a = 2; a = 3;
no nal o valor da varivel a ser 3.

Genericamente, para declarar uma varivel, usamos a seguinte instruo:


tipo_da_varivel nome_da_varivel;

9.4 Exemplo de erro

Por exemplo, para declarar uma varivel do tipo int com


o nome a, podemos escrever
a = 25;
int a;

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.

9.5 Nomes de variveis


Existem algumas restries quanto ao nome que podemos
dar a variveis. Essas regras se aplicam tambm para nomear funes e estruturas.
Os nomes de variveis devem ser nicos no mesmo
escopo: no podemos ter duas variveis com o
mesmo nome.
O nome pode ser igual ao de outra varivel j existente em escopo superior, porm recomendado
fortemente que no se use variveis iguais sob pena
de tornar o cdigo do programa incompreensvel ou
de difcil anlise;
O C, assim como muitas outras linguagens de programao, sensvel utilizao de maisculas e
minsculas(case sensitive). Portanto, o cdigo a seguir seria vlido e geraria trs variveis diferentes:
int nome; int NOME; int Nome;
Em nomes de variveis, podemos usar letras maisculas ou minsculas (de A a Z, sem acentos), algarismos arbicos (0-9) e o caractere sublinhado (_),
mas o primeiro caractere deve ser uma letra ou o
sublinhado.
Algumas palavras no podem ser usadas para nomes
de variveis por serem palavras reservadas (palavras
que tm signicado especial na linguagem).
O padro C atual especica que nomes de at 31
caracteres devem ser aceitos. Alguns compiladores
podem at aceitar nomes maiores que isso, mas no
considere isso uma regra e no use nomes to longos.

CAPTULO 9. PROGRAMAR EM C/VARIVEIS

Captulo 10

Programar em C/Tipos de dados


00000111 8 Combinao

'

At agora voc s viu as variveis do tipo int, que servem



para guardar nmeros inteiros. A linguagem C tem outros
tipos fundamentais. So eles:
E na verdade podemos estender este conceito para um
nmero innito de combinaes.
int, para nmeros inteiros entre 2147483648 e Ora o que aconteceu que nos bastavam pouco menos
2147483647, utiliza 4 bytes;
de 256 combinaes (8 bits ordenados) para termos uma
char, para caracteres individuais do padro ASCII, combinao para cada letra, maiscula e minscula, nmero, pontos de exclamao, interrogao, etc. e isso
utiliza 1 byte;
era o suciente para a nossa comunicao. Mas para ha oat, para reais entre (aproximadamente) 1038 e ver um certo consenso para que uma dada combinao
1038 , utiliza 4 bytes, preciso de 7 dgitos;
desse um dado smbolo surgiu a tabela ASCII (surgiram
outras tabelas quando se quis colocar os smbolos de ou double, para reais entre (aproximadamente) 104932 tras lnguas, como o japons ou o chins ver tabela ISO)
e 104932 , utiliza 8 bytes, preciso de 15 dgitos;
Portanto com 8 bits ou 8 casas conseguamos ter qualquer
bool, para indicar true (verdadeiro) ou false (falso), smbolo que utilizamos. A esse conjunto de 8 bits chautiliza 1 byte; Presente apenas no padro C99 em mamos de byte, mais convenientemente. Portanto, um
byte tem 8 casas de zeros /uns , ou seja 2 elevado a 8 d
diante.
as 256 combinaes. E o byte a unidade bsica que o
C++ consegue operar e representado pelo tipo char.

10.0.1

Explicando bits e bytes

Podemos pensar na memria do computador como uma


ta, uma grande ta feita de frames sequenciais.

Pergunta: Quando tivermos mais do que 256 bytes


acrescenta-se um outro byte?

Sim. Com dois bytes o nmero de combinaes


256*256.
Em cada um desses frames, podemos colocar uma certa
voltagem: tem voltagem ou no tem voltagem: se tem
voltagem associamos o valor 1, se no tem voltagem as- Pergunta: Qual a razo do computador usar apenas bysociamos o valor 0. Da termos a linguagem binria de tes como medida mnima? Ser que no seria possvel
utilizar 7 bits ou 5 bits?
zeros e uns.
Agora podemos fazer combinaes se tivermos posio
de zeros e uns, da direita para a esquerda.

No possvel pelo fato do computador s entender


0 e 1 ento no caso impossvel se ter um nmero
mpar de bits porque tudo tem que ter o 0 e o 1 por
isso que tudo na informtica evolui multiplicando-se
por 2 (32, 64, 256, 512)

00000000 1 Combinao
00000001 2 Combinao
00000010 3 Combinao
00000011 4 Combinao
00000100 5 Combinao
00000101 6 Combinao
00000110 7 Combinao

10.0.2 Nmeros inteiros


Se dissermos que 2 bytes representam inteiros, poderemos utilizar as 65 536 combinaes, pois 2 bytes
16bits- temos 2 elevado a 16 = 65 536 e isso dar-nosia esses nmeros todos. Assim se quisermos apenas os
positivos com o zero temos de [0, 65535].
17

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.

CAPTULO 10. PROGRAMAR EM C/TIPOS DE DADOS


Sinal: signed e unsigned
Existe outro tipo de modicador, que dene se o nmero
vai ser guardado com sinal ou no. So os modicadores
signed e unsigned, suportados pelos tipos inteiros apenas.
signed diz que o nmero deve ser guardado com sinal, ou seja, sero permitidos valores positivos e negativos. Esse o padro, portanto esse modicador
no muito usado.

unsigned diz que o nmero deve ser guardado sem


Tambm existem outros tipos, como short (ou short int),
sinal. Com isso, o valor mximo da varivel auque serve para inteiros menores, long (ou long int) para
menta, j que no teremos mais valores negativos.
inteiros maiores. Qualquer tipo inteiro pode ser precePor exemplo, com uma varivel char podemos guardido por unsigned (o signed para COM negativos), para
dar valores de 128 a 127, mas com uma varivel
cortar os nmeros negativos, permitindo maior capaciunsigned char pode guardar valores de 0 a 255.
dade de armazenamento de nmeros positivos. Alguns
compiladores aceitam o long long, para aumentar ainda
mais o tamanho da varivel, alguns desses s aceitam para Para usar esses modicadores, devemos coloc-los antes
do nome do tipo da varivel, sendo que o modicador
o tipo int, outros tambm para o tipo double.
de sinal deve vir antes do modicador de tamanho caso
Podemos alterar a maneira como os dados so guardados ambos sejam usados. Por exemplo:
com os modicadores de tipo. Voc pode modicar os
unsigned char c; short int valor; unsigned long int
tipos de duas maneiras.
resultado;
Nota: Voc pode abreviar short int e long int para
simplesmente short e long, respectivamente.
Tamanho: short e long
Voc pode modicar o tamanho de uma varivel usando
os modicadores de tipo, que so dois: short e long. Tabela de tipos inteiros
Note que oat e char no podem ser modicados em tamanho.
Convm ver a tabela de tipos inteiros.
Tipo Num de bits Formato para leitura com scanf Inter short diminui o espao necessrio para guardar a valo Inicio Fim char 8 %c 128 127 unsigned char 8 %c
varivel (diminuindo tambm a gama de valores que 0 255 signed char 8 %c 128 127 int 16 %i 32.768
esta pode assumir). S pode ser usado com int.
32.767 unsigned int 16 %u 0 65.535 signed int 16 %i
32.768 32.767 short int 16 %hi 32.768 32.767 un long aumenta o espao tomado pela varivel, e por- signed short int 16 %hu 0 65.535 signed short int 16
tanto aumenta seu valor mximo e/ou sua preciso. %hi 32.768 32.767 long int 32 %li 2.147.483.648
Pode ser usado com int e double.
2.147.483.647 signed long int 32 %li 2.147.483.648
2.147.483.647 unsigned long int 32 %lu 0 4.294.967.295
O padro C de 1999 adicionou um terceiro modi- Nota: O tipo long 32 bits como int em computadores
cador, suportado pelos compiladores mais recen- de arquitetura 32 bits e 64 bits em computadores de artes, inclusive o gcc: long long, que aumentaria ainda quitetura 64 bits no padro LP64 (Mac OS X e Unix).
mais a capacidade da varivel. Alguns deles suportam esse modicador apenas para o tipo int, e outros
suportam tambm para double.
10.0.3 Nmeros de ponto utuante
Uma observao necessria: segundo o padro, no
existe nenhuma garantia de que uma varivel short int
menor que uma varivel int, nem que long int maior que
int. Apenas garantido que int no maior que long nem
menor que short. De fato, nos sistemas x86 de 32 bits (ou
seja, a maioria dos computadores pessoais atualmente), o
tamanho de int igual ao de long. Geralmente, int ser
o tamanho nativo do processador ou seja, 32 bits num
processador de 32 bits, 16 bits num processador de 16
bits etc.

Os nmeros de ponto utuante so uma tentativa para


guardar nmeros reais, como 3,1415 (pi), 2,3333,
0,00015, 6,02 1023 . Ao contrrio dos nmeros reais,
os nmeros representveis pelo hardware so nitos. A
maneira como os tipos de ponto utuante so armazenados abstrata para o programador, entretanto, o hardware
segue o padro IEEE 754 (Standard for Floating-Point
Arithmetic).
O armazenamento feito usando notao cientca binria.

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

Este tipo surgiu porque muitas vezes apenas se quer ter


2 valores: sim/no ; verdadeiro/falso. Tem o tamanho de
um byte e tem apenas dois valores 0 e 1 que corresponde
a true e false.
Por que guardar um bool num byte quando se pode utilizar apenas um bit? A razo que o computador usa no
mnimo o byte, no o bit.

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

Compatibilidade de dados na atribuio de valor

Se tentarmos colocar um valor diferente do tipo esperado


da varivel? Temos um problema de compatibilidade de
dados:
Caso 1: Declaramos um int e colocamos uma letra
Aqui no teremos problemas. Os literais
de caracteres so, nativamente, do tipo
int. O resultado ser um inteiro que contm o valor ASCII do caractere dado.

Caso 2: Declaramos um int e colocamos uma string


(sequncia de caracteres)
Aqui teremos um erro de compilao,
em que nos diz que no conseguimos
converter const char [5]" em int. Perceba com isso que o compilador tem alguns sistemas de converso note o
caso 3.
Caso 3: Declaramos um int e colocamos um oat
Neste caso, se colocarmos 77.33, ir ser
apenas guardado o valor 77, perdendo-se
a parte decimal.
Caso 4: overow declaramos um short e colocamos um valor maior que o mximo
Lembre-se que o tipo short guarda valores de 32767 a 32767. Se colocarmos 32768 (e o compilador no estender esses limites), no vai acontecer nenhum erro de compilao; o que resulta
que vai ser impresso um nmero negativo, 32767 (ou, como comum em
vrios compiladores, 32768). A lgica
disto tem a ver com a maneira como o
computador guarda nmeros negativos.
Mas tambm podemos fazer uma analogia com as horas. Imaginemos que vamos somar 6 horas com 7 horas. O resultado seria 13, mas como no existe 13
no relgio, iramos dar a volta nas horas
e chegar ao 1. Assim o resultado ser 1.
Caso 5: underow declaramos um short e colocamos um valor inferior ao mnimo possvel.
Aqui temos exatamente a mesma lgica
do caso de overow, mas desta vez excedido o limite inferior e no o superior.
Caso 6: declaramos um unsigned int e colocamos
um nmero negativo
O que acontece aqui semelhante a um
underow. Mas o que ocorre que o nmero guardado como seria se fosse um
int comum, negativo. O que muda na
prtica a interpretao desse nmero,
de acordo com o tipo de dado que lhe
est atribudo. Se tentarmos l-lo como
um unsigned int, obteremos um valor positivo obtido pela mesma lgica do overow/underow; se o lermos como um
(signed) int, obteremos o mesmo valor
negativo que lhe atribumos.

20

CAPTULO 10. PROGRAMAR EM C/TIPOS DE DADOS

10.0.7

Converter um tipo de varivel

A converso de uma varivel consiste em converter o tipo


de uma varivel em um outro. Imagine que voc esteja
trabalhando com uma varivel do tipo oat e por alguma
razo queira eliminar os nmeros que esto depois da vrgula.
Esta operao pode ser realizada de duas maneiras.
Converses do tipo implcita: Consiste em uma modicao do tipo de varivel que feita automaticamente
pelo compilador.
Ex:
int x; x = 7.123;
Converses do tipo explcita: Tambm chamada de
operao cast, consiste em forar a modicao do tipo
de varivel usando o operador cast "( )".
Ex:
int y; y = (int)7.123;
Veja um exemplo da converso de tipo inteiro em caracteres. Aqui convertemos um numero decimal em um caractere ASCII.
#include <stdio.h> int main() { int y = 65; char x; x =
(char) y; printf(O numero inteiro: %d \n O caractere:
%c \n\n, y, x); }

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: '\''.

Literais de strings devem vir entre aspas duplas (").


Para usar aspas duplas dentro de strings, preceda-as
com barra invertida: Ele disse \"Ol\".. Note que
um literal de string adiciona o caractere nulo (\0)
ao nal da string, pois ele , em C, a maneira de
delimitar o nal de uma string.
Na verdade, segundo o padro C, literais de caracteres
podem conter a representao de mais um caractere, mas
o uso deles seria para representar nmeros e no sequncias de caracteres; um aspecto pouco utilizado da linguagem C.

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.

Existem 3 maneiras para criar constantes:


1. #dene

Vale lembrar que cada #dene preprocessador, ou seja,


no pode ser alterado dentro do programa durante sua
execuo.

2. [const] [tipo da varivel][nome da varivel]

// dened constants: calculate circumference #include


<stdio.h> #dene PI 3.14159 #dene NEWLINE "\n
int main (){ double r=5.0; // radius double circle; circle
Esta ltima vamos deixar para mais tarde, pois so uma
= 2 * PI * r; // utilizamos o Pi e no 3. printf("%f,
boa introduo para as classes.
circle); printf("%s, NEWLINE ); return 0; }
3. enumerations

11.2 DEFINED
(#DEFINE)

CONSTANTS

11.3 Declared constants (const)


Ns podemos transformar uma varivel numa constante
do gnero:

#dene PI 3.14159265 #dene NEWLINE "\n


Se colocarmos estas linhas no header, o que vai acontecer
o seguinte: O pr-processador ir vericar o nosso cdigo fonte e sempre que encontrar a diretiva #dene ir,
literalmente, substituir cada ocorrncia do identicador
no cdigo fonte pelo valor denido.

const int tamanho = 100;


const char tabul = '\t';
const int codigo = 12440;
Com o prexo const, dizemos que a varivel no poder
alterar o seu valor.

A vantagem disto que:


Podemos ter um identicador ao nosso gosto, e sempre que necessitarmos do valor escrevemos o identicador, em vez do valor, at porque se o valor
fosse complicado poderamos enganar-nos a escrever. Claro que nos poderamos enganar tambm a
escrever o identicador, da a escolhermos um nome
familiar.

Repare que se fosse uma varivel eu poderia ter:


int a=5;
e logo a seguir dizer
a=6;

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 11. PROGRAMAR EM C/CONSTANTES

Captulo 12

Programar em C/Entrada e sada simples


12.2 puts() e putchar()

12.1 Entrada e sada simples

puts signica put string (colocar string), utilizado para


colocar uma string na sada de dados. putchar signica
put char (colocar caractere), utilizado para colocar
um caractere na sada de dados.
Se voc pensar bem, perceber que um computador praticamente intil se no tiver nenhuma maneira de interagir com o usurio. Por exemplo, se voc abrir um processador de texto, nada ir acontecer at que voc abra um
arquivo ou digite algum texto no teclado. Mas, da mesma
maneira, necessrio que o computador fornea informao tambm: como voc poderia saber se uma tarefa foi
concluda?

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');

Note que junto com a funo puts devemos usar literais


de string (com aspas duplas), e com putchar devemos usar
As trocas de informao entre o computador e o usurio
literais de caractere (com aspas simples). Se voc tentasse
so chamadas entrada e sada (input e output, em ingls).
compilar algo como putchar (T), o compilador daria
Entrada a informao fornecida a um programa; sada
uma mensagem de erro. Lembre-se que T diferente
a informao fornecida pelo programa. comum referirde 'T'.
se aos dois termos simultaneamente: entrada/sada ou
Podemos tambm colocar caracteres especiais, como a
E/S (I/O, em ingls).
tabulao (\t) e a quebra de linha (\n):
Frequentemente so usados os termos sada padro
(standard output, stdout) e entrada padro (standard in- puts (Primeira linha\nSegunda linha\te um grande esput, stdin). Eles se referem, na maioria das vezes, ao mo- pao); putchar ('\n'); // apenas envia uma quebra de linitor e ao teclado, que so os meios bsicos de interao nha
com o usurio. No entanto, os sistemas operacionais per- Este cdigo resultaria em algo parecido com:
mitem redirecionar a sada e a entrada de programas para
Primeira linha Segunda linha e um grande espao
outros dispositivos ou arquivos.
As funes de entrada e sada na linguagem C traba- Observe que a funo puts() sempre coloca uma quebra
lham com uxos (streams, em ingls) de dados, que so de linha aps imprimir a string. J com as funes putuma forma de abstrao de dados de maneira sequencial. char() e printf() (vista a seguir), isso no ocorre. O cdigo
Assim, toda entrada e sada feita da mesma maneira, abaixo, por exemplo:
com as mesmas funes, no importando o dispositivo putchar('c'); putchar('h'); putchar('\n'); puts(String.);
com o qual estamos nos comunicando (teclado, termi- puts(Outra string.);
nal, arquivo, etc.). As mesmas funes que descrevem
o acesso aos arquivos podem ser utilizadas para se imprimiria algo parecido com isto:
ch String. Outra string.
acessar um terminal de vdeo.
Em C, as funes da biblioteca padro para entrada e
sada esto declaradas no cabealho stdio.h. Uma delas j foi introduzida em sees anteriores: printf(). A
seguir daremos mais detalhes sobre essa funo e introduziremos outras.

Observe que os caracteres 'c' e 'h' so exibidos na mesma


linha, pois no foi inserida uma quebra de linha entre eles.
J as strings String. e Outra string. so exibidas em linhas diferentes, pois a funo puts() insere uma quebra de
linha aps cada string, mesmo que no haja um caractere

23

24

CAPTULO 12. PROGRAMAR EM C/ENTRADA E SADA SIMPLES

'\n' nas literais de string do cdigo.

O cdigo acima ir retornar:

Os outros caracteres especiais so introduzidos adiante.

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);

int a, b, c; ... // leitura dos dados c = a + b; // c o resultado


da soma printf ("%d + %d = %d, a, b, c);
O que resultaria em, para a = 5 e b = 9:

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.

12.3.1 Especicaes de formato

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:

Observao Se voc quiser imprimir um sinal de


porcentagem, use %%. Exemplo: printf(O lucro para o
ltimo ms foi de 20%%.);
Numa sequncia de controle, possvel tambm indicar
a largura do campo, o nmero de casas decimais, o tamanho da varivel e algumas opes adicionais. O formato
geral :
%[opes][largura do campo][.preciso][tamanho da
varivel]tipo de dado
A nica parte obrigatria o tipo de dado. Todas as outras podem ser omitidas.

int teste; teste = 42; printf (A varivel 'teste' contm o


Opes
nmero %d., teste);
Tendo colocado isso no seu programa, voc dever ver na As opes so parmetros opcionais que alteram a fortela:
matao. Voc pode especicar zero ou mais delas,
colocando-as logo aps o sinal de porcentagem:
A varivel 'teste' contm o nmero 42.
Vamos supor que voc queira imprimir um nmero no
inteiro. Voc teria que trocar "%d por %f. Exemplo:
oat pi; pi = 3.1415; printf (O valor de pi %f., pi);

0: o tamanho do campo deve ser preenchido com


zeros esquerda quando necessrio, se o parmetro
correspondente for numrico.

12.3. PRINTF()

25

- (hfen): o valor resultante deve ser alinhado es- Preciso


querda dentro do campo (o padro alinhar diA preciso pode ter quatro signicados diferentes:
reita).
(espao): no caso de formatos que admitem sinal
negativo e positivo, deixa um espao em branco
esquerda de nmeros positivos.

Se a converso solicitada for inteira (d, i, o, u, x,


X): o nmero mnimo de dgitos a exibir (ser preenchido com zeros se necessrio).

+: o sinal do nmero ser sempre mostrado, mesmo


que seja positivo.

Se a converso for real (a, A, e, E, f, F): o nmero


de casas decimais a exibir. O valor ser arredondado
se a preciso especicada no formato for menor que
a do argumento.

' (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 a converso for em notao cientca (g, G): o


nmero de algarismos signicativos. O valor ser
arredondado se o nmero de algarismos signicativos pedido for maior que o do argumento.
Se a converso for de uma sequncia de caracteres
(s): o nmero mximo de caracteres a exibir.
Assim como a largura do campo, a preciso pode ser especicada diretamente por um nmero ou com um asterisco, mas deve ser precedida por um ponto.
Alguns exemplos:
printf ("%.5d, 314); // exibe 00314 printf
("%.5f, 2.4); // exibe 2.40000 printf ("%.5g,
23456789012345); // exibe 2.3457e+13 printf
("%.5s, Bom dia); // exibe Bom d
claro que podemos combinar a largura com a preciso.
Por exemplo, %10.4f indica um campo de nmero real de
comprimento total dez e com 4 casas decimais. Note que,
na largura do campo, o valor inteiro levado em conta,
inclusive o ponto decimal, e no apenas a parte inteira.
Por exemplo, essa formatao aplicada ao nmero 3.45
ir resultar nisto:

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"

hh: indica que a converso inteira corresponde a


uma varivel char. Por exemplo, poderamos usar o
formato %hhd para exibir uma varivel do tipo char
na base decimal.
h: indica que a converso inteira corresponde a uma
varivel short.
l: indica que a converso inteira corresponde a uma
varivel long.

26

CAPTULO 12. PROGRAMAR EM C/ENTRADA E SADA SIMPLES

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

Sequncias de escape so combinaes de caracteres


que tm signicado especial, e so sempre iniciadas por
uma barra invertida (\). Voc pode us-las em qualquer
literal de caractere ou string. Por exemplo, a string linha
1\nlinha 2 equivale a:
linha 1 linha 2
pois a sequncia \n indica uma quebra de linha. Como foi
citado anteriormente, a funo printf(), diferentemente
de puts(), no imprime automaticamente uma quebra de
linha no nal da string. O cdigo abaixo, por exemplo:

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);

printf(string 1); printf(string 2);

Dessa maneira, se o usurio digitar 120 z 17.63, teremos


a igual a 120, b igual ao caractere 'z' e c igual ao nmero
Imprimiria isto:
17,63. Se o usurio tentar digitar mais de um espao enstring 1string 2
tre os dados ou simplesmente nenhum espao, ainda asIsso pode ser til, pois s vezes desejvel permanecer sim o programa obter os dados certos. Por exemplo,
na mesma linha.
120z17.63 tambm dar o mesmo resultado.
A seguir apresentamos a tabela com as sequncias de es- Agora uma questo um pouco mais difcil: vamos supor
cape suportadas pela linguagem C:
que especicamos um formato inteiro e o usurio digitou
um nmero real, como por exemplo 12.5. O que dever
acontecer?
Representao octal e hexadecimal
#include <stdio.h> int main () { int a; printf (Digite um
Tambm possvel trocar uma sequncia de escape pelo nmero: "); scanf ("%d, &a); printf ("\nO nmero digiseu valor em octal ou hexadecimal. Voc pode, por exem- tado foi %d, a); return (0); }
plo, trocar o caractere "\n pelo valor octal "\12 ou he- Se voc testar com o valor 12.5, vai ver que o programa
xadecimal "\x0A. Vejamos mais alguns exemplos.
retornar o nmero 12, pois a funo scanf() apenas inHexadecimal Octal Caracter \x00 \00 \0 \x0A \12 \n \x0D terpreta os caracteres vlidos para aquele formato.
\15 \r \x07 \07 \a \x08 \10 \b \x0B \13 \v

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.

Os especicadores de converso so praticamente os


mesmos que os da funo printf(), com algumas mudanas. A maioria deles pula espaos em branco, exceto dois.
%i no mais sinnimo de %d. O que %i faz
interpretar o valor digitado como hexadecimal, se
iniciar-se por 0x ou 0X; como octal, se iniciar-se por
0; ou como decimal, caso nenhuma dessas condies
seja vericada.
%a, %e/%E e %g so sinnimos de %f.
%lf deve ser usado para variveis do tipo double.
%s l uma sequncia de caracteres no-brancos
(qualquer caractere exceto espao, tabulao, quebra de linha etc.), ou seja, uma palavra.

12.5. GETS() E GETCHAR()

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:

12.6 sprintf() e sscanf()


sprintf e sscanf so semelhantes a printf e scanf. Porm,
ao invs de escreverem na sada padro ou lerem da entrada padro, escrevem ou lem em uma string. A nica
mudana nos argumentos a necessidade de especicar
a string que deve ser lida ou atribuda no incio. Veja os
exemplos para entender melhor.
#include <stdio.h> int main() { int i; char string1[30];
printf(Entre um valor inteiro: "); scanf("%d, &i);

28

CAPTULO 12. PROGRAMAR EM C/ENTRADA E SADA SIMPLES

sprintf(string1, Valor de i = %d, i); puts(string1); return 0; }


Nesse exemplo, a mensagem que queramos exibir na
tela foi primeiramente salva em uma string, e depois essa
string foi enviada para a tela. Se voc olhar bem, se
voc tivesse alocado um valor menor para string1, tambm ocorreria um estouro de buer. Para evitar esse problema, existe a funo snprintf, que tem mais um argumento: o tamanho da string (deve ser colocado depois da
string onde a mensagem ser gravada).
#include <stdio.h> int main() { int i, j, k; char string1[]
= 10 20 30"; sscanf(string1, "%d %d %d, &i, &j, &k);
printf(Valores lidos: %d, %d, %d, i, j, k); return 0; }
Nesse exemplo, usamos a funo sscanf para interpretar
os valores contidos na string e guard-los nas variveis
numricas.

Captulo 13

Programar em C/Operaes matemticas


(Bsico)
13.1 Operaes matemticas

0; }

Mas, segundo a precedncia dos operadores, j / i deveria


Em C, fazer operaes matemticas simples bastante ser calculado primeiro, e como ambos os valores so do
fcil e intuitivo. Por exemplo, se quisermos que uma va- tipo inteiro, o valor dessa expresso zero.
rivel contenha o resultado da conta 123 + 912, fazemos
importante que voc grave um arquivo .c com o cdigo
assim:
acima e execute usando o compilador para ver o funciovar = 123 + 912;
namento com os prprios olhos.
Os operadores aritmticos bsicos so 5: + (adio), (subtrao), * (multiplicao), / (diviso) e % (resto de
13.1.1
diviso inteira).

Abreviaes

Outro exemplo:

Alguns tipos de atribuies so bastante comuns, e por


isso foram criadas abreviaes. Por exemplo, muito
comum incrementar em uma unidade o valor de uma vaPodemos usar mais de um operador na mesma expresso.
rivel (em loops, por exemplo). Em vez de escrever var
A precedncia igual usada na matemtica comum:
= var + 1, podemos escrever simplesmente var++. Da
a = 2 + 4 * 10; /* retornar 42, o mesmo que (2 + (4 * mesma maneira, existe o operador de decremento, que
10)) */ a = 2 + 40 / 2 + 5; /* retornar 27, o mesmo que decrementa em uma unidade o valor da varivel: var-(2 + (40 / 2) + 5) */
(equivalente a var = var - 1).
Voc pode usar parnteses, como em expresses mate- Os operadores de decremento e incremento tambm pomticas normais:
dem ser utilizados antes do nome da varivel. Isso signia = (2 + 4) * 10; /* retornar 60 */ a = (2 + 40) / (2 + 5); ca que estas duas instrues so equivalentes:
/* retornar 6 */
var++; ++var;
int a = 15; int b = 72; int c = a * b; /* c valer 1572 */

Note que uma operao entre nmeros inteiros sempre


retornar um nmero inteiro. Isso evidente para a adio, subtrao e multiplicao. Mas em uma diviso de
inteiros, por exemplo 3/2, a expresso retornar apenas a
parte inteira do resultado, ou seja, 1.

Agora vamos supor que voc use em seu programa uma


varivel que aumenta de 10 em 10 unidades. claro que
usar var++ dez vezes no abreviaria nada. Em vez disso,
existe a abreviao var += 10.

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 13. PROGRAMAR EM C/OPERAES MATEMTICAS (BSICO)

O resultado que voc deve obter ao executar o exemplo :


11 6 10 6
Esse resultado mostra que ++var e var++ no so a
mesma coisa se usados como uma expresso. Quando
usamos os operadores na forma prexal (antes do nome
da varivel), o valor retornado depois de ser incrementado; na forma suxal, o valor retornado e depois incrementado. O mesmo vale para o operador de decremento.
E o que aconteceria se voc escrevesse algo como o seguinte?
printf("%d\n, a / ++a);
A resposta : no sabemos. Segundo o padro C, o resultado disso indenido (o que signica que pode variar de
um compilador para outro). No existe uma regra sobre
avaliar primeiro o numerador ou o denominador de uma
frao. Ou seja, no use uma varivel mais de uma vez
numa expresso se usar operadores que a modicam.
Talvez voc tenha achado estranha a linha:
a = b = 5;
Isso possvel porque atribuies so feitas da direita
para a esquerda e uma instruo de atribuio tambm
uma expresso que retorna o valor atribudo. Ou seja, a
expresso b = 5 retornou o valor 5, que foi usado pela
atribuio a = (b = 5), equivalente a a = 5.

Captulo 14

Programar em C/Operaes matemticas


(Avanado)
O cabealho <math.h> contm prottipos de algumas
funes na rea de matemtica. Na verso de 1990 do
padro ISO, somente a verso double das funes foram
especcadas; na verso de 1999 foram adicionadas as
verses oat e long double.

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

14.1.3 As funes cos, sin e tan

5. Funes de Arredondamento para Nmeros Inteiros, Valores Absolutos e Resto da Diviso

As funes cos, sin, e tan retornam o coseno, seno, e tangente do argumento, expresso em radianos.

#include <math.h> oat cosf(oat x); /* C99 */ oat


sinf(oat x); /* C99 */ oat tanf(oat x); /* C99 */ double
cos(double x); double sin(double x); double tan(double
x); long double cosl(long double x); /* C99 */ long dou14.1.1 As funes acos e asin
ble sinl(long double x); /* C99 */ long double tanl(long
A funo acos retorna o arco-cosseno dos seus argumen- double x); /* C99 */
tos em radianos, e a funo asin retorna o arco-seno dos
seus argumentos em radianos. Todas as funes esperam por argumentos que estejam no intervalo [1,+1].
O arco-cosseno retorna valores no intervalo [0,]; o arcoseno retorna valores no intervalo [-/2,+/2].
14.2 Funes Hiperblicas

14.1 Funes Trigonomtricas

#include <math.h> oat asinf(oat x); /* C99 */ oat


acosf(oat x); /* C99 */ double asin(double x); double
acos(double x); long double asinl(long double x); /* C99 As funes cosh, sinh and tanh computam o coseno hiperblico, o seno hiperblico e a tangente hiperblica res*/ long double acosl(long double x); /* C99 */
pectivamente. Para as funes de seno e coseno hiperblico, um erro de ...

14.1.2

As funes atan e atan2

As funes atan retornam o arco-tangente dos arguments


em radianos, e a funo atan2 retorna o arco-tangente de
y/x em radianos. As funes atan retornam o valor no intervalo [-/2,+/2] (a razo pelo que /2 est incluido

#include <math.h> oat coshf(oat x); /* C99 */ oat


sinhf(oat x); /* C99 */ oat tanhf(oat x); /* C99 */
double cosh(double x); double sinh(double x); double
tanh(double x); long double coshl(long double x); /* C99
*/ long double sinhl(long double x); /* C99 */ long double
tanhl(long double x); /* C99 */

31

32

CAPTULO 14. PROGRAMAR EM C/OPERAES MATEMTICAS (AVANADO)

14.3 Funes Exponencial e Loga- 14.4 Funes pow e sqrt


ritmo
14.4.1 As funes pow

14.3.1

A funo exp

14.3.2

As funes frexp, ldexp e modf

As funes pow computam x elevado a y e retornam o


resultado. Um domain error ocorre se x for negativo e y
As funes exp computam a funo exponencial de x (ex ). no for um nmero inteiro. Um domain error ocorre se
Um range error ocorre se o valor de x muito grande. o resultado no puder ser representado quando x zero e
#include <math.h> oat expf(oat x); /* C99 */ double y menor ou igual a zero. Um range error pode ocorrer.
exp(double x); long double expl(long double x); /* C99 #include <math.h> oat powf(oat x, oat y); /* C99 */
*/
double pow(double x, double y); long double powl(long
double x, long double y); /* C99 */

14.4.2 As funes sqrt

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 e log10

14.5 Funes de Arredondamento


para Nmeros Inteiros, Valores Absolutos e Resto da Diviso
14.5.1 As funes ceil e oor
As funes ceil computam o menor nmero inteiro que
no seja menor que x e retornam o resultado; as funes oor computam o maior nmero inteiro que no seja
maior que x e retornam o resultado.
#include <math.h> oat ceilf(oat x); /* C99 */ double
ceil(double x); long double ceill(long double x); /* C99
*/ oat oorf(oat x); /* C99 */ double oor(double x);
long double oorl(long double x); /* C99 */

14.5.2 As funes fabs

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.

14.5.3 As funes fmod

#include <math.h> oat logf(oat x); /* C99 */ double


log(double x); long double logl(long double x); /* C99 */ As funes fmod computam o resto de x/y e retornam o
oat log10f(oat x); /* C99 */ double log10(double x); valor x - i * y, pra algum nmero inteiro i onde, se y for um
nmero diferente de zero, o resultado tem o mesmo sinal
long double log10l(long double x); /* C99 */

14.6. LIGAES EXTERNAS


de x e magnitude menor que a magnitude de y. Se y for
zero, dependendo da implementao da funo, ocorrer
um domain error ou a funo fmod retornar zero.
#include <math.h> oat fmodf(oat x, oat y); /* C99 */
double fmod(double x, double y); long double fmodl(long
double x, long double y); /* C99 */

14.6 Ligaes externas


Biblioteca de referncia C++ (C++ Reference Library) cmath (math.h)

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.3 type casting

fazer com que o resultado saia com a tipologia desejada.


Iremos ver que ter a++ ou ++a diferente! Mas isso
vai ser na histria dos loops. (iremos ter situaes Neste exemplo estamos a fazer com que o rstOp seja
convertido para tipo oat, quando antes tnhamos declatipo++a+5 que seria a+5 mas antes fazer a+1+5.)
rado como um int, ou seja o valor 10 passa a ser 10.0. e
Mais uma nota. Em relao ao operador adio ele para
agora como temos um oat a dividir por um int, o que
alm dos nmeros tambm permite adicionar strings, isto
acontece que h uma converso automtica, ou seja o
, junta a segunda string no m da primeira string. No
2 int convertido em oat, fazendo com que o resultado
entanto se juntarmos um dgito com uma string isso j
seja um oat Podemos utilizar qualquer uma das expresno permitido.
ses seguintes para exprimir o tycasting.

15.2 Precedncia de Operadores


aritmticos

oat result = (oat) rstOp / secondOp; oat result = oat


(rstOp) / secondOp; oat result = rstOp / (oat) secondOp; oat result = rstOp / oat (secondOp);

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.

Mais um ponto em relao ao operador % mdulo (mo- 15.5 Operadores relacionais


dulus). Podemos fazer o mdulo para nmeros inteiros
mas se tentarmos para nmeros do tipo oat (ou um de- Permite fazer comparaes lgicas de ordenao de nles) ca indenido. Geralmente resulta num erro de com- meros, e ainda de letras (mas no strings) Table: Relational Operators
pilao (mas isso vai depender do compilador)
34

15.8. PRECEDNCIA OPERADORES LGICOS E RELACIONAIS

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.

15.8 Precedncia Operadores lgicos e Relacionais

Estes operadores tambm so binrios, ie, comparam


dois operandos. o resultado de uma expresso relacional
d um valor bool (verdadeiro=1 ou falso=0)
Tabela: A preedenia dos operadores logicos e relacionais
4 != 4 false
4 == 5 false

Operador (da mais alta para a mais baixa) ! Relacionais


(>, >=, <, <=, ==. !=) && ||
cuidado!

Eu ainda posso comparar um int com um oat que isso


if (!age > 12 && age < 65)
no d problema. ou seja com dados nmericos no h
problema. Comparaes entre dois caracteres tambm
no h problema pois os caracteres so nmeros na tabela Note o ! no exemplo. sempre bom recorrer aos parnASCII. Mas no usem para strings (pois a estaramos a teses
comparar o qu, se as strings so conjunto de caracteres?)
No esquecer o ponto que o digito pode ser um char ou
estar em forma nmerica. e esse char vai ter o valor na 15.9 Operadores Lgicos Bit a Bit
tabela. ns num capitulo posterior iremos ver que poderemos fazer a converso de char para int e vice versa.

15.9.1 Deslocamento de bits

15.6 Precedncia dos operadores


relacionais
Table: Precedence of Relational Operators

x = a << b igual a x = a*2^b; x = a >> b igual a x =


a/2^b;

15.10 Todos os Operadores

Novamente existe a regra da esquerda para a direita caso Comparaes de precedncia entre Operadores aritmtihaja igualdade de precedncia
cos, relacionais e lgicos

15.7 Operadores lgicos


Estes operadores comparam j condies de precedncia
Table: Logical Operators
Estes operadores tambm so binrios mas desta vez os
operandos so resultados boolean, que podem advir dos

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 15. PROGRAMAR EM C/OPERADORES

Captulo 16

Programar em C/Controle de uxo


16.1 Controle de uxo

inteiro que sendo 0 (zero) signica falso, sendo qualquer


outro nmero signica verdadeiro.

Dicilmente um programa em C ir executar sempre


as mesmas instrues, na mesma ordem, independentemente do que tenha acontecido anteriormente ou do valor
que foi fornecido. muito comum que algum queira que
um pedao de cdigo s seja executado se uma certa condio for verdadeira; tambm comum querer que um
pedao de cdigo seja repetido vrias vezes, de tal maneira que simplesmente copiar o cdigo no resolveria o
problema ou seria trabalhoso demais. Para casos como
esses, existem as estruturas de controle de uxo.

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".

Note que para saber se dois nmeros so iguais devemos


usar dois sinais de igual. Um erro muito comum esquecer de um deles, transformando a comparao numa
Em C, existem vrias instrues relacionadas ao controle
atribuio por exemplo:
de uxo:
if (x = 1) ...
if, que executa um bloco apenas se uma condio
for verdadeira;
O que acontece aqui que a varivel x recebe o valor 1,
de modo que a expresso entre parnteses tambm ter
switch, que executa um bloco de acordo com o valor
o valor 1 tornando a condio sempre verdadeira.
de uma expresso ou varivel;
Similarmente, se usssemos o nmero zero, a expresso
for, que executa um bloco repetidas vezes enquanto sempre seria falsa. Portanto, sempre tome cuidado com
uma condio for verdadeira, executando uma ins- esse tipo de comparao. A maneira certa de comparar
truo (geralmente de incremento ou decremento de com um nmero :
uma varivel) aps cada execuo;

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.

16.2 Expresses de condio

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.

Uma expresso de condio uma expresso normal em


C que, quando avaliada, ser interpretada como verdadeira ou falsa. Em C, na verdade, esse valor um valor

O operador ou retorna verdadeiro se pelo


menos um dos operandos for verdadeiro; retorna
falso apenas se ambos forem falsos.

Porm, antes de entrar no estudo dessas estruturas, voc


deve saber como escrever uma condio. o que explicamos a seguir.

37

38

CAPTULO 16. PROGRAMAR EM C/CONTROLE DE FLUXO

O operador e retorna verdadeiro apenas se ambos os seus operandos forem verdadeiros.

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.

if (x > 9) { printf (x maior que 9.\n); } else if (x >=


5) { printf (x maior ou igual a 5, mas no maior que
9.\n); } else { if (x == 0) { printf (x igual a zero.\n);
} else { printf (x no-nulo e menor que 5.\n); } }

A comparao correta envolveria o operador e (&&):


16.3.2
10 < n && n < 50.

switch

Pelo fato de todo valor diferente de zero ser avaliado


O teste switch compara uma expresso com diversos vacomo verdadeiro e zero como falso, existem as seguintes
lores que podem estar associados a blocos de cdigos
equivalncias (apenas quando estas expresses so usadas
diferentes, e executa o bloco de cdigo correspondente
como condies):
ao valor encontrado. Voc tambm pode especicar um
(x == 0) equivale a (!x) (x != 0) equivale a (x)
bloco que deve ser executado caso nenhum dos outros valores seja encontrado: o bloco default (padro em ingls).

16.3 Testes

switch (expresso) { case valor1: instrues; break; case


valor2: instrues; break; ... default: instrues; }

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

if (x == 5) j++; printf (x igual a 5.\n);

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

Operador ternrio "?:"

Repare que o loop while como fosse um if, ou seja, o


bloco executado se a condio for verdadeira. A diO operador ternrio ?: uma alternativa abreviada da ferena que ao nal da execuo, o while executado
estrutura if/else. Ele avalia uma expresso e retorna um novamente, mas o if no. No loop while (assim como nos
certo valor se ela for verdadeira, ou outro valor se ela for loops do e for) tambm podemos usar a sintaxe abreviada
falsa. Sua sintaxe :
para apenas uma instruo:
condio ? valorSeVerdadeira : valorSeFalsa

while (a < b) a++;

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

Note que, ao contrrio das outras estruturas de controle,


necessrio colocar um ponto-e-vrgula aps a condiLoops so conjuntos de instrues que devem ser execuo.
tadas repetidas vezes, enquanto uma condio for verdadeira. Em C h 3 tipos de loops: while, do ... while e do { printf ("%d\n, a); a++; } while (a < b);
for.

16.4.1

while

O loop while testa uma condio; se ela for verdadeira,


o bloco correspondente executado e o teste repetido.
Se for falsa, a execuo continua logo aps o bloco. A
sintaxe de while :
while (condio) { ... }

Um exemplo de utilizao de do ... while em um menu.


Pediramos que o usurio escolhesse uma opo at que
ele escolhesse uma opo vlida:
#include <stdio.h> int main () { int i; do { printf (Escolha a fruta pelo nmero:\n\n); printf ("\t(1) Mamo\n);
printf ("\t(2) Abacaxi\n); printf ("\t(3) Laranja\n\n);
scanf("%d, &i); } while (i < 1 || i > 3); switch (i)
{ case 1: printf (Voc escolheu mamo.\n); break;
case 2: printf (Voc escolheu abacaxi.\n); break; case
3: printf (Voc escolheu laranja.\n); break; } return 0; }

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

CAPTULO 16. PROGRAMAR EM C/CONTROLE DE FLUXO

feita aps cada execuo sem incluir o cdigo dentro do


bloco. A sua forma geral
Por exemplo, suponha que temos uma biblioteca grca
for (inicializao; condio; incremento) { instrues; } que tem uma funo chamada graphicsReady(), que indica se podemos executar operaes grcas. Este cdigo
executaria a funo repetidas vezes at que ela retornasse
E equivale a
verdadeiro e ento pudssemos continuar com o proinicializao; while (condio) { instrues; incremento; grama:
}
while (!graphicsReady()) ;
Um exemplo do uso de for:
for (a = 1; a < 10; a++) { if(a == 1) puts (Numero de
voltas previstas 9.); printf(Numero de loop ou volta : 16.4.4 break e continue
%i ", a ); printf(Valor de a : %i ", a ); }
Voc j viu break sendo usado para sair do teste switch;
no entanto, ele funciona tambm nos loops while, do
Nesse exemplo, primeiro denimos o valor de a como 1; e for. Nos trs casos, ele sai do ltimo loop iniciado
depois, o cdigo (...) repetido enquanto a for menor que (mesmo que haja mais de um). Por exemplo:
dez, incrementando em uma unidade o valor de a aps
cada execuo do cdigo. Analisando essas condies, while (1) { if (a > b) break; a++; }
voc podera perceber que o cdigo ser executado nove
vezes: na primeira execuo, temos a = 1; aps a nona break sempre faz com que a execuo do programa conexecuo, a igual a 10, e portanto o bloco no ser mais tinue na primeira instruo seguinte ao loop ou bloco.
repetido.
A instruo continue parecida com break, porm ao
Tambm podemos dar mais de uma instruo de iniciali- execut-la saltamos para a prxima iterao loop ao invs
zao ou de incremento (separadas por vrgula), alm de de termin-lo. Usar continue equivale a chegar ao nal
poder usar naturalmente condies compostas com o uso do bloco; os incrementos so realizados (se estivermos
dos operadores lgicos:
em um loop for) e a condio reavaliada (qualquer que
for (a = 1, b = 1; a < 10 && (b / a) < 20; a++, b *= 2) { seja o loop atual).
... }
#include <stdio.h> int main() { int opcao = 0; while
(opcao != 5) { printf(Escolha uma opo entre 1 e 5: ");
Nesse exemplo, a e b so inicializados com o valor scanf("%d, &opcao); /* se a opo for invlida, volta
1. A cada loop, o valor de a incrementado em uma ao incio do loop */ if (opcao > 5 || opcao < 1) continue;
unidade e o de b dobrado. Isso ocorre enquanto a switch (opcao) { case 1: printf("\n --> Primeira opfor menor que 10 e a razo entre b e a for menor que cao..); break; case 2: printf("\n --> Segunda opcao..);
20. Se voc construir uma tabela com os valores de cada break; case 3: printf("\n --> Terceira opcao..); break;
varivel a cada loop (ou colocar algum contador dentro case 4: printf("\n --> Quarta opcao..); break; case 5:
printf("\n --> Abandonando..); break; } } return 0; }
do loop), ver que ocorrem oito execues.
Assim como while, o loop for testa a condio; se a condio for verdadeira ele executa o bloco, faz o incremento Esse exemplo recebe uma opo do usurio. Se ele digie volta a testar a condio. Ele repete essas operaes at tar uma opo invlida (ou seja, no for um nmero de
1 a 5), a instruo continue voltar ao comeo do loop
que a condio seja falsa.
e o programa pedir novamente a entrada do usurio. Se
Podemos omitir qualquer um dos elementos do for se de- ele digitar uma opo vlida, o programa seguir normalsejarmos. Se omitirmos a inicializao e o incremento, mente.
o comportamento ser exatamente igual ao de while. Se
omitirmos a condio, caremos com um loop innito:
for (inicializao; ; incremento) { ... }

16.5 Saltos incondicionais: goto

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:

O goto uma instruo que salta incondicionalmente


para um local especco no programa. Esse local identicado por um rtulo. A sintaxe da instruo goto :
goto nome_do_rtulo;

for (inicializao; condio; incremento) ; while (condiOs nomes de rtulo so identicadores suxados por doiso) ;
pontos (:), no comeo de uma linha (podendo ser prece-

16.6. TERMINANDO O PROGRAMA


didos por espaos). Por exemplo:
nome_do_rtulo: ... goto nome_do_rtulo;
Muitos programadores evitam usar o goto pois a maioria dos saltos pode ser feita de maneira mais clara com
outras estruturas da linguagem C. Na maioria das aplicaes usuais, pode-se substituir o goto por testes, loops e
chamadas de funes.

16.6 Terminando o programa


O programa pode ser terminado imediatamente usando a
funo exit:
void exit (int codigo_de_retorno);
Para utiliz-la deve-se colocar um include para o arquivo
de cabealho stdlib.h. Esta funo aborta a execuo do
programa. Pode ser chamada de qualquer ponto no programa e faz com que o programa termine e retorne, para
o sistema operacional, o cdigo_de_retorno. A conveno mais usada que um programa retorne zero no caso
de um trmino normal e retorne um nmero no nulo no
caso de ter ocorrido um problema.
#include <stdio.h> #include <stdlib.h> /* Para a funo
exit() */ int main (void) { FILE *fp; ... fp=fopen
(exemplo.bin,"wb); if (!fp) { printf (Erro na abertura
do arquivo. Fim de programa.); exit (1); } ... return 0; }

41

Captulo 17

Programar em C/Funes
17.1 O que funo

No exemplo acima, a funo imprime_par foi usada


para executar o pedao de programa que imprime um par
Uma funo um pedao de cdigo que faz alguma ta- de nmeros. A sada do programa acima ser:
refa especca e pode ser chamado de qualquer parte do {3,4} {2,8}
programa quantas vezes desejarmos.
A funo imprime_par denida da seguinte forma:
Podemos tambm dizer que funes agrupam operaes
void imprime_par(int a, int b) { printf("{ %d, %d
em um s nome que pode ser chamado em qualquer parte
}\n,a,b); }
do programa. Essas operaes so ento executadas todas
as vezes que chamamos o nome da funo.
O programa completo em C mostrado abaixo:
Utilizamos funes para obter:
#include <stdio.h> /** * Declarao da funo im Clareza do cdigo: separando pedaos de cdigo prime_par * Essa funo recebe dois inteiros como
da funo main(), podemos entender mais facil- argumento e os imprime * da seguinte forma {a,b}
mente o que cada parte do cdigo faz. Alm disso, */ void imprime_par(int a, int b); int main(int argc,
para procurarmos por uma certa ao feita pelo pro- char **argv) { imprime_par(3,4); //chamando a funo
grama, basta buscar a funo correspondente. Isso imprime_par(2,8); //chamando novamente return
0; } //Implementao da funo //A implementao
torna muito mais fcil o ato de procurar por erros.
da funo pode conter vrias linhas de cdigo void
imprime_par(int a, int b) { printf("{ %d, %d }\n,a,b); }
Reutilizao: muitas vezes queremos executar uma
certa tarefa vrias vezes ao longo do programa. Repetir todo o cdigo para essa operao muito tra- A denio de funes em C devem ser feitas antes do
balhoso, e torna mais difcil a manuteno do c- uso das mesmas. Por isso em nosso exemplo denimos a
digo: se acharmos um erro nesse cdigo, teremos funo imprime_par antes de us-la dentro do main.
que corrigi-lo em todas as repeties do cdigo. A linha que dene ou declara a funo tambm conheChamar uma funo diversas vezes contorna esses cida como assinatura da funo. Normalmente as assidois problemas.
naturas das funes so denidas dentro de arquivos de
cabealho .h
Independncia: uma funo relativamente independente do cdigo que a chamou. Uma funo
pode modicar variveis globais ou ponteiros, mas 17.2 Denindo uma funo
limitando-se aos dados fornecidos pela chamada de
funo.
Uma funo pode necessitar de alguns dados para que
A ideia funes permitir voc encapsular vrias operaes em um s escopo que pode ser invocado ou chamado
atravs de um nome. Assim possvel ento chamar a
funo de vrias partes do seu programa simplesmente
usando o seu nome.

possa realizar alguma ao baseada neles. Esses dados


so chamados parmetros da funo. Alm disso, a funo pode retornar um certo valor, que chamado valor
de retorno. Os parmetros (e seus tipos) devem ser especicados explicitamente, assim como o tipo do valor
de retorno.

Exemplo:

A forma geral da denio de uma funo :

#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

17.3. DOIS EXEMPLOS

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:

void funcao (void) void funcao ()


Note que os nomes dos parmetros so usados apenas na
prpria funo (para distinguir os argumentos); eles no
tm nenhuma relao com as variveis usadas para chamar a funo.

17.2.3 Chamadas de funes


Para executar uma funo, fazemos uma chamada de
funo, que uma instruo composta pelo nome da funo, seguido pela lista de argumentos entre parnteses:
nome_da_funo (arg1, arg2, ...);

int tres() { return 3; // poderia tambm ser return (3); }


Os argumentos podem ser qualquer tipo de expresso:
podem ser variveis, valores constantes, expresses maO tipo de retorno, alm dos tipos normais de variveis
temticas ou at mesmo outras chamadas de funo.
(char, int, oat, double e suas variaes), pode ser o tipo
especial void, que na verdade signica que no h valor Lembre que voc deve sempre dar o mesmo nmero de
argumentos que a funo pede. Alm disso, embora alde retorno.
gumas converses de tipo sejam feitas automaticamente
Nota Muitos livros dizem que a funo main tem tipo de
pelo compilador, voc deve atender aos tipos de argumenretorno void, o que no est correto. Segundo o padro
tos.
da linguagem C, a funo main deve ter retorno do tipo
int. Compiladores como o gcc daro mensagens de erro Note que o valor dos argumentos copiado para a funo, de maneira que as variveis originais cam inalteracaso a funo main() no seja denida corretamente.
das mesmo que na funo tentemos alter-las. A isso chamamos passagem de argumentos por valor (ao contrrio
17.2.2 Parmetros
de por referncia). Veremos como modicar as variveis
originais na seo Ponteiros.
Como j foi dito, um parmetro um valor que fornecido funo quando ela chamada. comum tam- A prpria chamada de funo tambm uma expresbm chamar os parmetros de argumentos, embora ar- so cujo valor o valor de retorno da funo, bastando
coloc-la no lado direito de um sinal de igual para guargumento esteja associado ao valor de um parmetro.
dar o valor numa varivel. Por exemplo, se a funo quaOs parmetros de uma funo podem ser acessados da drado retorna o quadrado de um nmero inteiro, podemesma maneira que variveis locais. Eles na verdade mos fazer assim para calcular o quadrado de 11 na varifuncionam exatamente como variveis locais, e modicar vel x:
um argumento no modica o valor original no contexto
da chamada de funo, pois, ao dar um argumento numa int x = quadrado (11);
chamada de funo, ele copiado como uma varivel local da funo. A nica maneira de modicar o valor de
um parmetro usar ponteiros, que sero introduzidos
mais adiante.
17.3 Dois exemplos
Para declarar a presena de parmetros, usamos uma lista
de parmetros entre parnteses, com os parmetros separados por vrgulas. Cada declarao de parmetro feita
de maneira semelhante declarao de variveis: a forma
geral tipo nome. Por exemplo:

#include <stdio.h> int quadrado (int x) { return (x *


x); } void saudacao (void) { printf (Ol!\n); } void
despedida (void) { printf (Fim do programa.\n); }
int main () { int numero, resultado; saudacao (); printf

44

CAPTULO 17. PROGRAMAR EM C/FUNES

(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:

Note que a denio da funo no deve contradizer a


#include <stdio.h> /* Multiplica 3 numeros */ void mult declarao da mesma funo. Se isso ocorrer, uma men(oat a, oat b, oat c) { printf ("%f,a*b*c); } int main sagem de erro ser dada pelo compilador.
() { oat x, y; x = 23.5; y = 12.9; mult (x, y, 3.87); return
0; }

17.5 Variveis locais versus globais


Quando declaramos as variveis, ns podemos faz-lo

17.4 Prottipo ou Declarao de


funo

Dentro de uma funo


Fora de todas as funes inclusive a main().

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.

Quando uma funo tem uma varivel local com o mesmo


nome de uma varivel global a funo dar preferncia
varivel local. Daqui conclui-se e bem que, podemos ter
variveis com o mesmo nome, o que contradiz o que ns
//Exemplo de erro de chamada de funo int main() { dissemos no capitulo das variveis.
int a = 1; int b = 2; soma(a,b); // erro: a funo est
Ento reformulamos:
denida abaixo desta linha! } void soma(int a, int b) {
printf("%d, a+b); }
Apenas na situao em que temos 2 variveis
locais que colocada a restrio de termos
Nesses casos, podemos declarar uma funo antes de
nomes diferentes caso contrrio no conseguideni-la. Isso facilita o trabalho de usar diversas funes:
ramos distinguir uma da outra.
voc no precisar se importar com a ordem em que elas
aparecem nos arquivos.
largo e alto so variveis internas fazem parte de miA declarao de funo (tambm chamada de prottipo nhaFuncion()".
de funo) nada mais que a denio da funo sem
o bloco de cdigo. Como uma instruo, ela deve ser /*espanhol para incultos :)*/ <== Comentrios da funo
seguida de um ponto-e-vrgula. Portanto, para declarar a void minhaFuncion() { double largo = 5; double alto = 6;
}
funo:
int quadrado (int x) { return (x * x); }
escreveramos:

As variveis largo e alto no esto denidas aqui abaixo,


isto quer dizer que elas nao tem nem um valor.

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.6 Passagem de parmetros por


valor e por referncia
O que ns temos feito quando chamamos uma funo
a dita chamada por valor. Quer dizer, quando chamamos uma funo e passamos parmetros para a funo
prottipo e depois para a funo denio, o valor dos argumentos passados so copiados para os parmetros da
funo. Estes existem independentemente das variveis
que foram passadas. Eles tomam apenas uma cpia do
valor passado, e se esse valor for alterado o valor dos argumentos passados no so alterados. Ou seja, no so
alterados os valores dos parmetros fora da funo. Este
tipo de chamada de funo denominado chamada (ou
passagem de parmetros) por valor.
Dito de outra maneira. Passamos a varivel a, ela entra
na denio da funo como copia de a e entra como
varivel b. Se a varivel b for alterada no decorrer da
funo, o valor de a no alterado.

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).

#include <stdio.h> oat quadrado(oat num); //prottipo


da funo quadrado() int main () { oat num, res;
//declaro 2 variveis: num , res printf(Entre com um
numero: "); scanf("%f, &num); //associo o valor
inserido varivel num res = quadrado(num); //chamo a
funo quadrado e passo o parmetro num printf("\n\nO
numero original e: %f\n, num); printf(e seu quadrado
vale: %f\n, res); getchar(); return 0; } oat quadrado 17.8 Recursividade
(oat num) //descrio da funo quadrado { return num
Uma funo pode chamar a si prpria. Uma funo assim
* num; //retorna num ao quadrado }
chamada funo recursiva. H vrias operaes mateQuando a funo main() executada, ela chega a meio mticas recursivas, das quais exemplos bem conhecidos
e v uma chamada para a funo quadrado() e onde so a seqncia de Fibonacci e o fatorial.
passado o parmetro num. Ela j estava a espera, pois Daremos o exemplo do clculo do fatorial de um nmero,
viu o prottipo. Ela ento vai executar a funo que denido como o produto de todos os nmeros naturais
est depois da funo do main(). E o que acontece que (no nulos) menores ou iguais a ele por exemplo, 5!

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 17. PROGRAMAR EM C/FUNES

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.

A diferena entre se usar "" e <> somente a ordem de


procura nos diretrios pelo arquivo especicado. Se voc
quiser informar o nome do arquivo com o caminho completo, ou se o arquivo estiver no diretrio de trabalho,
use arquivo. Se o arquivo estiver nos caminhos de procura pr-especicados do compilador, isto , se ele for
um arquivo do prprio sistema (como o caso de arquivos como stdio.h, string.h, etc...), use <arquivo>.

Portanto, o pr-processador modica o programa fonte,


que ainda no estaria pronto para ser entregue ao compilador. Todas as diretivas de compilao so iniciadas
pelo caractere # (sharp). As diretivas podem ser colocadas em qualquer parte do programa, mas no podem ser
colocadas na mesma linha que outra diretiva ou instruo.

18.2.2 #dene

As principais diretivas de compilao so:

#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-

Toda vez que o pr-processador encontrar


nome_da_constante no cdigo a ser compilado, ele
deve substitu-lo por valor_da_constante.

#ifdef
#ifndef

Toda vez que o pr-processador encontrar


nome_da_macro(parmetros), ele deve substituir por expresso_de_substituio, tambm
substituindo os parmetros encontrados na expresso de substituio; funciona mais ou menos como
uma funo. Veja o exemplo para entender melhor.

#if
#else
#elif
#endif

Exemplo 1:

18.2 Diretivas de compilao


18.2.1

#include

#include <stdio.h> #dene PI 3.1416 #dene VERSAO


2.02 int main () { printf (Programa verso %s\n,
VERSAO); printf (O numero pi vale: %f\n, PI); return
0; }

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

CAPTULO 18. PROGRAMAR EM C/PR-PROCESSADOR

Quando voc utiliza a diretiva #dene, nunca deve haver


espaos em branco no identicador (o nome da macro).
Por exemplo, a macro #dene PRINT (i) printf(" %d \n,
i) no funcionar corretamente porque existe um espao
em branco entre PRINT e (i).

18.2.3

#undef

A diretiva #undef tem a seguinte forma geral:


#undef nome_da_macro
Ela faz com que a macro que a segue seja apagada da
tabela interna que guarda as macros. O compilador passa
a partir deste ponto a no conhecer mais esta macro.

18.2.4

#ifdef e #ifndef

O pr-processador tambm tem estruturas condicionais.


No entanto, como as diretivas so processadas antes de
tudo, s podemos usar como condies expresses que
envolvam constantes e smbolos do pr-processador. A
estrutura ifdef a mais simples delas:
#ifdef nome_do_smbolo cdigo ... #endif

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).

18.3 Usos comuns das diretivas


Um uso muito comum das diretivas de compilao em
arquivos-cabealho, que s precisam/devem ser includos
uma vez. Muitas vezes inclumos indiretamente um arquivo vrias vezes, pois muitos cabealhos dependem de
outros cabealhos. Para evitar problemas, costuma-se envolver o arquivo inteiro com um bloco condicional que s
ser compilado se o arquivo j no tiver includo. Para
isso usamos um smbolo baseado no nome do arquivo.
Por exemplo, se nosso arquivo se chama cabecalho.h,
comum usar um smbolo com o nome CABECALHO_H:

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

A diretiva #if tem a seguinte forma geral:


#if expresso cdigo ... #endif
A sequncia de declaraes ser compilada apenas se a
expresso fornecida for verdadeira. muito importante
ressaltar que a expresso fornecida no pode conter nenhuma varivel, apenas valores constantes e smbolos do
pr-processador.

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

#include <stdio.h> #include <stdlib.h> int main() { int


ch; ch = getchar(); while(ch != 'x') { if(ch != '\n') {
printf(O caractere era %c, e o valor %d\n, ch, ch); ch
= getchar(); } } return 0; }

19.1 Questes
O que faz o seguinte programa?

#include <stdio.h> int main() { int x = 4; scanf("%d,


&x); printf("%d, 2*x); getchar(); }
19.2.4

Escreva um programa que comea pedindo um nmero N


ao usurio e depois pede N nmeros. O programa dever
mostrar na tela todos esses nmeros ordenados do menor
para o maior. Escreva sua prpria funo de ordenao.

19.2 Escrevendo programas


19.2.1

Exerccio 1

Escreva uma funo que pea dois nmeros inteiros ao


usurio e exibe o valor soma seguido pelo maior deles.

19.2.2

Exerccio 4

Exerccio 2

Faa um programa que converta Celsius para Fahrenheit.


#include <stdio.h> #include <stdlib.h> #dene FERVENDO 212 /* graus Fahrenheit */ int main() {
oat var_long; double var_double; long double
var_long_double; int i; i = 0; printf(Fahrenheit
para Celsius\n);
while(i <= FERVENDO) {
var_long_double = 5*(i-32); var_long_double =
var_long_double/9; var_double = var_long_double;
var_long = var_long_double; printf("%d %f %f %lf\n,

#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

CAPTULO 19. PROGRAMAR EM C/EXERCCIOS

Exerccio 5

19.2.7 Exerccio 7

#include <stdio.h> #include <stdlib.h> int main() {


Faa um programa que encontra a raiz quadrada apro- int este_car, qtd_virgulas, qtd_pontos; qtd_virgulas =
ximada de um nmero. Para isso, use um dos mtodos qtd_pontos = 0; este_car = getchar(); while(este_car !=
existentes.
EOF) { if(este_car == '.') qtd_pontos = qtd_pontos+1;
#include <stdio.h> #include <stdlib.h> #dene DELTA if(este_car == ',') qtd_virgulas = qtd_virgulas+1;
0.0001 int main() { double raiz_quad(double); /* pro- este_car = getchar(); } printf("%d virgulas, %d ponttipo */ int i; for(i = 1; i < 100; i++) { printf(Raiz tos\n, qtd_virgulas, qtd_pontos); return 0; }
de %d e' %f\n, i, raiz_quad(i)); } return 0; } double
raiz_quad(double x) { /* denio */ double aprox_atual,
ult_aprox, dif; ult_aprox = x; dif = DELTA+1;
while(dif > DELTA) { aprox_atual = 0.5*(ult_aprox + 19.2.8 Exerccio 8
x/ult_aprox); dif = aprox_atual - ult_aprox; if(dif < 0) dif
= -dif; ult_aprox = aprox_atual; } return(aprox_atual); #include <stdio.h> #include <stdlib.h> int main() { int
} void func_chamada(int, oat); int main() { i; for(i = 0; i <= 10; i++) { switch(i) { case 1: case 2:
func_chamada(1, 2*3.5); exit(EXIT_SUCCESS); } printf(1 or 2\n); break; case 7: printf(7\n); break;
void func_chamada(int arg_int, oat arg_oat) { oat default: printf(default\n); } } int i, j; for(i=0, j=0; i <=
10; i++, j = i*i) { printf(i %d j %d\n, i, j); } /* * Neste
temp; temp = arg_int * arg_oat; }
exemplo, todos os valores constantes, * exceto o ltimo,
so descartados * Note o uso dos parntesis para forar
uma * expresso vrgula em uma chamada de funo */
printf(Overall: %d\n, (abc, 1.2e6, 4*3+2)); return
EXIT_SUCCESS; }

19.2.6

Exerccio 6

O cdigo abaixo gera nmeros primos.


#include <stdio.h> int main() { int x,y, comp; int saida
= 1; while(saida==1) { comp=0; printf(Entre com o
numero inteiro para o teste\n\n); scanf("%d,&x);
for(y=1;y<=x;y++) { if(x%y==0) { comp++;
//prinf("%d,x);
} } if((comp>2)||(x==1)) {
printf("\n\nO numero %d, nao e primo\n,x); }
else { printf("\n\nO numero %d, e primo\n,x); }
printf("\n\nPara fazer um outra vericacao digite
1,\ncaso contrario digite outro numero qualquer);
scanf("%d,&saida); } }
Cdigo mais simples e fcil de entender. Vale a pena testar!
// Por Warley V. Barbosa #include <stdio.h> int main()
{ int num, primo, i, res; do { printf(Digite um nmero
(0 para encerrar): \n); scanf("%d, &num); primo = 1;
for (i = 2; i < num; i++) /* repete a partir do nmero
dois e vai at o nmero anterior de 'num', incrementando
varivel i a cada repetio */ { if (num % i == 0) { //
se o resto do 'num' por 'i' for zero o nmero no primo
primo = 0; break; // pula para a instruo seguinte } } if
((primo) && (num > 1)) // 1 no primo! nem zero...
printf(O nmero %d primo! \n, num); else printf(O
nmero %d no primo... \n, num); } while (num !=
0); // encerra quando usurio digitar 0 }

1. Repare que se no tivssemos colocado o comando


break, o programa continuaria a varrer os case seguintes.
Retire este comando e use outras instrues no seu lugar

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:

#include <stdio.h> #include <stdlib.h> int expr(void); int


mul_exp(void); int unary_exp(void); int primary(void);
int main() { int val; for(;;) { printf(expression: ");
val = expr(); if(getchar() != '\n') { printf(error\n);
while(getchar() != '\n'); /* nada */ } else { printf(result
is %d\n, val); } } return 0; } int expr(void) { int
val, ch_in; val = mul_exp(); for(;;) { switch(ch_in =
getchar()) { default: ungetc(ch_in,stdin); return(val);
case '+': val = val + mul_exp(); break; case '-': val =
Partindo deste cdigo, tente criar um que some o ltimo val - mul_exp(); break; } } } int mul_exp(void) { int
primo resultante com o anterior.
val, ch_in; val = unary_exp(); for(;;) { switch(ch_in =

19.2. ESCREVENDO PROGRAMAS


getchar()) { default: ungetc(ch_in, stdin); return(val);
case '*': val = val * unary_exp(); break; case '/': val = val
/ unary_exp(); break; case '%': val = val % unary_exp();
break; } } } int unary_exp(void) { int val, ch_in;
switch(ch_in = getchar()) { default: ungetc(ch_in, stdin);
val = primary(); break; case '+': val = unary_exp();
break; case '-': val = -unary_exp(); break; } return(val);
} int primary(void) { int val, ch_in; ch_in = getchar();
if(ch_in >= '0' && ch_in <= '9') { val = ch_in - '0';
goto out; } if(ch_in == '(') { val = expr(); getchar(); /*
skip closing ')' */ goto out; } printf(error: primary read
%d\n, ch_in); exit(EXIT_FAILURE); out: return(val);
}

19.2.11

Exerccio 11

Esse programa converte um inteiro em bytes e depois realiza a operao inversa.


Faa um programa que converte um short em bytes.
#include <stdio.h> int main (void) { unsigned char
bytes[4]; /* Aqui o ndice indica o nmero de elementos */ unsigned long n = 123000; bytes[0] =
(n >> 24) & 0xFF; bytes[1] = (n >> 16) & 0xFF;
bytes[2] = (n >> 8) & 0xFF; bytes[3] = n & 0xFF;
int i; char b[500]; sprintf(b,"0 = %d, 1 = %d, 2 =
%d, 3 = %d,bytes[0],bytes[1],bytes[2],bytes[3]); int
inteiro = (bytes[0]<<24)+(bytes[1] << 16)+(bytes[2]
<< 8)+bytes[3]; printf(bytes %s\n,b); printf(int =
%i\n,inteiro); getchar(); }

51

Captulo 20

Programar em C/Vetores
20.1 Vetores

20.1.1 Abreviando as declaraes

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.

int vetor[5] = {17, 42, 9, 33, 12};


Para fazer referncia a um valor de um elemento contido
20.2 Vetores
multidimensionais
em um vetor, usamos a notao vetor[ndice], que serve
tanto para obter quanto para denir o valor de um ele(matrizes)
mento especco, dada sua posio. Note que os elementos so numerados a comear do zero, e, portanto, se o Podemos declarar ainda mais variveis
nmero de elementos N , o ndice ou posio do ltimo
tipo_da_varivel nome_da_varivel [altura][largura];
elemento ser N 1 .
vetor[0] = 3; int x = vetor[2]; int y = vetor[5]; // ERRO! Ateno que:
Repare em que a ltima linha contm um erro: ela referencia um elemento do vetor que no existe. No entanto,
o compilador no se recusar a compilar esse cdigo; dar
apenas um aviso. Se essa linha for executada, a varivel
y receber um valor que no tem nada a ver com o vetor.
52

ndice mais direita varia mais rapidamente que o


ndice esquerda.
No esquecer os ndices variam de zero ao valor declarado menos um.

20.3. ARGUMENTOS NA FUNO MAIN

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 Argumentos na funo main


Na seo Funes, dissemos que a funo main() aceita
dois argumentos, mas no falamos mais pois um deles
envolve o conceito de vetores. Agora iremos falar mais
sobre eles.
Os dois argumentos de main() indicam os argumentos dados para o programa na linha de comando, na forma de
um vetor de strings.

20.3.1

Exemplo de uso de parmetros na


funo main

// somaComArgcArgv.c #include<stdio.h> #include<stdlib.h> int main(int argc, char *argv[]) {


int result; if ( argc != 3 ) { printf(Digite soma <valor1>
<valor2>\n); return 0; } // m if ( argc != 3 ) result =
atoi(argv[1]) + atoi(argv[2]); printf("\nO resultado da

Captulo 21

Programar em C/Strings
21.1 Strings

21.2.1 strlen

Strings (Ingls) so cadeias ou seqncias ordenadas de


caracteres. Na verdade j trabalhamos com strings neste
livro, mas preferimos deixar maiores explicaes para um
momento em que j tivesse sido introduzido o conceito de
vetor.

strlen retorna o tamanho, em caracteres, de uma string


dada. Na verdade o strlen() procura o terminador de
string e calcula a distncia dele ao incio da string. Por
exemplo:

char nome[15] = Maria da Silva"; int s = strlen (nome);


A linguagem C, ao contrrio de outras linguagens de pro- // s conter o valor 14
gramao, no possui um tipo de dados correspondente /*TL'*/
s strings; no lugar, usam-se vetores (e ponteiros, como
veremos mais adiante). Em C, strings so vetores de caracteres terminados pelo caractere nulo ('\0'). Por exem- 21.2.2 strcpy
plo:
strcpy copia o contedo de uma string para outra e coloca
um terminador de string. Sua sintaxe strcpy (destino,
No entanto, escrever strings dessa maneira muito traorigem).
balhoso; por isso, foi criada uma notao abreviada que
equivale notao acima e elimina a necessidade de co- char nome[] = Clarice Lispector"; char nome2[] =
Oswald de Andrade"; strcpy (nome, nome2); // agora
locar o caractere terminador:
nome conter Oswald de Andrade
char nome[] = Pedro";
Tome cuidado com strcpy(), pois se a string a ser coAssim como nos vetores, podemos acessar e modicar
piada for maior que a string de destino, provavelmente
elementos individuais de uma string. Podemos tambm
voc gravar dados em lugares indesejados um prodiminuir o tamanho de uma string: uma vez que a nica
blema conhecido como estouro de buer. Para evitar
marcao do tamanho o terminador \0, colocar um
esse problema, use a funo strncpy, que recebe um terterminador em outro local determinar o novo nal da
ceiro argumento que corresponde ao nmero mximo de
string. No entanto, aumentar o tamanho da string mais
caracteres a serem copiados:
difcil; isso car para outra seo.
char msg[] = Bom dia!"; char nome[] = Maria da Silva";
Ateno ao usar-se acentos numa string. Como existem
strncpy (msg, nome, strlen(msg)); // agora msg conter
diferentes formas de codicar caracteres acentuados, o
Maria da
tratamento de uma string do tipo:
char nome[] = {'P', 'e', 'd', 'r', 'o', '\0'};

char nome[] = Joo";


pode ser diferente de uma mquina para outra. Neste ca- 21.2.3 strcat
ptulo no sero tratados acentos, este assunto ser aborstrcat concatena duas strings, adicionando o contedo da
dado mais adiante.
segunda ao nal da primeira, alm do terminador (\0).
Note que a primeira string deve ter espao suciente para
a segunda, para que no ocorra um estouro de
21.2 Funes da biblioteca padro conter
buer. Por exemplo:
A biblioteca padro fornece vrias funes teis para manipular strings. A seguir mostraremos algumas delas.
Para us-las, voc deve incluir o cabealho string.h no
incio dos seus arquivos.

char nome[50] = Maria"; char sobrenome[] = " da Silva";


strcat (nome, sobrenome); // agora nome contm Maria
da Silva
Analogamente funo strncpy, existe tambm a funo

54

21.2. FUNES DA BIBLIOTECA PADRO

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

Se voc tentar criar duas strings com o mesmo contedo


e compar-las como faria como nmeros, ver que elas
no so iguais. Isso ocorre porque, na verdade, o que
est sendo comparado so os endereos de memria onde
esto guardadas as strings. Para comparar o contedo de
duas strings, voc deve usar a funo strcmp (ou suas
variantes):
int strcmp (char *s1, char *s2);
O valor de retorno :

Descrio: Copiar um bloco de n octetos de srce para


dest.
Ateno:Se as regies de srce e dest se sobreporem o
comportamento da funo imprevisvel.
Valor de retorno : memcpy retorna o valor de dest .
Ex:
#include <stdio.h> #include <string.h> int main() {
int tab[2][5] = { { 1, 2, 3, 4, 5}, {11, 12, 13, 14, 15}
}; int temp[2][5]; memcpy(temp, tab, sizeof(tab));
puts(Resultado:\n); printf(temp[1][4] = %d\n,
temp[1][4]); return 0; }

menor que zero se s1 for menor que s2;


igual a zero se s1 e s2 so iguais;
maior que zero se s1 for maior que s2.
Costuma parecer estranho dizer que uma string menor
ou maior que outra; na verdade essa comparao entre
a primeira letra que difere nas duas strings. Assim, se
tivermos s1 = abc e s2 = abd, diremos que s2 maior
que s1, pois na primeira posio em que as duas strings
diferem, a letra em s2 maior.

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.

Valor de retorno : O valor do buer.


importante notar que a comparao feita por strcmp
distingue maisculas de minsculas. Isto , as strings
Ex:
ABC e abc no so iguais para essa funo.
#include <stdio.h> #include <string.h> int main() { char
As variantes mais usadas de strcmp so:
buf[] = W.I.K.I."; printf(Buf antes 'memset': %s\n,
buf); memset(buf, '*', strlen(buf)); printf(Buf depois
strncmp - compara apenas os n primeiros caracteres 'memset': %s\n, buf); return 0; }
das duas strings, sendo n um terceiro argumento.
stricmp - compara duas strings sem distino entre maisculas e minsculas. A sintaxe igual de
21.2.8 sprintf
strcmp. Essa funo no faz parte da biblioteca padro, mas comumente encontrada como extenso
Descrio: A diferena entre printf e sprintf e que printf
particular de vrias delas.
retorna o resultado para a sada padro (tela), enquanto
sprintf retorna o resultado em uma varivel. Isto muito
conveniente, porque voc pode simplesmente digitar a
21.2.5 strrchr
frase que voc quer ter e sprintf lida com a prpria constrrchr Retorna um ponteiro sobre a ultima ocorrncia verso e coloca o resultado na string que voc deseja.
de c de uma string apontada por s se no retorna NULL . Sintaxe:
Sua sintaxe strrchr(const char *s, int c);.
#include <stdio.h> int sprintf(char *s, const char *forExemplo:
mato, ...);
char path[50] = "/teste/string"; char *p = strrchr(path, '/');
*p++; printf(Resultado: %s \n, p );
Ex:

21.2.6
Sintaxe:

memcpy

#include <stdio.h> #include <string.h> int main() { char


var[256]; char sobrenome[] = Simpson"; char nome[]
= Homer"; int idade = 30; sprintf(var, "%s %s tem
%d anos,sobrenome, nome, idade); printf (Resultado :

56
%s\n, var); return 0; }

CAPTULO 21. PROGRAMAR EM C/STRINGS

Captulo 22

Programar em C/Passagem de parmetros


22.1 Passagem de Parmetros

E argv arguments values : Vamos dizer que cada


argv[] um nome de parmetro.

Esta explicao para quem compila com o GNU gcc.


O que so parmetros?
Com os programas em interface grca usa-se botes ou
cones.
Quando utiliza-se os parmetros com o console ou
prompt os parmetros so reconhecidos como opes.
Para quem usa sistemas do tipo Unix como o Linux,
onde o console no banalizado como em outros SOs,
mais fcil de se entender.
Imagine que exista um programa cujo nome Calcular
e que ele serve para executar operaes aritmticas.
Pense agora na sua execuo no shell.

Ento temos um que nos da a quantidade de


parmetros e outro que nos da os nomes de cada
parmetro ou opo.

So nomes tradicionais eles podem ser modicado para


outros nomes desde que os tipos continuem sendo os mesmos.
Exe:
NOME opao1 opao2 opao3 : argc = 4 $./Calcular somar depois restar : argv[] vai de argv[0] a argv[3]
Aqui argc igual a 4.

$./Calcular restar

argv[] na realidade uma tabela de ponteiros exe:


Calcular o nome, a chamada ao seu programa, enargv[0] e igual a '.' '/' 'C' 'a' 'l' 'c' 'u' 'l ' 'a' 'r' '/0' Calcular
quanto que restar um parmetro, uma opo.
Esse programa pode comportar vrios parmetros como argv[1] e igual a 's 'o' 'm' 'a' 'r' '/0' somar
somar, subtrair e multiplicar, por exemplo.
Exemplo:
/*----------------------------Parmetros.c-----------------------------*/ #include <stdio.h> /* igual a int main(int
argc, char *argv[]) */ int main(int argument_count,
char *argument_value[]) { int i; printf(Nome do
Programa :%s\n, argument_value[0] ); for (i = 1 ; i <
argument_count; i++) printf(Parmetros passados %d :
%s\n, i, argument_value[i]); /* De um enter no m*/ }
Para compilar:
user@SO:/meu_diretotio\protect\char"0024\relax
Parametros.c -o Argumentos

gcc

Como diramos s passar alguns argumentos para o


compilador ;)
Examinando o cdigo
Vamos dar uma olhada na funo main(int argc, char
*argv[]) vocs podem remarcar os nomes:

argc argument count : Conta o numero de argumentos incluindo o nome do programa.


57

Captulo 23

Programar em C/Tipos de dados denidos


pelo usurio
23.1 Tipos de dados denidos pelo
usurio

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);

23.2.1 Denindo o tipo

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.

struct mystruct variavel = {4, 6, 5, 3.14, 2.718, 0.95,


58

23.3. UNIES
Teste"}; struct mystruct v2 = {9, 5, 7};

59

23.2.7 Passando para funes

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

No entanto, h dois possveis problemas nisso:

23.2.4

Acessando

Para acessar e modicar os membros de uma estrutura,


usamos o operador de seleo. (ponto). esquerda do
ponto deve estar o nome da varivel (estrutura) e direita,
o nome do membro. Podemos usar os membros como variveis normais, inclusive passando-os para funes como
argumentos:
variavel.a = 5; variavel.f = 6.17; strcpy (variavel.string,
Bom dia); printf ("%d %f %s\n, variavel.a, variavel.f,
variavel.string);

23.2.5

Vetores de estruturas

Sendo as estruturas como qualquer outro tipo de dados,


podemos criar vetores de estruturas. Por exemplo, suponha algum programa que funcione como um servidor
e permita at 10 usurios conectados simultaneamente.
Poderamos guardar as informaes desses usurios num
vetor de 10 estruturas:

Alteraes nos membros da estrutura s tero efeito


dentro da funo chamada, mas no na funo que a
chamou. Isso ocorre pois a estrutura passada por
valor (e no por referncia).
Quando a estrutura contiver muitos elementos, a
passagem por valor tornar-se- um processo de cpia de muitos dados. Por isso, de costume passar
estruturas por referncia (como ponteiros), mesmo
que a estrutura em questo seja pequena.

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

CAPTULO 23. PROGRAMAR EM C/TIPOS DE DADOS DEFINIDOS PELO USURIO

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

Da mesma maneira que criamos uma varivel de um tipo


struct ou union, podemos criar variveis de um tipo enumerado (enum):
enum cores cor_fundo;
Para atribuir valores a uma varivel enumerada, podemos
usar como valor tanto o identicador quanto o valor correspondente. Seriam equivalentes, portanto:
cor_fundo = VERDE; cor_fundo = 6;
Na verdade, variveis enumeradas agem de maneira
quase igual aos inteiros; possvel, assim, atribuir valores
que no correspondem a nenhum dos identicadores.

23.5 Campo de bits


Na linguagem c o campo de bits (bitelds) uma estrutura
um pouco estranha , em vez de usar variveis com tipos
diferentes os campos so formados com as partes de um
inteiro. O tamanho de um campo de bits no pode ser
maior que o tipo usado , aqui um short .
typedef struct { unsigned short campo_1: 6, /* Tamanho
6 bit */ campo_2: 6, campo_3: 1, campo_4: 1, campo_5:
2; }BIT_FIELD_1;

Captulo 24

Programar em C/Enumerao
24.1 Enumerations (enum)

#include <stdio.h> /*Denindo o cabealho*/ enum


cores { AZUL = 1, VERDE, BRANCO, }; /*Aqui um
ponto virgula*/ /*typedef transformamos 2 palavras em
Aqui vamos retornar a um tpico antigo.
uma -> tipo_cores*/ typedef enum cores tipo_cores ;
Enumerations so um outro mtodo de denir constantes. /*A funo default da lib ou glibc*/ int main(void) {
Recordam-se? Tnhamos o:
/*Agora usando o nosso novo tipo * Aqui sem typedef
teramos que colocar enum cores */ tipo_cores cor =
VERDE ; if(cor == 1) { printf(Cor azul \n); } if(cor
1. #dene
== 2) { printf(Cor verde \n); } /* printf no ser
executado */ if(cor == 3 ) { printf(Cor branco \n); }
2. const int a = 1;
return 0 ; /*De um enter depois de } para evitar warning
*/ }
3. enumerations.
Aqui podemos ver um exemplo com uma funo
mostrarRes()" e um switch:
Em este exemplo uma constante e denida e o valor das
outra ser denido automaticamente.

24.2 Criando um novo tipo de dados

#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

// Uso regular book.price.dollars book.price.yens // Uso


anonimo book.dollars book.yens

As unions so muito parecidas com as estruturas, estas


guardam variveis de vrios tipos, e portanto guardam
cada varivel de acordo com a seu tipo, ie, se tivermos
uma varivel membro que um int e outro oat, ela
guarda exatamente de acordo com esse tipo.
O que se passa aqui que vai guardar as variveis todas
com um nico tipo, que aquele que ocupa mais espao
dentro dos tipos das variveis membro, ou seja, se tivermos uma varivel membro int e outra oat , a union vai
guardar estas variveis como fossem as duas oat.

25.2 Declarao
union mytypes_t { int i; oat f; } mytypes;

25.3 Unions com estruturas


Neste exemplo temos unions e estruturas misturados.
union mix_t { long l; struct { short hi; short lo; } s; char
c[4]; } mix;
Repare que a estrutura no tem nome

25.4 Anonymous unions estruturas com unions


// estrutura usando regular union struct { char title[50];
char author[50]; union { oat dollars; int yens; } price;
} book; // estrutura usando anonymous union struct {
char title[50]; char author[50]; union { oat dollars; int
yens; }; } book;
Se declararmos uma unio sem nome, ela vai car annima e poderemos acessar seus membros diretamente
atravs dos nomes dos membros.
62

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:

26.2 Declarar uma estrutura

struct minha_estrutura chas [100];

A sintaxe :

Poderamos ento acessar um campo dando um ndice do


vetor chas:

struct <identicador> { <tipo> campo_um ; <tipo> chas[12].variavel_um;


campo_dois ; };
Aqui o tipo struct indica que vamos criar uma estrutura. O nome ou identicador pode ser alunos, fam- 26.4 Declarar instncias (objetos)
lia, etc . (tm de ser vlidos identiers) No esquecer
da estrutura
o ponto e vrgula ; no m da declarao. Campo_um
e Campo_dois so variveis membro member variables
Podemos declarar os objetos de duas formas:
ou campo da estrutura.
Assim criamos novos tipos de dados.

Ao mesmo tempo que declaramos a estrutura

Primeiro mtodo:
struct minha_estrutura { int
campo_dois; char fruta[40]; } ;

variavel_um;

int struct product { int weight; oat price; } apple, banana,


melon;

Aqui o identicador do tipo struct minha_estrutura


dentro dessa estrutura temos trs campos o ultimo
fruta

Ou como uma varivel normal

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

CAPTULO 26. PROGRAMAR EM C/ESTRUTURAS

Para cada objeto vo ser feito uma cpia dos elementos


da estrutura.

26.7 Ponteiros para estruturas

Agora isso signica que os objetos so distintos entre si


em termos de reserva de memria? ie, medida que
enumero os objetos vo ser reservado para cada objeto
o tamanho x de bytes? ou somam-se todos os objetos e
reserva-se para todos os objetos de uma forma seguida?
Penso que deve ser a 1 opo.

struct movies_t { string title; int year; }; movies_t amovie;


movies_t * pmovie;
Ns crimos algo
movies_t title year amovie * pmovie
Vejamos que temos um ponteiro como instncia.

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; }

26.5 Acessar as variveis membro


das estruturas

Como j devem ter deduzido o operador -> ser muito


similar a pmovie->title equivalente a (*pmovie).title
Mas olhem que diferente a:
*pmovie.title que equivalente a *(pmovie.title)

Agora queremos dar valores a cada uma das pessoas, queremos dar o nome e a altura, para isso faramos;
A forma genrica :

26.8 Passando estruturas como argumento de funes

structure-varname.member-name

A estrutura passada como ponteiro.

ou seja

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


{ string name; int height; }; void setValues(Person*);
void getValues(const Person*); int main () { Person
p1; setValues(&p1); printf(Outputting person data\n);
printf("======================\n);
getValues(&p1); return 0; } void setValues(Person* pers) {
printf(Enter persons name: "); fgets(pers.name, 100,
stdin); printf(Enter height in inches: "); scanf("%d,
&pers.height); } void getValues(const Person* pers)
{ printf(Persons name is %s and height is %d.,
pers.name, pers.height); }

strcpy(p1.name, Tiago); p1.altura =1.9;

[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; }

26.9 Estruturas aninhadas


A ideia ter uma estrutura dentro de outra estrutura.

26.6 Iniciar uma estrutura


Podemos iniciar uma estrutura usando uma lista de iniciao, que seria algo como:
Person p1 = {"Je Kent, 72};
isto basicamente igual a arrays, apenas com a diferena
de termos tipos diferentes. Logo a ordem vai interessar,
por exemplo se escrevssemos
Person p1 = {72, Je Kent"}; //no iria funcionar- erro
de compilao

#include <stdio.h> struct Date //estrutura chamada de


date { int day; int month; int year; }; struct Person { char
name[100]; int height; Date bDay; //temos uma nova
varivel, mas notem o tipo }; void setValues(Person*);
void getValues(const Person*); int main () { Person
p1; setValues(&p1); printf(Outputting person data\n);
printf("======================\n);
getValues(&p1); return 0; } void setValues(Person* pers) {
printf(Enter persons name: "); fgets(pers.name, 100,
stdin); printf(Enter height in inches: "); scanf("%d,
&pers.height); printf(Enter day, month and year of
birthday separated by spaces: "); scanf("%d %d %d\n,

26.9. ESTRUTURAS ANINHADAS


&pers.bDay.day, &pers.bDay.month, &pers.bDay.year
); } void getValues(const Person* pers) { printf(Persons
name: %s\n, pers.name); printf(Persons height in inches is: %d\n, pers.height); printf(Persons birthday in
dd/mm/yyyy format is: %d/%d/%d\n, pers.bDay.day,
pers.bDay.month, pers.bDay.year ); }
Reparem que a estrutura Date tem de ser declarada antes
da estrutura Person, pois caso contrrio o compilador no
entenderia o tipo declarado na estrutura Person.
Pergunta: Por que no podemos acrescentar mais membros (campos) nas estruturas?
Porque elas so compiladas estaticamente com posio
de memria j alocada e tipo j conhecido em tempo de
compilao
Pergunta: Ao invs de termos apenas variveis nas estruturas, poderamos ter tambm funes?
Sim, como ponteiros para funes.

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

endereo de uma varivel, utilizamos o operador & (E


comercial), chamado operador de referncia ou opeUm ponteiro simplesmente uma varivel que armazena rador de endereo. Como o nome sugere, ele retorna o
endereo na memria de seu operando. Ele unrio e
o endereo de outra varivel.
deve ser escrito antes do seu operando. Por exemplo, se
Um exemplo : O que o ponteiro de um relgio? o que uma varivel nome foi guardada no endereo de memria
aponta para as horas, minutos ou segundos. Um ponteiro 1000, a expresso &nome valer 1000.
aponta para algo. Em programao, temos as variveis
armazenadas na memria, e um ponteiro aponta para um Com isso, ca claro o esquema ao lado: a varivel a contm o valor 1234 e o ponteiro p contem o endereo de a
endereo de memria.
(&a).
Imagine as variveis como documentos, a memria do
computador como pastas para guardar os documentos, e Para atribuir um valor ao ponteiro, usamos apenas seu
nome de varivel. Esse valor deve ser um endereo de
o ponteiro como atalhos para as pastas.
memria, portanto obtido com o operador &:
No se desespere caso no consiga entender num primeiro
int a; int *p; p = &a;
momento, o conceito ca mais claro com a prtica.
Claro que tambm podemos inicializar um ponteiro:

27.1.1

O que um ponteiro?

27.1.2

Declarando e acessando ponteiros

int *p = &a;

Nos dois casos, o ponteiro p ir apontar para a varivel a.


Um ponteiro, como qualquer varivel, deve ter um tipo,
que o tipo da varivel para a qual ele aponta. Para de- Mas, como o ponteiro contm um endereo, podemos
clarar um ponteiro, especicamos o tipo da varivel para tambm atribuir um valor varivel guardada nesse endea qual ele aponta e seu nome precedido por asterisco: reo, ou seja, varivel apontada pelo ponteiro. Para
isso, usamos o operador * (asterisco), que basicamente
int ponteiro ; /* declara uma varivel comum do tipo in- signica o valor apontado por.
teiro */ int *ponteiro ; /* declara um ponteiro para um Ex:
inteiro */
int a ; int *p = &a ; *p = 20 ;
Tome cuidado ao declarar vrios ponteiros em uma linha,
pois o asterisco deve vir antes de cada nome de varivel. Para ver o resultado :
printf (" a :%i\n, a); printf ("*p :%i\n, *p);
Note os trs exemplos:
int p, q, r; // estamos a declarar trs variveis comuns int
*p, q, r; // cuidado! apenas p ser um ponteiro! int *p, Cuidado! Voc nunca deve usar um ponteiro sem antes
66

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

CAPTULO 27. PROGRAMAR EM C/PONTEIROS

&d; // b apontar para d *b = 8; // altero o valor existente


na variavel d *a = *b; // copio o valor de d (apontado por
b) // para c (apontado por a) *a = 1; // altero o valor da
varivel c b = a; // b aponta para o mesmo lugar que a, //
ou seja, para c *b = 0; // altero o valor de c

27.2 Intermedirio
27.2.1

Ponteiro de estrutura

temp = i; i = j; j = temp; } int main() { int a, b; a = 5; b


= 10; printf ("%d %d\n, a, b); swap (a, b); printf ("%d
%d\n, a, b); return 0; }
No entanto, o que queremos no ir acontecer. Voc ver
que o programa imprime duas vezes 5 10. Por que isso
acontece? Lembre-se do escopo das variveis: as variveis a e b so locais funo main(), e quando as passamos como argumentos para swap(), seus valores so copiados e passam a ser chamados de i e j; a troca ocorre
entre i e j, de modo que quando voltamos funo main()
nada mudou.

Para comear e deixar mais claro denimos uma estrutura


Ento como poderamos fazer isso? Como so retornados
simples com dois campos.
dois valores, no podemos usar o valor de retorno de uma
struct { int i; double f; } minha_estrutura;
funo. Mas existe uma alternativa: os ponteiros!
O passo seguinte denir um ponteiro para essa estru#include <stdio.h> void swap (int *i, int *j) { int temp;
tura.
temp = *i; *i = *j; *j = temp; } int main () { int a, b; a =
struct minha_estrutura *p_minha_estrutura;
5; b = 10; printf ("\n\nEles valem %d, %d\n, a, b); swap
A partir do ponteiro podemos ter acesso a um campo da (&a, &b); printf ("\n\nEles agora valem %d, %d\n, a,
b); return 0; }
estrutura usando um seletor "->" (uma echa).
p_minha_estrutura-> i = 1; p_minha_estrutura-> f = 1.2;
O mesmo resultado pode ser optido da seguinte forma.
(*p_minha_estrutura).i = 1; (*p_minha_estrutura).f =
1.2;
O operador cast tambm e bastante utilizado para estruturar reas de estoque temporrios (buer). Os tipos dentro da estrutura devem ser o mesmo do arranjo para evitar
problemas de alinhamento.
A seguir um pequeno exemplo:
#include <stdio.h> typedef struct estruturar{ char a
; char b ; }; int main() { char buer[2] = {17, 4};
estruturar *p; p = (struct estruturar*) &buer; printf(a:
%i b: %i, p->a,p->b); getchar(); return 0; }

27.2.2

Neste exemplo, denimos a funo swap() como uma


funo que toma como argumentos dois ponteiros para
inteiros; a funo faz a troca entre os valores apontados
pelos ponteiros. J na funo main(), passamos os endereos das variveis para a funo swap(), de modo que a
funo swap() possa modicar variveis locais de outra
funo. O nico possvel inconveniente que, quando
usarmos a funo, teremos de lembrar de colocar um &
na frente das variveis que estivermos passando para a
funo.
Se voc pensar bem, j vimos uma funo em que passamos os argumentos precedidos de &: a funo scanf()!
Por que fazemos isso? simples: chamamos a funo
scanf() para que ela ponha nas nossas variveis valores
digitados pelo usurio. Ora, essas variveis so locais, e
portanto s podem ser alteradas por outras funes atravs de ponteiros!

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); }

Em C, os elementos de um vetor so sempre guardados


sequencialmente, a uma distncia xa um do outro. Com
isso, possvel facilmente passar de um elemento a outro,
percorrendo sempre uma mesma distncia para frente ou
para trs na memria. Dessa maneira, podemos usar ponteiros e a aritmtica de ponteiros para percorrer vetores.
Na verdade, vetores so ponteiros um uso particular
dos ponteiros. Acompanhe o exemplo a seguir.

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.

#include <stdio.h> int main () { int i; int vetorTeste[3]


= {4, 7, 1}; int *ptr = vetorTeste; printf("%p\n,
vetorTeste); printf("%p\n, ptr); printf("%p\n, &ptr);
for (i = 0; i < 3; i++) { printf(O endereo do ndice %d
do vetor %p\n, i, &ptr[i]); printf(O valor do ndice
%d do vetor %d\n, i, ptr[i]); } return 0; }

Como os endereos so nmeros, eles tambm podem ser


comparados entre si. Veja o exemplo a seguir, com efeito
equivalente ao primeiro exemplo da seo anterior:

27.2.5 Comparando endereos

#include <stdio.h> int main() { int vetorTeste[3] = {4,


7, 1}; int *ptr = vetorTeste; int i = 0; while (ptr <=
&vetorTeste[2]) { printf(O endereo do ndice %d do
vetor %p\n, i, ptr); printf(O valor do ndice %d do
Comeamos declarando um vetor com trs elementos; vetor %d\n, i, *ptr); ptr++; i++; } return 0; }
depois, criamos um ponteiro para esse vetor. Mas repare que no colocamos o operador de endereo em Esse programa incrementa o ponteiro enquanto esse envetorTeste; fazemos isso porque um vetor j representa dereo for igual (ou menor) ao endereo do ltimo eleum endereo, como voc pode vericar pelo resultado da mento do vetor (lembre-se que os ndices do vetor so 0,
primeira chamada a printf().
1 e 2).
Como voc j viu anteriormente neste captulo, podemos
usar a sintaxe *(ptr + 1) para acessar o inteiro seguinte
ao apontado pelo ponteiro ptr. Mas, se o ponteiro aponta 27.3
para o vetor, o prximo inteiro na memria ser o prximo elemento do vetor! De fato, em C as duas formas
27.3.1
*(ptr + n) e ptr[n] so equivalentes.
No necessrio criar um ponteiro para usar essa sintaxe;
como j vimos, o vetor em si j um ponteiro, de modo
que qualquer operao com ptr ser feita igualmente com
vetorTeste. Todas as formas abaixo de acessar o segundo
elemento do vetor so equivalentes:

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.

vetorTeste[1]; *(vetorTeste + 1); ptr[1]; *(ptr + 1)

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

Indexao estranha de ponteiros

int * p_x = &x;

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

CAPTULO 27. PROGRAMAR EM C/PONTEIROS

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

#include <stdio.h> int soma(int a, int b) { return (a + b);


Os ponteiros podem ser passados como argumentos de } int operacao(int x, int y, int (*func)(int,int)) { int g;
g = (*func)(x, y); return (g); } int main () { int m; m =
funes.
operacao(7, 5, soma); printf("%d\n, m); return 0; }
Parmetro ponteiro passando um array.
#include <stdio.h> void atribuiValores(int[], int); void
mostraValores(int[], int); int main() { int vetorTeste[3];
// crio um vetor sem atribuir valores atribuiValores(vetorTeste, 3); mostraValores(vetorTeste, 3); return
0; } void atribuiValores(int valores[], int num) { for (int
i = 0; i < num; i++) { printf(Insira valor #%d: ", i +
1); scanf("%d, &valores[i]); } } void mostraValores(int
valores[], int num) { for (int i = 0; i < num; i++) {
printf(Valor #%d: %d\n, i + 1, valores[i]); } }

Veja que criamos uma funo que retorna a soma dos


dois inteiros a ela fornecidos; no entanto, ela no chamada diretamente. Ela chamada pela funo operacao,
atravs de um ponteiro. A funo main passa a funo
soma como argumento para operacao, e a funo operacao chama essa funo que lhe foi dada como argumento.

Note bem o terceiro argumento da funo operacao: ele


um ponteiro para uma funo. Nesse caso, ele foi
declarado como um ponteiro para uma funo que toma
dois inteiros como argumentos e retorna outro inteiro. O
Repare que passamos dois parmetros para as funes:
* indica que estamos declarando um ponteiro, e no uma
funo. Os parnteses em torno de *func so essenci1. O nome do vetor, que representa o seu endereo ais, pois sem eles o compilador entenderia o argumento
na memria. (Temos 3 maneiras para passar o ende- como uma funo que retorna um ponteiro para um inreo do vetor: diretamente pelo seu nome, via um teiro.
ponteiro ou pelo endereo do primeiro elemento.)
A forma geral para declarar um ponteiro para uma funo
2. Uma constante, que representa o nmero de elemen- :
tos do vetor. Isso importante pois o C no guarda tipo_retorno (*nome_do_ponteiro)(lista de argumeninformaes sobre o tamanho dos vetores; voc no tos)
deve tentar alterar ou acessar valores que no perPara chamar a funo apontada pelo ponteiro, h duas
tencem ao vetor.
sintaxes. A sintaxe original
claro que devemos passar o endereo do vetor (por re- (*nome_do_ponteiro)(argumentos);

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

Programar em C/Mais sobre variveis


28.1 typedef

do tipo FILE; sua composio foi apresentada apenas


como exemplo ou ilustrao.

A instruo typedef serve para denir um novo nome


para um certo tipo de dados intrnseco da linguagem
ou denido pelo usurio. Por exemplo, se zssemos a
seguinte declarao:
typedef unsigned int uint;

28.2 sizeof

poderamos declarar variveis inteiras sem sinal (unsigned int) da seguinte maneira:

O operador sizeof usado para se saber o tamanho de


variveis ou de tipos. Ele retorna o tamanho do tipo ou
varivel em bytes como uma constante. Devemos usuint numero; // equivalente a unsigned int numero;"
lo para garantir portabilidade. Por exemplo, o tamanho
Como exemplo vamos dar o nome de inteiro para o tipo
de um inteiro pode depender do sistema para o qual se
int:
est compilando. O sizeof um operador porque ele
typedef int inteiro;
substitudo pelo tamanho do tipo ou varivel no momento
Como se v, typedef cria uma espcie de apelido para da compilao. Ele no uma funo. O sizeof admite
um tipo de dados, permitindo que esse tipo seja referen- duas formas:
ciado atravs desse apelido em vez de seu identicador sizeof nome_da_varivel sizeof (nome_do_tipo)
normal.
Se quisermos ento saber o tamanho de um oat fazemos
Um dos usos mais comuns de typedef abreviar a de- sizeof(oat). Se declararmos a varivel f como oat e
clarao de tipos complexos, como structs ou estruturas. quisermos saber o seu tamanho faremos sizeof f. O opeVeja este exemplo:
rador sizeof tambm funciona com estruturas, unies e
struct pessoa { char nome[40]; int idade; }; struct pessoa enumeraes.
joao;

Outra aplicao importante do operador sizeof para se


Observe que, para declarar a varivel joao, precisamos saber o tamanho de tipos denidos pelo usurio. Seescrever a palavra struct. Podemos usar typedef para ria, por exemplo, uma tarefa um tanto complicada a de
alocar a memria para um ponteiro para a estrutura abreviar essa escrita:
cha_pessoal, criada na primeira pgina desta aula, se no
typedef struct _pessoa { char nome[40]; int idade; } Pes- fosse o uso de sizeof. Veja o exemplo:
soa; Pessoa joao;
typedef struct { const char *nome; const char *soUm apelido de tipo utilizado com bastante frequn- brenome; int idade; } Pessoa; int main(void) { Pessoa
cia, embora no costumemos dar por isso: o tipo FILE, *joaquim; joaquim = malloc(sizeof(Pessoa)); joaquimusado nas funes de entrada/sada de arquivos.
>nome = Joaquim"; joaquim->sobrenome = Silva";
typedef struct _iobuf { char* _ptr; int _cnt; char* _base; joaquim->idade = 15; }
int _ag; int _le; int _charbuf; int _bufsiz; char* _tmpfname; } FILE;
Outro exemplo:
Ento, quando declaramos algo como

#include <string.h> #include <stdio.h> int main(void)


{ char *nome; nome = malloc(sizeof(char) *
FILE *fp;
10);
sprintf(nome,
wikibooks);
printf(Site:
na verdade estamos a declarar um ponteiro para uma es- http://pt.%s.org/", nome);
/* Imprime:
Site:
trutura, que ser preenchida mais tarde pela funo fopen. http://pt.wikibooks.org/ */ }
Ateno! Voc no deve tentar manipular uma estrutura
72

28.4. ATRIBUTOS DAS VARIVEIS

73

A sentena abaixo NO funciona, pois sizeof substi- Mesmo que declarssemos:


tudo pelo tamanho de um tipo em tempo de compilao. oat a;
const char *FRASE; FRASE = Wikibooks eh legal";
o resultado continua a ser 3 mas desta vez, 3,0000.
printf(Eu acho que o tamanho da string FRASE %d,
Para fazer diviso que resulte nmero real, necessrio
sizeof(FRASE));
fazer cast para um tipo de ponto utuante:
a = (oat)10/3 a = 10/(oat)3

28.3 Converso de tipos


As atribuies no C tem o seguinte formato:

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.

Repare que a converso feita de menor para o maior.


possvel fazer a converso ao contrrio de um tipo com
mais bits para um com menos bits e isso truncar. Nesse
caso, o cast explcito necessrio. Assim, um nmero
oat: 43.023 ao ser convertido para int dever ser cortado, cando inteiro: 43. Se converter long para short,
os bits mais signicativos so perdidos na converso.

Abaixo vemos uma tabela de converses numricas com


perda de preciso, para um compilador com palavra de O operador cast tambm e bastante utilizado para estruturar reas de estoque temporrios (buer). A seguir um
16 bits:
pequeno exemplo:
De Para Informao Perdida unsigned char char Valores
maiores que 127 so alterados short int char Os 8 bits de #include <stdio.h> typedef struct estruturar{ char a
mais alta ordem int char Os 8 bits de mais alta ordem long ; char b ; }; int main() { char buer[2] = {17, 4};
int char Os 24 bits de mais alta ordem long int short int estruturar *p; p = (struct estruturar*) &buer; char* x
Os 16 bits de mais alta ordem long int int Os 16 bits de = (char*)malloc(10); printf(a: %i b: %i, p->a,p->b);
mais alta ordem oat int Preciso - resultado arredondado getchar(); return 0; }
double oat Preciso - resultado arredondado long double
double Preciso - resultado arredondado

28.3.1

Casting: converso manual

Se declararmos a = 10/3, sabemos que o resultado


3,333, ou seja a diviso de dois nmeros inteiros d um
nmero real. Porm o resultado em C ser o inteiro 3. 28.4 Atributos das variveis
Isso acontece, porque as constantes so do tipo inteiro e
operaes com inteiros tem resultado inteiro. O mesmo
ocorreria em a = b/c se b e c forem inteiros.
Estes modicadores, como o prprio nome indica, mudam a maneira com a qual a varivel acessada e modiSe declararmos:
cada. Alguns dos exemplos usam conceitos que s sero
int a;
abordados nas sees seguintes, ento voc pode deixar
O resultado ser 3.
esta seo para depois se assim o desejar.

74

28.4.1

CAPTULO 28. PROGRAMAR EM C/MAIS SOBRE VARIVEIS

const

uma nova varivel com o nome especicado, ocultando


a varivel que realmente desejamos usar. E se simplesO modicador const faz com que a varivel no possa ser mente no declarssemos a varivel, j sabemos que o
modicada no programa. Como o nome j sugere til compilador no saberia o tamanho da varivel.
para se declarar constantes. Poderamos ter, por exem- Quando o compilador encontra o modicador extern, ele
plo:
marca a varivel como no resolvida, e o montador se enconst oat PI = 3.1415;

carregar de substituir o endereo correto da varivel.

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.

extern oat sum; extern int count; oat returnSum (void)


{ count++; return sum; }

Outro uso de const, alis muito comum que o outro,


evitar que um parmetro de uma funo seja alterado pela
funo. Isto muito til no caso de um ponteiro, pois
o contedo de um ponteiro pode ser alterado por uma
funo. Para proteger o ponteiro contra alteraes, basta
declarar o parmetro como const.

Uma varivel externa frequentemente usada a varivel


errno (declarada no arquivo-cabealho errno.h), que indica o ltimo cdigo de erro encontrado na execuo de
uma funo da biblioteca padro ou do sistema.

<

28.4.4 static

Neste exemplo, o compilador ir saber que count e sum


esto sendo usados no arquivo mas que foram declarados
em outro.

nclude <stdio.h>

O funcionamento das variveis declaradas como static


int sqr (const int *num); int main(void) { int a = 10; depende de se estas so globais ou locais.
int b; b = sqr(&a); } int sqr (const int *num) { return
((*num)*(*num)); }
Variveis globais static funcionam como variveis
globais dentro de um mdulo, ou seja, so variNo exemplo, num est protegido contra alteraes. Isto
veis globais que no so (e nem podem ser) conhequer dizer que, se tentssemos fazer
cidas em outros mdulos (arquivos). Isto util se
*num = 10;
quisermos isolar pedaos de um programa para evitar mudanas acidentais em variveis globais. Isso
dentro da funo sqr(), o compilador daria uma mensa um tipo de encapsulamento que , simplicagem de erro.
damente, o ato de no permitir que uma varivel
seja modicada diretamente, mas apenas por meio
de uma funo.
28.4.2 volatile
Variveis locais estticas so variveis cujo valor
O modicador volatile diz ao compilador que a varivel
mantido de uma chamada da funo para a outra.
em questo pode ser alterada sem que este seja avisado.
Veja o exemplo:
Isto evita bugs que poderiam ocorrer se o compilador
tentasse fazer uma otimizao no cdigo que no segura
int count (void) { static int num = 0; num++; return num;
quando a memria modicada externamente.
}
Digamos que, por exemplo, tenhamos uma varivel que
o BIOS do computador altera de minuto em minuto (um A funo count() retorna o nmero de vezes que ela j foi
relgio, por exemplo). Seria importante que declarsse- chamada. Veja que a varivel local int inicializada. Esta
inicializao s vale para a primeira vez que a funo
mos esta varivel como volatile.
chamada pois num deve manter o seu valor de uma chaUm uso importante de variveis volatile em aplicaes mada para a outra. O que a funo faz incrementar num
com vrias threads (linhas de execuo), onde a memria a cada chamada e retornar o seu valor. A melhor maneira
compartilhada por vrios pedaos de cdigo que so de se entender esta varivel local static implementando.
executados simultaneamente.
Veja por si mesmo, executando seu prprio programa que
use este conceito.

28.4.3

extern
28.4.5 register

O modicador extern diz ao compilador que a varivel


indicada foi declarada em outro arquivo que no podemos incluir diretamente, por exemplo o cdigo de uma
biblioteca padro. Isso importante pois, se no colocarmos o modicador extern, o compilador ir declarar

O computador pode guardar dados na memria (RAM)


e nos registradores internos do processador. As variveis
(assim como o programa como um todo) costumam ser
armazenadas na memria. O modicador register diz ao

28.4. ATRIBUTOS DAS VARIVEIS


compilador que a varivel em questo deve ser, se possvel, guardada em um registrador da CPU.
Vamos agora ressaltar vrios pontos importantes:
Porque usar register? Variveis nos registradores
da CPU vo ser acessadas em um tempo muito menor pois os registradores so muito mais rpidos que
a memria. No entanto, a maioria dos compiladores otimizantes atuais usa registradores da CPU para
variveis, ento o uso de register freqentemente
desnecessrio.
Em que tipo de varivel podemos usar o register? Antes da criao do padro ANSI C, register
aplicava-se apenas aos tipos int e char, mas o padro
atual permite o uso de register para qualquer um dos
quatro tipos fundamentais. claro que seqncias
de caracteres, arrays e estruturas tambm no podem ser guardadas nos registradores da CPU por serem grandes demais.
register um pedido que o programador faz ao
compilador. Este no precisa ser atendido necessariamente, e alguns compiladores at ignoram o modicador register, o que permitido pelo padro C.
register no pode ser usado em variveis globais,
pois isto implicaria em um registrador da CPU car
o tempo todo ocupado por essa varivel.
Um exemplo do uso do register dado a seguir:
int main (void) { register int count; for (count = 0; count
< 10; count++) { ... } return 0; }
O loop acima, em compiladores que no guardam variveis em registradores por padro, deve ser executado
mais rapidamente do que seria se no usssemos o register. Este o uso mais recomendvel para o register: uma
varivel que ser usada muitas vezes em seguida.

75

Captulo 29

Programar em C/Mais sobre funes


29.1 Os argumentos argc e argv
A funo main(), como dissemos antes, uma funo especial. Introduzimo-la como uma funo sem parmetros; no entanto, ela tambm pode receber parmetros
formais. No entanto, o programador no pode escolher
quais sero. Eles devem ser os seguintes:
int main (int argc, char *argv[])

strings. A string referente ao mes deve ser transformada


em um numero inteiro. A funcao atoi esta sendo
usada para isto: recebe a string e transforma no inteiro
equivalente */ if (mes<1 || mes>12) /* Testa se o mes
e' valido */ printf(Erro!\nUso: data dia mes ano, todos
inteiros); else printf("\n%s de %s de 19%s, argv[1],
nome_mes[mes-1], argv[3]); } else printf(Erro!\nUso:
data dia mes ano, todos inteiros); }

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

va_start, va_arg et va_end (va como variable argument)

#include <stdio.h> #include <stdlib.h> int main(int


argc, char *argv[]) { int mes; char *nome_mes [] =
{ Janeiro, Fevereiro, Maro, Abril, Maio,
Junho, Julho, Agosto, Setembro, Outubro,
Novembro, Dezembro }; if(argc == 4) /* Testa
se o nmero de parmetros fornecidos est correto, o
primeiro parmetro o nome do programa, o segundo
o dia, o terceiro o mes e o quarto os dois ltimos algarismos do ano */ { mes = atoi(argv[2]); /* argv contem

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

A macro va_start inicializa ap para uso poste-

29.2. LISTA DE ARGUMENTOS


rior por va_arg e va_end e deve ser chamada
primeiro.
O parmetro last o nome do ltimo parmetro
antes da lista de argumentos variveis, isto ,
o ltimo parmetro o qual a funo conhee o
tipo.
Porque o endereo deste parmetro pode ser
usado na macro va_start, ele no deve ser declarado como uma varivel register, ou como
uma funo ou como um array.
va_arg:
A macro va_arg retorna o primeiro argumento
varivel e faz ap apontar o prximo argumento. O parmetro ap aquele inicializado
por va_start. O parmetro type um nome de
tipo. Pode-se apontar para um objeto de um
tipo especco simplesmente adicionando um
* ao tipo.
O primeiro uso da macro va_arg aps a macro
va_start retorna o argumento aps last. Chamadas sucessivas retornam os valores dos outros argumentos.
Se no existe prximo argumento, ou se type
no compatvel com o tipo do prximo argumento, erros aleatrios ocorrero.
Se ap passado para uma funo que usa
va_arg(ap,type) ento o valor de ap destrudo
aps o retorno da funo.
va_end:
Cada chamada de va_start deve ter uma
chamada correspondente a va_end na mesma
funo. Aps a chamada de va_end a varivel
ap destruda. Vrias chamadas com va_start
e va_end aninhadas so possveis. va_end
pode ser uma macro ou uma funo.

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.

Algo que voc deve ter notado que nesse arquivo no


demos nenhuma informao sobre as funes vf e rand
nele usadas. Realmente, se voc tentar compilar o cdigo
como est, o compilador dar um aviso; mas ao tentar
criar o executvel, o montador no poder continuar pois
no recebeu nenhuma informao sobre onde as funes
esto.

Alm da vantagem de organizar o cdigo, bibliotecas


tambm tm a vantagem de poderem ser utilizadas em
vrios programas sem necessidade de copiar grandes trechos de cdigo; basta dizer ao compilador que queremos Para isso, precisamos realizar trs passos adicionais antes
de compilar o programa teste:
adicionar aquela biblioteca ao executvel.
Por exemplo, vamos tentar criar a nossa prpria biblioteca, com duas funes: uma para gerar nmeros
(pseudo-)aleatrios e uma para calcular o valor de pagamento de uma amortizao com juros compostos. Tambm incluiremos uma funo para gerar um nmero inicial a partir da hora atual, o que far com que as seqncias de nmeros no sejam sempre as mesmas.

1. Fazer um arquivo-cabealho com informaes sobre


as funes. Esse arquivo ser incluido com a diretiva
#include, da mesma maneira que cabealhos padro
como stdio.h ou math.h.
2. Compilar a biblioteca separadamente.

Chamaremos a biblioteca de teste1.


#include <math.h> #include <time.h> int rand_seed
= 10; /* Gerador de nmeros pseudo-aleatrios */
int rand () { rand_seed = rand_seed * 1103515245
+ 12345; return (unsigned int) (rand_seed / 65536)
% 32768; } void init_seed () { rand_seed = time
(NULL); } /* Clculo do valor de cada pagamento
de uma amortizao * Dados: vp = valor presente; *
n = nmero de pagamentos; * i = taxa de juros (em
formato decimal) */ double vf (double vp, int n, double i)
{ return (vp * i * pow (1 + i, n - 1) / (pow (1 + i, n) - 1)); }

3. Instruir o compilador/montador a procurar pela biblioteca ao compilar o programa teste.

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

30.4. COMPILAO DO PROGRAMA


Se voc se lembra da ltima lio, poder sugerir que coloquemos algumas linhas a mais:

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.

30.3 Compilao da biblioteca

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

Compile o arquivo-fonte normalmente, mas sem gerar o executvel:


gcc -c teste1.c -o libteste1.o
Crie o arquivo da biblioteca com o comando ar.
Voc ainda no o conhece, mas a sintaxe simples: basta digitar ar rv, seguido do nome do arquivo da biblioteca e depois dos nomes dos arquivosobjeto a serem includos (separados por espaos).
No GCC, as bibliotecas estticas costumam ter o
nome libnome.a.
ar rv libteste1.a libteste1.o

30.3.2

No MS Visual C++

No Visual C++, o nome padro das bibliotecas


"nome.lib, assim como em vrios outros compiladores
para Windows. Nele, os comandos correspondentes aos
dois passos acima so:
cl /c teste1.c lib /out:teste1.lib teste1.obj

30.4 Compilao do programa


Aps criar o arquivo objeto libteste1.o com o comando (
gcc -c teste1.c -o libteste1.o ) e a biblioteca esttica com
o comando ar , voc deve instruir o compilador com
as opes de edio de links para poder inclu-la no seu
programa:

Captulo 31

Programar em C/Entrada e sada em


arquivos
31.1 Trabalhando com arquivos

O nome do arquivo deve ser uma string


ou com o caminho completo (por exemplo,
/usr/share/appname/app.conf
ou
C:\Documentos\nomes.txt) ou o caminho em
relao ao diretrio atual (nomes.txt, ../app.conf)
do arquivo que se deseja abrir ou criar.

J vimos como podemos receber e enviar dados para


usurio atravs do teclado e da tela; agora veremos tambm como ler e gravar dados em arquivos, o que alis
muito importante ou at essencial em muitas aplicaes.
Assim como as funes de entrada/sada padro (teclado e tela), as funes de entrada/sada em arquivos esto declaradas no cabealho stdio.h que signica STanDard Input-Output. Alis, as funes para manipulao de arquivos so muito semelhantes s usadas para entrada/sada padro. Como j dissemos na seo sobre a
entrada e sada padres, a manipulao de arquivos tambm se d por meio de uxos (streams).
Na manipulao de um arquivo, h basicamente trs etapas que precisam ser realizadas:
1. abrir o arquivo;
2. ler e/ou gravar os dados desejados;
3. fechar o arquivo.
Em C, todas as operaes realizadas com arquivos envolvem seu identicador de uxo, que uma varivel do
tipo FILE * (sobre o qual no cabe agora falar). Para declarar um identicador de uxo, faa como se fosse uma
varivel normal:

O modo de acesso uma string que contm uma


seqncia de caracteres que dizem se o arquivo ser
aberto para gravao ou leitura. Depois de aberto
o arquivo, voc s poder executar os tipos de ao
previstos pelo modo de acesso: no poder ler de
um arquivo que foi aberto somente para escrita, por
exemplo. Os modos de acesso esto descritos na tabela a seguir.
Em ambientes DOS/Windows, ao ler arquivos binrios
(por exemplo, programas executveis ou certos tipos de
arquivos de dados), deve-se adicionar o caractere b ao
nal da string de modo (por exemplo, wb ou r+b) para
que o arquivo seja lido/gravado corretamente.
Isso necessrio porque no modo texto (o padro quando
no adicionado o b) ocorrem algumas tradues de caracteres (por exemplo, a terminao de linha "\r\n
substituda apenas por "\n na leitura) que poderiam afetar a leitura/gravao dos arquivos binrios (indevidamente inserindo ou suprimindo caracteres).
O valor de retorno da funo fopen() muito importante! Ele o identicador do uxo que voc abriu
e s com ele que voc conseguir ler e escrever no
arquivo aberto.

FILE *fp; // no se esquea do asterisco!

31.2 Abrindo e fechando um arquivo


No surpreendentemente, a primeira coisa que se deve
fazer para manipular um arquivo abri-lo. Para isso, usamos a funo fopen(). Sua sintaxe :
FILE *fopen (char
*modo_de_acesso);

*nome_do_arquivo,

char

Se houver um erro na abertura/criao do arquivo, a


funo retornar o valor NULL. O erro geralmente
acontece por duas razes:
O arquivo no existe, caso tenha sido requisitado para leitura.
O usurio atual no tem permisso para abrir
o arquivo com o modo de acesso pedido. Por

80

31.3. ESCREVENDO EM ARQUIVOS

81

exemplo, o arquivo somente-leitura, ou est


bloqueado para gravao por outro programa,
ou pertence a outro usurio e no tem permisso para ser lido por outros.

stdin: dispositivo de entrada padro (geralmente o


teclado)

Ao terminar de usar um arquivo, voc deve fech-lo. Isso


feito pela funo fclose():

stderr: dispositivo de sada de erro padro (geralmente o vdeo)

int fclose (FILE *uxo);

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.

stdout: dispositivo de sada padro (geralmente o


vdeo)

stdprn: dispositivo de impresso padro (em muitos


sistemas, associado porta paralela)

31.3 Escrevendo em arquivos


Para escrever em arquivos, h quatro funes, das quais
trs so anlogas s usadas para sada padro:
A seguir apresentamos os prottipos dessas funes:
void fputc (int caractere, FILE *uxo);
void fputs (char *string, FILE *uxo);
void fprintf (FILE *uxo, char *formatao, ...);
int fwrite (void *dados, int tamanho_do_elemento, int
num_elementos, FILE *uxo);

Sintaxe quase igual de printf(); s necessrio adicionar o identicador de uxo no incio.

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

unsigned fwrite(void *buer,int numero_de_bytes,int


count,FILE *fp);

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

CAPTULO 31. PROGRAMAR EM C/ENTRADA E SADA EM ARQUIVOS

anteriormente */ printf(Erro na leitura do arquivo); } while((c = fgetc()) != EOF) printf(Caractere lido:


printf("\nO valor de PI, lido do arquivo e': %f, pilido); %c\n, c); if((c == EOF) && (feof() == 0) &&
fclose(pf); return 0; }
(ferror() != 0)) perror(Erro: fgetc); fclose(); return
EXIT_SUCCESS; }
Nota-se o uso do operador sizeof, que retorna o tamanho
em bytes da varivel ou do tipo de dados.

31.4.2 fgets
31.3.2

fputc

A funo fputc a primeira funo de escrita de arquivo


que veremos. Seu prottipo :
int fputc (int ch, FILE *fp);

Ao chamar a funo fgets(), voc deve fornecer o


ponteiro para a string onde os dados lidos devem ser
guardados, alm do tamanho mximo dos dados a
serem lidos (para que a memria reservada string
no seja ultrapassada).

Escreve um caractere no arquivo.O programa a seguir l


uma string do teclado e escreve-a, caractere por caractere Para se ler uma string num arquivo podemos usar fgets()
em um arquivo em disco (o arquivo arquivo.txt, que ser cujo prottipo :
aberto no diretrio corrente).
char *fgets (char *str, int tamanho,FILE *fp);
#include <stdio.h> #include <stdlib.h> int main() { FILE A funo recebe 3 argumentos: a string a ser lida, o li*fp; char string[100]; int i; fp = fopen(arquivo.txt,"w); mite mximo de caracteres a serem lidos e o ponteiro para
/* Arquivo ASCII, para escrita */ if(!fp) { printf( Erro FILE, que est associado ao arquivo de onde a string ser
na abertura do arquivo); exit(0); } printf(Entre com a lida. A funo l a string at que um caracter de nova listring a ser gravada no arquivo:"); gets(string); for(i=0; nha seja lido ou tamanho-1 caracteres tenham sido lidos.
string[i]; i++) putc(string[i], fp); /* Grava a string, Se o caracter de nova linha ('\n') for lido, ele far parte da
caractere a caractere */ fclose(fp); return 0; }
string, o que no acontecia com gets.
Depois de executar este programa, verique o contedo
do arquivo arquivo.txt (voc pode usar qualquer editor de
textos). Voc ver que a string que voc digitou est armazenada nele.

31.4 Lendo de arquivos

A funo fgets semelhante funo gets(), porm, alm


dela poder fazer a leitura a partir de um arquivo de dados
e incluir o caracter de nova linha na string, ela ainda especica o tamanho mximo da string de entrada. Como
vimos, a funo gets no tinha este controle, o que poderia acarretar erros de estouro de buer. Portanto,
levando em conta que o ponteiro fp pode ser substitudo
por stdin, como vimos acima, uma alternativa ao uso de
gets usar a seguinte construo:

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

A funo fscanf() funciona como a funo scanf(). A


diferena que fscanf() l de um arquivo e no do teclado
Est funo requer como parmetro o indicador de do computador. Prottipo:
uxo do arquivo, retorna um caractere do arquivo
ou EOF, caso ocorra um erro ou o nal do ar- int fscanf (FILE *fp,char *str,...);
quivo seja atingido, podendo ser vericado respec- #include <stdio.h> #include <stdlib.h> int main() {
FILE *p; char str[80],c; printf("\n\n Entre com um
tivamente por ferror e feof.
nome para o arquivo:\n); /* Le um nome para o arquivo
a ser aberto: */ gets(str); if (!(p = fopen(str,"w))) /*
Exemplo:
Caso ocorra algum erro na abertura do arquivo..*/ { /*
#include <stdio.h> #include <stdlib.h> int main() { FILE o programa aborta automaticamente */ printf(Erro!
*; int c; if(( = fopen(caminho/do/arquivo, r)) == Impossivel abrir o arquivo!\n); exit(1); } fprintf(p,"Este
NULL) { perror(Erro: fopen); exit(EXIT_FAILURE); e um arquivo chamado:\n%s\n, str); fclose(p); /* Se

31.6. OUTRAS FUNES

83

nao houve erro, imprime no arquivo, fecha ...*/ p = 31.5.3 feof


fopen(str,"r); /* abre novamente para a leitura */
while (!feof(p)) { fscanf(p,"%c,&c); printf("%c,c); } EOF (End of le) indica o m de um arquivo. s vezes,
fclose(p); return 0; }
necessrio vericar se um arquivo chegou ao m. Para
isto podemos usar a funo feof(). Ela retorna no-zero
se o arquivo chegou ao EOF, caso contrrio retorna zero.
Seu prottipo :

31.4.5

fread

int feof (FILE *fp);

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);

31.6 Outras funes

O parmetro origem determina a partir de onde os


numbytes de movimentao sero contados. Os valores
31.6.1
possveis so denidos por macros em stdio.h e so:

ferror e perror

Nome Valor Signicado SEEK_SET 0 Incio do arquivo Prottipo de ferror:


SEEK_CUR 1 Ponto corrente no arquivo SEEK_END 2
int ferror (FILE *fp);
Fim do arquivo
Tendo-se denido a partir de onde ir se contar, numbytes A funo retorna zero, se nenhum erro ocorreu e um ndetermina quantos bytes de deslocamento sero dados na mero diferente de zero se algum erro ocorreu durante o
acesso ao arquivo. se torna muito til quando queremos
posio atual.
vericar se cada acesso a um arquivo teve sucesso, de
modo que consigamos garantir a integridade dos nossos
dados. Na maioria dos casos, se um arquivo pode ser
31.5.2 rewind
aberto, ele pode ser lido ou gravado.
Volta para o comeo do arquivo de um uxo

Porm, existem situaes em que isto no ocorre. Por

84

CAPTULO 31. PROGRAMAR EM C/ENTRADA E SADA EM ARQUIVOS

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

#include <stdio.h> #include <stdlib.h> int main(int


argc, char *argv[]) { /* ponteiro para memria que ser
alocada */ int *p; int i; /* alocar 10 elementos inteiros,
ou seja, ( sizeof (int) * 10 ) */ p = (int *) malloc ( sizeof
(int) * 10); if ( p == NULL ) { printf (Erro: No foi
possivel alocar memria\n); exit(1); } for(i = 0; i <
10; i++) { p[i] = i * 2; printf ("%d\n, p[i]); } /* libera a memria alocada por malloc */ free (p); return 0; }

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

O compilador aceita tambm p=q porque ambos so


ponteiros e apontam para o mesmo tipo.

malloc e free

Podemos simplicar p = malloc(sizeof(int)); por p


= malloc(4); mas como temos sistemas operacionais
de 16,32, 64 bits a primeira declarao torna as coisas mais portveis.

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);

A funo calloc reserva um bloco com o tamanho (nelem


x elsize) octetos consecutivos, isto , aloca memria suciente para um vetor de num objetos de tamanho size.
Para saber o tamanho do bloco a alocar, precisaremos Diferente de malloc(), o bloco reservado inicializado a
usar o operador sizeof. Ele permite tambm saber auto- 0. Essa funo retorna um ponteiro void* para o primeiro
maticamente o tamanho de structs criadas pelo usurio.
byte alocado. O ponteiro void* pode ser atribudo a qualquer tipo de ponteiro. Se no houver memria suciente
Veja um exemplo de alocao dinmica:
85

86

CAPTULO 32. PROGRAMAR EM C/GERENCIAMENTO DE MEMRIA

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; }

32.1.4 Alocao Dinmica de Vetores


A alocao dinmica de vetores utiliza os conceitos
aprendidos na aula sobre ponteiros e as funes de alocao dinmica apresentados. Um exemplo de implementao para vetor real fornecido a seguir:

No exemplo acima, alocada memria suciente para se


colocar n nmeros inteiros. O operador sizeof() retorna
o nmero de bytes de um inteiro. Ele til para se saber o tamanho de tipos. O ponteiro void * que calloc()
retorna convertido para um int* pelo cast e atribudo
a p. A declarao seguinte testa se a operao foi bem
sucedida. Se no tiver sido, p ter um valor nulo, o que
far com que !p retorne verdadeiro. Se a operao tiver
sido bem sucedida, podemos usar o vetor de inteiros alocados normalmente, por exemplo, indexando-o de p[0] a
p[(a-1)].

#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

32.1.5 Alocao Dinmica de Matrizes

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

32.1. ALOCAO DINMICA


**Liberar_matriz_real (int m, int n, oat **v) { int i;
/* variavel auxiliar */ if (v == NULL) return (NULL);
if (m < 1 || n < 1) { /* verica parametros recebidos */
printf ("** Erro: Parametro invalido **\n); return (v);
} for (i=0; i<m; i++) free (v[i]); /* libera as linhas da
matriz */ free (v); /* libera a matriz (vetor de ponteiros)
*/ return (NULL); /* retorna um ponteiro nulo */ } int
main (void) { oat **mat; /* matriz a ser alocada */ int
l, c; /* numero de linhas e colunas da matriz */ int i,
j; ... /* outros comandos, inclusive inicializacao para
l e c */ mat = Alocar_matriz_real (l, c); for (i = 0; i
< l; i++) for ( j = 0; j < c; j++) mat[i][j] = i+j; ... /*
outros comandos utilizando mat[][] normalmente */ mat
= Liberar_matriz_real (l, c, mat); ... }

87

Captulo 33

Programar em C/Sockets
33.1 Abstraes

AF_UNIX: Protocolo interno do UNIX


AF_INET: Protocolo Internet
A verso Unix BSD 4.1c de 1982 para VAX foi a pri- AF_NS : Protocolo de Xerox NS
meira a incluir TCP/IP no kernel do sistema operacional,
oferecendo ao mesmo tempo uma interface de programao como abstrao para esses protocolos. Os soquetes
ou sockets so uma API (Application Program Interface) 33.4 Estruturas de endereo
isso quer dizer uma interface entre os programas e a camada de transporte. Exemplo: TCP, UDP. Os soquetes Varias chamada ao sistema de redes do unix precisam
podem usar outros protocolos como AppleTalk, Xrox apontar para uma estrutura de endereo de socket.
XNS, etc. A API de sockets foi desenvolvida para a lin- A denio dessas estruturas esta denida dentro do
guagem C e so uma das principais API para sistemas cabealho <sys/socket.h>.
do tipo UNIX. O Windows possui uma interface similar
conhecida com o nome de Winsock.
struct sockaddr { u_short sa_family ; char sa_data[14] ;
};

33.2 Funes da biblioteca padro

sa_family: Famlia de endereo leva o valor AF_xxx .


sa_data: endereo especico de protocolo .

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]);

Para a famlia internet as estrutura esto denidas dentro


do cabealho <netinet/in.h>.
struct in_addr { u_long s_addr ; } ;
struct sockaddr_in { short sin_family ; u_short sin_port ;
struct in_addr sin_addr ; char sin_zero[8] ; } ;

33.3 Famlias de endereo


Existem varias famlias de endereo e cada uma corresponde a um protocolo em particular.
As famlias mais usadas so :

88

Captulo 34

Programar em C/Makeles
34.1 Makele

De um nome para a pasta Projeto.

O objetivo de Makele denir regras de compilao


para projetos de software. Tais regras so denidas
em arquivo chamado Makele. O programa make
interpreta o contedo do Makele e executa as regras
l denidas. Alguns Sistemas Operacionais trazem
programas similares ao make, tais como gmake, nmake,
tmake, etc. O programa make pode variar de um sistema
a outro pois no faz parte de nenhuma normalizao .

/*================
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 :

all : o nome das regras a serem executadas.


teste: teste.c .Pode ser interpretado com arquivo_de_destino: arquivo_de_origem.

teste.c ,teste.h , main.c, Makele.

89

90

CAPTULO 34. PROGRAMAR EM C/MAKEFILES

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

Sintaxe de criao do arquivo

O makele funciona de acordo com regras, a sintaxe de


uma regra :

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

NOME=CONTEDO E para utilizar esta varivel colo- SRC = main.c teste.c


OBJ= $(SRC:.c=.o)
camos entre $() .
Ento ela vai car assim $(NOME)
E super manero a tua idia camarada.
Vamos para o exemplo com o nosso Makele.
Colocamos em vez de :
Mais tenho 200 arquivos.c e no quero olhar o
nome de todos um por um.
NOME SRC
E em vez de CONTEDO main.c .
E para poder usar $(SRC)

Ser que na pratica funciona?. Vamos ver..

Tem outra idia??


Poderamos utilizar *c mais no podemos utilizar este caracter joker na denio de uma
varivel.
Ento vamos utilizar o comando " wildcard "
ele permite a utilizao de caracteres joker na
denio de variveis.
Fica assim.

#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

Po legal ;) parece at trabalho de gente grande.


Sub Makeles

$@ 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 .

Bom, ao trabalho. Crie dentro da pasta Projetos outra


pasta com o nome sub-make.Dentro da pasta sub-make
crie um arquivo
%.o: %.c .A mesma coisa. A linha teste.o: teste.c
Makele e um arquivo submake.c
pode ser modicada com essa regra.
Dentro da pasta sub-make coloque este Makele.
.PHONY: .Preste bem ateno. Esta regra permite
##################Pasta:sub-make ## Makele
de evitar conitos.
################### CC=gcc CFLAGS=-W -Wall
Por exemplo clean:" e uma regra sem nem -ansi -pedantic EXEC=teste2 SRC= $(wildcard *.c)
uma dependncia no temos nada na pasta que OBJ= $(SRC:.c=.o) all: $(EXEC) @echo compilando
se chame clean.
sub-makele @echo sub-makele compilado teste2:
Agora vamos colocar na pasta um arquivo cha- $(OBJ) @$(CC) -o $@ $^ .PHONY: clean mrproper
mado clean. Se voc tentar apagar os arqui- clean: @rm -rf *.o mrproper: clean @rm -rf $(EXEC)
vos.o escrevendo make clean no vai acon- Agora vamos escrever o arquivo submake.c .
tecer nada porque make diz que clean no foi
#include <stdio.h> #include <stdlib.h> /* Informao *
modicado.
Nao utilizem este cdigo para fazer um kernel */ int
Para evitar esse problema usamos a regra main(void) { printf(Sou o binrio que est em sub.PHONY : . Fica assim.
make); printf(Finalmente em m vivo graas ao Patro
Makeles ;)"); return (0); }
.PHONY: clean mrproper
.PHONY: diz que clean e mrproper devem ser Agora retorne na pasta Projeto vamos modicar o Maexecutados mesmo se arquivos com esses no- kele .
mes existem.
Vamos colocar a seguinte linha:
Agora vamos modicar mais uma vez o nosso Makele
com tudo o que sabemos sobre variveis.

@cd sub-make && $(MAKE)


Explicando: "@" silencioso cd para abrir a pasta
sub-make "&&" e executar make "$(MAKE)"

#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

CAPTULO 34. PROGRAMAR EM C/MAKEFILES

*.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) $@

-c $< $(CFLAGS) #Entao depois e so executar make e


depois make install install:all @mv $(EXEC) $(bindir)/
.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 @cd bin && rm -rf $(EXEC) #modicamos aqui tambem @cd sub-make && $(MAKE) $@

Ento quando voc digitar no console make depois


make install ele vai colocar o binario que esta em Projetos dentro de bin.
Se voc quiser colocar o binario que esta na pasta subNo esquea de dar TAB em todas as linhas que esto make na pasta bin
em baixo dos ":" dois pontinhos. OK agora s dar um
F4 dentro da pasta projetos e voc tem trs comandos a
Copiar e colar no makele da sub-make as variadisposio.
veis prex e bindir"e a regra install:com seu comando.
make
make clean
make mrproper
Make install
Automatizando a instalao do programa com a regra
install: .

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

Programar em C/Lista de palavras


reservadas
A linguagem C possui um total de 32 palavras conforme
denido pelo padro ANSI, que so elas:
importante lembrar que todas as palavras reservadas
so escritas em minsculo e no podem ser utilizadas para
outro propsito. Alguns compiladores incluem outras palavras reservadas como, asm, cdecl, far, fortran, huge,
interrupt, near, pascal, typeof.

93

Captulo 36

Programar em C/Seqncias de escape


O C tem vrias seqncias de escape. Elas servem geralmente para inserir um caractere especial numa String.
Algumas dessas seqncias so:
\a - Alarm, Alarme = Toca o alarme sonoro do sistema
\b - Back space, Retrocesso = Apaga o caractere
esquerda do cursor
\n - NewLine, Nova linha = Pula uma linha
\t - Tabulao horizontal = Equivale dar um TAB
na string
\r - Carriage Return, Retorno do Carro = Volta para
o incio da linha.
\t - Horz. Tab, Tabulao Harizontal = Salta frente
conforme seus ajustes de tabulao
\0 - Null, Nulo = Caractere nulo ou zero geralmente
estabelecido como m de string

94

Captulo 37

Programar em C/Lista de funes


Aqui esto as vrias funes presentes em C separadas
por cabealho:

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

Programar em C/Lista de bibliotecas


Cabealhos de bibliotecas padro ANSI C (C89)/ISO C
(C90):
Cabealhos adicionados no ISO C (C94/C95):
Cabealhos adicionados no ISO C (C99) (suportados somente em compiladores mais novos):

38.1 Ligaes externas


The Open Group Base Specications Issue 7 (english)
Biblioteca C (english)

96

Captulo 39

Programar em C/Dicas de programao


em C
39.1 Convenes tipogrcas

iniciando funcao3); funcao3(...); printf(completa funo3, iniciando funcao4); funcao4(...); printf(completa


Uma das melhores maneiras de obter um cdigo claro e funo4); ... return 0; }
usando identicadores coerentes.
Por exemplo bom poder identicar rapidamente as Isto permite o programador determinar at que ponto o
variveis em funo de suas propriedades .
programa roda antes de dar erro, facilitando muito a deVeja abaixo algumas delas.
teco deste.
Outro exemplo de como o printf til na deteco de proprexos identicadores - ponteiro p_ - tabela est- blemas. Suponha um programa cheio de laos aninhados.
tica(static array) a_ ou sa_ - tabela dinmica (dynamic Tal como:
array) da_ - cadeia de caracteres(string) s_
for(...) { while(...) { ... for(...) { ... } } }
Em um cdigo com a varivel p_exemplo podemos deduzir rapidamente que estamos usando um ponteiro .
Caso durante a execuo o programa entre em um loop
innito, uma forma de detectar em qual dos laos est o
problema :

39.2 A funo printf a melhor


amiga de um programador

for(...) { printf(Teste 1); while(...) { printf(Teste 2);


... for(...) { printf(Teste 3); ... } } }

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.

Caso o valor de x dependa do valor de outras variveis que


Digamos que o programa tenha sido compilado com su- no so impressas, imprimi-las pode ajudar na deteco
cesso, mas ocorra algum erro durante sua execuo. Po- do problema.
demos usar o printf para detectar o erro da seguinte maPara uso como debug, a linguagem C apresenta duas maneira:
cros que quando utilizadas junto com o printf so timos
int main(int argc, char *argv[]) { ... printf(iniciando recursos.
funcao1); funcao1(...); printf(completa funo1, inici __FILE__ = nome do arquivo.
ando funcao2); funcao2(...); printf(completa funo2,
97

98

CAPTULO 39. PROGRAMAR EM C/DICAS DE PROGRAMAO EM C

__LINE__ = numero da linha de execuo.


O Compilador gcc ainda dispe de uma outra macro bastante util:
__PRETTY_FUNCTION__ = nome da funo
atual.
...
printf("%d:%s:%s\n, __LINE__, __FILE__,
__PRETTY_FUNCTION__); ...
O trecho acima vai te dar uma saida para debug muito util
com o seguinte conteudo:
Exemplo: 3:hello.c:main

39.3 Tecle 1 para rodar


Existem duas formas de manter um programa rodando
enquanto o usurio desejar:
1. Conter a maior parte do programa dentro de um
lao.
2. Usar o comando goto(lembre-se que o comando
goto no de uso aconselhado para a programao
estruturada).
Alguns exemplos:
Com while:
int main(int argc, char *argv[]) { int rodando=1;
while(rodando==1)/*Este laco mantem o programa rodando enquanto o usuario desejar*/ { ... printf("\nDigite
1 para continuar rodando o programa.); printf("\nDigite
qualquer outro numero para encerrar o programa. ");
scanf("%d, &rodando); } return 0; }
Com do...while
int main(int argc, char *argv[]) { short int rodando; do
/*Este laco mantem o programa rodando enquanto o
usuario desejar*/ { ... printf("\nDigite 1 para manter
o programa rodando. "); scanf("%d, &rodando);
}while(rodando==1); return 0; }
Com o goto
int main(int argc, char *argv[]) { MARCA: ... FIM: int
y; printf(Tecle 1 para continuar rodando o programa.
Tecle 0 para encerrar o programa\n); scanf("%d,&y);
if(y==1) { goto MARCA; } if(y!=1 && y!=0) { goto
FIM; } return 0; }

Captulo 40

Programar em C/Listas encadeadas


Listas encadeadas so estruturas de dados lineares e dinmicas, a grande vantagem que elas possuem em relao
ao uso de vetor o fato de terem tamanho mximo relativamente innito (o tamanho mximo o da memria
do computador), ao mesmo tempo que podem ter o tamanho mnimo de 1 elemento evitando o desperdcio de
memria.

40.2 Lista encadeada linear


Cada n ou elemento de uma lista encadeada ir possuir
guardar o valor do n e o endereo do prximo n. Em
uma lista encadeada linear o ultimo elemento aponta para
NULL .
struct No{ char *p_dados; struct No *p_prox; };

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

Colocar o ndice sobre o elemento que precede o


elemento atual .

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

CAPTULO 40. PROGRAMAR EM C/LISTAS ENCADEADAS

NULL) *p_Raiz = p_Novo; else{ struct No *e_atual; p_atual->p_prox; } } }


/*@ Elemento atual*/ e_atual = *p_Raiz; /*@ Primeiro
elemento*/ while(e_atual->p_prox != NULL){ e_atual
= e_atual->p_prox; } e_atual->p_prox = p_Novo; } }

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

void remover_No_Inicio(struct No **p_Raiz){


if(*p_Raiz == NULL) printf("\nA lista ja esta vazia\n); else{ struct No *p_atual; p_atual = *p_Raiz;
*p_Raiz = (*p_Raiz)->p_prox; free(p_atual); } }

40.5.2

Remoo no m

void remover_No_Fim(struct No **p_Raiz){ if(*p_Raiz


== NULL) printf("\nA lista ja esta vazia); else{
struct No *p_atual, *p_anterior ; p_atual = *p_Raiz;
while(p_atual->p_prox != NULL){ p_anterior = p_atual
; p_atual = p_atual->p_prox; } p_anterior->p_prox =
NULL; free(p_atual); } }

40.6 Exibio
40.6.1

Do m para a raiz

void mostrar_Do_Fim_Para_Raiz(struct No *p_Raiz){


if(p_Raiz == NULL) printf("\nLista vazia); else{
struct No *p_Atual_Corredor,
*p_Atual_Fim;
p_Atual_Corredor = p_Raiz; p_Atual_Fim = p_Raiz;
while(p_Atual_Fim->p_prox != NULL){ //ir para
o ultimo elemento p_Atual_Fim = p_Atual_Fim>p_prox; } while(p_Atual_Corredor != p_Atual_Fim){
if(p_Atual_Corredor->p_prox
==
p_Atual_Fim){
printf(" <- %s, p_Atual_Fim->p_dados); p_Atual_Fim
= p_Atual_Corredor; p_Atual_Corredor = p_Raiz; }
else p_Atual_Corredor = p_Atual_Corredor->p_prox; }
printf(" <- %s, p_Atual_Fim->p_dados); } }

40.6.2

Da raiz para o m

void mostrar_Da_Raiz_Para_Fim(struct No *p_Raiz){


if(p_Raiz == NULL) printf("\nLista vazia); else{
struct No *p_atual; p_atual = *p_Raiz; while(p_atual
!= NULL){ printf("%s, p_atual->p_dados); p_atual =

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.2 Construo do prottipo de


um elemento da lista.
typedef struct Elemento_da_lista{ char *dados; struct
Elemento_da_lista *proximo; }Elemento; struct Localizar{ Elemento *inicio; int tamanho; } Pilha;

41.5 Retirar um elemento da pilha


(pop)
int desempilhar (Localizar *monte){ Elemento
*p_elemento; if (monte->tamanho == 0) return
1; p_elemento = monte->inicio; monte->inicio =
monte->inicio->proximo; free (p_elemento->dados);
free (p_elemento); monte->tamanho--; return 0; }

41.6 Imprimir os elementos da pilha

41.3 Inicializao

void mostrar(Localizar * monte){ Elemento *atual; int i;


atual = monte->inicio; for(i=0;i<monte->tamanho;++i){
void iniciar (Localizar *monte){ monte->inicio = printf("\t\t%s\n, atual->dados); atual = atual->proximo;
NULL; monte->tamanho = 0; }
}}

41.4 Inserir um elemento na pilha(push)


Algoritmo:
Declarao do elemento(s) a ser inserido.
Alocao da memria para o novo elemento
Inicializar o campo de dados.
Preencher o ponteiro inicio com o primeiro elemento
Colocar em dia o tamanho da pilha.
int empilhar(Localizar * monte, char *dados){ Elemento
*novo_elemento; if ((novo_elemento = (Elemento *)
malloc (sizeof (Elemento))) == NULL) return 1; if
((novo_elemento->dados = (char *) malloc (50 * sizeof
(char))) == NULL) return 1; strcpy (novo_elemento>dados, dados); novo_elemento->proximo = monte>inicio; monte->inicio = novo_elemento; monte101

Captulo 42

Programar em C/Fila ou Queue

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

Programar em C/rvores binrias


44.5 Remoo

44.1 Arvore binria


Uma arvore binria uma estrutura de dados que pode ser
representada como uma hierarquia onde cada elemento
chamado de n. O n inicial ou o primeiro elemento
chamado de raiz. Em uma rvore binria um elemento
pode ter um mximo de dois lhos no nvel inferior denominados como sub-rvore esquerda e sub-rvore direita.Um n sem lhos chamado de folha. A profundidade de um n a distncia deste n at a raiz e a distancia entre a folha mais distante e a raiz a altura da
arvore.Um conjunto de ns com a mesma profundidade
denominado, nvel da rvore.

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); } }

No *MaiorDireita(No **no){ if((*no)->direita !=


NULL) return MaiorDireita(&(*no)->direita); else{
No *aux = *no; if((*no)->esquerda != NULL) // se
nao houver essa vericacao, esse n vai perder todos
os seus lhos da esquerda! *no = (*no)->esquerda;
else *no = NULL; return aux; } } No *MenorEsquerda(No **no){ if((*no)->esquerda != NULL) return
MenorEsquerda(&(*no)->esquerda); else{ No *aux =
*no; if((*no)->direita != NULL) // se nao houver essa
vericacao, esse n vai perder todos os seus lhos da direita! *no = (*no)->direita; else *no = NULL; return aux;
} } void remover(No **pRaiz, int numero){ if(*pRaiz ==
NULL){ // esta vericacao serve para caso o numero nao
exista na arvore. printf(Numero nao existe na arvore!");
getch(); return; } if(numero < (*pRaiz)->numero)
remover(&(*pRaiz)->esquerda, numero); else if(numero
> (*pRaiz)->numero) remover(&(*pRaiz)->direita,
numero); else{ // se nao eh menor nem maior, logo, eh o
numero que estou procurando! :) No *pAux = *pRaiz;
// quem programar no Embarcadero vai ter que declarar
o pAux no inicio do void! :[ if (((*pRaiz)->esquerda ==
NULL) && ((*pRaiz)->direita == NULL)){ // se nao
houver lhos... free(pAux); (*pRaiz) = NULL; } else{
// so tem o lho da direita if ((*pRaiz)->esquerda ==
NULL){ (*pRaiz) = (*pRaiz)->direita; pAux->direita
= NULL; free(pAux); pAux = NULL; } else{ //so tem
lho da esquerda if ((*pRaiz)->direita == NULL){
(*pRaiz) = (*pRaiz)->esquerda; pAux->esquerda =
NULL free(pAux); pAux = NULL; } else{ //Escolhi
fazer o maior lho direito da subarvore esquerda. pAux
= MaiorDireita(&(*pRaiz)->esquerda); //se vc quiser
usar o Menor da esquerda, so o que mudaria seria
isso: pAux->esquerda = (*pRaiz)->esquerda; // pAux
= MenorEsquerda(&(*pRaiz)->direita); pAux->direita
= (*pRaiz)->direita; (*pRaiz)->esquerda = (*pRaiz)>direita = NULL; free((*pRaiz)); *pRaiz = pAux; pAux
= NULL; } } } } }

104

44.9. ESTRUTURA COMPLETA

44.5.1

Em ordem

void exibirEmOrdem(No *pRaiz){ if(pRaiz != NULL){


exibirEmOrdem(pRaiz->esquerda);
printf("\n%i,
pRaiz->numero); exibirEmOrdem(pRaiz->direita); } }

44.5.2

Pr-ordem

void exibirPreOrdem(No *pRaiz){ if(pRaiz != NULL){


printf("\n%i, pRaiz->numero); exibirPreOrdem(pRaiz>esquerda); exibirPreOrdem(pRaiz->direita); } }

44.5.3

Ps-ordem

void exibirPosOrdem(No *pRaiz){ if(pRaiz !=


NULL){
exibirPosOrdem(pRaiz->esquerda);
exibirPosOrdem(pRaiz->direita); printf("\n%i, pRaiz>numero); } }

44.6 Contar ns
int contarNos(No *pRaiz){ if(pRaiz == NULL) return 0; else return 1 + contarNos(pRaiz->esquerda) +
contarNos(pRaiz->direita); }

44.7 Contar folhas


int contarFolhas(No *pRaiz){ if(pRaiz == NULL) return
0; if(pRaiz->esquerda == NULL && pRaiz->direita ==
NULL) return 1; return contarFolhas(pRaiz->esquerda)
+ contarFolhas(pRaiz->direita); }

44.8 Altura da rvore


int maior(int a, int b){ if(a > b) return a; else return b; }
int altura(No *pRaiz){ if((pRaiz == NULL) || (pRaiz>esquerda == NULL && pRaiz->direita == NULL))
return 0; else return 1 + maior(altura(pRaiz->esquerda),
altura(pRaiz->direita)); }

44.9 Estrutura Completa

105

Captulo 45

Programar em C/Algoritmos de ordenao

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

void BubbleSort(int vetor[], int tamanho) { int aux,


i, j; for(j=tamanho-1; j>=1; j--) { for(i=0; i<j;
i++) { if(vetor[i]>vetor[i+1]) { aux=vetor[i]; vetor[i]=vetor[i+1]; vetor[i+1]=aux; } } } }

48.0.2

Cdigo da Funo Melhorado

Termina a execuo quando nenhuma troca realizada


aps uma passada pelo vetor.
void BubbleSort(int vetor[], int tamanho) { int memoria,
troca, i, j; troca=1; /*A varivel troca ser a vericao da troca em cada passada*/ for(j=tamanho-1;
(j>=1) && (troca==1); j--) { troca=0; /*Se o valor
continuar 0 na prxima passada quer dizer que no
houve troca e a funo encerrada.*/ for(i=0; i<j;
i++) { if(vetor[i]>vetor[i+1]) { memoria=vetor[i];
vetor[i]=vetor[i+1]; vetor[i+1]=memoria; troca=1; /*Se
houve troca, troca recebe 1 para continuar rodando.*/
}}}}

109

Captulo 49

Programar em C/Algoritmo de alocao


49.1 rst st

49.4 Next Fit

49.2 best t

49.5 Buddy System

Varre toda a memria e escolhe a pgina mais ajustada ao


tamanho do processo.
#include <stdio.h> #include <windows.h> int main(){
int p,m; printf(Entre o numero de processos:");
scanf("%d,&p); printf(Entre o numero de blocos de
memoria:"); scanf("%d,&m); int parr[p]; struct memoria{ int id; // identicador int tamanho; }marr[m]; int i;
for(i=0;i<p;i++) { printf(Entre o tamanho do processo
%d:",i+1); scanf("%d,&parr[i]); } for(i=0;i<m;i++) {
printf(Entre o tamanho do bloco de memoria %d:",i+1);
scanf("%d,&marr[i].tamanho); marr[i].id=i+1; } int j;
int tamanho = 0; for(i; tamanho <= marr[i].tamanho; i++
) tamanho = marr[i].tamanho; int tamanho_velho = tamanho ; int im ; bool marcador = false ; for(i=0;i<p;i++){
for(j=0;j<m;j++){ if((marr[j].tamanho>=parr[i]) &&
(marr[j].tamanho < tamanho) ){ im = j; tamanho =
marr[j].tamanho; marcador = true ; } } if(marcador){
marcador = false ; marr[im].tamanho-=parr[i]; tamanho = tamanho_velho ; printf("\n\nAloca o processo
%d no bloco memoria %d\n Tamanho restante apos
alocar
%d\n,i+1,marr[im].id,marr[im].tamanho);
}else {printf(Memoria insuciente para o processo
%d,i);break;} } system (pause); return 0; }

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

Programar em C/Lista de autores


50.1 Lista de autores
Edudobay - Eduardo Sangiorgio Dobay
EvertonS - Everton.S.Baron
Lightningspirit
ThiagoL
Uder
Wbrito
RenatoResende
Maxtremus
Noturno99 - Bruno Sampaio Pinho da Silva

111

112

CAPTULO 50. PROGRAMAR EM C/LISTA DE AUTORES

50.2 Fontes, contribuidores e licenas de texto e imagem


50.2.1

Texto

Programar em C/Capa Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Capa?oldid=186016 Contribuidores: Joaodaveiro,


Lightningspirit, Jorge Morais, SallesNeto BR, Edudobay, Wbrito, Master, Voz da Verdade, Delemon, David Stress,
robot, Elvire,
He7d3r.bot e Annimo: 9
Programar em C/Por que aprender a linguagem C Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Por%20que%
20aprender%20a%20linguagem%20C?oldid=271298 Contribuidores: Joo Jernimo, Lightningspirit, Jorge Morais, SallesNeto BR, Edudobay, Sourf, Wbrito, Thiagol, He7d3r.bot, Fabiobasso, Abacaxi e Annimo: 10
Programar em C/Histria da linguagem C Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Hist%C3%B3ria%20da%
20linguagem%20C?oldid=271327 Contribuidores: Lightningspirit, Jorge Morais, Scorpion, Edudobay, He7d3r, He7d3r.bot, JackPotte,
Abacaxi e Annimo: 14
Programar em C/Pr-requisitos Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Pr%C3%A9-requisitos?oldid=271305
Contribuidores: Marcos Antnio Nunes de Moura, Lightningspirit, Jorge Morais, Edudobay, Wbrito, Albmont, He7d3r, He7d3r.bot, Abacaxi e Annimo: 13
Programar em C/Utilizando um compilador Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Utilizando%20um%
20compilador?oldid=263662 Contribuidores: Edudobay, Master, Albmont, Thiagol, EvertonS, He7d3r.bot, JackBot, Fabiobasso, Abacaxi, Wesley Ferdinando R. Carvalho e Annimo: 3
Programar em C/Noes de compilao Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/No%C3%A7%C3%B5es%
20de%20compila%C3%A7%C3%A3o?oldid=212773 Contribuidores: SallesNeto BR, Edudobay, Wbrito, Thiagol, PatiBot, He7d3r.bot e
Aprendiz de feiticeiro
Programar em C/Um programa em C Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Um%20programa%20em%20C?
oldid=263594 Contribuidores: Marcos Antnio Nunes de Moura, Jorge Morais, Edudobay, Wbrito, Thiagol, EvertonS, Awillian,
He7d3r.bot, Fabiobasso e Annimo: 11
Programar em C/Conceitos bsicos Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Conceitos%20b%C3%A1sicos?
oldid=246560 Contribuidores: Edudobay, Wbrito, Thiagol, He7d3r, He7d3r.bot, Algum, Fabiobasso e Annimo: 3
Programar em C/Variveis Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Vari%C3%A1veis?oldid=271328 Contribuidores: Marcos Antnio Nunes de Moura, Jorge Morais, Edudobay, Wbrito, Thiagol, He7d3r, EvertonS, Mr.Yahoo!, He7d3r.bot, JackPotte,
Defender, Abacaxi e Annimo: 13
Programar em C/Tipos de dados Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Tipos%20de%20dados?oldid=272760
Contribuidores: Marcos Antnio Nunes de Moura, Daveiro, Jorge Morais, Marcelo-Silva, Wbrito, Master, Raylton P. Sousa, He7d3r.bot,
Fabiobasso, Abacaxi, PODEROS ARAN e Annimo: 12
Programar em C/Constantes Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Constantes?oldid=256737 Contribuidores:
Marcos Antnio Nunes de Moura, Daveiro, Jorge Morais, SallesNeto BR, Marcelo-Silva, Wbrito, Master, He7d3r, Abacaxi, Iraziel e
Annimo: 6
Programar em C/Entrada e sada simples Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Entrada%20e%20sa%C3%
ADda%20simples?oldid=263547 Contribuidores: Edudobay, Wbrito, Albmont, Thiagol, EvertonS, He7d3r.bot, Yuu eo, Abacaxi e Annimo: 12
Programar em C/Operaes matemticas (Bsico) Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Opera%C3%A7%
C3%B5es%20matem%C3%A1ticas%20(B%C3%A1sico)?oldid=248640 Contribuidores: Edudobay, Wbrito, He7d3r.bot, Abacaxi e
Annimo: 4
Programar em C/Operaes matemticas (Avanado) Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Opera%C3%A7%
C3%B5es%20matem%C3%A1ticas%20(Avan%C3%A7ado)?oldid=270610 Contribuidores: Marcos Antnio Nunes de Moura, SallesNeto BR, Wbrito, Thiagol, Rogerbo, He7d3r.bot e Annimo: 5
Programar em C/Operadores Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Operadores?oldid=271743 Contribuidores:
Marcos Antnio Nunes de Moura, Daveiro, Jorge Morais, Marcelo-Silva, Wbrito, Master, Petrusz1, Raylton P. Sousa, He7d3r.bot, Abacaxi
e Annimo: 5
Programar em C/Controle de uxo Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Controle%20de%20fluxo?oldid=
267376 Contribuidores: Edudobay, Wbrito, Albmont, Thiagol, He7d3r, Rogerbo, He7d3r.bot, Hycesar, Abacaxi e Annimo: 8
Programar em C/Funes Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Fun%C3%A7%C3%B5es?oldid=272289 Contribuidores: Marcos Antnio Nunes de Moura, Edudobay, Wbrito, Albmont, Rogerbo, EvertonS, Awillian, He7d3r.bot, Fabiobasso,
Hycesar, Victor Aurlio, Abacaxi, Cleiton wi e Annimo: 25
Programar em C/Pr-processador Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Pr%C3%A9-processador?oldid=
266815 Contribuidores: Lgrave, SallesNeto BR, Edudobay, Rogerbo, EvertonS, He7d3r.bot, Hycesar, Abacaxi e Annimo: 2
Programar em C/Exerccios Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Exerc%C3%ADcios?oldid=273632 Contribuidores: Marcos Antnio Nunes de Moura, Lightningspirit, Jorge Morais, Wbrito, Albmont, Delemon, Raylton P. Sousa, He7d3r.bot,
Algum, Abacaxi e Annimo: 8
Programar em C/Vetores Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Vetores?oldid=272709 Contribuidores: Marcos
Antnio Nunes de Moura, Dante Cardoso Pinto de Almeida, Edudobay, Wbrito, He7d3r, EvertonS, He7d3r.bot, Jonas AGX, Ajraddatz,
Fabiobasso, Hycesar, Abacaxi e Annimo: 20
Programar em C/Strings Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Strings?oldid=274023 Contribuidores: Marcos
Antnio Nunes de Moura, Jorge Morais, Edudobay, Wbrito, Albmont, PatiBot, He7d3r.bot, Defender, Stryn, Abacaxi e Annimo: 13
Programar em C/Passagem de parmetros Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Passagem%20de%20par%
C3%A2metros?oldid=245335 Contribuidores: Wbrito, David Stress, EvertonS, He7d3r.bot, Abacaxi e Annimo: 3

50.2. FONTES, CONTRIBUIDORES E LICENAS DE TEXTO E IMAGEM

113

Programar em C/Tipos de dados denidos pelo usurio Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Tipos%20de%


20dados%20definidos%20pelo%20usu%C3%A1rio?oldid=234520 Contribuidores: Edudobay, Wbrito, He7d3r.bot e Annimo: 5
Programar em C/Enumerao Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Enumera%C3%A7%C3%A3o?oldid=
255616 Contribuidores: Marcos Antnio Nunes de Moura, Daveiro, Jorge Morais, Marcelo-Silva, Wbrito, Master, He7d3r, EvertonS,
Abacaxi e Annimo: 10
Programar em C/Unio Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Uni%C3%A3o?oldid=255617 Contribuidores:
Marcos Antnio Nunes de Moura, Daveiro, Jorge Morais, Marcelo-Silva, Wbrito, Master, He7d3r.bot, Abacaxi e Annimo: 4
Programar em C/Estruturas Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Estruturas?oldid=270091 Contribuidores:
Marcos Antnio Nunes de Moura, Daveiro, Jorge Morais, Marcelo-Silva, Wbrito, Master, Albmont, EvertonS, He7d3r.bot, Abacaxi e
Annimo: 19
Programar em C/Ponteiros Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Ponteiros?oldid=274221 Contribuidores: Marcos Antnio Nunes de Moura, Jorge Morais, Edudobay, Wbrito, Albmont, EvertonS, Jesielt, He7d3r.bot, Noturno99, Fabiobasso, Hycesar,
Abacaxi, Jnior D. Eskelsen,, C++NERD, Su e Annimo: 19
Programar em C/Mais sobre variveis Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Mais%20sobre%20vari%C3%
A1veis?oldid=273621 Contribuidores: Edudobay, Wbrito, He7d3r, GabrielFalcao, PatiBot, He7d3r.bot, Abacaxi e Annimo: 4
Programar em C/Mais sobre funes Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Mais%20sobre%20fun%C3%A7%
C3%B5es?oldid=250214 Contribuidores: EvertonS e Abacaxi
Programar em C/Bibliotecas Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Bibliotecas?oldid=265808 Contribuidores:
Edudobay, Wbrito, He7d3r, Rogerbo, EvertonS, He7d3r.bot, Torneira e Annimo: 4
Programar em C/Entrada e sada em arquivos Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Entrada%20e%20sa%
C3%ADda%20em%20arquivos?oldid=272771 Contribuidores: Marcos Antnio Nunes de Moura, Edudobay, Wbrito, EvertonS, PatiBot,
He7d3r.bot, MateusGPe, Abacaxi e Annimo: 5
Programar em C/Gerenciamento de memria Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Gerenciamento%20de%
20mem%C3%B3ria?oldid=266464 Contribuidores: Marcos Antnio Nunes de Moura, Edudobay, PatiBot, He7d3r.bot, Frigotoni, Abacaxi,
Gabrielhtec e Annimo: 7
Programar em C/Sockets Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Sockets?oldid=253321 Contribuidores: Jorge
Morais, Albmont, EvertonS, He7d3r.bot, Abacaxi e Annimo: 6
Programar em C/Makeles Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Makefiles?oldid=272765 Contribuidores:
Jorge Morais, David Stress, He7d3r, EvertonS, He7d3r.bot e Annimo: 31
Programar em C/Lista de palavras reservadas Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Lista%20de%
20palavras%20reservadas?oldid=186025 Contribuidores: Jorge Morais, He7d3r.bot e Annimo: 1
Programar em C/Seqncias de escape Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Seq%C3%BC%C3%AAncias%
20de%20escape?oldid=186035 Contribuidores: SallesNeto BR, Master, Devarde, He7d3r.bot e Annimo: 1
Programar em C/Lista de funes Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Lista%20de%20fun%C3%A7%C3%
B5es?oldid=186024 Contribuidores: SallesNeto BR, Master, Devarde e He7d3r.bot
Programar em C/Lista de bibliotecas Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Lista%20de%20bibliotecas?oldid=
254253 Contribuidores: Marcos Antnio Nunes de Moura, Jorge Morais, EvertonS, He7d3r.bot, Abacaxi e Annimo: 2
Programar em C/Dicas de programao em C Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Dicas%20de%
20programa%C3%A7%C3%A3o%20em%20C?oldid=258291 Contribuidores: Dante Cardoso Pinto de Almeida, He7d3r, He7d3r.bot,
Abacaxi e Annimo: 6
Programar em C/Listas encadeadas Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Listas%20encadeadas?oldid=263996
Contribuidores: Jorge Morais, Maxtremus, EvertonS, He7d3r.bot, Abacaxi, Gabrielhtec e Annimo: 13
Programar em C/Pilha Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Pilha?oldid=269386 Contribuidores: He7d3r.bot,
Lukas e Annimo: 4
Programar em C/Fila ou Queue Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Fila%20ou%20Queue?oldid=243774
Contribuidores: Defender, Abacaxi e Annimo: 3
Programar em C/rvores binrias Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/%C3%81rvores%20bin%C3%A1rias?
oldid=273253 Contribuidores: Marcos Antnio Nunes de Moura, Maxtremus, EvertonS, Ruy Pugliesi, He7d3r.bot, Abacaxi, Aldnonymous
e Annimo: 27
Programar em C/Algoritmos de ordenao Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Algoritmos%20de%
20ordena%C3%A7%C3%A3o?oldid=254603 Contribuidores: EvertonS, He7d3r.bot, Abacaxi e Annimo: 6
Programar em C/Algoritmo de alocao Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Algoritmo%20de%20aloca%
C3%A7%C3%A3o?oldid=270419 Contribuidores: Jorge Morais, EvertonS, He7d3r.bot, Torneira e Annimo: 3
Programar em C/Lista de autores Fonte: http://pt.wikibooks.org/wiki/Programar%20em%20C/Lista%20de%20autores?oldid=274359
Contribuidores: Marcos Antnio Nunes de Moura, EvertonS, He7d3r.bot, RenatoResende, Cardinhotk e Annimo: 4

50.2.2

Imagens

Ficheiro:Crystal_Clear_app_kaddressbook.png Fonte: http://upload.wikimedia.org/wikipedia/commons/7/74/Crystal_Clear_app_


kaddressbook.png Licena: LGPL Contribuidores: All Crystal icons were posted by the author as LGPL on kde-look Artista original:
Everaldo Coelho and YellowIcon
Ficheiro:EsquemaPonteiro.png Fonte: http://upload.wikimedia.org/wikibooks/pt/1/12/EsquemaPonteiro.png Licena: ? Contribuidores: ? Artista original: ?

114

CAPTULO 50. PROGRAMAR EM C/LISTA DE AUTORES

Ficheiro:Exercicios_c_cover.png Fonte: http://upload.wikimedia.org/wikibooks/pt/0/01/Exercicios_c_cover.png Licena: ? Contribuidores: ? Artista original: ?


Ficheiro:Ken_n_dennis.jpg Fonte: http://upload.wikimedia.org/wikipedia/commons/3/36/Ken_n_dennis.jpg Licena: Public domain
Contribuidores: http://www.catb.org/~{}esr/jargon/html/U/Unix.html Artista original: Desconhecido
Ficheiro:Merge-arrows.svg Fonte: http://upload.wikimedia.org/wikipedia/commons/5/52/Merge-arrows.svg Licena: Public domain
Contribuidores: ? Artista original: ?
Ficheiro:Nuvola_apps_konsole.png Fonte: http://upload.wikimedia.org/wikipedia/commons/2/24/Nuvola_apps_konsole.png Licena:
LGPL Contribuidores: http://icon-king.com Artista original: David Vignoni / ICON KING
Ficheiro:Programar_c_cover.png Fonte: http://upload.wikimedia.org/wikibooks/pt/6/6d/Programar_c_cover.png Licena: ? Contribuidores: ? Artista original: ?
Ficheiro:Recycle001.svg Fonte: http://upload.wikimedia.org/wikipedia/commons/4/44/Recycle001.svg Licena: Public domain Contribuidores: Originally from en.wikipedia; description page is (was) here Artista original: Users Cbuckley, Jpowell on en.wikipedia
Ficheiro:Searchtool.svg Fonte: http://upload.wikimedia.org/wikipedia/commons/6/61/Searchtool.svg Licena: LGPL Contribuidores:
http://ftp.gnome.org/pub/GNOME/sources/gnome-themes-extras/0.9/gnome-themes-extras-0.9.0.tar.gz Artista original: David Vignoni,
Ysangkok

50.2.3

Licena

Creative Commons Attribution-Share Alike 3.0

Вам также может понравиться