Anda di halaman 1dari 105

Progamar en C

wikilibros

ndice general
1

Programacin en C

1.1

Prlogo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.1.1

Para quin es este libro? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.1.2

Por qu otro manual de C?

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

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

Anexos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.3

Enlaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.4

Licencia y autores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.5

Cmo contribuir a este WikiLibro? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.2

ndice de contenidos
1.2.1

Programacin en C/Introduccin

2.1

Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.2

Nota sobre la exactitud . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3

Estndar utilizado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.4

Para los principiantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.5

Para los ms avanzados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.6

Requisitos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.7

Herramientas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.8

Windows

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

2.9

GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Programacin en C/Historia de C

3.1

Evolucin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3.2

Ms informacin

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

Programacin en C/Fundamentos de programacin

10

4.1

Deniciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

4.2

Tipos de lenguajes

10

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

4.2.1

Esquemas de programacin

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

10

4.2.2

Alto o bajo nivel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

ii

NDICE GENERAL
4.2.3
4.3

Compilados o interpretados

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

11

Estructura de la memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

Programacin en C/Primer programa en C

12

5.1

Pre-requisitos para la compilacin de programas . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

12

5.2

Compilacin de programas segn la plataforma

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

13

5.2.1

Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13

5.2.2

GNU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

5.3

Diseccionando el Hola Mundo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

5.4

Comentarios

16

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

Programacin en C/Tipos de datos

17

6.1

Historia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17

6.2

Enteros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17

6.3

Flotantes

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

18

6.4

Caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

Programacin en C/Expresiones

19

Programacin en C/Interaccin con el usuario

21

8.1

Imprimir por pantalla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

21

8.2

Lectura de datos del teclado

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

22

La funcin scanf() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

22

8.2.1
9

Programacin en C/Instrucciones de control

23

9.1

La estructura condicional if ... else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

23

9.1.1

Operadores de comparacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

24

9.1.2

Operadores lgicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

24

9.1.3

Evaluacin de cortocircuito

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

24

9.2

La estructura condicional abierta y cerrada switch ... case . . . . . . . . . . . . . . . . . . . . . . . . .

25

9.3

El bucle while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

25

9.4

El bucle for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

26

9.5

El bucle do...while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

26

9.6

La sentencia goto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

26

10 Programacin en C/Uso de funciones

28

10.1 Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

28

10.1.1 La sentencia return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

28

10.1.2 Argumentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

28

10.1.3 Declaracin y denicin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29

10.1.4 Paso de Parmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29

NDICE GENERAL

iii

10.1.5 Variables Locales y Globales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

30

10.2 Funciones Recursivas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

30

10.2.1 Recursividad indirecta o recursin mutua . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31

10.2.2 Recursin versus Iteracin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

11 Programacin en C/Vectores

33

12 Programacin en C/Cadenas de caracteres

35

13 Programacin en C/Manejo de archivos

37

13.1 Ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

37

13.1.1 fopen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

37

13.1.2 fclose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38

13.1.3 feof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38

13.1.4 rewind . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38

13.2 Lectura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39

13.2.1 fgetc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39

13.2.2 fgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39

13.2.3 fread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

13.2.4 fscanf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

13.3 Escritura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

13.3.1 fputc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

41

13.3.2 fputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

41

13.3.3 fwrite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

41

13.3.4 fprintf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

41

14 Programacin en C/Estructuras y Uniones

43

14.1 Estructuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

43

14.1.1 Estructuras Anidadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

44

14.2 Uniones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

45

14.3 Enumeraciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

45

15 Programacin en C/Punteros

47

16 Concepto

48

17 Declarando punteros

49

18 Explicacin

50

19 Operadores

51

iv

NDICE GENERAL

20 Operaciones Aritmticas

52

21 Punteros Constantes

53

22 Punteros Genericos

54

23 Punteros y Matrices

55

24 Punteros a cadenas de caracteres

56

25 Matrices de Punteros

57

26 Punteros a Punteros

58

27 Matrices de punteros a cadenas de caracteres

59

28 Ejemplos

60

28.0.1 Asignando valores a punteros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


29 Programacin en C/Manejo dinmico de memoria
29.1 Memoria dinmica

60
62

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

62

29.2 Memoria esttica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

62

29.3 Diferencias, ventajas y desventajas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

62

29.4 El lenguaje C y el manejo de la memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

63

29.4.1 malloc

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

63

29.4.2 calloc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

64

29.4.3 realloc

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

64

29.4.4 free . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

64

29.5 Buenas prcticas

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

65

30 Programacin en C/Matrices Dinamicas

66

31 Concepto

67

32 Matrices Dinamicas de Dos Dimensiones

68

33 Programacin en C/Algoritmos y Estructuras de Datos

69

34 Concepto

70

35 Metodo de Burbuja (Buble Sort)

71

35.1 Explicacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

71

35.2 Ejemplos

72

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

NDICE GENERAL

36 Mtodo de Insercin

73

36.1 Concepto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

73

36.2 Explicacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

73

36.3 Ejemplos

73

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

37 Mtodo QuickSort

74

37.1 Concepto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

74

37.2 Explicacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

74

37.3 Ejemplos

75

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

38 Programacin en C/El proceso de compilacin

76

39 Los pasos del proceso

77

39.1 Ejemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40 Programacin en C/Los errores

77
79

40.1 Chequeos del C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


41 Programacin en C/Herramientas externas tiles
41.1 Sistemas de construccin de cdigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
42 make

79
80
80
81

42.1 Sistemas de control de versiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


43 Programacin en C/Ejemplos

82
83

43.1 El Hola Mundo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

83

43.2 El Hola Mundo comentado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

83

43.3 El Hola Mundo estructurado en funciones

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

83

43.4 Ejemplo de clculo con enteros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

84

43.5 Control de acceso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

84

44 Programacin en C/Glib

86

44.1 Introduccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

86

44.2 Ejemplos de uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

87

44.3 Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

87

45 Programacin en C/Referencia

88

45.1 Tipos de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

88

45.2 Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

89

45.3 Estructuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

90

45.4 Bibliotecas y funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

90

45.5 Preprocesador de C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

91

vi

NDICE GENERAL

46 Programacin en C/Cmo compilar un programa


46.1 Un poco ms sobre compilacin

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

92
92

47 Programacin en C/Cdigo embebido

93

48 Programacin en C/Recursos en la red

94

48.1 Manuales, tutoriales y otros documentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

94

48.1.1 Espaol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

94

48.1.2 Ingls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

94

48.2 Compiladores e IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

94

49 Programacin en C/Bibliografa

96

49.1 Bibliografa en espaol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

96

49.2 Bibliografa en ingls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

96

49.3 Text and image sources, contributors, and licenses . . . . . . . . . . . . . . . . . . . . . . . . . . . .

97

49.3.1 Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

97

49.3.2 Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

98

49.3.3 Content license . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

98

Captulo 1

Programacin en C
1.1 Prlogo
El avance de la tecnologa y la concurrente entrega de informacin, nos permite generar una edicin, variable y alternativa
en la enseanza del lenguaje de programacin que ms impacto social ha tenido en la historia de la informtica. Este libro
ha sido forjado con la incansable ayuda de informticos de habla hispana, quienes byte a byte han colaborado por hacer de
la informacin una fuente de conocimiento global. De la misma forma, contina hoy siendo modicado en una constante
bsqueda de superacin de la calidad.
Esta obra est llamada a ser la piedra angular en la enseanza de la programacin, logrando abarcar todos los aspectos del
lenguaje en diversos niveles y de esta forma ser tanto una referencia tcnica para quienes ya dominan el lenguaje como
una introduccin sencilla para quienes estn empezando a conocerlo.
Viajaremos por la historia del lenguaje, veremos su propsito e indagaremos en la ciencia de la programacin. El n es
otorgar al lector una doctrina clara de la programacin y el lenguaje C; lo induciremos a conseguir un manejo importante
del lenguaje.

1.1.1

Para quin es este libro?

Este libro est dirigido a todos los que deseen obtener conocimientos de programacin, pues el objetivo explcito que nos
ha motivado a crearlo es difundir la importancia del lenguaje C en el mundo de la informtica. Si nos enfocamos a un
grupo social especco, podremos indicar que este libro contribuir con los estudiantes de carreras del rea informtica,
debido a que los temas convenidos, son parte de su plan de estudios.

1.1.2

Por qu otro manual de C?

Porque el lenguaje C es la base fundamental de la programacin. Para quienes estn en el ambiente de la informtica
es crucial tener por lo menos nociones de este lenguaje. Varios sistemas operativos, cientos de bibliotecas, y miles de
programas estn construidos utilizando C, al conocerlo es posible entender, colaborar y desarrollar en este lenguaje.
Los sistemas, programas, juegos y herramientas que nosotros disfrutamos hoy fueron construidos por personas como
nosotros, que empezaron con nuestro mismo potencial y fueron aprendiendo a hacer cosas fantsticas con las herramientas
que tenan a mano.
Una razn importante para otro libro de lenguaje C es tambin que los libros existentes muestran muy poca documentacin de calidad. En Internet existe una cantidad inmensa de informacin publicada pero est dispersa, y mal manejada
en algunos sitios. Es la intencin de este libro crear un buen compendio de informacin, que permita a los interesados
aprender a programar en C.
1

CAPTULO 1. PROGRAMACIN EN C

1.2 ndice de contenidos


1. Introduccin
(a) Herramientas necesarias
2. Historia de C
3. Fundamentos de programacin
4. Primer programa en C
(a) Compilacin de programas en C
5. Tipos de datos
(a) Enteros
(b) Reales
(c) Caracteres
6. Expresiones
7. Interaccin con el usuario
8. Instrucciones de control
(a) La estructura condicional if...else
(b) La estructura condicional switch...case
(c) El bucle for
(d) El bucle while
(e) El bucle do...while
(f) La sentencia goto
9. Uso de Funciones
10. Vectores
11. Cadenas de caracteres
12. Manejo de archivos
(a) Lectura
(b) Escritura
(c) fread y fwrite
13. Estructuras y Uniones
(a) Estructuras
(b) Uniones
14. Punteros
15. Manejo dinmico de memoria
16. Matrices Dinamicas
17. Algoritmos y Estructuras de Datos
(a) Punteros a Estructuras

1.2. NDICE DE CONTENIDOS


(b) Ordenamiento de Datos
i. Burbuja
ii. Induccion
iii. QuickSort
18. Detalles sobre el proceso de compilacin
19. Los errores
(a) Chequeos del C
(b) El depurador
20. Herramientas externas tiles
21. Resumen de ejemplos
(a) El Hola Mundo
(b) El Hola Mundo comentado
(c) El Hola Mundo estructurado en funciones
(d) Ejemplo de clculo con enteros
(e) Ejemplo comentado de clculo con enteros
(f) Calendario en C
(g) Clculo del logaritmo binario
22. La librera glib
23. Programacin paralela en memoria compartida

1.2.1

Anexos

1. Referencia
(a) Tipos de datos
(b) Operadores
(c) Estructuras
(d) Bibliotecas y funciones
2. Cmo compilar un programa
(a) Un poco ms sobre compilacin
3. Cdigo embebido
4. Recursos en la red
(a) Manuales, tutoriales y otros documentos
(b) Compiladores e IDEs
5. Bibliografa

CAPTULO 1. PROGRAMACIN EN C

1.3 Enlaces
Nociones bsicas de programacin (generales, independientes del lenguaje):
Fundamentos de programacin
Wikilibro similar a ste en ingls
C Programming
esquema de operadores y expresiones

1.4 Licencia y autores


Copyright 2004 Envite
Copyright 2005 Alejandro Moreno Calvo
Copyright 2006 Andreu Correa Casablanca
Copyright 2009 zerohours
Ver el historial de cada pgina para el resto de autores.

1.5 Cmo contribuir a este WikiLibro?


Contribuir con este libro es muy simple primero deberas registrarte un usuario y/o entrar (esto no es necesario pero si muy
conveniente) a Wikilibros, para que podamos identicar tus ediciones. Luego, si nunca has contribuido en un proyecto de
wikipedia o en otro wiki deberas leer el manual de uso de wikilibros.
Una vez hecho esto todo lo que tienes que hacer es agregar el contenido que consideres necesario para el libro. Para editar
cualquier seccin basta con hacer click al link que dice editar en la pestaa en la parte superior de la pagina, seria bueno
revisar (antes de editar cualquier cosa) la pestaa de discusin que est ah para ser usada. Ten en cuenta que el material
que ya est fue escrito por personas que deseaban contribuir igual que t, as que trata de respetarlo. Aunque con esto no
me reero a que si se necesita alguna correccin, reorganizacin, quitar partes que sean ambiguas, no dejes de hacerlo.
Lo mejor sera que todos contribuyramos de cualquier manera al libro.
Adems, es recomendable consultar la pgina de discusin del libro y la del articulo en particular que quieras modicar,
ya que de esta manera se pueden coordinar esfuerzos.
Recuerda que todo el contenido que aadas al libro es publicado bajo la licencia GFDL, por lo que no uses material que
no haya sido escrito por ti o que no est ya publicado bajo GFDL. Recientemente wikimedia decidi adoptar la Licencia
Creative Commons Compartir-Igual 3.0 para todos los aportes, por lo que actualmente el libro tiene una licencia dual.

Captulo 2

Programacin en C/Introduccin
2.1 Objetivos
El objetivo principal de este Wikilibro es que cualquier persona sin conocimientos previos de programacin pueda ser
capaz de programar en el lenguaje C.
Una vez logrado el dominio del lenguaje, es probable que los lectores se interesen por otros temas ms complejos que
superen a los temas bsicos. Tambin les ser ms o menos sencillo aprender cualquier otro lenguaje de programacin
estructurada.
Sin embargo, este no es un libro que apunte nicamente a programadores principiantes. Tambin puede resultar de inters
para quienes ya tengan experiencia en el rea de programacin. En esta introduccin hay dos secciones en las que se
explica para los dos grupos principales de lectores qu camino seguir para comenzar a programar en el lenguaje C o bien
perfeccionar conocimientos.
El lenguaje C es tan usado porque es un lenguaje de programacin que emplea pocas instrucciones en lenguaje mquina
para traducir elementos del cdigo. Esto reduce los tiempos de ejecucin de los programas.

2.2 Nota sobre la exactitud


Muchas de las cosas expresadas en este wikilibro, especialmente en los primeros captulos, no son completamente exactas,
aunque son buenas aproximaciones. Los detalles ms exactos irn apareciendo posteriormente, una vez que los materiales
anteriores hayan sido correctamente asimilados por el lector. En general, dadas dos deniciones o datos contradictorios
en este wikilibro, debe considerarse siempre como ms exacto al segundo, habiendo aparecido el primero como una
introduccin ms general al tema.

2.3 Estndar utilizado


El lenguaje C fue creado en los aos setenta, y a lo largo de su historia ha pasado por muchas modicaciones, tanto con
respecto a la sintaxis como con respecto al cdigo incluido dentro de la biblioteca estndar. Es por ello que se fueron
desarrollando estndares, para que todos sepan con qu versin del lenguaje se est trabajando.
Los distintos estndares del lenguaje C han sido: el C de Kernighan y Ritchie, un estndar no-ocial que surgi luego de
la publicacin de su libro en 1978; el C89 o C90, el primer estndar ocial, posterior a la publicacin de los estndares
ANSI en 1989 e ISO en 1990; y el C99, publicado en 1999.
En este libro se utilizar el estndar C99, si bien por cuestiones de estilo y compatibilidad muchas veces se utilizar cdigo
compatible con el estndar C89.
5

CAPTULO 2. PROGRAMACIN EN C/INTRODUCCIN

2.4 Para los principiantes


Para quien no haya programado antes, es recomendable seguir el orden del libro. Los temas estn especialmente organizados de manera incremental o acumulativa. Tal vez, lo que se te va a hacer ms til en el camino del aprendizaje es
la constancia; s terco, no trastabilles, no te rindas, tal vez tu pregunta sea cuntas veces tengo que intentar?, las veces
necesarias para lograr tu objetivo, sera la respuesta.
Claro que el principal enemigo de nosotros los humanos es el tiempo y por eso en caso de que de verdad ests trancado en
algo busca ayuda de alguien que sepa ms que t". Que no tienes a nadie a tu alrededor con esa caracterstica? Tal vez
no buscaste bien y tal vez quieras usar la red de redes. Utiliza los buscadores, pregunta en IRC, en foros de programacin,
en listas de correo.

2.5 Para los ms avanzados


El lanzamiento queda libre por supuesto, solo t sabes lo que necesitas. Las reglas del juego son las mismas de siempre:
primero saber lo que se quiere o necesita y atacar por ah.
En este caso, te ser til acceder a los contenidos a partir del ndice, eligiendo slo aquellos que te sean necesarios.

2.6 Requisitos
Se presupone que los lectores tienen conocimientos elementales de informtica a nivel de usuario, y son capaces de instalar
un compilador del lenguaje C en sus sistema. Los detalles sobre la instalacin se vern en la seccin Herramientas.
Con respecto al Hardware, slo ser necesario contar con una PC con sistema operativo, donde sea posible instalar un
compilador, y en lo posible un entorno de desarrollo. Cuanto mejor sea la computadora, ms rpido ser el proceso de
compilacin y ejecucin de los programas. Sin embargo, cualquier PC sirve para aprender con los ejemplos de este libro.
Para quienes no tengan conocimientos bsicos de programacin, puede ser una buena idea comenzar leyendo los primeros captulos del Wikilibro Fundamentos de programacin, ya que algunos temas explicados en ese libro se asumen ya
conocidos.
Finalmente, un requisito imprescindible en todo programador es tener sentido comn. Muchas veces se pueden adoptar
mejores o peores soluciones ante los diversos problemas, y la decisin de cul elegir pasa por la aplicacin del sentido
comn.

2.7 Herramientas
Para programar tanto en C, como en C++, Java o cualquier otro lenguaje de programacin, necesitamos contar con
aplicaciones o herramientas que nos permitan poner en funcionamiento nuestro programa.
El lenguaje de programacin C es compilado, as que en este caso necesitaremos un compilador, que ser el encargado
de transformar nuestro cdigo fuente en cdigo que la computadora pueda ejecutar.
Adems, para facilitar la tarea de los programadores existen los denominados Entorno de desarrollo integrados (IDE).
En muchos casos, estos entornos incluyen un compilador, un depurador, y otras herramientas.
Las herramientas a instalar dependern del sistema operativo utilizado. A continuacin se listan algunas posibilidades
para el sistema operativo Windows o GNU/Linux, no es imprescindible utilizar estas herramientas en particular, cualquier
compilador puede servir.

2.8. WINDOWS

2.8 Windows
Uno de los entornos de desarrollo ms conocidos entre los programadores de C sobre Windows, tanto novatos como
expertos, es el Bloodshed Dev-C++, que es un entorno libre multiplataforma. Tal entorno de desarrollo fue abandonado y
retomado mejorndolo pasando a llamarse WxDev-C++. Otro entorno libre y gratuito es el Code::Blocks. Ambos entornos
pueden utilizarse tanto para C como para C++.
Tambin hay otras alternativas privativas como los compiladores de Borland o de Microsoft (Microsoft Visual C++).

2.9 GNU/Linux
En los sistemas GNU/Linux, ser necesario tener instaladas las herramientas gcc y make y la versin 6 de la glibc con
su documentacin, que son las que permitirn compilar los programas.
Para escribir y modicar el cdigo, es posible utilizar cualquier editor de texto plano (en lo posible que cuente con resaltado
de sintaxis), como son emacs, vim, kate, gedit o geany.
Sin embargo, para quienes son novatos en la programacin, es recomendable utilizar un entorno de desarrollo como son el
Anjuta DevStudio (para el entorno GNOME) o KDevelop (para el entorno KDE), ya que incluyen facilidades adicionales
para la ejecucin y solucin de problemas.
Los programas mencionados se incluyen dentro de la instalacin estndar de la mayora de las distribuciones actuales de
GNU/Linux, de modo que para instalarlos slo ser necesario seguir el procedimiento usual de instalacin de aplicaciones
para la distribucin deseada.

Captulo 3

Programacin en C/Historia de C
El lenguaje de programacin C fue creado por Dennis Ritchie entre 1969 y 1973 cuando trabajaba en Bell Laboratories
de AT&T junto con Ken Thompson en el diseo del sistema operativo UNIX. C fue creado para poder escribir dicho
sistema operativo en un lenguaje de alto nivel, independiente del hardware donde se ejecutara.
Contar con un lenguaje de alto nivel permiti el avance de los sistemas operativos, ya que el mismo cdigo poda ser
utilizado en las distintas plataformas, propiciando la reutilizacin de cdigo y reduciendo los tiempos de desarrollo. As es
que los sistemas operativos basados en UNIX, el sistema BSD, el sistema GNU/Linux y muchos otros fueron desarrollados
en C.
Adems, con el paso del tiempo se han desarrollado cientos de bibliotecas que permiten a los programadores de C utilizar
el cdigo desarrollado por otros para la realizacin de tareas comunes. Esto, a su vez, ha propiciado el desarrollo de
aplicaciones en lenguaje C.
Actualmente es imposible contar la cantidad de aplicaciones y herramientas desarrolladas en C.

3.1 Evolucin
A mediados de los aos 60s, Martin Richards dise el lenguaje BCPL con la nalidad de usarlo para escribir software
de sistemas operativos y compiladores.
En 1969, Ken Thompson escribi el Lenguaje B, en Bell Laboratories, con el objetivo de recodicar UNIX (escrito hasta
ese momento en lenguaje ensamblador) usando un lenguaje de alto nivel ms portable y exible.
Durante los siguientes aos, Dennis Ritchie modic el lenguaje B, llegando a crear el lenguaje C y reescribiendo el
sistema UNIX en dicho lenguaje; aadi caractersticas nuevas, como son el diseo de tipos y las estructuras de datos.
En 1978, Dennis Ritchie y Brian Kernighan publicaron la primera edicin del libro El lenguaje de programacin C. Este
libro fue durante aos la especicacin informal del lenguaje. El lenguaje descrito en la primera edicin de este libro, fue
conocido como el C de Kernighan y Ritchie o simplemente K&R C. En este libro se introdujeron nuevas caractersticas
al lenguaje: los tipo de datos struct, long int y unsigned int; los operadores =+ y =- fueron sustituidos por += y -=.
A mediados de los aos 80, Bjarne Stroustrup (tambin de los laboratorios Bell), crea el lenguaje C++, un lenguaje basado
en C, con numerosas caractersticas adicionales, siendo la principal que est orientado a objetos. Si bien se han creado
muchos lenguajes basados en C, C++ es el que ha permanecido ms asociado a C.
En los aos siguientes a la publicacin del C de Kernighan y Ritchie, se aadieron al lenguaje muchas caractersticas
no ociales, que estaban presentes en algunos compiladores y no en otros. Fue por ello que en 1989 ANSI (American
National Standards Institute) public el primer estndar ocial de C, que es conocido como ANSI C.
En este estndar se tomaron muchas de las funcionalidades no ociales y se agregaron funcionalidades nuevas como los
prototipos de funcin, y un preprocesador mejorado. Tambin se cambi la sintaxis de la declaracin de parmetros de
funciones, para que incluyeran el tipo junto con el nombre.
8

3.2. MS INFORMACIN

Al ao siguiente, en 1990 se public la estandarizacin ISO del lenguaje. Este estndar es bsicamente el estndar ANSI,
con unas pocas modicaciones de formato. A este estndar se lo conoce, entonces, como C89, o C90, y se trata del mismo
lenguaje.
Basndose en el estndar ANSI que estaba en preparacin, en 1988 Kernighan y Ritchie publicaron la segunda edicin
de su libro, que es an hoy utilizada como una de las referencias principales del lenguaje.
Durante los siguientes aos, el lenguaje C permaneci sin demasiados cambios. Sin embargo, como haba sucedido antes,
los distintos compiladores fueron incorporando caractersticas adicionales, que otros compiladores no tenan, siendo C++
la principal inuencia.
Fue por ello que a nales de los noventa se decidi revisar el estndar de C, lo que llev a la publicacin del estndar C99.
Este estndar incluye varias nuevas caractersticas como son: las funciones inline; la posibilidad de declarar variables en
cualquier parte del cdigo; los comentarios de una sola lnea utilizando //; los tipos de datos long long int, bool y complex,
entre otras.
An hoy el proceso de evolucin del lenguaje sigue avanzando, y desde 2007 se est trabajando en el armado de un nuevo
estndar.

3.2 Ms informacin
Lenguaje de programacin BCPL
Historia del lenguaje del programacin C
The Development of the C Language

Captulo 4

Programacin en C/Fundamentos de
programacin
En este captulo veremos un resumido listado de conceptos bsicos, esta informacin puede encontrarse en forma ms
elaborada en el WikiLibro Fundamentos de programacin.

4.1 Deniciones
Se denomina algoritmo a una secuencia de instrucciones que permiten obtener un resultado en particular. No
necesariamente son programas de computadora, una receta de cocina, o las instrucciones para cambiar un neumtico
son ejemplos de algoritmos de la vida real.
Las computadoras, son maquinas sin inteligencia propia, cuya nica nalidad es interpretar el cdigo que se les
provee.
El lenguaje de mquina es el nico lenguaje que la computadora entiende y es capaz de ejecutar.
Los lenguajes de programacin son el medio de comunicacin entre el programador y una computadora. El
programador escribe en algn lenguaje de programacin y utiliza las herramientas provistas por ese lenguaje para
transformarlo en lenguaje de mquina.
Finalmente, denominamos programa a una secuencia de rdenes a ser ejecutadas por una computadora. Un programa debe estar escrito en algn lenguaje de programacin, y puede incluir uno o ms algoritmos.

4.2 Tipos de lenguajes


Existe una gran cantidad de lenguajes de programacin, que estn pensados para distintas nalidades, siguen distintos
paradigmas, y de una u otra forma se diferencian de los dems.

4.2.1

Esquemas de programacin

El esquema de programacin llamado Programacin Imperativa, consiste en escribir una secuencia de instrucciones
una detrs de la otra, que se ejecutarn en orden. Algunas de esas instrucciones pueden hacer que la mquina pase a una
instruccin que no sea la siguiente, tal vez porque se cumpla una condicin que hayamos establecido.
10

4.3. ESTRUCTURA DE LA MEMORIA

11

En los ltimos aos ha tomado fuerza otro paradigma de computacin, llamado Programacin Orientada a Objetos ,
en el cual se intentan modelar los sistemas creados como extensiones de la realidad mediante la denicin de objetos
que modelan entidades de la vida real y que interactan entre s mediante mensajes llamadas mtodos.
El lenguaje C es un lenguaje imperativo, no orientado a objetos.

4.2.2

Alto o bajo nivel

Por otro lado, los lenguajes de programacin se clasican en niveles. Un lenguaje es de ms bajo nivel cuanto ms cercano
est al cdigo de mquina, y un lenguaje que es de ms alto nivel cuanto ms lejano est de la mquina y ms cercano al
lenguaje humano.
C es un lenguaje de alto nivel aunque tiene muchas caractersticas de lenguaje de bajo nivel (como el uso que permite hacer
de la memoria). Estas caractersticas hacen que C sea un lenguaje muy potente, ya que permite optimizar al mximo los
recursos de la mquina. Por ende, esto tambin hace que la dicultad y que los errores que se puedan cometer programando
aumenten. As que a C se le considera de nivel medio.
Lenguajes de ms alto nivel que C son aquellos en los que el programador no necesita encargarse de manipular la memoria,
como Java, C#, Python, Ruby, entre otros.

4.2.3

Compilados o interpretados

Otra forma de clasicar a los lenguajes de programacin que es segn la forma en que se ejecutan sus rdenes. Existen
los lenguajes que son interpretados, cuyas rdenes pasan a travs de un intrprete que se encarga de ejecutarlas (a partir
del cdigo fuente) en el mismo momento en que estn siendo ledas. Algunos de los lenguajes interpretados son Python,
Perl o Tcl, entre muchos otros.
La contraparte de los lenguajes interpretados son los lenguajes compilados (como el mismo C) que se diferencian en
que las rdenes son transformadas a lenguaje de mquina que se almacena en un archivo ejecutable. Ese archivo puede
ejecutarse luego, sin recurrir al compilador.
Los lenguajes compilados tienen la ventaja de la velocidad y la eciencia, pero los interpretados tienen la ventaja de que,
generalmente, son muy portables y de ms alto nivel.

4.3 Estructura de la memoria


Parte de esta potencia de C viene de que permite acceder con mucha libertad a la memoria de la mquina. Para entender
un poco cmo es posible, debemos entender cmo se guardan los datos en la memoria.
Imaginemos que la memoria tiene un montn de casillas, una enorme la de casillas, cada una de las cuales contiene un
dgito binario (bit):
0101001010100001010101001010000100111010110010010101001011010110001101010110101010110111...
Es exactamente as, pero es ms cmodo recordar que esos bits se encuentran agrupados de ocho en ocho, formando
octetos (bytes):
Cada octeto puede contener 28 = 256 combinaciones distintas de ceros y unos, es decir, cualquier nmero entre 0 y 255:
Tambin podemos representar estos nmeros en base hexadecimal:
O considerarlos caracteres, mediante alguna codicacin:
Este es el tipo de dato ms elemental que nos podemos encontrar en C: el caracter. Un caracter ocupa exactamente un
byte (8 bits) de memoria, y puede contener un nmero entre 0 y 255, o entre 128 y 127, dependiendo si queremos
considerarlo como sin signo o con l.

Captulo 5

Programacin en C/Primer programa en C


En el libro El Lenguaje de Programacin C, Kernighan y Ritchie introdujeron al lenguaje C utilizando un sencillo
programa que mostraba un saludo por la pantalla. Desde entonces se hizo tradicin empezar con cualquier lenguaje de
programacin con el ejemplo del Hola mundo.
En particular en C se involucran muchas partes y sintaxis del lenguaje, por lo cual es especialmente til verlo como el
primer ejemplo de programacin en C.
Ejemplo: Hola mundo
/* Inclusin de archivos */ #include <stdio.h> /* Funcin principal */ int main (int argc,char **argv) { /* Impresin por
pantalla y salida del programa*/ printf(Hola mundo\n); return 0; }
Para poder editar y ejecutar este programa ser necesario utilizar algn editor y luego un compilador, como se explic en
la seccin Herramientas necesarias.
Si se tiene el compilador gcc en un entorno UNIX o GNU/Linux, la forma sencilla de compilar y ejecutar ser:
$ gcc holamundo.c $ ./a.out Hola Mundo $
Es decir que el compilador genera un archivo, en este caso llamado a.out, y la salida generada por ese archivo es Hola
mundo. A continuacin una explicacin detallada sobre el proceso de compilacin del programa, y luego un anlisis lnea
por lnea del contenido de este ejemplo.

5.1 Pre-requisitos para la compilacin de programas


Como ya se mencion, ser necesario tener instalado el compilador y un editor o entorno de desarrollo que permitan
escribir el cdigo a compilar. Para ms informacin ver la seccin Herramientas necesarias.
El cdigo a compilar debe guardarse con un nombre que represente al programa en cuestin y la extensin .c. En el caso
del ejemplo del Hola mundo, el archivo puede llamarse hola.c.
En las explicaciones a continuacin, se asume que se cuenta con un compilador instalado y se ha editado un archivo hola.c
que se quiere compilar. Si tu sistema operativo no aparece en esta lista busca en internet, ya que seguro que existe algn
compilador para ese sistema.
12

5.2. COMPILACIN DE PROGRAMAS SEGN LA PLATAFORMA

13

5.2 Compilacin de programas segn la plataforma


5.2.1

Windows

Para compilar un programa C en entornos Windows, debemos seguir una serie de pasos que varan segn el compilador
de C que queramos utilizar. Antes que nada, sera bueno que se revises la documentacin del compilador elegido para
conocer los comandos exactos.
Compilacin del cdigo fuente
Si se utiliza un entorno de desarrollo, ser posible compilar directamente desde el entorno, mediante un botn o una
combinacin de teclas.
Si se ejecuta el compilador desde la lnea de comandos, la lnea ser distinta segn el compilador utilizado. A continuacin
algunos ejemplos de ciertos comandos segn el compilador:
En Turbo C de Borland es: tcc hola.c
En C++ de Borland: bcc hola.c
En Visual C de Microsoft: cl hola.c
En GNU gcc: gcc hola.c o cc hola.c
El C de Zortech: ztc hola.c
Una vez compilado el cdigo fuente se genera un archivo llamado archivo objeto o programa objeto que es luego
enlazado mediante el enlazador, para generar el archivo ejecutable.
Los compiladores actuales suelen hacer dos funciones de una vez, compilando y enlazando todo en una sola funcin,
aunque es posible pedirles que no lo hagan mediante parmetros adicionales.
Segn el compilador y la conguracin utilizada, se obtendrn dos o tres archivos:
El archivo fuente
hola.c
El archivo objeto
hola.obj
El archivo ejecutable
hola.exe
Este ltimo es el que nos interesa, puesto a que es el cdigo ejecutable, el programa en s. Al ejecutarlo se producir la
salida deseada en una ventana de consola.
Salida por pantalla
Si ejecutamos en entorno Windows el programa directamente desde el navegador de archivos, o tambin desde algunos
entornos de desarrollo, lo que suceder ser que apenas abierta la ventana de la consola, se mostrar la cadena esperada
y luego de terminada la funcin, la consola se cerrar sin tener el tiempo suciente de ver nuestro mensaje en pantalla.
Para poder ver la salida por pantalla ser necesario ejecutar el programa desde la lnea de comandos, o modicar la
conguracin del entorno de desarrollo para que muestre la salida por pantalla al ejecutar el programa.
Una posible solucin es agregar una funcin adicional a nuestro hola.c":

14

CAPTULO 5. PROGRAMACIN EN C/PRIMER PROGRAMA EN C

/* Inclusin de archivos */ #include <stdio.h> #include <stdlib.h> /* Funcin principal */ int main (int argc,char **argv)
{ /* Impresin por pantalla y salida del programa*/ printf(Hola mundo\n); system (pause); return 0; }
Las dos lneas agregadas permiten que utilicemos la biblioteca stdlib, que incluye la funcin system y que mediante esta
funcin se ejecute el comando pause del sistema, que evita que el programa siga hasta que se presione una tecla.
As es posible visualizar que la salida de hola.c se complet perfectamente.

5.2.2

GNU

Si bien existen otros compiladores, lo ms usual y ms sencillo para compilar un programa en GNU/Linux es el compilador
gcc, ya que es el que se incluye en todas las distribuciones.
De cualquier forma, es posible realizar la compilacin desde lnea de comandos o desde el entorno grco.
Para realizarla desde lnea de comandos, ser necesario contar con una terminal (xterm, konsole, gnome-terminal, etc).
No es necesario contar con permisos de root para crear o compilar programas. En esa terminal ser necesario escribir
gcc hola.c
Si no existen errores en el cdigo, este comando nos crear un archivo ejecutable, que por omisin se llama a.out, y que
podemos ejecutar desde la lnea de comandos de la siguiente forma:
./a.out Hola mundo
Es una buena idea especicar el nombre que el archivo ejecutable tendr, pasando como parmetro al compilador la opcin
-o, de la siguiente forma:
gcc hola.c -o hola
Con lo cual, el nombre del archivo creado ser hola. Este archivo no tiene extensin ya que es la forma usual de llamar a
los archivos ejecutables en los entornos UNIX y GNU/Linux, sin embargo funcionara de la misma forma si se llamara
hola.exe.
Para ejecutarlo, haremos los mismo que en el caso anterior:
./hola Hola mundo
Existen otros parmetros que podemos especicar al compilador en la lnea de comandos, dependiendo del tipo de programa, y en funcin de la complejidad del mismo. Por ejemplo, podemos agregar las siguientes opciones:
gcc hola.c -o hola -Wall -pedantic
La opcin -Wall nos mostrar todos los avisos que produzca el compilador, no solamente los errores. Los avisos nos
indican dnde y/o porqu podra surgir algn error en nuestro programa.
La opcin -pedantic nos aporta ms informacin sobre los errores y los avisos mostrados por GCC.

5.3 Diseccionando el Hola Mundo


A continuacin veremos cul es la estructura bsica de un programa en C, para poder entender qu hace cada una de las
lneas de nuestro sencillo programa.
Es probable que lo primero que salte a la vista sea la lnea:
printf(Hola mundo\n);
Esta es la lnea que hace aparecer la cadena Hola Mundo en nuestra pantalla. Notamos que en C la sentencia para imprimir
algo por pantalla es printf() y, adems, hay que colocar parntesis alrededor de lo que queremos imprimir para utilizarla.
Esto se debe a que en C, printf es una funcin, que imprime su argumento (la cadena Hola Mundo\n) en la pantalla. Se

5.3. DISECCIONANDO EL HOLA MUNDO

15

denomina invocar una funcin a la accin de utilizarla para que realice una accin.
Podemos observar tambin que la cadena a imprimir termina con una extraa combinacin: \n. La combinacin \n no
representa a dos caracteres independientes, sino que representa un nico carcter no imprimible: el salto de lnea. Sin el
salto de lnea, el resultado al ejecutar el programa sera:
$ ./a.out Hola Mundo$
Es decir que no hay salto de lnea entre la cadena impresa, y la siguiente entrada de la lnea de rdenes, que no es lo que
esperbamos.
Lo ltimo a notar en la lnea es que termina con un punto y coma. En C, todas las sentencias terminan con un punto y
coma. Al principio puede parecer obvio dnde termina una sentencia, pero ya veremos ms adelante que no lo es tanto.
Observemos ahora la siguiente sentencia del programa:
return 0;
Luego de esta sentencia, termina el programa. En el caso de la instruccin return dentro de la funcin main, el resultado
es que se naliza el programa, comunicndole al sistema operativo que el valor de retorno (un cdigo numrico que
el sistema utiliza para saber si el programa ha funcionado bien o ha dado fallos) es 0, es decir, correcto.
Las dos ltimas sentencias se encuentran encerradas entre llaves. De esta manera, forman un bloque, es decir, un grupo
de sentencias que se ejecutarn siempre de forma correlativa.
Y qu es esa lnea que precede (en realidad, que da nombre) al bloque?
int main (int argc, char **argv)
Pues es la denicin de una funcin, en este caso llamada main. En C (y en general en todos los lenguajes de programacin
estructurada) todo se hace a base de funciones, como main y printf.
La funcin main es especial, porque es el la que se invoca cuando se ejecuta el programa. Todos los programas en C
comienzan su ejecucin al principio de la funcin main, y cuando sta acaba, el programa tambin.
Veamos con ms detalle la denicin de la funcin:
int main (int argc, char **argv) { ... }

El nombre de la funcin que viene a continuacin, entre llaves, es main.


Recibe dos argumentos: int argc y char **argv (que representan a la cantidad de argumentos ingresados al ejecutar
el programa y a los valores de estos argumentos respectivamente).[1]
La funcin devuelve como resultado un nmero entero, int (que es el 0 de la instruccin return).[2]
Finalmente, y un tanto aparte (est separada del resto por una lnea en blanco), tenemos la lnea:
#include <stdio.h>
Que parece bastante distinta al resto del programa, y que, adems, parece no tener sentido, puesto que ya hemos denido
la funcin main que hace todo el trabajo.
Efectivamente, esa lnea no es parte del programa, aunque sea imprescindible. La lnea es una instruccin del preprocesador
de C, como nos lo indica el smbolo #, y lo que hace es incluir en ese punto el contenido de otro chero, antes (de ah
el nombre de preprocesador) de que comience la compilacin. El chero stdio.h es el que contiene la denicin de la
funcin printf(), que antes utilizamos pero que no escribimos, ya que forma parte de la biblioteca estndar de C.

16

CAPTULO 5. PROGRAMACIN EN C/PRIMER PROGRAMA EN C

5.4 Comentarios
Una vez escrito un cdigo, tratar de entenderlo un ao ms tarde solo con leerlo puede ser frustrante: no hay manera de
saber (si el programa es medianamente complicado) qu es cada variable, o qu hace cada bloque de cdigo. Por esto, en
cualquier lenguaje de programacin son importantes los comentarios.
Un comentario en C es todo lo que se encuentre entre los smbolos /* y */. Hay que tener en cuenta que los comentarios
no se pueden anidar: si dentro de un comentario hay un /*, seguir siendo el primer */ el que nalice el comentario, no se
esperar al segundo.
Hay otro tipo de comentarios en C, procedentes del lenguaje C++, e incorporadas al estndar de C a partir de C99: //.
Todo lo que est despus de estos signos, hasta el nal de la lnea, se considerar un comentario y el compilador no lo
tomar en cuenta.
En el ejemplo presentado pueden verse tres lneas con comentarios, que documentan someramente las distintas funcionalidades del cdigo. En los prximos captulos podrn verse mejores usos de los comentarios dentro del cdigo.
Tambin podra decirse que es una herramienta bsica basada en compilador
[1] En un captulo posterior podr ver un ejemplo del uso de los parmetros que recibe main.
[2] Es importante sealar que el estndar dice que main deber denirse como funcin que retorna un entero, o de lo contrario el
resultado queda indenido.

Captulo 6

Programacin en C/Tipos de datos


6.1 Historia
En el lenguaje C estandarizado como C89, existan cuatro tipos de datos bsicos que son: los nmeros enteros, los nmeros
reales, los caracteres, y los punteros. A partir del estndar C99 se agregan: los valores lgicos (verdadero o falso) y los
nmeros complejos.
Estos tipos de datos son parte del lenguaje, y por ello se los considera primitivos. Ms adelante veremos que con el uso
de estructuras y uniones es posible crear tipos compuestos de datos a partir de estos tipos primitivos.
En este captulo veremos los enteros, los reales y los caracteres. Ms adelante se vern otros tipos de datos ms complejos,
como son los vectores, las cadenas de caracteres, y los punteros en general.

6.2 Enteros
Los enteros son el tipo de dato ms primitivo en C. Se usan para representar nmeros enteros. Pero siempre se pueden
encontrar otras aplicaciones para los nmeros enteros. En general se pueden usar para representar cualquier variable
discreta.
Los tipos de datos enteros son: short, int, long y long long, cada uno representando un nmero entero de un tamao o
capacidad determinado. Segn el compilador y la plataforma de hardware, cada uno de estos tipos de dato puede ocupar
desde 1 byte hasta 8 bytes en memoria (para ms detalles busca en la referencia).
Adems, el lenguaje C hace la distincin de si el entero es con signo (signed) o sin signo (unsigned). En caso de que no se
declare si es con signo o sin signo, se toma con signo.
Algunos ejemplos de declaraciones de enteros:
int a; unsigned int a; signed long a; signed long long a = 10000000;
Todos los nmeros son representados en memoria mediante una cadena de bits. En el caso de los nmeros con signo, el
bit ms signicativo es el que se usa para representar el signo. La representacin de los nmeros negativos se realiza
mediante el complemento a dos, que es una tcnica que permite operar con los nmeros negativos de forma lgica.
A modo de ejemplo, la representacin en memoria del nmero 8 en una variable de 2 bytes, entera, con signo, sera la
siguiente:
1111111111111000
17

18

CAPTULO 6. PROGRAMACIN EN C/TIPOS DE DATOS

6.3 Flotantes
Se denomina otantes a los tipos de datos que representan a los nmeros reales, ya que utilizan un sistema de representacin
basado en la tcnica de coma otante, que permite operar con nmeros reales de diversas magnitudes, mediante un
nmero decimal llamado mantisa y un exponente que indica el orden de magnitud.
El tipo de dato otante en lenguaje C slo tiene dos tamaos: el oat y el double, que son 4 bytes y 8 bytes respectivamente.
Se los puede utilizar tanto para representar nmeros decimales, como para representar nmeros enteros con un orden de
magnitud muy grande.
La forma de declarar una variable otante es escribiendo en una lnea uno de los tipos de datos otantes y a continuacin
el nombre de la variable y tal vez algn valor que se les quiera dar.
Algunos ejemplos:
oat a; double a = 1e23; double a = 3.1416; oat a = 4e-9; double a = 78;
Hay que tener en cuenta que aunque los valores otantes son ms convenientes para algunas aplicaciones, hay casos en
los que se preeren los enteros. Esto se debe a que los nmeros otantes no necesariamente tienen soporte de hardware,
en particular en las plataformas integradas. Una alternativa que se utiliza en estas situaciones es interpretar los enteros
como decimales de forma que 150 se interprete como 1.5 y 2345 como 23.45.
Para el caso de los otantes de 4 bytes, se utiliza 1 bit para el signo, 8 bits para el exponente y 23 bits para el valor del
nmero. El procedimiento para almacenar un nmero en una variable otante es el siguiente:
1. Se convierte a binario la parte entera.
2. Se coloca el signo en el bit ms signicativo de la misma manera que en los enteros (1 para el - y 0 para el +).
3. Se mueve la coma (en la representacin binaria de la parte entera) hasta que est a la derecha del primer uno y ste
se descarta (el uno ms signicativo). El valor del exponente ser el nmero de posiciones que se movi la coma.
El exponente usa la representacin de un entero con complemento a dos.
4. Se convierte en binario la parte decimal del nmero. Esto usando el peso de los bits. el bit decimal ms signicativo
vale 1/2, el siguiente vale 1/4, el otro 1/8, el otro 1/16 y as hasta completar lo que falta para los 23bits del valor.
5. Se concatena todo y ese es el valor otante representado en memoria.

6.4 Caracteres
Los caracteres se representan utilizando el tipo char, que tiene slo 1 byte de tamao. Este tipo se utiliza para representar
los 256 caracteres de la tabla de caracteres del sistema. El tipo char es tambin un tipo entero, ya que puede tomar valores
de 0 a 255. Por lo tanto tambin puede ser signed o unsigned.
En cuanto a la forma de declarar variables de tipo char es la misma forma que con los otros tipos.
char a; char a = 's; unsigned char a = 48;
Como puedes ver, se le puede asignar un nmero a una variable char, ya que se trata de un tipo entero. En muchas
situaciones se utiliza el tipo char para almacenar nmeros pequeos, ya que ocupa en memoria slamente un byte.
Es importante notar que con la llegada de la codicacin UTF-8, los caracteres de los diversos idiomas pueden ocupar 1,
2, 3 o 4 bytes, de modo que el tipo char ya no alcanza para la representacin de todos los caracteres posibles. Por ello, el
estndar C99 introduce el tipo wchar que puede ocupar ms de 1 byte, segn sea necesario para la codicacin utilizada
por el sistema.

Captulo 7

Programacin en C/Expresiones
Vamos a tratar ahora de que el ordenador haga un poco de matemticas para nosotros. Por ejemplo, que realice unas pocas
sumas, restas multiplicaciones y divisiones.
#include <stdio.h> int main(void) { int resultado; resultado=5+2; printf(Resultado de la suma: %i\n,resultado); resultado=52; printf(Resultado de la resta: %i\n,resultado); resultado=5*2; printf(Resultado de la multiplicacin: %i\n,resultado);
resultado=5/2; printf(Resultado de la divisin: %i\n,resultado); return(0); }
Despus de grabarlo (por ejemplo, con el nombre ejemplo.c), lo compilamos y ejecutamos, con (respectivamente):
$ gcc ejemplo.c $ ./a.out Resultado de la suma: 7 Resultado de la resta: 3 Resultado de la multiplicacin: 10 Resultado de
la divisin: 2 $
Fijmonos en la lnea del principio de la funcin main:
int resultado;
Esta lnea lo que hace es reservar un trozo de memoria, del tamao de un int (normalmente 4 bytes), y asignarle el nombre
resultado, para poder despus referirnos a l. A partir de este momento, podemos considerar que en nuestro programa
existe una variable, que no tiene valor denido, pero a la que le podremos dar valor posteriormente.
Las lneas con printf() ya las conocemos, pero hay algo en ellas que no habamos visto antes. Esos %i y la parte de
resultado son nuevas para nosotros.
La funcin printf() no slo sabe imprimir cadenas simples, como Hola Mundo\n, sino tambin imprimir variables. Para
ello, en el lugar de la cadena donde queremos que aparezca el valor de la variable, introducimos lo que se llama una cadena
de conversin de printf(). Estas cadenas siempre empiezan por %, siendo %i la cadena para imprimir un entero, como
es en nuestro caso int resultado. Finalmente, printf() debe saber qu valor escribir, por eso le damos otro argumento (u
otros), usando , como separador, que contienen las variables cuyos valores queremos mostrar.
En el resto del programa hemos visto cmo decirle al ordenador que ejecute una suma, una resta, una multiplicacin y
una divisin entera, con los operadores +, -, * y /. Es de notar que el resultado de una operacin como estas entre nmeros
enteros ser siempre otro entero, como se puede observar en la divisin, en la que no obtenemos un bonito decimal, sino
un resultado entero. Adems, hemos visto que el resultado de esas operaciones, que llamamos expresiones, puede ser
asignado a una variable:
resultado = 7;
Esa asignacin se hace mediante el operador de asignacin: =. Con l, ya conocemos cinco operadores.
Pero, como = tambin es un operador, cmo sabe el ordenador qu operador debe ejecutar primero? Y si es un operador,
por qu no da un resultado? No crea una expresin?

19

20

CAPTULO 7. PROGRAMACIN EN C/EXPRESIONES

Empezando por las ltimas preguntas, el operador de asignacin s crea una expresin, como los operadores de suma,
resta, multiplicacin y divisin, y esa expresin tiene un resultado, que es el valor que obtiene el lado izquierdo al realizar
la operacin. En cuanto a saber qu se debe ejecutar primero, el ordenador tiene una lista de precedencia, segn la cual
siempre ejecuta primero las multiplicaciones y divisiones, de izquierda a derecha, a continuacin las sumas y restas, de
izquierda a derecha, y a continuacin las asignaciones, de derecha a izquierda. Para ms detalles acerca de la precedencia
de los operadores ver el anexo de los operadores.
En cuanto a los caracteres de punto y coma, notamos aqu que una expresin tambin puede ser una sentencia por s
misma, sin necesidad de que haya ninguna funcin. De hecho, una sentencia puede no tener siquiera una expresin. La
lnea: ; es una sentencia perfectamente vlida, la sentencia vaca, que sera til en puntos donde el lenguaje requiera una
sentencia pero no sea necesaria para nuestro programa.

Captulo 8

Programacin en C/Interaccin con el


usuario
En este captulo veremos un poco ms sobre como interactuar con el usuario de nuestros programas desde la consola,
utilizando printf() como vimos en el primer ejemplo Hola mundo, as como scanf() para la lectura del teclado.

8.1 Imprimir por pantalla


Como hemos visto hasta ahora en los ejemplos, hay una funcin que utilizamos para sacar por pantalla textos arbitrarios
o el resultado de alguna operacin: la funcin printf().
Si miramos (en la documentacin) su denicin, no nos aclarar demasiado:
int printf (const char *TEMPLATE, ...)
...claro que por algo tiene una seccin completa de la documentacin para ella sola.
Vemosla poco a poco. Se trata de una funcin de la biblioteca estndar, lo que quiere decir que para utilizarla tenemos
que incluir previamente su denicin. La encontraremos en <stdio.h>.
Lo primero que vemos en la denicin es que es una funcin de tipo int, lo que quiere decir que devuelve un entero. Ese
entero es el nmero de caracteres impresos en la pantalla, o un nmero negativo en caso de que se produzca algn error.
Lo siguiente a notar es su primer argumento: const char *TEMPLATE. Se trata de una cadena de caracteres (char *) que
no ser modicada por la funcin (const), con lo que puede ser una constante de cadena o una variable que contenga una
cadena, pero siempre debe acabar con el carcter nulo \0.
Y luego vienen esos extraos puntos suspensivos. Esa elipsis nos indica que como argumentos adicionales de printf()
podemos poner una serie ilimitada de otros argumentos, que se supone que la funcin sabr qu hacer con ellos. Y eso es
justamente lo que hace tan fabulosa y til a printf().
Como hemos visto, el uso ms simple de printf() es imprimir una cadena de texto simple y corriente. Como ya vimos:
printf(Hola Mundo\n); /*imprime la cadena*/
Y tambin hemos visto printf() tambin puede, con un argumento extra y una sintaxis especial, imprimir un nmero entero
que hayamos almacenado en una variable:
char resultado;
resultado=5+2;
printf(Resultado de la suma: %i\n,resultado);
Aqu el punto de insercin es la secuencia %i. printf() siempre trata las secuencias que comiencen por % como secuencias
21

22

CAPTULO 8. PROGRAMACIN EN C/INTERACCIN CON EL USUARIO

de control que le dicen que debe imprimir algo que le proporcionamos en los otros argumentos. As, podemos imprimir
varios enteros distintos en los sitios que queramos de la cadena, insertando varias de estas secuencias %i:
int numero;
numero=3;
printf(El doble de %i es %i y su cuadrado es %i\n,numero,numero*2,numero*numero);

8.2 Lectura de datos del teclado


La entrada de datos se puede hacer de muchas maneras y entre ellas estn desde el uso de dispositivos especiales hasta
nuestro simple teclado. La entrada de datos se reere a cualquier forma de inuencia del usuario sobre los datos que posee
el sistema.
Con el n de mostrar una forma de entrada simple para el aprendizaje vamos a hablar de la funcin scanf() que se encuentra
denida en <stdio.h> y que se usa para capturar diferentes tipos de datos.

8.2.1

La funcin scanf()

scanf() es una de las funciones ms usadas por los principiantes para hacer entrada de datos en el lenguaje C. Tiene una
sintaxis muy parecida a printf: recibe una cadena con el formato de los datos y luego se ponen las variables en orden que
correspondan a ese tipo de datos. Es decir, as como en printf se pueden mostrar por pantalla los datos de varias variables
en una misma sentencia, en scanf se pueden capturar varios datos en una sola sentencia.
#include <stdio.h> int main() { int a; printf (diga un valor para a:"); scanf("%i,&a); printf (el valor es: %i\n,a); return
0; }
Por ahora no nos interesan las dems sentencias, slo la que contiene scanf. En el cdigo se ve lo siguiente:
scanf("%i,&a);
Se observa que la funcion printf dej en pantalla una peticin para que el usuario introdujera un valor. Entonces, scanf
recibe como argumento una cadena del formato en que se van a capturar los datos y la lista de variables que van a recibir
valores y que deben coincidir con los del formato.
En este caso la cadena de formato, "%i, especica que el usuario ingresar un nmero entero. Luego se designa a la
variable a para contener a ese nmero. El smbolo (&) que precede a a es para especicar que lo que se est enviando
como argumento no es el valor que posee la variable a sino la direccin de memoria en que se encuentra. En este momento
eso no tiene mucha relevancia, slo hay que recordar que se debe usar el smbolo & dentro del scanf. En el momento en
que hablemos de punteros veremos ms detalles de esto.
Otro ejemplo del uso de scanf:
#include <stdio.h> int main() { int a,b; printf (introduzca dos valores con el formato \"a,b\" :"); scanf("%i,%i,&a,&b);
printf (el primer valor : %i\n,a); printf (el segundo valor : %i\n,b); return 0; }
Aqu hemos introducido una nueva variable en el cdigo. La cadena de formato, "%i,%i especica que el usuario ingresar
un nmero, seguido de una coma, y luego otro nmero. El primer %i ser capturado por la variable a y el segundo por b.

Captulo 9

Programacin en C/Instrucciones de control


Como ya se ha mencionado, C es un ejemplo de programacin estructurada. En este tipo de programacin, es necesario
contar con ciertas estructuras que permitan controlar el ujo del programa, es decir, tomar decisiones y repetir acciones.

9.1 La estructura condicional if ... else


En la gran mayora de los programas ser necesario tomar decisiones sobre qu acciones realizar. Esas decisiones pueden
depender de los datos que introduzca el usuario, de si se ha producido algn error o de cualquier otra cosa.
La estructura condicional if ... else es la que nos permite tomar ese tipo de decisiones. Traducida literalmente del ingls,
se la podra llamar la estructura si...si no, es decir, si se cumple la condicin, haz esto, y si no, haz esto otro.
Un ejemplo sencillo sera el siguiente (no se trata de un programa completo, sino tan slo una porcin de cdigo):
if (edad < 18) printf(No puedes acceder.\n); else printf(Bienvenido.\n);
Este cdigo de ejemplo dice que si el valor de la variable edad es menor que 18 se imprimir No puedes acceder.\n,
mientras que en caso contrario se imprimir Bienvenido.\n.
Como se ve en el ejemplo, la estructura de un condicional es bastante simple:
if (condicin) { sentencias_si_verdadero; } else { sentencias_si_falso; }
La condicin, encerrada entre parntesis, es una expresin que puede dar como resultado 0 (interpretado como falso)
o cualquier valor distinto de 0 (interpretado como verdadero). Cuando la condicin sea verdadera, se ejecutarn las
sentencias dentro del primer bloque de cdigo, cuando la condicin sea falsa, se ejecutarn las sentencias del segundo
bloque de cdigo. Las expresiones y valores de tipo verdadero/falso son tambin llamados valores lgicos o booleanos.
La indentacin o sangra (los espacios al comienzo de las lneas) no es necesaria, pero ayuda a la claridad del cdigo. La
utilizacin de las llaves {...} es obligatoria cuando se quiere utilizar ms de una instruccin por bloque, y optativa cuando
slo se quiere escribir una instruccin. Por claridad, sin embargo, es recomendable utilizarlas an cuando slo vaya a
haber una instruccin.
El bloque del else es opcional. Si no se lo encuentra, slo se realizar la accin correspondiente al bloque if.
A continuacin, un ejemplo con una funcin, que devuelve el mayor de dos nmeros:
int mayor(int a, int b) { if (b > a) { return b; }// No posee especicacin de la parte else, ya que no es necesaria. return
a; // Finaliza la funcin retornando el valor de a. }

23

24

9.1.1

CAPTULO 9. PROGRAMACIN EN C/INSTRUCCIONES DE CONTROL

Operadores de comparacin

El smbolo > visto en el ltimo ejemplo es un operador, que en este caso compara dos nmeros enteros y devuelve
verdadero si el primero es mayor, falso en caso contrario.
A continuacin un listado de los posibles operadores de comparacin en C y su signicado.
Teniendo en cuenta que en C se toma como falso el valor 0, y como verdadero cualquier otro valor, una prctica comn
es expresar condiciones sin utilizar ningn operador:
oat division(int dividendo, int divisor) { if (divisor) { return dividendo / divisor; } else { printf (No se puede dividir
por cero\n); return 0; } }
En este caso, la expresin (divisor) es equivalente a (divisor != 0).

9.1.2

Operadores lgicos

Los operadores && (y), || (o) y ! (no) son operadores lgicos. Permiten operar con expresiones lgicas para generar
expresiones ms complejas.
Por ejemplo: determinar si un ao es bisiesto o no. Los aos son bisiestos si son divisibles por 4, pero no si son divisibles
por 100, a menos que tambin sean divisibles por 400.
if ( (!(a % 4) && (a % 100)) || !(a % 400) ) { printf(es un ao bisiesto.\n); } else { printf(no es un ao bisiesto.\n); }
En realidad, teniendo en cuenta la prioridad de los operadores utilizados, podemos simplicar la expresin anterior del
siguiente modo:
if ( !(a % 4) && (a % 100) || !(a % 400) ) { printf(es un ao bisiesto.\n); } else { printf(no es un ao bisiesto.\n); }
Adems, como a cada rama del if le sigue una nica instruccin, podemos expresar la expresin anterior del siguiente
modo:
if ( !(a % 4) && (a % 100) || !(a % 400) ) printf(es un ao bisiesto.\n); else printf(no es un ao bisiesto.\n);
En este caso, se utiliza el operador mdulo (%), que obtiene el resto de la divisin entera de un nmero por otro. Cuando
un nmero es divisible por otro, el resto de su divisin entera ser cero. Siendo que cero es equivalente a falso, y cualquier
valor distinto de cero es equivalente a verdadero, podemos usar el operador % para vericar si el nmero es mltiplo de
4, de 100 o de 400.

9.1.3

Evaluacin de cortocircuito

La evaluacin en corto circuito es una caracterstica del lenguaje C que se utiliza para optimizar la ejecucin de programas.
Consiste en que el programa puede vericar si una expresin es verdadera o falsa antes de haber evaluado toda condicin.
Por ejemplo, si se tiene una condicin como la siguiente:
if ((a > 2) || (b < 4)) { ... }
Al ejecutarse el programa, se evaluar primero si a > 2. En el caso en que sea verdadero, no continuar con la siguiente
condicin, ya que el resultado ser de cualquier modo verdadero.
De la misma forma, si la condicin fuera:
if ((a > 2) && (b < 4)) { ... }

9.2. LA ESTRUCTURA CONDICIONAL ABIERTA Y CERRADA SWITCH ... CASE

25

En este caso, si no se cumple que a > 2, no se evaluar la siguiente condicin, ya que el resultado ser falso de todos
modos.
Esta caracterstica no tiene demasiada importancia al comenzar a programar, pero facilitar ciertas operaciones y optimizaciones en programas avanzados.

9.2 La estructura condicional abierta y cerrada switch ... case


La estructura condicional switch ... case se utiliza cuando queremos evitarnos las llamadas escaleras de decisiones. La
estructura if nos puede proporcionar, nicamente, dos resultados, uno para verdadero y otro para falso. Una estructura
switch ... case, por su parte, nos permite elegir entre muchas opciones. Ejemplo:
#include <stdio.h> #include <stdlib.h> int main(void) { int dia; printf(que nmero de da de la semana es?"); scanf("%d,&dia);
switch(dia) { case 1 : printf(Lun, Lunes); break; case 2 : printf(Mar, Martes); break; case 3 : printf(Mier, Miercoles); break; case 4 : printf(Jue, Jueves); break; case 5 : printf(Vie, Viernes); break; case 6 : printf(Sab, Sabado);
break; case 7 : printf(Dom, Domingo); break; default : printf(No existe); } return 0; }
La estructura anterior, de realizarse con sentencias if, necesitara cuatro de ellas, resultando un enorme bloque muy difcil
de leer. En la mayora de los casos, adems, la sentencia switch proporciona una ganancia en velocidad del cdigo, pues
permite al compilador trabajar en base a que se trata de una decisin mltiple para una nica variable, cosa que con
sentencias if el compilador no tiene por qu detectar.
Como vemos, para cada valor de la variable se ejecuta un bloque de sentencias distinto, en el que no necesitamos llaves. Hay
un caso especial, default, que se ejecuta si ningn otro corresponde, y que no es necesario poner. Es, en todo, equivalente
al bloque else de una sentencia if.
Las sentencias break son muy importantes, ya que el comportamiento normal de un bloque switch es ejecutarlo todo desde
la etiqueta case que corresponda hasta el nal. Por ello, si no queremos que se nos ejecute ms de un bloque, pondremos
sentencias break al nal de cada bloque excepto el ltimo.
Es decir, las etiquetas case son puntos de entrada de la ejecucin, y no implican que al acabarse el bloque case la ejecucin
salte al nal del bloque switch. Las etiquetas case siguientes a la que hemos utilizado para entrar son, sencillamente,
ignoradas.
A la ausencia de sentencias break se le llama, en ocasiones, dejar caer la cascada switch.

9.3 El bucle while


El bucle while sirve para ejecutar cdigo reiteradas veces.
while (/*condicion*/) { /* Cdigo */ }
La condicin debe de ser una expresin lgica, similar a la de la sentencia if. Primero se evala la condicin. Si el resultado
es verdadero, se ejecuta el bloque de cdigo. Luego se vuelve a evaluar la condicin, y en caso de dar verdadero se vuelve
a ejecutar el bloque. El bucle se corta cuando la condicin da falso.
Ejemplo: imprimir los nmeros de 0 a 99:
int i = 0; while (i < 100) { printf("%d\n, i); i = i + 1; }

26

CAPTULO 9. PROGRAMACIN EN C/INSTRUCCIONES DE CONTROL

9.4 El bucle for


El bucle for es un bucle muy exible y a la vez muy potente ya que tiene varias formas interesantes de implementarlo, su
forma ms tradicional es la siguiente:
for (/* inicializacin */; /* condicin */; /* incremento */) { /* cdigo a ejecutar */ }
Inicializacin: en esta parte se inicia la variable que controla el bucle y es la primera sentencia que ejecuta el bucle. Slo
se ejecuta una vez ya que solo se necesita al principio del bucle.
Expresin condicional: al igual que en el bucle while, esta expresin determina si el bucle continuar ejecutndose o no.
Incremento: es una sentencia que ejecuta al nal de cada iteracin del bucle. Por lo general, se utiliza para incrementar
la variable con que se inicio el ciclo. Luego de ejecutar el incremento, el bucle revisa nuevamente la condicin, si es
verdadera tiene lugar una ejecucin ms del cuerpo del ciclo, si es falsa se termina el ciclo y as.
Aqu se muestra el mismo ejemplo visto para el bucle while, pero implementado con un bucle for:
int i; for (i=0; i < 100; i = i + 1) { printf("%d\n, i); }
Nota: En C, la sentencia i = i + 1 puede escribirse en forma ms reducida como i++. Esta forma se utiliza ms comnmente
en el bucle for:
int i; for (i=0; i < 100; i++) { printf("%d\n, i); }

9.5 El bucle do...while


El bucle do...while es un bucle que, por lo menos, se ejecuta una vez. Do signica literalmente hacer, y while signica
mientras
Su forma es esta:
do { /* CODIGO */ } while (/* Condicin de ejecucin del bucle */)
Os muestro un ejemplo sencillo de uso:
int aleatorio; do { aleatorio = rand(); } while (aleatorio != 25);
La verdad es que este ejemplo puede resultar un poco absurdo, pero es bastante intuitivo. El cdigo del bucle asigna un
valor aleatorio a la variable denida anteriormente, y mientras esa variable no tenga el valor 25, el bucle sigue ejecutndose.

9.6 La sentencia goto


La sentencia goto sirve para indicar al programa que continue ejecutndose desde la lnea de cdigo indicada. Su sintaxis
es ms o menos as:
/* Cdigo */ ETIQUETA: /* Cdigo */ goto ETIQUETA; /* Cdigo */
As, cuando se ejecute la sentencia goto, el programa saltar" y continuar su ejecucin a partir de la etiqueta marcada.
Como se puede observar se puede usar para crear un bucle, o para ir a una parte del cdigo u otra si se combina con una
sentencia if...else. Pero por lo general puede obtenerse el mismo efecto utilizando los bucles anteriormente vistos.
Por eso, la sentencia goto es poco aceptada por la comunidad de programadores, pues puede provocar que se hagan
programas un poco sucios y confusos. Slo en ocasiones muy excepcionales ser recomendado el uso del goto al crear

9.6. LA SENTENCIA GOTO

27

iteraciones muy complejas. Sin embargo, con el pasar de los aos este comando ya ha quedado prcticamente descartado
del lenguaje de los programadores.

Captulo 10

Programacin en C/Uso de funciones


10.1 Funciones
Como vimos anteriormente C tiene como bloque bsico la funcin main() , tambin hemos visto la sentencia printf() que
es otra funcin, y de igual forma hay muchas ms funciones predenidas, pero nosotros mismos tambin podemos denir
nuestras propias funciones. De hecho, es fundamental hacerlo.
Podemos denir una funcin cualquiera de la misma manera en que denimos la funcin main(). Basta con poner su tipo,
su nombre, sus argumentos entre parntesis y luego, entre llaves, su cdigo:
/* Inclusin de archivos */ #include <stdio.h> void holamundo(void) /* Funcin donde se ejecuta la lgica del programa
*/ { printf(Hola Mundo\n); /* imprime la cadena */ return; /* sale de la funcin */ } int main(void) /* Funcin principal del programa */ { holamundo(); /* llamada a la funcin holamundo */ return 0; /* sale del programa con cdigo 0
(correcto) */ }
Este cdigo es en todo equivalente al Hola Mundo original, slo que nos muestra cmo escribir y cmo utilizar una
funcin. Y adems nos muestra un principio de buena programacin: meter las sentencias que hacen el trabajo en otras
funciones especcas para sacarlas de main(), dejando en sta tan slo un guin general de lo que hace el programa, no las
rdenes especcas. De esta manera se facilita la comprensin del programa, y por tanto el futuro trabajo de modicarlo.

10.1.1

La sentencia return

La sentencia return puede utilizarse dentro de una funcin para terminar su ejecucin.
En el ejemplo anterior, la funcin holamundo fue declarada con valor de retorno de tipo void (es decir, valor de retorno
nulo). En ese caso, la sentencia return no lleva ningn parmetro adicional, ya que la funcin no debe devolver ningn
valor a la funcin que la llama.
En cambio, la funcin main tiene un valor de retorno de tipo int, por lo que return debe ir seguido de un valor entero (0
en el ejemplo). El valor 0 se utiliza para indicar que el programa ha llegado a un punto en el que todo se ha desarrollado
correctamente y se utiliza cualquier otro valor para indicar que ha habido algn tipo de error.
La instruccin return no es una funcin, se trata de una sentencia que lo que hace es retornar como valor de la funcin el
valor que se le proporciona como argumento.

10.1.2

Argumentos

Las funciones tambin pueden recibir argumentos o parmetros, para modicar su comportamiento. Por ejemplo, la
denicin de una funcin para sumar dos nmeros sera de la siguiente manera:
28

10.1. FUNCIONES

29

#include <stdio.h> int sumar(int numero1, int numero2) { return numero1 + numero2; } int main(void) { int suma =
sumar(5, 3); printf(La suma es: %d ", suma); return 0; }
En este ejemplo, la funcin sumar recibe dos argumentos de tipo int y su valor de retorno tambin es de tipo int. Dentro
de la funcin main, se llama a la funcin sumar poniendo entre parntesis los valores deseados para sus argumentos, en
orden, separados por una coma. As, dentro de sumar el nmero 5 ser asignado a la variable numero1 y el nmero 3 a
numero2.

10.1.3

Declaracin y denicin

En el ejemplo anterior podemos notar que la funcin sumar gura en el cdigo antes que main. Qu pasara si las
escribiramos en distinto orden?
#include <stdio.h> int main(void) { int suma = sumar(5, 3); /* ERROR, sumar no ha sido declarada an */ printf(La
suma es: %d ", suma); return 0; } int sumar(int numero1, int numero2) { return numero1 + numero2; }
En este caso el programa es errneo y no compila, ya que en la lnea donde se llama a la funcin sumar, el compilador
an no conoce ninguna funcin con ese nombre, y cules son sus argumentos y valor de retorno.
Una posible solucin es declarar el prototipo de la funcin al principio, para informar al compilador que existe, y luego
denir el cuerpo de la misma en cualquier lugar del programa:
#include <stdio.h> /* Declaracin */ int sumar(int numero1, int numero2); int main(void) { int suma = sumar(5, 3);
printf(La suma es: %d ", suma); return 0; } /* Denicin */ int sumar(int numero1, int numero2) { return numero1 +
numero2; }

10.1.4

Paso de Parmetros

Las funciones pueden recibir datos como lo hemos observado, pero existen dos formas de enviar los datos hacia una
funcin por valor y por referencia, las cuales modican en diferente forma el comportamiento de el programa.

Por Valor
El paso por valor enva una copia de los parmetros a la funcin por lo tanto los cambios que se hagan en ella no son
tomados en cuenta dentro de la funcin main(). Ejemplo:
/* * por_valor.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en
C * bajo licencia FDL, adaptado del Dominio Pblico */ #include <stdio.h> void sumar_valor(int numero); /* prototipo de la funcin */ int main(void) { int numero = 57; /* denimos numero con valor de 57*/ sumar_valor(numero); /*
enviamos numero a la funcin */ printf(Valor de numero dentro de main() es: %d\n, numero); /* podemos notar que
el valor de numero se modica * slo dentro de la funcin sumar_valor pero en la principal * nmero sigue valiendo 57
*/ return 0; } void sumar_valor(int numero) { numero++; /* le sumamos 1 al numero */ /* el valor de nmero recibido
se aumenta en 1 * y se modica dentro de la funcin sumar_valor() */ printf(Valor de numero dentro sumar_valor() es:
%d\n, numero); return; }

Por Referencia
El paso por referencia se hace utilizando apuntadores. Se enva la direccin de memoria de la variable, por lo tanto los
cambios que haga la funcin si afectan el valor de la variable. Ejemplo:

30

CAPTULO 10. PROGRAMACIN EN C/USO DE FUNCIONES

/* * por_referencia.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en C * bajo licencia FDL, adaptado del Dominio Pblico */ #include <stdio.h> void sumar_referencia(int *numero); /* prototipo de la funcin */ int main(void) { int numero = 57; /* denimos numero con valor de 57*/ sumar_referencia(&numero); /* enviamos numero a la funcin */ printf("\nValor de numero dentro de main() es: %d ",
numero); /* podemos notar que el valor de numero se modica * y que ahora dentro de main() tambin se ha modicado
* aunque la funcin no haya retornado ningn valor. */ return 0; } void sumar_referencia(int *numero) { *numero +=
1; /* le sumamos 1 al numero */ /* el valor de numero recibido se aumenta en 1 * y se modica dentro de la funcin */
printf("\nValor de numero dentro sumar_referencia() es: %d, *numero); return; }

10.1.5

Variables Locales y Globales

Adems de pasar valores a una funcin, tambin se pueden declarar tipos de datos dentro de las funciones, estos tipos de
datos declarados dentro de una funcin solo son accesibles dentro de esta misma funcin y se les conocen como variables
locales, as pues podemos denir los mismos nombres de variables en diferentes funciones, ya que estas variables solo son
accesibles dentro de esas funciones. Ejemplo:
/* * locales.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en C *
bajo licencia FDL, adaptado del Dominio Pblico */ #include <stdio.h> void funcion1() { int dato = 53; /* denimos dato
en 53*/ char num1 = 'a'; /* num1 vale a */ /* imprimimos */ printf(Funcion1, dato=%d, num1=%c\n, dato, num1);
return; } void funcion2() { int dato = 25; /* denimos dato en 25*/ char num2 = 'z'; /* num2 vale z*/ /* imprimimos */
printf(Funcion2, dato=%d, num2=%c\n, dato, num2); return; } int main(void) { funcion1(); /* llamamos a funcion1()
*/ funcion2(); /* llamamos a funcion2() */ return 0; }
En este caso la variable dato, esta denida dentro de cada una de las funciones y son totalmente distinta una de otra y no
se puede utilizar fuera de esta, as pues num2 no puede ser utilizada por la funcion1() y num1 tampoco puede ser utilizada
por funcion2().
Existen pues variables que se denen fuera de la funcin principal main() y fuera de cualquier otra funcin creada por
nosotros, estas variables se les conoce con el nombre de Variables Globales ya que se pueden utilizar dentro de main() y
dentro de cualquier funcin creada por nosotros. Ejemplo:
/* * global.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en C
* bajo licencia FDL, adaptado del Dominio Pblico */ #include <stdio.h> int variable_global = 99; /* inicializamos
la variable global */ void funcion(); int main(void) { /* imprimimos el valor*/ printf(main(), acceso a variable_global
%d\n, variable_global); /* llamamos a la funcin */ funcion(); return 0; } void funcion() { /* imprimimos el valor*/
printf(funcion(), acceso a variable_global %d\n, variable_global); return; }

10.2 Funciones Recursivas


La recursividad (recursin) es la propiedad por la cual una funcin se llama a s misma directa o indirectamente. La
recursin indirecta implica utilizar ms de una funcin.
Se puede considerar la recursividad como una alternativa a la iteracin. La recursin permite especicar soluciones naturales, sencillas, que seran, en caso contrario, difciles de resolver. Toda funcin recursiva debe contemplar un caso base
o condicin de salida, para terminar, o la recursividad no podr terminar nunca.
Una funcin recursiva podra denirse as:
funcion_recursiva( /* parmetros recibidos por la funcin */ ) { /* Cdigo */ funcion_recursiva( ); /* llamada a la funcin
misma */ /* Cdigo */ }
Uno de los ejemplos ms representativos en la recursividad es el factorial de un numero ( n! ):

10.2. FUNCIONES RECURSIVAS

n! =

31

n N

k=1

la denicin de recursividad del factorial es:


{
n! =

1
n(n 1)!

Si n = 0
Si n > 0

n N.

En esta denicin, n = 0, es nuestro caso base, que le da n a la recursividad.


Entonces nuestro programa que calcula el factorial es:
/* *factorial.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en
C * bajo licencia FDL, adaptado del Dominio Pblico */ #include <stdio.h> long factorial(int n) { if (n == 0) /* caso base */ return 1; /* como 0! = 1, se retorna 1*/ else return n * factorial (n - 1); /* llamada a esta misma funcin */
} int main(void) { /* en este caso se llama a la funcin y se imprime directamente*/ printf("%ld ", factorial(5)); return 0; }
Tambin existen otros tipos de funciones recursivas como lo es el producto de dos nmeros. El producto de a b, donde
a y b son nmeros enteros positivos seria:
Solucin iterativa:
a + a + + a b
{z
}=
ab=|
i=1 a
b veces
Solucin recursiva:
{
0
ab=
a + a (b 1)

Si b = 0
Si b > 0

As pues 7 3 es:
7 3 = 7 + 7 2 = 7 + 7 + 7 1 = 7 + 7 + 7 + 0 = 21
Podemos ver que la multiplicacin de dos nmeros a, b se puede transformar en otro problema ms pequeo multiplicar
a por (b-1), el caso base se produce cuando b = 0 y el producto es 0. Ejemplo:
/* * producto.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en C
* bajo licencia FDL, adaptado del Dominio Pblico */ #include <stdio.h> int producto(int a, int b) { if (b == 0) /* caso
base */ return 0; /* como b = 0, se retorna 0*/ else return a + producto (a, b - 1); /* llamada a esta misma funcin */ }
int main(void) { /* en este caso se llama a la funcin y se imprime directamente*/ printf("%i ", producto( 7, 3)); return 0; }

10.2.1

Recursividad indirecta o recursin mutua

Esta se produce cuando una funcin llama a otra, que esta a su vez terminar llamando de nuevo a la primera funcin. El
siguiente programa visualiza el alfabeto utilizando recursin indirecta o mutua:
/* * elalfabeto.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en
C * bajo licencia FDL, adaptado del Dominio Pblico */ #include <stdio.h> void funcionA(char c); /* se declara el
prototipo de la funcin para que el llamado */ void funcionB(char c); /* a la misma en la funcin no sea implcita */ int
main(void) { funcionA('z'); /* llamado a funcionA */ return 0; } void funcionA(char c) { if (c > 'a') /* caso base mientras
c no sea menor que A */ funcionB(c); /* llamado a la funcionB */ printf("%c ", c); /* imprimimos el valor de c */ *la
variable es un parametro no utilizado para este proceso } void funcionB(char c) { funcionA(--c); /* llamado a la funcionA
decrementando el valor de 'z' */ }

32

10.2.2

CAPTULO 10. PROGRAMACIN EN C/USO DE FUNCIONES

Recursin versus Iteracin

Tanto la iteracin como la recursin se basan en estructura de control: la iteracin utiliza una estructura repetitiva y la
recursin una estructura de seleccin. La iteracin utiliza explcitamente una estructura repetitiva mientras que la recursin
consigue la repeticin mediante llamadas repetitivas a funciones.
La iteracin termina si la condicin del bucle no se cumple, mientras que la recursin termina cuando se reconoce un
caso base.
La recursin puede presentar desventajas ante la iteracin ya que se invoca repetidas veces al mecanismo de llamada de
funciones y se necesita un tiempo mayor para realizar cada llamada.
La razn por la cual se puede elegir u optar por usar recursividad es que existen muchos problemas complejos que poseen
naturaleza recursiva y, en consecuencia, son mas fciles de implementar.
Ejemplo Iterativo
/* * iterativo.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en
C * bajo licencia FDL, adaptado del Dominio Pblico */ #include <stdio.h> long factorial(int numero); int main(int
argc, char** argv) { int contador = 0; /* calcula el factorial de 0 a 10 */ for ( contador = 0; contador <= 10; contador++
) printf("%d! = %ld\n, contador, factorial( contador )); return 0; } /* funcion factorial iterativa */ long factorial( int
numero ) { long resultado = 1; int i = 0; /* declaracion de la funcin factorial iterativa */ for ( i = numero; i >= 1; i-- )
resultado *= i; return resultado; }

Ejemplo Recursivo
/* * recursivo.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en
C * bajo licencia FDL, adaptado del Dominio Pblico */ #include <stdio.h> long factorial(int numero); int main(int
argc, char** argv) { int contador = 0; /* calcula el factorial de 0 a 10 */ for ( contador = 0; contador <= 10; contador++
) printf("%d! = %ld\n, contador, factorial( contador )); return 0; } /* funcin factorial recursiva */ long factorial( int
numero ) { if ( numero <= 0 ) /* caso base */ return 1; /* casos bases: 0! = 1 y 1! = 1 */ else /* llamada recursiva */
return numero * factorial( numero - 1 ); /* llamada a la funcin factorial */ }

Captulo 11

Programacin en C/Vectores
Los vectores son una forma de almacenar datos que permiten contener una serie de valores del mismo tipo, cada uno de
los valores contenidos tiene una posicin asociada que se usar para accederlos. Est posicin o ndice ser siempre un
nmero entero positivo.
En C la cantidad de elementos que podr contener un vector es jo, y en principio se dene cuando se declara el vector.
Los vectores se pueden declarar de la siguiente forma:
tipo_elemento nombre[largo];
Esto declara la variable nombre como un vector de tipo_elementos que podr contener largo cantidad de elementos, y cada
uno de estos elemento podr contener un valor de tipo tipo_elemento.
Por ejemplo:
double valores[128];
En este ejemplo declaramos un vector de 128 elementos del tipo double, los ndices de los elementos iran entre 0 (para
el primer elemento y 127 para el ltimo).
De la misma forma que con las otras declaraciones de variables que hemos visto se le puede asignar un valor iniciar a los
elementos.
O tambin se pueden declarar:
tipo_elemento nombre[largo]={valor_0, valor_1, valor_2};
En caso estamos asignadole valores a los primeros 3 elementos del vector nombre. Notar que largo debe ser mayor o igual
a la cantidad de valores que le estamos asignando al vector, en el caso de ser la misma cantidad no aporta informacin,
por lo que el lenguaje nos permite escribir:
tipo_elemento nombre[]={valor_0, valor_1, valor_2};
Que declarar nombre como el vector de largo 3.
Para acceder a un elemento accederemos a travs de su posicin. Es decir:
tipo_elemento elemento; ... elemento = nombre[2];
Asumiendo que tenemos el vector anterior denido estaramos guardando valor_2 en elemento.
Veamos algunos ejemplos:
/* * Ejemplo : El producto escalar de dos vectores */ #include <stdio.h> double producto_escalar(double v1[], double
33

34

CAPTULO 11. PROGRAMACIN EN C/VECTORES

v2[], int d); int main() { const int largo = 3; double vector_1[] = {5,1,0}; double vector_2[] = {1,5,3}; double resultado
= producto_escalar(vector_1, vector_2, largo); // imprime el resultado printf("(%f, %f, %f) . (%f, %f, %f) = %f\n,
vector_1[0], vector_1[1], vector_1[2], vector_2[0], vector_2[1], vector_2[2], resultado); return 0; } /* producto escalar
entre dos vectores */ double producto_escalar(double v1[], double v2[], int d) { double resultado = 0; int i; for (i=0; i <
d; i++) { resultado += v1[i] * v2[i]; } return resultado; }
En el ejemplo anterior usamos los vectores de C para representar vectores matemticos y calcular el producto escalar entre
ellos. Una peculiaridad que se puede notar es que al recibir un arreglo en una funcin no se especica el largo, volveremos
a esto en un captulo posterior.
Otra funcin clsica es la bsqueda de un mximo o mnimo, que podemos escribirla de la siguiente manera:
int buscar_maximo(double valores[], int num_valores) { int maximo_pos = 0; for (int i = 1; i < num_valores; i++) { if
(valores[i] > valores[maximo_pos]) { maximo_pos = i; } } return maximo_pos; }
Otro ejemplo sencillo, calcular el promedio de los valores.
double promedio(double valores[], int largo) { double suma=0; for (int i=0;i<largo;i++) { suma+=valores[i]; } return
suma/largo; }
Cuando una funcin recibe un vector por parmetro y cambia su contenido y el cambio es permanente (se ve an fuera
de la funcin). Esto puede parecer extrao despus del nfasis que pusimos en resaltar que todos los parmetros de una
funcin se reciben por valor, pero se aclarar en el siguiente capitulo.
Mientras tanto usemos esto para denir una funcin que le aplique otra funcin que recibe por parmetro a cada elemento
del vector, guardando el resultado en el mismo vector y una llamada de ejemplo a esta.
void cuadrados(double vector[], int largo) { for (int i=0;i<largo;i++) { vector[i]=cuadrado(vector[i]); } } ... double cuadrado(double valor) { return valor*valor; } ... cuadrados(elementos,num_elem); ...
De la misma forma que venimos usando vectores de tipos bsicos, podemos tener vectores de vectores, estos se declaran
de la siguiente forma:
int matriz[3][7]; int tabla[3][4]={ { 1, 2, 3, 4}, { 5, 6, 7, 8}, /* los espacios y saltos de lneas no son tomados en cuenta
*/ { 9,10,11,12} }; double v[2][2][2]; ... printf(tabla[0][1]: %i\n, tabla[0][3]); // Imprime 4 printf(tabla[2][0]: %i\n,
tabla[2][0]); // Imprime 9 ...
En este ejemplo tabla es un vector de longitud 3, cuyos elementos son vectores de longitud 4 de elementos de tipo int.
En resumen, suponiendo que v[n] es un vector de cualquier tipo de dato con n cantidad de posiciones, al vector v se le
aplican las siguientes reglas:
1. La primera posicin siempre ser v[0]
2. La ltima posicin es v[n-1]
3. En versiones previas a C99 n es una constante denida antes de la declaracin de v[n]

Captulo 12

Programacin en C/Cadenas de caracteres


Las cadenas de caracteres (tambin llamadas cadenas o strings) son un tipo particular de vectores, son de hecho vectores
de char, con la particularidad que tienen una marca de n (el caracter '\0'), adems el lenguaje nos permite escribirlas
como texto dentro de comillas dobles. Veamos unos ejemplos de su declaracin:
char cadena_hola[]="Hola"; char otro_hola[]={'H','o','l','a','\0'}; // Igual al anterior char vector[]={'H','o','l','a'}; /* Un
vector de 4 elementos, con los elementos 'H','o','l' y 'a' */ char espacio_cadena[1024]="Una cadena en C"; char cadena_vacia[]="";
Cmo vimos anteriormente al declarar un vector se dene la cantidad de elementos que puede contener, en el caso de
las cadenas se debe tener en cuenta el espacio adicional necesario para el \0. Viendo el ejemplo, tanto cadena_hola y
otro_hola tienen un largo 5 y cadena_vacia tiene un largo de 1.
Tambin vimos anteriormente que al usar vectores debemos tener en cuenta su largo, y as es que el largo o cantidad de
elemento lo necesitamos en todas las funciones que denimos usando vectores y lo recibimos como un parmetro ms en
estas, en el caso de las cadenas al tener una marca de n podemos prescindir del largo y procesar una cadenas hasta llegar
a la marca de n.
Por ejemplo, la siguiente funcin calcula el largo de una cadena:
/* devuelve la cantidad de caracteres en cadena sin contar el '\0' */ int largo_cadena(char cadena[]) { int largo=0 while
(cadena[largo]!='\0') largo++; return largo; }
Se debe tener en cuenta que el largo de una cadena y el largo del vector con la que se representa son distintos, tanto por
como largo_cadena() cuenta el largo de la cadena, como por espacio_cadena del ejemplo anterior.
Algo bastante usual es necesitar unir dos cadenas, veamos un ejemplo:
bool unir_cadenas(char destino[], char origen[], int largo) { int largo_origen = largo_cadena(origen); int largo_destino =
largo_cadena(destino); if ( largo_origen+largo_destino+1 > largo ) { return false; } for (int i=0; i<largo_origen;i++) { destino[largo_destino+i] = origen[i]; } destino[largo_destino+largo_origen]='\0'; return true; } ... if ( unir_cadenas(espacio_cadena,
que puede crecer hasta 1023 caracteres,1024) ) { ...
Estos dos ejemplos son versiones simplicadas de funciones provistas por la biblioteca estndar de C a travs del encabezado string.h. Nuestro largo_cadena() es similar al strlen() de la biblioteca estndar, y unir_cadenas() se asemeja al
strncat(). Si bien ver estas versiones nos sirven para entender las cadenas en C, en general ser preferible usar las funciones provistas por la biblioteca estndar, ya que podemos estar seguros que van a estar programadas de la mejor manera
posible.
Entre las funcione que provee la biblioteca estndar de C, las ms importantes son:
largo = strlen(cadena) // Para obtener el largo de una cadena strcpy(destino, origen) // Copia el contenido de origen en

35

36

CAPTULO 12. PROGRAMACIN EN C/CADENAS DE CARACTERES

destino // destino debe ser lo sucientemente grande strcat(destino, origen) // Agrega el contenido de origen al nal de
destino // destino debe ser lo sucientemente grande resultado = strcmp(cadena1, cadena2) // Compara dos cadenas //
devuelve un valor menor, igual o mayor que 0 segn si cadena1 es menor, // igual o mayor que cadena2, respectivamente.
posicion = strchr(cadena, caracter) // Devuelve la posicin en memoria de la primer // aparicin de caracter dentro de
cadena posicion = strstr(cadena,subcadena) // Devuelve la posicin en memoria de la primer // aparicin de subcadena
dentro de cadena
Veamos algunos ejemplos usando <string.h>:
#include <stdio.h> #include <string.h> ... char color[] = rojo"; char grosor[] = grueso"; ... char descripcion[1024];
strcpy(descripcion, Lapiz color "); strncat(descripcion, color, 1024); strncat(descripcion, " de trazo ", 1024); strncat(descripcion,
grosor, 1024); // descripcion contiene Lapiz color rojo de trazo grueso ...
void intercambiar(char vector[], int pos1, int pos2); void invierte_cadena(char cadena[]) { int largo = strlen(cadena); for
(int i=0; i < (largo/2); i++) { intercambiar(cadena, i, (largo-1)-i); } } void intercambiar(char vector[], int pos1, int pos2)
{ char aux=vector[pos1]; vector[pos1]=vector[pos2]; vector[pos2]=aux; }

Captulo 13

Programacin en C/Manejo de archivos


As como hemos revisado la salida y entrada por pantalla y teclado respectivamente, veremos ahora la entrada y/o salida
de datos utilizando cheros, lo cual ser imprescindible para un gran nmero de aplicaciones que deseemos desarrollar.

13.1 Ficheros
El estndar de C contiene varias funciones para la edicin de cheros, estas estn denidas en la cabecera stdio.h y por lo
general empiezan con la letra f, haciendo referencia a le. Adicionalmente se agrega un tipo FILE, el cual se usar como
apuntador a la informacin del chero. La secuencia que usaremos para realizar operaciones ser la siguiente:
Crear un apuntador del tipo FILE *
Abrir el archivo utilizando la funcin fopen y asignndole el resultado de la llamada a nuestro apuntador.
Hacer las diversas operaciones (lectura, escritura, etc).
Cerrar el archivo utilizando la funcin fclose.

13.1.1

fopen

Esta funcin sirve para abrir y crear cheros en disco.


El prototipo correspondiente de fopen es:
FILE * fopen (const char *lename, const char *opentype);
Los parmetros de entrada de fopen son:
lename: una cadena que contiene un nombre de chero vlido. opentype: especica el tipo de chero que se abrir o se
crear.
Una lista de parmetros opentype para la funcin fopen son:
r : abrir un archivo para lectura, el chero debe existir.
w : abrir un archivo para escritura, se crea si no existe o se sobreescribe si existe.
a : abrir un archivo para escritura al nal del contenido, si no existe se crea.
rt : abrir un archivo para lectura y escritura, el chero debe existir.
37

38

CAPTULO 13. PROGRAMACIN EN C/MANEJO DE ARCHIVOS


wt : crear un archivo para lectura y escritura, se crea si no existe o se sobreescribe si existe.
r+b rb+" : Abre un archivo en modo binario para actualizacin (lectura y escritura).
rb : Abre un archivo en modo binario para lectura.

Adicionalmente hay tipos utilizando b (binary) los cuales no sern mostrados por ahora y que solo se usan en los sistemas
operativos que no pertenecen a la familia de unix.

13.1.2

fclose

Esta funcin sirve para poder cerrar un chero que se ha abierto.


El prototipo correspondiente de fclose es:
int fclose (FILE *stream);
Un valor de retorno cero indica que el chero ha sido correctamente cerrado, si ha habido algn error, el valor de retorno
es la constante EOF.
Un ejemplo pequeo para abrir y cerrar el archivo llamado chero.in en modo lectura:
#include <stdio.h> #include <stdlib.h> int main(int argc, char** argv) { FILE *fp; fp = fopen ( chero.in, r ); if
(fp==NULL) {fputs (File error,stderr); exit (1);} fclose ( fp ); return 0; }
Como vemos, en el ejemplo se utiliz el opentype r, que es para la lectura.
Otra cosa importante es que el lenguaje C no tiene dentro de si una estructura para el manejo de excepciones o de errores,
por eso es necesario comprobar que el archivo fue abierto con xito if (fp == NULL)". Si fopen pudo abrir el archivo
con xito devuelve la referencia al archivo (FILE *), de lo contrario devuelve NULL y en este caso se debera revisar la
direccion del archivo o los permisos del mismo. En estos ejemplos solo vamos a dar una salida con un retorno de 1 que
sirve para sealar que el programa termino por un error.

13.1.3

feof

Esta funcin sirve para determinar si el cursor dentro del archivo encontr el nal (end of file). Existe otra forma de
vericar el nal del archivo que es comparar el caracter que trae fgetc del archivo con el macro EOF declarado dentro
de stdio.h, pero este mtodo no ofrece la misma seguridad (en especial al tratar con los archivos binarios). La funcin
feof siempre devolver cero (Falso) si no es encontrado EOF en el archivo, de lo contrario regresar un valor distinto de
cero (Verdadero).
El prototipo correspondiente de feof es:
int feof(FILE *chero);

13.1.4

rewind

Literalmente signica rebobinar, sita el cursor de lectura/escritura al principio del archivo.


El prototipo correspondiente de rewind es:
void rewind(FILE *chero);

13.2. LECTURA

39

13.2 Lectura
Un archivo generalmente debe verse como un string (una cadena de caracteres) que esta guardado en el disco duro. Para
trabajar con los archivos existen diferentes formas y diferentes funciones. Las funciones que podramos usar para leer un
archivo son:
char fgetc(FILE *archivo)
char *fgets(char *buer, int tamano, FILE *archivo)
size_t fread(void *puntero, size_t tamano, size_t cantidad, FILE *archivo);
int fscanf(FILE *chero, const char *formato, argumento, ...);
Las primeras dos de estas funciones son muy parecidas entre si. Pero la tercera, por el numero y el tipo de parmetros,
nos podemos dar cuenta de que es muy diferente, por eso la trataremos aparte junto al fwrite que es su contraparte para
escritura.

13.2.1

fgetc

Esta funcin lee un caracter a la vez del archivo que esta siendo sealado con el puntero *archivo. En caso de que la
lectura sea exitosa devuelve el caracter ledo y en caso de que no lo sea o de encontrar el nal del archivo devuelve EOF.
El prototipo correspondiente de fgetc es:
char fgetc(FILE *archivo);
Esta funcin se usa generalmente para recorrer archivos de texto. A manera de ejemplo vamos a suponer que tenemos
un archivo de texto llamado prueba.txt en el mismo directorio en que se encuentra el fuente de nuestro programa. Un
pequeo programa que lea ese archivo ser:
#include <stdio.h> #include <stdlib.h> int main() { FILE *archivo; char caracter; archivo = fopen(prueba.txt,"r); if
(archivo == NULL){ printf("\nError de apertura del archivo. \n\n); }else{ printf("\nEl contenido del archivo de prueba
es \n\n); while (feof(archivo) == 0) { caracter = fgetc(archivo); printf("%c,caracter); } } fclose(archivo); return 0; }

13.2.2

fgets

Esta funcin est diseada para leer cadenas de caracteres. Leer hasta n-1 caracteres o hasta que lea un cambio de lnea
'\n' o un nal de archivo EOF. En este ltimo caso, el carcter de cambio de lnea '\n' tambin es ledo.
El prototipo correspondiente de fgets es:
char *fgets(char *buer, int tamao, FILE *archivo);
El primer parmetro buer lo hemos llamado as porque es un puntero a un espacio de memoria del tipo char (podramos
usar un arreglo de char). El segundo parmetro es tamao que es el limite en cantidad de caracteres a leer para la funcion
fgets. Y por ultimo el puntero del archivo por supuesto que es la forma en que fgets sabra a que archivo debe leer.
#include <stdio.h> #include <stdlib.h> int main() { FILE *archivo; char caracteres[100]; archivo = fopen(prueba.txt,"r);
if (archivo == NULL) exit(1); printf("\nEl contenido del archivo de prueba es \n\n); while (feof(archivo) == 0) {
fgets(caracteres,100,archivo); printf("%s,caracteres); } system(PAUSE); fclose(archivo); return 0; }
Este es el mismo ejemplo de antes con la diferencia de que este hace uso de fgets en lugar de fgetc. La funcin fgets
se comporta de la siguiente manera, leer del archivo apuntado por archivo los caracteres que encuentre y a ponerlos en

40

CAPTULO 13. PROGRAMACIN EN C/MANEJO DE ARCHIVOS

buer hasta que lea un caracter menos que la cantidad de caracteres especicada en tamao o hasta que encuentre el nal
de una linea (\n) o hasta que encuentre el nal del archivo (EOF). En este ejemplo no vamos a profundizar mas que para
decir que caracteres es un buer, los pormenores seran explicados en la seccin de manejo dinmico de memoria.
El benecio de esta funcin es que se puede obtener una linea completa a la vez. Y resulta muy til para algunos nes
como la construccin de un parser de algn tipo de archivo de texto.

13.2.3

fread

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
Esta funcin lee un bloque de una stream de datos. Efecta la lectura de un arreglo de elementos count, cada uno
de los cuales tiene un tamao denido por size. Luego los guarda en el bloque de memoria especicado por ptr. El
indicador de posicin de la cadena de caracteres avanza hasta leer la totalidad de bytes. Si esto es exitoso la cantidad de
bytes ledos es (size*count).
PARAMETROS:
ptr : Puntero a un bloque de memoria con un tamao mnimo de (size*count) bytes.
size : Tamao en bytes de cada elemento (de los que voy a leer).
count : Nmero de elementos, los cuales tienen un tamao size.
stream: Puntero a objetos FILE, que especica la cadena de entrada.

13.2.4

fscanf

La funcin fscanf funciona igual que scanf en cuanto a parmetros, pero la entrada se toma de un chero en lugar del
teclado.
El prototipo correspondiente de fscanf es:
int fscanf(FILE *chero, const char *formato, argumento, ...);
Podemos ver un ejemplo de su uso, abrimos el documento chero.txt en modo lectura y leyendo dentro de el.
#include <stdio.h> int main ( int argc, char **argv ) { FILE *fp; char buer[100]; fp = fopen ( chero.txt, r ); fscanf(fp, "%s ,buer); printf("%s,buer); fclose ( fp ); return 0; }

13.3 Escritura
As como podemos leer datos desde un chero, tambin se pueden crear y escribir cheros con la informacin que
deseamos almacenar, Para trabajar con los archivos existen diferentes formas y diferentes funciones. Las funciones que
podramos usar para escribir dentro de un archivo son:
int fputc(int caracter, FILE *archivo)
int fputs(const char *buer, FILE *archivo)
size_t fwrite(void *puntero, size_t tamano, size_t cantidad, FILE *archivo);
int fprintf(FILE *archivo, const char *formato, argumento, ...);

13.3. ESCRITURA

13.3.1

41

fputc

Esta funcin escribe un carcter a la vez del archivo que esta siendo sealado con el puntero *archivo. El valor de retorno
es el carcter escrito, si la operacin fue completada con xito, en caso contrario ser EOF.
El prototipo correspondiente de fputc es:
int fputc(int carcter, FILE *archivo);
Mostramos un ejemplo del uso de fputc en un chero.txt, se escribira dentro del chero hasta que presionemos la tecla
enter.
#include <stdio.h> int main ( int argc, char **argv ) { FILE *fp; char caracter; fp = fopen ( chero.txt, r+" );
printf("\nIntrouce un texto al chero: "); while((caracter = getchar()) != '\n') { fprintf("%c, fputc(caracter, fp)); } fclose
( fp ); return 0; }

13.3.2

fputs

La funcin fputs escribe una cadena en un chero. No se aade el carcter de retorno de lnea ni el carcter nulo nal.
El valor de retorno es un nmero no negativo o EOF en caso de error. Los parmetros de entrada son la cadena a escribir
y un puntero a la estructura FILE del chero donde se realizar la escritura.
El prototipo correspondiente de fputs es:
int fputs(const char *buer, FILE *archivo)
para ver su funcionamiento mostramos el siguiente ejemplo:
#include <stdio.h> int main ( int argc, char **argv ) { FILE *fp; char cadena[] = Mostrando el uso de fputs en un chero.\n"; fp = fopen ( chero.txt, r+" ); fputs( cadena, fp ); fclose ( fp ); return 0; }

13.3.3

fwrite

Esta funcin est pensada para trabajar con registros de longitud constante y forma pareja con fread. Es capaz de escribir
hacia un chero uno o varios registros de la misma longitud almacenados a partir de una direccin de memoria determinada. El valor de retorno es el nmero de registros escritos, no el nmero de bytes. Los parmetros son: un puntero a la
zona de memoria de donde se obtendrn los datos a escribir, el tamao de cada registro, el nmero de registros a escribir
y un puntero a la estructura FILE del chero al que se har la escritura.
El prototipo correspondiente de fwrite es:
size_t fwrite(void *puntero, size_t tamano, size_t cantidad, FILE *archivo);
Un ejemplo concreto del uso de fwrite con su contraparte fread y usando funciones es:

13.3.4

fprintf

La funcin fprintf funciona igual que printf en cuanto a parmetros, pero la salida se dirige a un archivo en lugar de a la
pantalla.
El prototipo correspondiente de fprintf es:
int fprintf(FILE *archivo, const char *formato, argumento, ...);

42

CAPTULO 13. PROGRAMACIN EN C/MANEJO DE ARCHIVOS

Podemos ver un ejemplo de su uso, abrimos el documento chero.txt en modo lectura/escritura y escribimos dentro de
el.
#include <stdio.h> int main ( int argc, char **argv ) { FILE *fp; char buer[100] = Esto es un texto dentro del chero.";
fp = fopen ( chero.txt, r+" ); fprintf(fp, buer); fprintf(fp, "%s, "\nEsto es otro texto dentro del chero.); fclose (
fp ); return 0; }

Captulo 14

Programacin en C/Estructuras y Uniones


En la creacion de soluciones para algunos problemas surge la necesidad de agrupar datos de diferente tipo o de manejar datos que serian muy dicil de describir en los tipos de datos primitivos, esta es la situacion en la que debemos
aprovecharnos de las caracteristicas que hacen al lenguaje C especial, o sea el uso de estructuras, uniones y punteros.

14.1 Estructuras
Una estructura contiene varios datos. La forma de denir una estructura es haciendo uso de la palabra clave struct. Aqui
hay ejemplo de la declaracion de una estructura:
struct mystruct { int int_member; double double_member; char string_member[25]; } variable;
variable es una instancia de mystruct y no es necesario ponerla aqu. Se podria omitir de la declaracion de mystruct
y ms tarde declararla usando:
struct mystruct variable;
Tambin es una prctica muy comn asignarle un alias o sinnimo al nombre de la estructura, para evitar el tener que
poner struct mystruct cada vez. C nos permite la posibilidad de hacer esto usando la palabra clave typedef, lo que crea
un alias a un tipo:
typedef struct { ... } Mystruct;
La estructura misma no tiene nombre (por la ausencia de nombre en la primera linea), pero tiene de alias Mystruct.
Entonces se puede usar as:
Mystruct variable;
Note que es una convencion, y una buena costumbre usar mayscula en la primera letra de un sinnimo de tipo. De
todos modos lo importante es darle algn identicador para poder hacer referencia a la estructura: podriamos tener una
estructura de datos recursiva de algn tipo.
Ejemplo de una estructura :
/* * estructura.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en
C (fundamentos)" * bajo licencia FDL, adaptado del Dominio Pblico * * Nombre Miembro Tipo * Titulo char[30]
* Artista char[25] * Precio oat * Total Canciones int */ #include <stdio.h> #include <string.h> /* denimos una estructura para cds */ struct cd { char titulo[30]; char artista[25]; oat precio; int canciones; } Cd1 = { /* inicializamos la
estructura Cd1 creaa con sus valores * usando las deniciones iniciales*/ Canciones Bebe, /* titulo */ Pinocho, /*
43

44

CAPTULO 14. PROGRAMACIN EN C/ESTRUCTURAS Y UNIONES

artista */ 12.50, /* precio */ 16 /* total canciones */ }; int main(void) { struct cd Cd2; /* denimos una nueva estructura llamado cd2 */ /* asignamos valores a los tipos de datos del cd2 */ strcpy(Cd2.titulo, New Age); /* la forma de
insertar valores a un * tipo char en una estructura es usando strcpy * de la libreria string.h */ strcpy(Cd2.artista, Old
Man); Cd2.precio = 15.00; Cd2.canciones = 12; /* la forma de acceder a los valores de una estructura */ /* es usando
el ". despues de la denicion del dato*/ printf("\n Cd 1); printf("\n Titulo: %s ", Cd1.titulo); printf("\n Artista: %s
", Cd1.artista); printf("\n Total Canciones: %d ", Cd1.canciones); printf("\n Precio Cd: %f ", Cd1.precio); printf("\n);
printf("\n Cd 2); printf("\n Titulo: %s ", Cd2.titulo); printf("\n Artista: %s ", Cd2.artista); printf("\n Total Canciones:
%d ", Cd2.canciones); printf("\n Precio Cd: %.2f ", Cd2.precio); /* el .2 que esta entre %f * sirve para mostrar unicamente * 2 decimales despues del punto*/ return 0; }

14.1.1

Estructuras Anidadas

Una estructura puede estar dentro de otra estructura a esto se le conoce como anidamiento o estructuras anidadas. Ya que
se trabajan con datos en estructuras si denimos un tipo de dato en una estructura y necesitamos denir ese dato dentro
de otra estructura solamente se llama el dato de la estructura anterior.
Denamos una estructura en nuestro programa:
struct empleado /* creamos una estructura llamado empleado*/ { char nombre_empleado[25]; char direccion[25]; char
ciudad[20]; char provincia[20]; long int codigo_postal; double salario; }; /* las estructuras necesitan punto y coma (;) al
nal */
Y luego necesitamos una nueva estructura en nuestro programa:
struct cliente /* creamos una estructura llamada cliente */ { char nombre_cliente[25]; char direccion[25]; char ciudad[20];
char provincia[20]; long int codigo_postal; double saldo; }; /* las estructuras necesitan punto y coma (;) al nal */
Podemos ver que tenemos datos muy similares en nuestras estructuras, asi que podemos crear una sola estructura llamada
infopersona con estos datos idnticos:
struct infopersona /* creamos la estructura que contiene datos parecidos */ { char direccion[25]; char ciudad[20]; char
provincia[20]; long int codigo_postal; }; /* las estructuras necesitan punto y coma (;) al nal */
Y crear las nuevas estructuras anteriores, anidando la estructura necesaria:
struct empleado /* se crea nuevamente la estructura */ { char nombre_empleado[25]; /* creamos direcc_empleado con
struct del tipo estructura infopersona */ struct infopersona direcc_empleado; double salario; }; /* las estructuras
necesitan punto y coma (;) al nal */ <source lang=c> struct cliente /* se crea nuevamente la estructura */ { char
nombre_cliente[25]; /* creamos direcc_cliente con struct del tipo estructura infopersona */ struct infopersona direcc_cliente; double saldo; }; /* las estructuras necesitan punto y coma (;) al nal */
Y ac el ejemplo completo con estructuras anidadas:
/* * estructura2.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en
C (fundamentos)" * bajo licencia FDL, adaptado del Dominio Pblico * * Nombre Miembro Tipo * * Titulo char[30]
* Artista char[25] * Precio oat * Total Canciones int */ #include <stdio.h> #include <string.h> /* creamos nuestra
estructura con datos similares */ struct infopersona { char direccion[25]; char ciudad[20]; char provincia[20]; long int
codigo_postal; }; /* las estructuras necesitan punto y coma (;) al nal */ /* creamos nuestra estructura empleado */ struct
empleado { char nombre_empleado[25]; /* agregamos la estructura infopersona * con nombre direcc_empleado */ struct
infopersona direcc_empleado; double salario; }; /* las estructuras necesitan punto y coma (;) al nal */ /* creamos nuestra estructura cliente */ struct cliente { char nombre_cliente[25]; /* agregamos la estructura infopersona * con nombre
direcc_cliente */ struct infopersona direcc_cliente; double saldo; }; /* las estructuras necesitan punto y coma (;) al nal */
int main(void) { /* creamos un nuevo cliente */ struct cliente MiCliente; /*inicializamos un par de datos de Micliente */
strcpy(MiCliente.nombre_cliente,"Jose Antonio); strcpy(MiCliente.direcc_cliente.direccion, Altos del Cielo); /* note-

14.2. UNIONES

45

se que se agrega direcc_cliente haciendo referencia * a la estructura infopersona por el dato direccion */ /* imprimimos los
datos */ printf("\n Cliente: "); printf("\n Nombre: %s, MiCliente.nombre_cliente); /* notese la forma de hacer referencia
al dato */ printf("\n Direccion: %s, MiCliente.direcc_cliente.direccion); /* creamos un nuevo empleado */ struct empleado MiEmpleado; /*inicializamos un par de datos de MiEmplado */ strcpy(MiEmpleado.nombre_empleado,"Miguel
Angel); strcpy(MiEmpleado.direcc_empleado.ciudad,"Madrid); /* para hacer referencia a ciudad de la estructura infopersona * utilizamos direcc_empleado que es una estructura anidada */ /* imprimimos los datos */ printf("\n); printf("\n
Empleado: "); printf("\n Nombre: %s, MiEmpleado.nombre_empleado); /* notese la forma de hacer referencia al dato
*/ printf("\n Ciudad: %s, MiEmpleado.direcc_empleado.ciudad); return 0; }

14.2 Uniones
La denicion de union es similar a la de estructura, La diferencia entre las dos es que en una estructura, los miembros
ocupan diferentes areas de la memoria, pero en una union, los miembros ocupan la misma area de memoria. Entonces
como ejemplo:
union { int i; double d; } u;
El programador puede acceder a travs de u.i o de u.d, pero no de ambos al mismo tiempo. Como u.i y u.d ocupan
la misma rea de memoria, modicar uno modica el valor del otro, algunas veces de maneras impredecibles.
El tamao de una union es el de su miembro de mayor tamao.
Ejemplo de una unin:
/* * uniones.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en C
(fundamentos)" * bajo licencia FDL, adaptado del Dominio Pblico */ #include <stdio.h> #include <string.h> /*Creamos
una union*/ union frases { char mensajes[50]; char ayudas[50]; char lineas[50]; } palabra; /*Creamos una estructura*/
struct comparte { char mensajes[50]; char ayudas[50]; char lineas[50]; }Sistema; /*Ntese que la estructura y la union
tienen los mismos tipos de datos*/ int main(int argc, char** argv) { /*Inicializamos*/ strcpy(palabra.mensajes, Primer
Mensaje); /*Inicializamos*/ strcpy(palabra.ayudas, Una Ayuda); printf("\nFrases en Union: "); /*Imprimimos mensajes de union*/ printf("\n1- %s, palabra.mensajes); /*Imprimimos ayudas de union*/ printf("\n2- %s, palabra.ayudas);
/*Inicializamos*/ strcpy(Sistema.mensajes, Primer Mensaje); /*Inicializamos*/ strcpy(Sistema.ayudas, Una Ayuda);
/* Podemos notar que aunque inicializamos los valores * al imprimir se tiene el mismo valor para cada miembro * de la
estructura, esto se debe a que las uniones usan el * mismo espacio de memoria para todos los elementos * de la union,
siendo del tamao de su miembro de * mayor tamao, en este caso 50 bytes. * Entonces los tres miembros creados
dentro de la * union comparten esos 50 bytes. * Entonces el ultimo valor agregado a la union es * el que se tiene. */
printf("\n\nFrases en Struct: "); /*Imprimimos mensajes de struct*/ printf("\n1- %s, Sistema.mensajes); /*Imprimimos
ayudas de union*/ printf("\n2- %s, Sistema.ayudas); /* En la estructura comparte, se reservan 150 bytes * de memoria
para los tres miembros, en este caso * cada uno es independiente en memoria, asi pues se * puede inicializar cada uno o
usar como un campo * independiente. */ return 0; }

14.3 Enumeraciones
Una enumeracion (enum) es un tipo denido con constante de tipo entero. En la declaracion de un tipo enum creamos
una lista de tipo de datos que se asocian con las constantes enteras 0, 1, 2, 3, 4, 5...
su forma de denirlas es la siguiente:
enum { enumerador1, enumerador2, enumeradorn }; enum Nombre { enumerador1, enumerador2, enumeradorn };
En este caso al ser declaradas enumerador1 toma el valor entero de 0, enumerador2 el valor de 1 y asi sucesivamente para
cada una de las expresiones siguientes.

46

CAPTULO 14. PROGRAMACIN EN C/ESTRUCTURAS Y UNIONES

Al declarar la enum se puede asociar a los tipos de datos a valores constantes en vez de la asociacion que por defecto se
realiza (0, 1, 2, ), se utiliza entonces este formato:
enum Nombre { enumerador1 = valor_constante1, enumerador2 = valor_constante2, ... enumeradorn = valor_constanten,
};
Un ejemplo de una enum:
enum Boolean { FALSE, TRUE };
Se denen dos constantes para las constantes true y false con valores iguales a 0 para False y 1 para True.
Ejemplo:
/* * Enum.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en C
(fundamentos)" * bajo licencia FDL, adaptado del Dominio Pblico */ #include <stdio.h> enum Boolean { FALSE,
TRUE }; /* Se dene un enum para emular las constantes * True y False con valores de 0 y 1. * Notese que las enum no
necesitan ; al nal * de cada tipo de dato. */ /* Denimos una funcion del tipo enum llamada numero*/ enum Boolean
numero(char c); int main(int argc, char** argv) { char caracter; int Numeros = 0; printf("\nIntroduce un texto. Para terminar: Enter. \n\t); /* Tenemos un while que mientras no se presione Enter * seguira leyendo un tipo de dato caracter */
while((caracter = getchar()) != '\n') { if (numero(caracter)) { Numeros++; } } printf("\nTotal de Numeros leidos: %d,
Numeros); return 0; } enum Boolean numero(char c) { switch(c) { case '0': case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9': return TRUE; /* Mientras el caracter valga de 0 a 9 retornara TRUE (1) */ default:
return FALSE; /* Por default retornara FALSE (0) */ } }
En la siguiente enum se declaran las variables inicializando la primera y las demas con los siguientes valores enteros:
/* * Enum2.c * * Julio Csar Brizuela <brizuelaalvarado@gmail.com> 2009 * * para el wikilibro Programacin en C
(fundamentos)" * bajo licencia FDL, adaptado del Dominio Pblico */ #include <stdio.h> enum DiasSemanas { Domingo = 1, Lunes, Marte, Miercoles, Jueves, Viernes, Sabado }; /* Podemos inicializar nuestra primer constante Domingo
* en 2, asi pues las demas los siguientes valores enteros. */ int main(int argc, char** argv) { enum DiasSemanas dia; for
(dia = Domingo; dia <= Sabado; dia++) { printf("%d ", dia); /* Salida: 1 2 3 4 5 6 7 */ } return 0; }
A los enumeradores se pueden asignar valores o expresiones constantes durante la declaracion:
enum Hexaedro { VERTICE = 8, LADOS = 12, CARAS = 6 };

Captulo 15

Programacin en C/Punteros

47

Captulo 16

Concepto
Un puntero es una variable que contiene la direccin de memoria de un dato o de otra variable que contiene al dato.
Quiere esto decir, que el puntero apunta al espacio fsico donde est el dato o la variable. Un puntero puede apuntar a un
objeto de cualquier tipo, como por ejemplo, a una estructura o una funcin. Los punteros se pueden utilizar para referencia
y manipular estructuras de datos, para referenciar bloques de memoria asignados dinamicamente y para proveer el paso
de argumentos por referencias en las llamadas a funciones.
Muchas de las funciones estandares de C, trabajan con punteros, como es el caso del scanf o strcpy. Estas reciben o
devuelve un valor que es un puntero. Por Ej. A scanf se le pasa la direccin de memoria del dato a leer (esto es un
puntero)...
char a; scanf ("%c,&a);

48

Captulo 17

Declarando punteros
Ya se dijo que un puntero es una variable que guarda la direccin de memoria de otra variable, haciendo logica a esto,
decimos que un puntero se declara igual que cualquier otra variable, pero anteponiendo un * (asterisco) antes del nombre
de la variable.
Su sintaxis seria:
tipo *NombrePuntero;
Donde tipo es el tipo de dato al que referenciar este puntero, es decir, que si se necesita guardar la direccin de memoria
de un dato int, se necesita un puntero de tipo int.

49

Captulo 18

Explicacin
Veamos el siguiente codigo:
#include <stdio.h> int main() { int a=0; //Declaracin de variable entera de tipo entero int *puntero; //Declaracin de
variable puntero de tipo entero puntero = &a; //Asignacin de la direccin memoria de a printf(El valor de a es: %d.
\nEl valor de *puntero es: %d. \n,a,*puntero); printf(La direccion de memoria de *puntero es: %p,puntero); return 0; }
Igual que cuando usamos un &, en la lectura de datos con scanf, igual de esta forma lo usamos aqu, tal vez te acordaras
que decamos que las cadenas de caracteres (%s) no usaban este operador, esto es por que en una cadena de caracteres es
un arreglo de caracteres, por lo que el primer carcter es la direccin de inicio de la cadena.
El operador *, nos permite acceder al valor de la direccion del puntero, en este caso nos permite acceder al valor que
contiene a la variable a. De esta forma a y "*puntero muestran el mismo dato, pero esto no quiere decir que sea lo
mismo, uno es un entero el otro un puntero.
La impresin con %p, es para poder imprimir la direccin de memoria en valor hexadecimal (0x...), tambin podemos
imprimir: ...%p,&a) y funciona de la misma forma, y es lgico que tanto a, como puntero tienen la misma direccin de
memoria.
Diferentes direcciones?
Tal vez notaste que en cada ejecucin la direccin de memoria cambia, esto es por que es el sistema operativo es quien
esta encargado de administrar la memoria y es este quien dice que espacios podra tomar el programa.
Esto quiere decir que uno no puede asignarle una direccin de memoria a un puntero directamente, es decir yo no puedo
hacer lo siguiente.
int *puntero=0xbfc5b1c8;
Esto no puedo ni debo hacerlo ya que yo no se que esta haciendo esta direccin de memoria, si el sistema la tiene o no
disponible, etc... Pero si puedo hacer esto:
int *puntero=NULL;
NULL, es el espacio en memoria con direccin 0, esto quiere decir que existe, lo que signica que le asignamos una
direccion valida al puntero, pero el valor que tiene NULL no se nos permite modicarlo, ya que pertenece al sistema.

50

Captulo 19

Operadores
Ya anteriormente te ponamos algunos ejemplos de como asignar la direccin de memoria a un puntero y de como acceder
al valor de este.
Operador de Direccin (&): Este nos permite acceder a la direccin de memoria de una variable.
Operador de Indireccin (*): Adems de que nos permite declarar un tipo de dato puntero, tambin nos permite ver el
VALOR que est en la direccin asignada.
Incrementos (++) y Decrementos (--): Te dars cuenta que puedes usar un puntero como si de un array se tratase, es
por esto que permite estos operadores.
De lo anterior podemos decir que:
int a; Es Igual int *puntero=&a; printf("%d,a); Es Igual printf("%d,*puntero);

51

Captulo 20

Operaciones Aritmticas
Un puntero nos permite sumar o restar nmeros enteros, pero su funcionamiento ahora es de posiciones, es decir nos
permitir movernos a la siguiente direccin de memoria.
A un puntero no se le puede realizar multiplicaciones, divisiones, sumas o restas con otro puntero o con un valor de tipo
coma otante (oat, double...). Esto es por que un puntero no es un valor es una direccin.
En un puntero se pueden realizar varias operaciones de tipo enteras, pero en dependencia de como se usen sus resultados
pueden ser muy diferentes, a continuacin les muestro algunas de estas operaciones:
//Denamos estas variables: int x[100],b,*pa,*pb; //... x[50]=10; //Le asignamos el valor de 10, al array #50 pa=&x[50];
//Le asignamos al puntero pa, la direccion de memoria que tiene x[50] //Ahora mostramos algunas posibles operaciones:
b = *pa+1; //Esto es como decir el valor que tiene el array de x[50] sumarle 1. //Esto es igual a: b=x[50]+1; => Su valor
seria igual a 11. b = *(pa+1); //Esto primero pasa a la siguiente direccion de memoria y luego lo referencia //El resultado
es: b = x[51]; pb = &x[10]; //al puntero pb se le asigna la direccion de x[10] *pb = 0; //Al valor que tiene el puntero se
le asigna 0 //Esto es igual que decir: x[10] = 0 *pb += 2; //El valor del puntero se incrementa en dos unidades, es decir
x[10] = 2 (*pb)--; //El valor del puntero se decrementa en una unidad. x[0] = *pb--; //A x[0] se le pasa el valor de x[10]
y el puntero pb, pasa a apuntar a x[9] //recuerda, que -- es post-incremento, primero asignara y luego restara.

52

Captulo 21

Punteros Constantes
Es posible que hayas pensado como declarar un puntero como una constante, tal vez pensaste en un #dene, o en un
atributo const. Bueno es posible usar el atributo const, pero para un puntero hay que hacerlo de otra forma.
FORMA ERRADA:
int a=10,b=20; const int *p = &a; //objeto constante y puntero variable *p = 15; // ERROR: el valor apuntado por p es
constante. p=&b; //Correcto: p pasa a apuntar a un nuevo objeto.
Pero de esta forma no es muy til declararlo, pues el que hicimos constante fue el valor al que apunte p, es decir, mejor
hubisemos hecho que el puntero fuese una constante.
FORMA CORRECTA:
int a=10,b=20; int * const p = &a; //objeto variable y puntero constante *p = 15; // Correcto: El valor apuntado es variable. p=&b; //ERROR: p es constante.

53

Captulo 22

Punteros Genericos
Un puntero a cualquier tipo de dato puede convertirse a un puntero del tipo void *. Por esto un puntero a void *, recibe
el nombre de puntero generico.
En C, se permite la conversin implcita de punteros, pero en C++ esto no es posible, asi que por compatibilidad y buena
practica recomendamos usar la conversion explicita (cast).
Supongamos:
int *puntero; funcion (*puntero); .... void funcion (void *p) int *q; q=(int *)p; //En C se podria hacer q = p;
Es decir que un puntero a void se puede usar sin importar el tipo de dato, recuerden que uno no puede trabajar con
punteros que referencia a un tipo de dato diferente, como lo es un puntero a char, con un puntero a int.

54

Captulo 23

Punteros y Matrices
Anteriormente decamos que una matriz es una secuencia de espacios en memoria, que nos permitan alojar datos en cada
uno y un puntero es una variable que guarda la direccin de memoria, tambin decamos como recorre las direcciones de
memoria con los operadores ++ y -.
Aqu veremos como puede usarse un puntero como si de una matriz se tratase, luego de que veas que es tcnicamente lo
mismo, te preguntaras por que usar punteros, pero estos son muy necesarios y nicos que nos permiten realizar cosas que
con un array normal, no se puede, como asignarle memoria dinmica, etc...
#include <stdio.h> int main() { int array[10]={0,2,3,5,5,6,7,8,9,0}; //Declarar e inicializar un array. int *puntero =
&array[0]; //Le damos la direccin de inicio del array int i; //variable contadora... for (i=0;i<10;i++) printf("%d\n,*(puntero+i));
//imprimimos los valores del puntero. return 0; }
Habrs notado que he usado *(puntero+i), as como explica la seccin de operaciones aritmticas, pero tambin podemos
acceder de otras maneras como lo son:
array[i] => Accede como un array normal
(array+i) => Tambin accede como un array normal.
puntero[i] => Accedemos al valor de puntero sub i
(puntero+i) => Accedemos al valor de puntero + i.

55

Captulo 24

Punteros a cadenas de caracteres


Ya hemos visto el uso que se le puede dar a un puntero como si de un array se tratase, entonces usando esta misma logica
podemos hacer un array de caracteres usando punteros.
char *nombre="Gustavo A. Chavarria";//Es como un array de 20 caracteres printf("%s,nombre);
Sin embargo al tratarse de una constante de caracteres no podemos modicarla luego de denir sus valores. Como por
ejemplo no podemos remplazar un carcter, o leer un nuevo valor.
gets(nombre); //ERROR en ejecucin
Para poder modicar el valor de este puntero, este tendra que apuntar a una direccin que no sea una constante, como
un array.
char nombre[]="Gustavo A. Chavarria"; //declaramos un array de caracteres char *puntero=nombre;//Asignamos al puntero el comienzo del array printf("%s \nIngrese otro nombre: ",puntero);//Escribimos en pantalla nombre... gets(puntero);
//leemos otro nombre printf("%s,puntero); //escribimos el nuevo nombre...
Esta vez pudiste notar que si se pudo remplazar el valor del nombre, pero aun la cantidad de caracteres esta limitada por
el array original, mas adelante veremos como solucionar esto con memoria dinmica.

56

Captulo 25

Matrices de Punteros
Es muy probable que ya te hayas dicho: Si un puntero es una variable, Puedo tener un array de punteros? La respuesta
seria NO Exactamente.
Como ya habiamos explicado antes, un puntero trabaja de la misma forma que un array, tanto que podemos decir que un
puntero es un array, entonces si denimos un array de un array, nos dara como resultados un array bidimensional.
En la practica es mucho mas comn utilizar un array de punteros que un array bidimensional.
Hay que recordar que siguen siendo punteros, es decir solo apuntan a una direccin de memoria, por ende hay que
asignarles la direccin de memoria a cada uno de los elementos del puntero. Sin embargo podemos asignar en un solo
ciclo todas las las.
Ejemplo:
#include <stdio.h> int main() { int *puntero[5]; //array de puntero int a[5][5]; //Array bidimensional. int i; for (i=0;i<5;i++)
puntero[i]=a[i]; //Asignamos las las al puntero. //Pueden imprimir tambien en un ciclo //Tambien pueden acceder mediante un ciclo anidado a la variables del puntero[i][j] }

57

Captulo 26

Punteros a Punteros
Es una variable que contiene la direccin de memoria de un puntero, el cual a su vez contiene la direccin de memoria
de un tipo de dato. Recuerden que un puntero sigue siendo un espacio en memoria, pero en vez de almacenar un valor
almacena una direccin.
Si decimos que:
int a=0; //Supongamos que es una variable cuya direccion es 0x1601 int *puntero1=&a; //El puntero tiene guardada la
direccion de a, //pero este tiene como direccion 0x1890 int **puntero2=&puntero1; //**puntero 2 guarda la direccion
0x1890
Ahora se entiende mejor. Al uso de punteros se le llama variables con niveles de indireccion, ya que no apuntan directamente a un valor, sino que apuntan a alguien que lo tiene. Basndonos en esto podemos decir que *puntero1 es un puntero
con un nivel de indireccion y *puntero2 es un puntero con dos niveles de indireccion.
En general estos tipos de datos son usados con matrices multidimensionales, es por esto que decid no dejar ejemplos,
pues su uso es bastante fcil de implementar.

58

Captulo 27

Matrices de punteros a cadenas de


caracteres
No hablaremos sobre este tema, debido a que es prcticamente una matriz de caracteres que se usa mediante punteros, y
esto es tcnicamente lo mismo que hemos estado viendo anteriormente.
Tambien podemos usar punteros a punteros y guardar multiples cadenas.

59

Captulo 28

Ejemplos
Tenga en cuenta el siguiente bloque de cdigo que declara 2 punteros
/*1*/ struct MyStruct { /*2*/ int m_aNumber; /*3*/ oat num2; /*4*/ }; /*5*/ /*6*/ int * pJ2; /*7*/ struct MyStruct *
pAnItem;
Las primeras 4 lneas denen la estructura. La linea 6 declara una variable que apuntar a un entero, y la lnea 7 declara
una variable que apunta a algo de la estructura MyStruct. Entonces declarar un puntero es algo que apunta a algo de algn
tipo, ms que contener el tipo. El asterisco (*) se coloca antes del nombre de la variable.
En las siguientes lneas de cdigo, var1 es un puntero a un entero largo (long) mientras var2 es un entero largo (long) y
no un puntero a un entero largo. En la segunda lnea se declara p3 como un puntero a un puntero de un entero.
long * var1, var2; int ** p3;
Los punteros se usan habitualmente como parmetros de funciones. El siguiente cdigo muestra como declarar una funcin
que usa un puntero como argumento. Teniendo en cuenta que C pasa todos los argumentos por valor, para poder modicar
un valor desde el cdigo de la funcin, se debe usar un puntero al valor a modicar. Tambin se usan punteros a estructuras
como argumentos de una funcin an cuando la estructura no sea modicada dentro de la funcin. Esto es realizado para
evitar copiar todo el contenido de la estructura dentro de la pila.
int MyFunction( struct MyStruct *pStruct );

28.0.1

Asignando valores a punteros

Continuamos con el proceso de asignar valores a los punteros, para esto utilizamos el operador & o 'la direccin de'.
int myInt; int *pPointer; struct MyStruct dvorak; struct MyStruct *pKeyboard; pPointer = &myInt; pKeyboard = &dvorak;
Aqu, pPointer apuntara a myInt y pKeyboard apuntara a dvorak.
Los punteros tambin pueden ser asignados a referencias de memorias dinamicas creadas comnmente por las funciones
malloc() y calloc().
#include <stdlib.h> ... struct MyStruct *pKeyboard; ... pKeyboard = malloc(sizeof(struct MyStruct)); ...
La funcin malloc retorna un puntero de memoria asignada de manera dinmica (o NULL si falla). El tamao de esta
memoria es denido de modo que pueda contener la estructura MyStruct
El siguiente cdigo es un ejemplo mostrando un puntero siendo asignado a una referencia y se retorna el valor del puntero
60

61
en la funcin.
static struct MyStruct val1, val2, val3, val4; ... struct MyStruct *ASillyFunction( int b ) { struct MyStruct *myReturn; if
(b == 1) myReturn = &val1; else if (b==2) myReturn = &val2; else if (b==3) myReturn = &val3; else myReturn = &val4;
return myReturn; } ... struct MyStruct *strPointer; int *c, *d; int j; ... c = &j; /* puntero asignado usando el operador &
*/ d = c; /* asignando un puntero a otro */ strPointer = ASillyFunction( 3 ); /* puntero retornado de la funcion */
Cuando se retorna un puntero de una funcion, se tiene que tener cuidado de que el valor apuntado no sea de una referencia
de una variable local a la funcion, porque estos valores desaparecen despues de salir de la funcion y el puntero estaria mal
referenciado, causando errores en tiempo de ejecucion en el programa. La memoria creada dinamicamente dentro de la
funcion puede devolverse como puntero, el valor de retorno aunque es creado en una variable local la direccion como tal
se devuelve por valor dejando esta informacion valida.

Captulo 29

Programacin en C/Manejo dinmico de


memoria
Seguramente durante todo tu recorrido con este libro, especialmente en la seccin de punteros, te hablbamos sobre la
asignacin dinmica de memoria. Como su nombre lo dice, este es una forma de conseguir espacio en memoria, dndote
mas eciencia y tcnicamente hacer lo que requieras hacer con este.
En esta seccin haremos uso bastante (inevitablemente) de los punteros, por lo que te recomendamos que tengas muy
bien establecidos estos conocimientos.

29.1 Memoria dinmica


Es memoria que se reserva en tiempo de ejecucin. Su principal ventaja frente a la esttica, es que su tamao puede variar
durante la ejecucin del programa. (En C, el programador es encargado de liberar esta memoria cuando no la utilice ms).
El uso de memoria dinmica es necesario cuando a priori no conocemos el nmero de datos/elementos a tratar.

29.2 Memoria esttica


Es el espacio en memoria que se crea al declarar variables de cualquier tipo de dato (primitivas [int,char...] o derivados
[struct,matrices,punteros...]). La memoria que estas variables ocupan no puede cambiarse durante la ejecucin y tampoco
puede ser liberada manualmente.

29.3 Diferencias, ventajas y desventajas


La memoria reservada de forma dinmica suele estar alojada en el heap o almacenamiento libre, y la memoria esttica en
el stack o pila (con excepcin de los objetos de duracin esttica, que se vern ms adelante, los cuales normalmente se
colocan en una zona esttica de datos). La pila generalmente es una zona muy limitada. El heap, en cambio, en principio
podra estar limitado por la cantidad de memoria disponible durante la ejecucin del programa y el mximo de memoria
que el sistema operativo permita direccionar a un proceso. La pila puede crecer de forma dinmica, pero esto depende del
sistema operativo. En cualquier caso, lo nico que se puede asumir es que muy probablemente dispondremos de menor
espacio en la pila que en el heap.
Otra ventaja de la memoria dinmica es que se puede ir incrementando durante la ejecucin del programa. Esto permite,
por ejemplo, trabajar con arreglos dinmicos. Aunque en C, a partir del estndar C99 se permite la creacin de arreglos
cuyo tamao se determina en tiempo de ejecucin, no todos los compiladores implementan este estndar. Adems, se
62

29.4. EL LENGUAJE C Y EL MANEJO DE LA MEMORIA

63

sigue teniendo la limitante de que su tamao no puede cambiar una vez que se especica, cosa que s se puede lograr
asignando memoria de forma dinmica.
Una desventaja de la memoria dinmica es que es ms difcil de manejar. La memoria esttica tiene una duracin ja,
que se reserva y libera de forma automtica. En contraste, la memoria dinmica se reserva de forma explcita y contina
existiendo hasta que sea liberada, generalmente por parte del programador.
La memoria dinmica puede afectar el rendimiento. Puesto que con la memoria esttica el tamao de las variables se
conoce en tiempo de compilacin, esta informacin est incluida en el cdigo objeto generado, por lo cual el proceso es
muy eciente. Cuando se reserva memoria de manera dinmica, se tienen que llevar a cabo varias tareas, como buscar
un bloque de memoria libre y almacenar la posicin y tamao de la memoria asignada, de manera que pueda ser liberada
ms adelante. Todo esto representa una carga adicional, aunque esto depende de la implementacin y hay tcnicas para
reducir su impacto.

29.4 El lenguaje C y el manejo de la memoria


Todos los objetos tienen un tiempo de vida, es decir, el tiempo durante el cual se garantiza que el objeto exista. En C,
existen 3 tipos de duracin: esttica, automtica y asignada. Las variables globales y las variables locales declaradas con el
especicador static tienen duracin esttica. Se crean antes de que el programa inicie su ejecucin y se destruyen cuando el
programa termina. Las variables locales no static tienen duracin automtica. Se crean al entrar al bloque en el que fueron
declaradas y se destruyen al salir de ese bloque. Duracin asignada se reere a los objetos cuya memoria se reserva de
forma dinmica. Como se explic anteriormente, esta memoria se crea y se debe liberar de forma explcita. Los arreglos
de longitud variable de C99 son un caso especial. Tienen duracin automtica, con la particularidad de que son creados
a partir de su declaracin.
La biblioteca estndar de C proporciona las funciones malloc, calloc, realloc y free para el manejo de memoria dinmica.
Estas funciones estn denidas en el archivo de cabecera stdlib.h.

29.4.1

malloc

La funcin malloc reserva un bloque de memoria y devuelve un puntero void al inicio de la misma. Tiene la siguiente
denicin:
void *malloc(size_t size);
donde el parmetro size especica el nmero de bytes a reservar. En caso de que no se pueda realizar la asignacin,
devuelve el valor nulo (denido en la macro NULL), lo que permite saber si hubo errores en la asignacin de memoria.
Ej:
int *puntero; char *puntcarc; puntero=(int *)malloc(4); puntcarc=(char *)malloc(200);
A continuacin se muestra un ejemplo de su uso:
int *i; /* Reservamos la memoria suciente para almacenar un int y asignamos su direccin a i */ i = malloc(sizeof(int));
/* Vericamos que la asignacin se haya realizado correctamente */ if (i == NULL) { /* Error al intentar reservar memoria */ }
Uno de los usos ms comunes de la memoria dinmica es la creacin de vectores cuyo nmero de elementos se dene en
tiempo de ejecucin:
int *vect1, n; printf(Nmero de elementos del vector: "); scanf("%d, &n); /* reservar memoria para almacenar n enteros */ vect1 = malloc(n * sizeof(int)); /* Vericamos que la asignacin se haya realizado correctamente */ if (vect1 ==
NULL) { /* Error al intentar reservar memoria */ }

64

29.4.2

CAPTULO 29. PROGRAMACIN EN C/MANEJO DINMICO DE MEMORIA

calloc

La funcin calloc funciona de modo similar a malloc, pero adems de reservar memoria, inicializa a 0 la memoria reservada. Se usa comnmente para arreglos y matrices. Est denida de esta forma:
void *calloc(size_t nmemb, size_t size);
El parmetro nmemb indica el nmero de elementos a reservar, y size el tamao de cada elemento. El ejemplo anterior
se podra reescribir con calloc de esta forma:
int *vect1, n; printf(Nmero de elementos del vector: "); scanf("%d, &n); /* Reservar memoria para almacenar n enteros */ vect1 = calloc(n, sizeof(int)); /* Vericamos que la asignacin se haya realizado correctamente */ if (vect1 ==
NULL) { /* Error al intentar reservar memoria */ }

29.4.3

realloc

La funcin realloc redimensiona el espacio asignado de forma dinmica anteriormente a un puntero. Tiene la siguiente
denicin:
void *realloc(void *ptr, size_t size);
Donde ptr es el puntero a redimensionar, y size el nuevo tamao, en bytes, que tendr. Si el puntero que se le pasa tiene
el valor nulo, esta funcin acta como malloc. Si la reasignacin no se pudo hacer con xito, devuelve un puntero nulo,
dejando intacto el puntero que se pasa por parmetro. Al usar realloc, se debera usar un puntero temporal. De lo contrario,
podramos tener una fuga de memoria, si es que ocurriera un error en realloc.
Ejemplo de realloc usando puntero temporal:
/* Reservamos 5 bytes */ void *ptr = malloc(5); /* Redimensionamos el puntero (a 10 bytes) y lo asignamos a un
puntero temporal */ void *tmp_ptr = realloc(ptr, 10); if (tmp_ptr == NULL) { /* Error: tomar medidas necesarias */ }
else { /* Reasignacin exitosa. Asignar memoria a ptr */ ptr = tmp_ptr; }
Cuando se redimensiona la memoria con realloc, si el nuevo tamao (parmetro size) es mayor que el anterior, se conservan
todos los valores originales, quedando los bytes restantes sin inicializar. Si el nuevo tamao es menor, se conservan los
valores de los primeros size bytes. Los restantes tambin se dejan intactos, pero no son parte del bloque regresado por la
funcin.

29.4.4

free

La funcin free sirve para liberar memoria que se asign dinmicamente. Si el puntero es nulo, free no hace nada. Tiene
la siguiente denicin:
void free(void *ptr);
El parmetro ptr es el puntero a la memoria que se desea liberar:
int *i; i = malloc(sizeof(int)); free(i);
Una vez liberada la memoria, si se quiere volver a utilizar el puntero, primero se debe reservar nueva memoria con malloc
o calloc:
int *i = malloc(sizeof(int)); free(i); /* Reutilizamos i, ahora para reservar memoria para dos enteros */ i = malloc(2 *
sizeof(int)); /* Volvemos a liberar la memoria cuando ya no la necesitamos */ free(i);

29.5. BUENAS PRCTICAS

65

29.5 Buenas prcticas


Como se vio en las secciones anteriores, siempre que se reserve memoria de forma dinmica con malloc, realloc o calloc,
se debe vericar que no haya habido errores (vericando que el puntero no sea NULL). Cuando se trata de vericar el
valor de un puntero (y slo en ese caso), se puede usar de forma indistinta 0 NULL. Usar uno u otro es cuestin de
estilo. Como ya se vio, las funciones de asignacin dinmica de memoria devuelven un puntero void. Las reglas de C
establecen que un puntero void se puede convertir automticamente a un puntero de cualquier otro tipo, por lo que no es
necesario hacer una conversin (cast), como en el siguiente ejemplo:
/* El puntero void devuelto por malloc es convertido explcitamente a puntero int */ int *i = (int *)malloc(sizeof(int));
Aunque no hay un consenso, muchos programadores preeren omitir la conversin anterior porque la consideran menos
segura. Si accidentalmente se olvida incluir el archivo stdlib.h (donde estn denidas malloc, calloc, realloc y free) en un
programa que use dichas funciones, el comportamiento puede quedar indenido. Si omitimos la conversin explcita, el
compilador lanzar una advertencia. Si, en cambio, realizamos la conversin, el compilador generar el cdigo objeto de
forma normal, ocultado el bug.
Una posible razn para usar la conversin explcita es si se escribe cdigo en C que se vaya a compilar junto con cdigo
C++, ya que en C++ s es necesario realizar esa conversin.
En cualquier caso, dado que el manejo de memoria es un tema complejo, y ste es un error muy comn, se debe hacer
nfasis en que cuando se trabaja con memoria dinmica, siempre se debe vericar que se incluya el archivo stdlib.h.
Tratar de utilizar un puntero cuyo bloque de memoria ha sido liberado con free puede ser sumamente peligroso. El
comportamiento del programa queda indenido: puede terminar de forma inesperada, sobrescribir otros datos y provocar
problemas de seguridad. Liberar un puntero que ya ha sido liberado tambin es fuente de errores.
Para evitar estos problemas, se recomienda que despus de liberar un puntero siempre se establezca su valor a NULL.
int *i; i = malloc(sizeof(int)); free(i); i = NULL;

Captulo 30

Programacin en C/Matrices Dinamicas


Esta seccin es mas como un tema mas de asignacin dinmica de memoria, pero por motivos pedaggicos he decidido
dividirlo.

66

Captulo 31

Concepto
Dejando afuera el uso de matrices en C99, en donde uno puede declarar los valores luego de una lectura. Podemos decir
que solo hemos usado matrices estticas, ya que no permitan el cambio de dimensiones una vez que el programa fuese
compilado.
Con la asignacin dinmica de memoria un puede denir en tipo de ejecucin la cantidad de memoria, con las ventajas y
desventajas que esta posee.
Solo para demostrar rapidamente el potencial y el por que usarlo, vean lo siguiente:
Anteriormente si uno deseaba leer una cadena de caracteres, declaraba un array, supongamos que deseamos leer un
nombre, pero, no todos se llaman igual es por esto que debiamos darle suciente espacio al arreglo.
char nombre[100];
Pero si escribimos: Gustavo Chavarria. Solo necesitamos unos 20 caracteres (20 bytes), es decir desperdiciamos 80
bytes en memoria. Imaginate sucediendo esto en un programa muy grande...
Ejemplo:
//Hecho por: Gustavo Chavarria. //UNAN-LEON - Nicaragua. #include <stdio.h> #include <stdlib.h> int main() { int
*puntero=NULL; puntero = (int *)malloc(100*sizeof(int)); //Asignacion dinamica de memoria if (puntero == NULL)
//evaluacion de condicion. { printf(NO hay suciente espacio en memoria); //Mensaje return 1; //Cierra el programa con un error. }else printf(Se asigno memoria "); free(puntero);//liberacion de memoria return 0; } //El programa
solo asigna memoria, imprime un mensaje en dependecia de la condicion y libera //Revisado por: Gustavo Chavarria.
//UNAN-LEON - Nicaragua.

67

Captulo 32

Matrices Dinamicas de Dos Dimensiones


En esta parte aprenderemos como usar la asignacion dinamica en matrices bidimensionales. Este proceso se divide en dos
partes:
Asignar memoria a una matriz de punteros, cuyos elementos referenciaran cada una de las las de la matriz de dos
dimensiones que se desea crear.
Asignar memoria para cada una de las las. El numero de elementos de cada la puede ser variable.
Una vista rapida seria:
#dene FILAS 5 #dene COLS 6 ... int **matriz; matriz = (int **)malloc (FILAS*sizeof(int *)); for (i=0;i<FILAS;i++)
matriz[i] = (int *) malloc (COLS*sizeof(int));
Segun el codigo anterior podemos decir que cada la puede tener una cantidad de columnas de diferentes tamaos. El
uso del for, es para poder acceder a cada la (matriz[i]) asignandole memoria.

68

Captulo 33

Programacin en C/Algoritmos y
Estructuras de Datos

69

Captulo 34

Concepto
Uno de los procedimientos ms comunes y tiles en el procesamiento de datos, es la ordenacin de los mismos. Se considera ordenar al proceso de reorganizar un conjunto dado de objetos en una secuencia determinada (patrn de arreglo).
El objetivo de este proceso generalmente es facilitar la bsqueda de uno o ms elementos pertenecientes a un conjunto.
Como ejemplos de conjunto de datos ordenados tenemos:
Meses del ao (ordenados de 1 al 12).
Listado de estudiantes (ordenados alfabeticamente).
Guias Telefonicas (ordenadas por Pais/por region/por sector/por orden alfabetico)
La ordenacion, tanto numerica como alfanumerica, sigue las mismas reglas que empleamos nosotros en la vida normal.
Esto es, un dato numerico es mayor que otro cuando su valor es mas grande, y una cadena de caracteres es mayor que
otra cuando esta despues por orden alfabetico.
Los metodos de ordenacion, pueden agruparse en dos grandes grupos:
Los internos: Es cuando los datos estan disponibles de una area de la memoria principal, como cuando se leen un
conjunto de datos desde el teclado.
Los externos: Los datos estan guardados en un medio externo, como puede ser un chero, una base de datos, etc.
En donde los datos estan alojados en el disco duro u otro medio sico.
En este seccion explicaremos solo tres modos de ordenamiento, los mas usados como son:
Algoritmo de Ordenamiento Burbuja (Buble Sort)
Algoritmo de Ordenamiento Insercion
Algoritmo de Ordenamiento Quick Sort

70

Captulo 35

Metodo de Burbuja (Buble Sort)


El metodo de ordenamiento de burbuja, es un algoritmo que se aplica para poder ordenar una cantidad de datos ya sea de
forma ascendente o descendente.
Es el algoritmo ms facil de implementar, pero a cambio pagamos un alto precio en procesamiento, ya que este metodo
evalua una cantidad los datos muchas veces y en ocasiones innecesariamente (como por ejemplo cuando son iguales).
A estas alturas posiblemente ya tengas conocimiento de sencillos pasos para ordenar datos, como por ejemplo, Determinar
cual es el mayor o menor de dos numeros, pues aplicando este metodo podremos ordenar array, estructuras y cualquier
tipo de dato NO atomico (es decir que se pueda dividir)
Este libro trata de programacin en C, entonces a continuacin nos aplicamos a esto:

35.1 Explicacion
Este metodo necesita de lo siguiente para implementarse:
Un array o estructura que ordenar (>1 elemento).
Dos variables contadoras de ciclos (i,j por ejemplo).
Una variable temporal (para almacenar un dato momentaneamente).
Dos ciclos y un Condicional...
.... //DE MENOR A MAYOR (Ascendente) #dene Nelementos 4 .... int i,j; //Variables contadoras del ciclo. int lista[Nelementos]={6,9,3,1}; //Declaracion e inicializacion de un arreglo de 4 elementos. int temp=0; //Variable temporal.
for (i=1;i<Nelementos;i++) { for (j=0; j <= Nelementos-1 ;j++) { if (lista[j] > lista[j+1])//Condicion mayor-menor {
temp=lista[j]; lista[j]=lista[j+1]; lista[j+1]=temp; } } } //Para cambiar el modo de ordenamiento solo debemos cambiar
la condicion < > '''<big>Explicando un poco lo que dice el codigo tenemos:</big>''' # Iniciamos i a 1, de esta forma
correremos el ciclo solamente 3 veces. Asi evitamos correr ciclos innecesariamente. # El segundo for, se ejecutara 3 veces
por cada primer ciclo. # La condicion nos dice: * Si, el valor de lista 0 es mayor al valor de lista 1, es decir * '''Si, 6 >
9''', pero como la condicion no se cumple, pasamos del ciclo y '''J=1'''. * Si, el valor de lista 1 es mayor al valor de lista
2, es decir * '''Si, 9 > 3''', como es '''verdadera''' hacemos: # Guardamos momentaneamente en la variable temporal el
valor de lista 1, es decir 9. # En la posicion de lista 1, guardamos el valor de lista 2, es decir 3. # En la posicion de lista
2, guardamos el valor de temp, es decir 9 '''Volvemos'' nuevamente '''al ciclo''', ahora '''J=2'''... * Si, el valor de lista 2
es mayor al valor de lista 3, es decir * Si, '''9 > 1''', (recuerda que anteriormente '''movimos'' al 9 a la posicion de 3),
es verdadera => # Guardamos momentaneamente en la variable temporal el valor de lista 2, es decir 9. # En la posicion
de lista 2, guardamos el valor de lista 3, es decir 1. # En la posicion de lista 3, guardamos el valor de temp, es decir 9.
De esta forma el ciclo se repite hasta que todos los datos se hallan movido. Como veras hasta ahora solo hemos estado
71

72

CAPTULO 35. METODO DE BURBUJA (BUBLE SORT)

moviendo el 9. Tu lista se veria asi: * ''Original:'' 6 '''9''' 3 1 :* ''1er Mov:'' 6 3 '''9''' 1 :* ''2do Mov:'' 6 3 1 '''9''' Si bien ya
esta mas ordenada que la original, aun falta bastante, pero recuerda que estbamos en el primer ciclo del primer for (i).
'''Aca te dejo como seran los demas movimientos:''' * ''Segundo Ciclo i:'' :* 3 6 1 9 :* 3 1 6 9 * ''Tercer Ciclo i:'' :* 1 3
6 9 :* YA! En un principio, pensaba no presentarles las variaciones que hay de este algoritmo, pero revisando en varios
libros me percate de que aunque es el mismo algoritmo y funciona de la misma forma (con sus ventajas y desventajas),
Creo que es preferible mostrarselos para evitar confusiones y enredos innecesarios. == Variantes == Buscando en varios
libros e Internet me he encontrado numerosas variantes, y por motivos pedaggicos voy a mostrarlos, ya que considero
que aunque sean el mismo algoritmo, su diferente implementacion puede llevar a confusiones. En lo personal considero
que el algoritmo planteado al principio es el que mejor se expresa (entiende), y es el que recomiendo implementar, pero
hay libros que lo implementan de otra forma, por lo que los que se guan con el, pueden tener confusiones a la hora de
apoyarse con este libro. ==== Variante: 1 Ciclo. ==== Aunque en realidad usa dos ciclos un while y un for, el while hace
la funcin de nuestro primer for. Sin embargo la dems implementaciones son tcnicamente las mismas, solo que en vez
de usar una variable ya preparada (j en nuestro caso), este evala con la variable i. <source lang=c>

Variante: Restar
Esta es una de las mas usuales que he visto en los libros, folletos y otros. Todo es igual, pero cambian las condiciones, de
esta forma se trabaja a la inversa de nuestro algoritmo.

35.2 Ejemplos
El algoritmo burbuja esta preparado para correr con todo tipo de datos NO atomicos, es por esto que no importa si el
arreglo es de tipo char, int, oat, etc. Funcionara con sus respectivas modicaciones.
El siguiente ejemplo ordenara una lista de tamao 6, que esta ordenada. Recuerden como buena practica:
Denir las variables en un solo punto del codigo.
Denir el tamao del array como constante.
Usar la indentacion correspondiente (Tabulaciones).
//Realizado por Master crack cocaino //UNAN-LEON Nicaragua. #include <stdio.h> #dene TAM 6 int main() { int
lista[TAM]={12,10,5,6,1,3}; //Declaracion e Inicializacion de un array int temp=0; //Variable temporal int i,j; //variables
corredoras del ciclo printf(La lista DESORDENADA es: \n); for (i=0;i<TAM;i++) printf("%3d,lista[i]); //impresion
de la lista con espacio de 3 lineas (%3d) for (i=1;i<TAM;i++) { for (j=0;j<TAM-1;j++) { if (lista[j] > lista[j+1]) //condicion { temp = lista[j]; //temp guarda momentaneamente el valor de lista[j] lista[j]=lista[j+1]; //Asigno al la posicion
lista[j], lo que hay en lista[j+1] lista[j+1]=temp; //obtendra un nuevo valor por parte de temp. } } } printf("\nLos valores ORDENADOS de lista son: \n); for(i=0;i<TAM;i++) printf("%3d,lista[i]); return 0; } //Revisado por: Gustavo A.
Chavarria. //UNAN-LEON Nicaragua

Captulo 36

Mtodo de Insercin
Este mtodo se podra decir que es algo superior al mtodo de la burbuja, ya que logra evaluar menos veces la condicin.
Sin embargo aun es un algoritmo muy pobre y que utiliza recursos tcnicamente igual que el algoritmo burbuja.

36.1 Concepto
El algoritmo consiste en ordenar los dos primeros elementos de la matriz, luego se inserta el tercer elemento en la posicin
correcta con respecto a los dos primeros, a continuacin se inserta el cuarto elemento en la posicin correcta con respecto
a los tres primeros elementos ya ordenados y as sucesivamente hasta llegar al ultimo elemento de la matriz.

36.2 Explicacin
36.3 Ejemplos
brbtgn

73

Captulo 37

Mtodo QuickSort
Es el ultimo mtodo del que hablaremos en este libro, es el algoritmo que mas calidad tiene, pudiendo llegar a lo mismo
que el mtodo burbuja e insercin, mas rpido y con uso de menos recursos.

37.1 Concepto
El ordenamiento rpido (quicksort en ingls) es un algoritmo basado en la tcnica de divide y vencers. Esta es probablemente la tcnica ms rpida conocida. Fue desarrollada por Tony Hoare en 1960.
La idea del algoritmo es simple, se basa en la divisin en particiones de la lista a ordenar, por lo que se puede considerar
que aplica la tcnica divide y vencers. El mtodo es, posiblemente, el ms pequeo de cdigo, ms rpido, ms elegante,
ms interesante y eciente de los algoritmos de ordenacin conocidos.

37.2 Explicacin
El mtodo se basa en dividir los n elementos de la lista a ordenar en dos partes o particiones separadas por un elemento: una
particin izquierda, un elemento central denominado pivote o elemento de particin, y una particin derecha. La particin
o divisin se hace de tal forma que todos los elementos de la primera sublista (particin izquierda) son menores que todos
los elementos de la segunda sublista (particin derecha). Las dos sublistas se ordenan entonces independientemente. Para
dividir la lista en particiones (sublistas) se elige uno de los elementos de la lista y se utiliza como pivote o elemento de
particin. Si se elige una lista cualquiera con los elementos en orden aleatorio, se puede seleccionar cualquier elemento
de la lista como pivote, por ejemplo, el primer elemento de la lista. Si la lista tiene algn orden parcial conocido, se puede
tomar otra decisin para el pivote. Idealmente, el pivote se debe elegir de modo que se divida la lista exactamente por la
mitad, de acuerdo al tamao relativo de las claves.
Una vez que el pivote ha sido elegido, se utiliza para ordenar el resto de la lista en dos sublistas: una tiene todas las
claves menores que el pivote y la otra, todos los elementos (claves) mayores que o iguales que el pivote (o al revs). Estas
dos listas parciales se ordenan recursivamente utilizando el mismo algoritmo; es decir, se llama sucesivamente al propio
algoritmo quicksort. La lista nal ordenada se consigue concatenando la primera sublista, el pivote y la segunda lista, en
ese orden, en una nica lista. La primera etapa de quicksort es la divisin o particionado recursivo de la lista hasta que
todas las sublistas constan de slo un elemento. El algoritmo es ste: Recorres la lista simultneamente con i y j: por
la izquierda con i (desde el primer elemento), y por la derecha con j (desde el ltimo elemento). Cuando lista[i] sea
mayor que el elemento de divisin y lista[j] sea menor los intercambias. Repites esto hasta que se crucen los ndices.
El punto en que se cruzan los ndices es la posicin adecuada para colocar el elemento de divisin, porque sabemos
que a un lado los elementos son todos menores y al otro son todos mayores (o habran sido intercambiados). Al nalizar
este procedimiento el elemento de divisin queda en una posicin en que todos los elementos a su izquierda son menores
que l, y los que estn a su derecha son mayores.
74

37.3. EJEMPLOS

37.3 Ejemplos

75

Captulo 38

Programacin en C/El proceso de


compilacin
Normalmente, a la hora de programar no creamos un nico archivo C .c, sino varios de ellos conteniendo diferentes
funciones del programa. Esto nos proporciona varias ventajas: una mejor organizacin del cdigo, una mejor modularidad
y, sobre todo, ms facilidad (y velocidad) a la hora de compilar.
El proceso de compilacin que hemos tratado hasta ahora se divide en realidad en dos etapas, que el compilador nos
esconde en una: compilacin propiamente dicha y enlazado. En la primera etapa, la de compilacin, nuestro cdigo en
C se transforma en cdigo objeto, es decir, cdigo mquina (instrucciones que el ordenador puede ejecutar) en cheros
.o, mientras que en la segunda etapa (enlazado) estos cheros objeto son unidos entre s para formar el chero ejecutable
(normalmente sin extensin en el mundo Unix, o con extensin .com o .exe en el mundo MS-DOS/Windows).
De esta manera, si no hemos modicado el chero .c que se compila a un determinado chero .o podemos ahorrarnos esa
parte de la compilacin cuando hagamos un cambio en otra parte del programa.
Adems tenemos los archivos de cabecera .h, que utilizamos para denir parmetros que se utilizan en el cdigo (caso
del fuente1.h del ejemplo) o para denir todas las funciones que vamos a utilizar en todos los archivos .c (caso del
cabeceras.h), ya que si recordamos, las funciones (como todo en C) deben denirse antes de usarse, y es posible que estn
en otro chero, lo cual nunca es considerado por el compilador como antes. Hay que tener en cuenta que el chero en
el que se encuentra la funcin main() llama, necesariamente, a todos los dems cheros .c, directa o indirectamente, ya
que de lo contrario lo que tendramos en esos cheros sera perfectamente intil.
Si tpicamente compilaramos el ejemplo con
$ gcc -o programa fuente1.c fuente2.c fuente3.c
para realizar esta compilacin por pasos, stos seran:
$ gcc -c fuente1.c #crea fuente1.o $ gcc -c fuente2.c #crea fuente2.o $ gcc -c fuente3.c #crea fuente3.o $ gcc -o programa
fuente1.o fuente2.o fuente3.o #crea programa
ya que la opcin -c del compilador lo que le dice es que detenga el proceso antes de enlazar, creando los cheros .o
necesarios.

76

Captulo 39

Los pasos del proceso


Lo primero que le ocurre a un chero .c de cdigo C es el preprocesado. En este paso se sustituyen todas las macros y se
eliminan los comentarios. El resultado, si lo vemos independientemente, es un chero de cdigo C preprocesado, o .i.
El segundo paso es la compilacin propiamente dicha, en el que el cdigo C preprocesado se convierte en cdigo ensamblador, que si lo vemos independientemente es un chero .s.
El tercer paso es el ensamblado del cdigo ensamblador, lo que lo convierte en cdigo mquina. Un chero de cdigo
mquina tambin es llamado chero objeto, y su extensin tpica es .o.
Dado que el camino anterior normalmente convierte un chero en un chero, se suele hacer en un slo paso, de cdigo C
a chero objeto.
El ltimo paso es el enlazado de los cheros objeto en el ejecutable nal.

39.1 Ejemplos
Tomemos el cdigo C ms simple posible:
int main(void) /*Ejemplo*/ { return(0); }
Al preprocesarlo tendremos:
# 1 prueba.c # 1 "<built-in>" # 1 "<command line>" # 1 prueba.c int main(void) { return(0); }
Vemos que el comentario ha desaparecido. En su lugar aparecen comentarios especcos del preprocesador. Al compilarlo
tenemos:
.le prueba.c .text .globl main .type main, @function main: pushl %ebp movl %esp, %ebp subl $8, %esp andl $16,
%esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax subl %eax, %esp movl $0, %eax
leave ret .size main, .-main .ident GCC: (GNU) 4.0.3 20051023 (prerelease) (Debian 4.0.2-3)" .section .note.GNUstack,"",@progbits
Un precioso cdigo ensamblador que enseguida convertimos en un ilegible cdigo mquina:

ELF4( U)GCC: (GNU) 4.0.3 20051023 (prerelease) (Debian 4.0.2-3) .symtab.strtab.shstrtab.text.data.bss.comment.n


stack4#!XX,X95E@ #prueba.cmain
Ese cdigo mquina es el chero .o que normalmente obtenemos directamente del cdigo C. Finalmente, ese cdigo
objeto es enlazado con las libreras necesarias para formar un ejecutable:
uUttPTRhhQVhhUSQ[t X[U=t+n_used__libc_start_mainGLIBC_2.0$ii
hU)UWVS [ )Eu [^_]&1G;}r [^_]'UWVS
[ )EHt41G9}uD [^_]USRtCuX[]USP[VX[$
Hp \ Y o$ooGCC: (GNU) 4.0.2 (Debian 4.0.2-2)GCC: (GNU) 4.0.2 (Debian 4.0.2-2)GCC: (GNU)
77

78

CAPTULO 39. LOS PASOS DEL PROCESO

4.0.3 20051023 (prerelease) (Debian 4.0.2-3)GCC: (GNU) 4.0.3 20051023 (prerelease) (Debian 4.0.2-3)GCC: (GNU)
4.0.2 (Debian 4.0.2-2)GCC: (GNU) 4.0.3 20051023 (prerelease) (Debian 4.0.2-3)GCC: (GNU) 4.0.2 (Debian 4.0.22)",\ $$q!y_IO_stdin_used../sysdeps/i386/elf/start.S/ space/debian/glibc/build-area/glibc-2.3.5/ build-tree/glibc2.3.5/csuGNU AS 2.16.1XF}xgMint\}nOV|/space/debian/glibc/build-area/glibc-2.3.5/ build-tree/i386-libc/csu/crti.S/space/debian/g
area/glibc-2.3.5/build-tree/glibc-2.3.5/ csuGNU AS 2.16.1f(/space/debian/glibc/build-area/glibc-2.3.5/ build-tree/i386libc/csu/crtn.S/space/debian/glibc/build-area/ glibc-2.3.5/build-tree/glibc-2.3.5/csuGNU AS 2.16.1% $ > $ > 4: ; I? T/
../sysdeps/i386/elfstart.S01:"VWYX init.c^ /space/debian/glibc/build-area/glibc-2.3.5/build-tree/i386-libc/csucrti.S3,W\#,:
,Wdd,,W^ /space/debian/glibc/build-area/glibc-2.3.5/build-tree/i386-libc/csucrtn.Sq /space/debian/glibc /build-area/glibc2.3.5/build-tree/glibc-2.3.5/csuinit.cshort intlong long intunsigned charlong long unsigned intshort unsigned int_IO_stdin_usedGNU
C 4.0.2 (Debian 4.0.2-2) .symtab.strtab.shstrtab.interp.note.ABI-tag.hash.dynsym.dynstr.gnu.version. gnu.version_r.rel.dyn.rel.plt.init.text.
frame.ctors.dtors.jcr.dynamic.got.got.plt.data.bss.comment. debug_aranges.debug_pubnames.debug_ info.debug_abbrev.debug_line.debug_
1HH(7 ppP?YGo To$$ c lD LL u\\ptt0{ 7p%} v 0: '|`!5 (Hp$L
\ t -: f@ r` #*7X G\ M Tc dph#
call_gmon_start__CTOR_LIST____DTOR_LIST____JCR_LIST__ completed.4463p.4462__do_global_dtors_auxframe_dummy__CTO
END____DTOR_END____FRAME_END____JCR_END____do_global_ctors_aux_DYNAMIC__ ni_array_end__ni_array_start__in
end_GLOBAL_OFFSET_TABLE___init_array_start_fp_hw__dso_handle__libc_csu_ni_init_start__libc_csu_init__bss_startmain
__libc_start_main@@GLIBC_2.0data_start_ni_edata_end_IO_stdin_used__data_start_Jv_RegisterClasses__gmon_start__

Captulo 40

Programacin en C/Los errores


Esta seccin no est lista si tienes algn conocimiento sobre este tema por favor, regstrate y contribuye con nuestro libro.
Esta seccin est aqui para los sermones y para dar un par de ideas de como resolver los errores.
Qu tipo de errores se podran presentar ?
error de sintaxis: cuando el programador escribe algo mal. Usualmente el compilador no va a poder hacer su trabajo
por lo que nos va a advertir que hay algo equivocado.
error en runtime: cuando esta todo bien escrito pero el programa se comporta de forma incorrecta (viola los espacios
de memoria, trata de abrir un archivo que no existe, hace divisiones entre 0, ...). Normalmente es el sistema operativo
que nos advierte de estos errores.
error de logica: cuando el programa a pesar de estar bien escrito y comportarse bien no cumple con el objetivo
para el que fue hecho. (deba hacer divisiones y esta haciendo multiplicaciones). Ni el compilador, Ni el sistema
operativo nos van a advertir de estos errores, nos vamos a dar cuenta del error por resultados equivocados.
... etc
Cmo se resuelve cada tipo ?
Cuales son las practicas que se deben seguir para evitar los errores (tambien podria ser por tipo)?

40.1 Chequeos del C


Cual es la dinamica de c con los errores (por ejemplo me falta un ";" y el compilador muestra 7 errores diferentes)?
Que errores puede ver el compilador de C y cuales no?
El compilador de C, solamente puede ver los errores sintcticos del propio lenguaje y aquellos en los que se referencia mal
una posicion de memoria, no se inicializan variables, etc. Los errores que tenemos que tener cuidado de no cometer los
programadores son aquellos en los que aunque el compilador no de errores, hayamos creado un programa que en tiempo
de ejecucion s tenga errores o que simplemente no haga lo que queramos que hiciera.

79

Captulo 41

Programacin en C/Herramientas externas


tiles
41.1 Sistemas de construccin de cdigo

80

Captulo 42

make
make es un programa para la construccin de cdigo. Su funcin principal es evitarnos recompilar archivos innecesariamente. Se basa en reglas de dependencia, que especican qu cheros dependen de cuales, y rdenes de construccin.
Para ver un ejemplo sencillo. En la seccin anterior vimos un programa que dependa de tres cheros objeto, los cuales
dependan a su vez de cheros fuente y cheros de cabecera. As, slo ser necesario enlazar de nuevo el programa cuando
cambie alguno de los cheros objeto. Esto lo podemos expresar, con dependencias, de esta manera:
programa: fuente1.o fuente2.o fuente3.o
Igualmente, los cheros objeto dependen de los cheros fuente y los cheros de cabecera de una manera que podemos
expresar como:
fuente1.o: fuente1.c fuente1.h cabecera.h
fuente2.o: fuente2.c cabecera.h
fuente3.o: fuente3.c cabecera.h
De esta manera, si hacemos un cambio en fuente2.c, la regla para fuente2.o lo detectar y recompilar fuente2.o, y a
continuacin la regla para programa detectar el cambio en fuente2.o y reenlazar programa.
Para ello, make necesita saber tambin cmo reconstruir sus objetivos. Estas rdenes (que, ojo, van siempre precedidas
de un tabulador, no de espacios) son las mismas que usaramos a mano y que vimos en el captulo anterior:
programa: fuente1.o fuente2.o fuente3.o
gcc -o programa fuente1.o fuente2.o fuente3.o
fuente1.o: fuente1.c fuente1.h cabecera.h
gcc -c -o fuente1.o fuente1.c
fuente2.o: fuente2.c cabecera.h
gcc -c -o fuente2.o fuente2.c
fuente3.o: fuente3.c cabecera.h
gcc -c -o fuente3.o fuente3.c
Todas estas rdenes van en chero, el chero de make, cuyo nombre suele ser makele. Utilizando la versin de GNU de
make es ms normal llamarlo Makele, ya que aunque el programa buscar primero si existe el nombre con minscula,
el capitalizado aparecer ms arriba al listar un directorio.
Una vez escrito el Makele, para construir nuestro programa basta con ejecutar make:
$ make gcc -c -o fuente1.o fuente1.c gcc -c -o fuente2.o fuente2.c gcc -c -o fuente3.o fuente3.c gcc -o programa fuente1.o
fuente2.o fuente3.o
Esto se debe a que, si no especicamos un objetivo para make, el programa tomar como objetivo por defecto el de la

81

82

CAPTULO 42. MAKE

primera regla que hayamos escrito en el Makele.


Si tenindolo todo ya compilado ejecutamos make de nuevo veremos:
$ make make: `programa' est actualizado.
Y si ahora hacemos un cambio en fuente2.c, al ejecutar make una vez ms tendremos:
$ make gcc -c -o fuente2.o fuente2.c gcc -o programa fuente1.o fuente2.o fuente3.o
De esta manera, el programa nos ahorra recompilar o reenlazar los cheros cuyas dependencias no hayan cambiado. Para
ello, make se ja en la fecha y hora de la ltima actualizacin de cada chero. Si sta es posterior a la de todas sus
dependencias, make no reconstruir el objetivo. Si, en cambio, alguna de las dependencias de un chero es posterior a l,
el programa ejecutar las instrucciones que le hemos dado para reconstruir el objetivo.
Y como en todo lo que hemos visto hasta ahora, los comentarios son muy importantes. En un Makele (o makele) stos
se hacen con el carcter #:
######
# Makele
#
# (c) Envite, 2004
# para el wikilibro Programacin en C (fundamentos)"
# bajo licencia FDL
#####
#Regla para construir el programa
programa: fuente1.o fuente2.o fuente3.o
gcc -o programa fuente1.o fuente2.o fuente3.o
#Reglas para construir los cheros objeto
fuente1.o: fuente1.c fuente1.h cabecera.h
gcc -c -o fuente1.o fuente1.c
fuente2.o: fuente2.c cabecera.h
gcc -c -o fuente2.o fuente2.c
fuente3.o: fuente3.c cabecera.h
gcc -c -o fuente3.o fuente3.c

42.1 Sistemas de control de versiones


CVS

Subversion

Captulo 43

Programacin en C/Ejemplos
43.1 El "Hola Mundo"
#include <stdio.h> int main (int argc,char **argv) { printf(Hola mundo\n); return 0; }
Nota: este programa est tomado del Dominio Pblico
$ ./holamundo Hola Mundo $

43.2 El Hola Mundo comentado


[Contexto]
/* Inclusin de archivos */ #include <stdio.h> /* Funcin principal */ int main (int argc,char **argv) { /* Impresin por
pantalla y salida del programa*/ printf(Hola mundo\n); return 0; }
$ ./holamundoc Hola Mundo $

43.3 El Hola Mundo estructurado en funciones


[Contexto]
/*
holamundo.c
(c) Envite, 2004
para el wikilibro Programacin en C (fundamentos)"
bajo licencia FDL, adaptado del Dominio Pblico
*/
#include <stdio.h> /*Necesario para la funcin printf()*/
void holamundo(void) /*Funcin donde se ejecuta la lgica del programa*/
{
printf(Hola Mundo\n); /*imprime la cadena*/
return; /*sale de la funcin*/
}
int main(void) /*Funcin principal del programa*/
{
holamundo(); /*llamada a la funcin que lleva el peso*/
return(0); /*sale del programa: correcto*/
83

84

CAPTULO 43. PROGRAMACIN EN C/EJEMPLOS

}
$ ./holamundof Hola mundo $

43.4 Ejemplo de clculo con enteros


[Contexto]
/*
ejemplo.c
(c) Envite, 2004
para el wikilibro Programacin en C (fundamentos)"
bajo licencia FDL
*/
#include <stdio.h> /*Necesario para la funcin printf()*/
int main(void) /*Funcin principal del programa*/
{
char resultado; /*Variable de tipo carcter donde se almacenar el resultado de
las operaciones.*/
resultado=5+2; /*Realizamos una suma.*/
printf(Resultado de la suma: %i\n,resultado);
resultado=5-2; /*Realizamos una resta.*/
printf(Resultado de la resta:%i\char"005C\relax{}n,resultado);
resultado=5*2; /*Realizamos una multiplicacin.*/
printf(Resultado de la multiplicacin: %i\n,resultado);
resultado=5/2; /*Realizamos una divisin entera.*/
printf(Resultado de la divisin:%i\n,resultado);
return(0); /*Salimos del programa con el cdigo 0 porque no ha habido errores.*/
}
$ ./ejemploc Resultado de la suma: 7 Resultado de la resta: 3 Resultado de la multiplicacin: 10 Resultado de la divisin:
2$

43.5 Control de acceso


[Volver al ndice general] [Arriba]
[Contexto]
#include <stdio.h>
void acceso(unsigned char edad)
{
if (edad < 18)
printf(No puedes acceder.\n);
else
printf(Bienvenido.\n);
return;
}
int main(void)
{
acceso(18);
acceso(17);
return(0);

43.5. CONTROL DE ACCESO


}
$ ./acceso Bienvenido. No puedes acceder. $
[Volver al ndice general] [Anterior: Salida por pantalla: printf()] [Arriba]
--Envite 01:31 11 dic, 2004 (UTC)

85

Captulo 44

Programacin en C/Glib
44.1 Introduccin
El lenguaje C fue creado como un lenguaje multiplataforma capaz de sustituir al ensamblador y generar cdigo portable.
Sin embargo a lo largo de los aos se empiezan a hacer visibles algunas lagunas del diseo original. Algunos ejemplos que
pueden citarse:
No existe estandarizacin en torno a la longitud real (en bits) de un entero. Un tipo int puede variar entre 16, 32 y
64 bits de longitud en funcin del sistema operativo y compilador utilizado.
No existe un soporte estndar en el lenguaje para programacin orientada a objetos.
No existe un soporte estndar para tipos de estructuras de datos frecuentemente utilizadas como listas enlazadas,
tablas hash (tambin llamadas diccionarios).
No existe un soporte estndar para textos Unicode (el estndar Unicode es posterior a la creacin del C).
No existe un soporte estndar para patrones de diseo frecuentemente utilizados como el bucle principal de eventos.
No existe un API comn para manejar aplicaciones multihilo como puede existir en Java y otros lenguajes/plataformas.
La librera glib se cre con el fn de solucionar estas y otras lagunas originales del lenguaje proporcionando una capa de
compatibilidad real multiplataforma en sistemas tipo UNIX (Linux, Solaris, AIX, BSD, ...), Windows, OS/2 y BeOS.
La librera glib es gratuita y licenciada bajo LGPL (Lesser GPL), lo cual signica en la prctica que puede ser utilizada
tanto en programas de cdigo abierto como cerrado.
glib provee soporte para expresiones regulares tipo PERL, un conjunto de datos tipados ms seguros que el C estndar, soporte multihilo multiplataforma, un sistema de bucle principal de eventos, colas asncronas, carga dinmica de mdulos,
soporte portable para uso de cheros, tuberas y sockets, programacin orientada a objetos, utilidades de todo tipo para
manipular textos, escaneado sintctico, Timers y multitud de estructuras de datos frecuentemente utilizadas slices
de memoria, listas doblemente enlazadas, colas, secuencias (listas escalables), tablas hash para bsqueda mediante llaves
(donde la llave puede ser un texto o un objeto complejo), arrays dinmicos, rboles binarios balanceados, rboles Nrios (rboles con N ramas por nodo), quarks, listas de datos indexadas (accesibles mediante un identicador GQuark,
relaciones y tuplas que pueden ser indexadas mediante un nmero arbitrario de campos, caches para comparticin de
estructuras complejas de datos.
glib provee adems un marco base de utilidades para realizar tests de funcionamiento en tiempo de desarrollo.
glib no provee soporte grco. Frecuentemente suele emparejarse con la librera grca GTK+ ya que la misma utiliza
glib internamente como soporte base. Sin embargo glib puede ser utilizado para aplicaciones embebidas o servidor sin
dependencia alguna del sistema grco.
86

44.2. EJEMPLOS DE USO

87

44.2 Ejemplos de uso


glib se encuentra ampliamente documentado por los propios desarrolladores de la librera y existen tutoriales disponibles
en Internet. Aqu se expondr un ejemplo de cdigo real dnde se utiliza glib para facilitar el desarrollo en C:
Este cdigo se utiliz para monitorizar un sistema Linux donde el disco duro haba sido sustituido por un sistema de
cheros en red. El cdigo se encarga de crear un perro vigia encargado de resetear el sistema en caso de detectar un
fallo en el sistema de cheros NFS (Net File System) del cual depende la mquina para su correcto funcionamiento. El
mismo sirve para comprobar la facilidad con que glib permite crear timers, callbacks invocadas por el bucle principal de
eventos o gestionar acceso de entrada/salida de forma ms ordenada que las libreras estndar de C:
#include <glib.h> /* glib */ GError* err = NULL; gboolean isNFSUpAndRunning() { /* Salvo que se indique lo contrario devuelve KO"(0) * Superados todos los test devolver'a OK (1) */ gboolean result = 0; GIOChannel *gioChan
= g_io_channel_new_le("/NFSFlag, r, &err); /*|*/ /*|*/startBlock1: { /*|*/ if(NULL != err && g_error_matches(err,
G_FILE_ERROR, G_FILE_ERROR_NOENT)) { goto endBlock1; } g_io_channel_set_encoding(gioChan, NULL, NULL);
gsize *len = 0; char* ret; if(G_IO_STATUS_ERROR == g_io_channel_read_to_end(gioChan, &ret, len, &err)) { goto endBlock1; } printf("%s, ret); result = 1; // Todo es correcto. Devolvemos OK /*|*/ /*|*/} endBlock1: { /*|*/
if(NULL != err) { g_error_free(err); err = NULL; } if(NULL != gioChan) g_io_channel_unref(gioChan); /*|*/ /*|*/}
/*|*/ return result; } void hardReset() { // http://en.wikipedia.org/wiki/Magic_SysRq_key GIOChannel *gioChan =
g_io_channel_new_le("/proc/sysrq-trigger, w, &err); gsize bytes_written; g_io_channel_write_chars(gioChan, b,
1, &bytes_written, &err); if (NULL != err) { printf("debug:hardReset Se detect'o un error\n); ush(stdout); } g_io_channel_shutdown
(gioChan, /*bFlush*/ TRUE, &err); } static gboolean callBackCheckNFS(gpointer user_data){ if (! isNFSUpAndRunning() ){ hardReset(); } return TRUE; } static gboolean setTimeOut(GMainContext* ctx) { g_return_if_fail (ctx !=
NULL); // Creamos un objeto timer. source indica que es la fuente de eventos GSource* source = g_timeout_source_new
(60*1000 /*milisecs*/); // Asociamos un callBack a la fuente de eventos (timer). g_source_set_callback (source, callBackCheckNFS, (gpointer) ctx, NULL); // Finalmente asociamos la fuente al contexto (bucle principal de eventos)
g_source_attach (source, ctx /*ctx->g_main_ctx*/); g_source_unref (source); return TRUE; } int main(int argc, char
*argv[]) { // Creamos el objeto bucle principal de eventos. GMainLoop *loop = g_main_loop_new (NULL, FALSE);
/* * Asociamos un Timer al bucle principal. Si falla algo abortamos el programa * pues no tiene sentido continuar en
tal caso. */ if (! setTimeOut(g_main_loop_get_context(loop)) ) { return 1; } // Ejecutamos el bucle principal de eventos.
g_main_run (loop); return 0; }

44.3 Referencias
El Interfaz de Programacin de Aplicaciones (API) puede consultarse (en ingls) en la siguiente URL:
http://library.gnome.org/devel/glib/stable/
El tutorial de la librera grca GTK+ (http://library.gnome.org/devel/gtk-tutorial/stable/) incluye tambin ejemplos de glib y herramientas para compilar y linkar contra estas dos libreras.
El exitoso escritorio para UNIX de cdigo abierto GNOME (GNU Network Model Environment) as como la
plataforma Moblin de Intel, Nokia Maemo, Google Android y Google Chrome, la versin UNIX de Firefox y otros
programas de cdigo abierto como The Gimp, Inkscape o DIA, etc ... hacen un uso extenso de glib. El cdigo
est disponible gratuitamente en la web y puede servir como una gua y referencia para utilizar glib en proyectos
de software complejos con millones de lneas de cdigo y que son utilizados diariamente por millones de personas.

Captulo 45

Programacin en C/Referencia
Esta parte pretende ser una referencia completa de los elementos del lenguaje C. Se pretende que aqu se presenten todos
los datos disponibles de los tipos de datos del lenguaje C, toda la informacin relevante de los operadores del lenguaje C,
las formas en la que se deben usar la principales estructuras e informacin acerca de algunas bibliotecas y funciones que
son estndares. Todo esto con la mayor calidad posible. O sea que en un momento aqu va a existir algo as como una
super sntesis del manual de programacin en C con los datos que son importantes pero que son fciles de olvidar.

45.1 Tipos de datos


char
bytes = 1
Mximo = 127 (255 cuando es unsigned)
Mnimo = 128 (0 cuando es unsigned)
int
bytes = 4
Mximo = 2,147,483,647 (4294967295 cuando es unsigned)
Mnimo = 2,147,483,648 (0 cuando es unsigned)
oat
bytes = 4
Mximo Exponente = 1037
Mnimo Exponente = 1037
long
bytes = 4
Mximo = 2,147,483,647 (4294967295 cuando es unsigned)
88

45.2. OPERADORES

89

Mnimo = 2,147,483,648 (0 cuando es unsigned)


long long
bytes = 8
Mximo = 9,223,372,036,854,775,807 (18,446,744,073,709,551,616 cuando es unsigned)
Mnimo = 9,223,372,036,854,775,808 (0 cuando es unsigned)
short
bytes = 2
Mximo = 32767 (65,535 cuando es unsigned)
Mnimo = 32768 (0 cuando es unsigned)
double
bytes = 8
Mximo Exponente = 10308
Mnimo Exponente = 10308
void -sin tipo-

45.2 Operadores
Todos los operadores estn puestos en el orden en que estn en la jerarqua del lenguaje C. En caso de que estn en una
expresin todos los operadores juntos y de que no se use el operador (), que rompe la precedencia, entonces van a ser
evaluados desde el primero de la tabla hasta el ltimo en ese orden. En caso de que se encuentren varios operadores iguales
o de la misma precedencia en una expresin sin parntesis se van a resolver en el orden en que diga la columna de Orden
de agrupacin. La precedencia es una cosa importante porque nos dice en que orden va a ser resuelta una expresin y el
orden en que se resuelve una expresin inuye en su resultado.
un ejemplito: 1 + 2 / 3 + 4 no es igual a (1 + 2) / (3 + 4) eso porque segn la precedencia: 1 + 2 / 3 + 4 es igual a 1 + (2 /
3) + 4) (2/3 = 0 por ser una operacin entre enteros, 1 + 4 = 5) (en el otro caso 1 + 2 = 3 y 3 + 4 = 7 y 3 / 7 = 0 por ser
una operacin entera)
Como la divisin tiene mayor precedencia que la suma se resuelve primero la divisin.
otro ejemplito: 72 / 3 / 2 / 6 no es igual a (72 / 3) / (2 / 6) eso porque segn la precedencia: 72 / 3 / 2 / 6 es igual a ((72 /
3) / 2) / 6 (La divisin no es una operacin asociativa y por eso cambia el resultado si resolvemos en orden diferente, no
es lo mismo cuando usamos la precedencia del lenguaje C como en la tabla de precedencias, que cuando obligamos a que
se resuelva la operacin en otro orden usando parntesis).
Para los operadores de Incremento (++) y decremento (--) hay que tener en cuenta el sitio en el que se encuentran con
respecto a la variable que estn inuenciando. Con esto me reero a que siendo a una variable ++a no es igual que
a++, aunque en algunas ocasiones parezca lo contrario. Para el caso de ++a el incremento ser realizado antes de
evaluar la expresin. Y para a++ se evaluara primero la expresin completa y luego se realizara el incremento.
En la tabla hay tres operadores que estn identicados con un calicativo para bits. Con esto me reero a que inuenciaran los bits de una variable. Si tengo dos valores a y b el resultado de un a && b ser el valor del AND lgico entre los
valores respectivos pero el a & b tendr como resultado varios ANDs lgicos individuales entre cada uno de los bits de
las dos variables.

90

CAPTULO 45. PROGRAMACIN EN C/REFERENCIA

45.3 Estructuras
Estructura general de un programa de lenguaje C:
inclusin de bibliotecas ... denicin de macros y constantes ... deniciones de funciones o/y prototipos ... deniciones de
variables globales ... int main(argumentos){ sentencias ... return 0; } deniciones de cuerpos de funciones (cuyos prototipos
ya fueron declarados) ...
Estructura general de un header le de lenguaje C:
inclusin de bibliotecas ... denicin de macros y constantes ... deniciones de funciones o/y prototipos ... deniciones de
variables globales ... deniciones de cuerpos de funciones (cuyos prototipos ya fueron declarados) ...
Estructura de un bloque/sentencia:
{ sentencia/s }
En cualquier momento un bloque de sentencias puede sustituir a una sentencia.
Estructura general de una funcin de lenguaje C:
tipo_de_retorno nombre_de_la_funcion (tipo argumento1, tipo argumento2) { variables ... sentencia/s ... return valor_de_retorno;
}
Estructura del if:
if (condicion) sentencia/s else if (condicion) sentencia/s else sentencia/s;
Estructura del switch:
switch (valor) { case valor: sentencias ... break; case valor: sentencias ... break; ... default: sentencias ... }
Estructura del while:
while(condicion) { sentencias ... }
Estructura del do - while:
do { sentencias ... }while(condicion);
Estructura del for:
for (iniciacion; condicion; incremento) { sentencias ... }
Estructura de un struct:
struct { tipo variable; tipo variable; ... }
Estructura de un unin:
union { tipo variable; tipo variable; ... }

45.4 Bibliotecas y funciones


Cuando no se especica un tipo de dato es porque la funcin permite mas de uno ya sea a travs de casting o de otra
maa. Esta parte como ya se explico antes es solo para mostrar el formato de las funciones.
Funciones de <stdio.h>:
int printf(cadena de formato, variable1, variable2); //Muestra por pantalla int scanf(cadena de formato, variable1,
variable2); //Lee de pantalla
Funciones de <stdlib.h>:
int system(llamada);
Funciones de <math.h>:

45.5. PREPROCESADOR DE C

91

double sin(valor); //Calcula el sinus double cos(valor); //Calcula el cosinus double tan(valor); //Calcula la tangente double
asin(valor); double atan(valor); double acos(valor); double sinh(valor); double cosh(valor); double tanh(valor); double
log10(valor); double log(valor); double ldexp(valor1,valor2); double pow(valor); double sqrt(valor); //Calcula races
cuadradas
Funciones de <time.h>:
struct tm time();
Funciones de <string.h>:
int strcmp(cadena1, cadena2); //Compara dos cadenas de carcteres int strcat(cadena1, cadena2); int strcpy(cadena1,
cadena2); //Copia la primera cadena en la segunda int strlen(cadena); //Da la longitud de una cadena
Funciones de <ctype.h>:
Funcin toupper ANSI C Convierte un carcter, en un parmetro entero ch, a mayscula.
Valor de retorno: ch debe estar en el rango 0 a 255, y si est entre a y z lo convierte a su equivalente en el rango A a Z,
el resto de los valores no son modicados. El valor de retorno es el valor convertido si ch era una minscula, o el valor
original en caso contrario. Nota: los caracteres en acentuados, o con diresis, en minscula y la no sufren modicaciones.
Ejemplo:
#include <stdio.h> #include <ctype.h> int main() { char cadena[] = esto es una cadena de prueba"; int i; for(i = 0; cadena[i]; i++) cadena[i] = toupper(cadena[i]); printf("%s\n, cadena); return 0; }

45.5 Preprocesador de C

Captulo 46

Programacin en C/Cmo compilar un


programa
La palabra compilar signica traducir un cdigo de programacin a codigo ejecutable por la mquina. Para compilar un
codigo fuente y convertirlo en ejecutable hay distintas formas dependiendo del compilador que se utilice. Entre estos
compiladores, uno de los ms famosos es GCC (GNU Compiler Collection) el cual trae soporte para diversos lenguajes
(C, C++, Ada, Java, etc). Su fama y buen desempeo van ligados con la gratuidad con la cual se distribuye.
Un ejemplo simple para compilar un programa con gcc:
gcc -o ouput input.c
Lo cual dara como resultado un binario con el nombre ouput. Gcc adems trae varias ags de optimizacin las cuales
permiten sacarle mayor desempeo a los binarios en un tipo de mquina predeterminada.

46.1 Un poco ms sobre compilacin


[Volver al ndice general]
Hasta ahora hemos compilado los programas mediante la orden:
$ gcc [nombre].c $
y los ejecutbamos mediante la orden
$ ./a.out <resultado> $
Ello se debe a que los compiladores de C, en general, y gcc, en particular, crean un ejecutable de nombre a.out en el
directorio actual si no se les especica otra cosa. ./a.out es la manera de ejecutar ese archivo. Pero es en general ms
cmodo nombrar los archivos ejecutables a partir de los archivos fuente de los que vienen. Para ello con gcc utilizamos
el modicador -o [nombre], con lo que las dos compilaciones que hemos visto hasta ahora podran quedar as:
$ gcc -o holamundo holamundo.c $ gcc -o ejemplo ejemplo.c $
y los ejecutaramos correspondientemente:
$ ./holamundo Hola Mundo $ ./ejemplo Resultado de la suma: 7 Resultado de la resta: 3 Resultado de la multiplicacin:
10 Resultado de la divisin: 2 $
[Volver al ndice general] [Anterior: El Hola Mundo"] [Siguiente: Instrucciones de control] [Arriba]
--Envite 01:54 10 dic, 2004 (UTC)

92

Captulo 47

Programacin en C/Cdigo embebido


Esta seccin no est lista si tienes algn conocimiento sobre este tema por favor, regstrate y contribuye con nuestro libro.
Que es cdigo embebido ?
El cdigo embebido es parte de cdigo fuente de otro lenguaje de programacin diferente al lenguaje C, pero que se
incluye en nuestros programas. Por ejemplo: se permite la inclusin de cdigo en lenguaje ensamblador en un programa
escrito en lenguaje C.
Ventajas de utilizar cdigo embebido assembler o python u otros?
Algunas de las ventajas que ofrece es mayor control de rutinas e instrucciones de bajo nivel -en el caso del lenguaje
ensamblador- que de otra manera seria muy difcil de lograr.
Cdigo embebido de assembler en Gcc, otros? Cmo usar ?
Este es un ejemplo de cdigo embedido del lenguaje ensamblador dentro de un programa escrito en lenguaje C:
#include<stdio.h> int main ( int argc, char **argv ) { int modo = 1 ; asm { mov cx, contador mov al, 10 int 10h } printf
( Este texto se presenta en modo de video VGA ) ; return 0 ; }
El ejemplo anterior permite cambiar el modo de video de la pantalla a un modo VGA estandar con codigo ensamblador,
es mucho mas sencillo

93

Captulo 48

Programacin en C/Recursos en la red


48.1 Manuales, tutoriales y otros documentos
48.1.1

Espaol

Aprenda lenguaje ANSI C como si estuviera en Primero


Apuntes de la Escuela Superior de Ingenieros Industriales de la Universidad de Navarra. Muy buenos para
aprender a programar.
Apuntes de Fundamentos de programacin en C
Apuntes y ejercicios resueltos de Fundamentos de programacin en C para Formacin Profesional.
El Rincn del C
Curso de C, foros e informacin relacionada con el C/C++

48.1.2

Ingls

The C Book
Es la versin online del libro The C Book de Mike Banahan, Declan Brady y Mark Doran.

48.2 Compiladores e IDE


Code::Blocks: IDE libre para Windows y Linux que permite el uso de plugin para aadir funcionalidades.
Dev-c++: IDE para C y C++ libre para Windows que usa GCC de fcil manejo.
Eclipse CDT: Framework de Eclipse para programar en C/C++ con soporte para refactorizacin de cdigo.
Anjuta: Entorno avanzado de desarrollo para desarrollo de aplicaciones Glib/GTK en UNIX.
Qt Creator: Realmente se trata de un entorno centrado en la librera QT de C++. Actualmente este entorno es
desarrollado y soportado por Nokia y al igual que Eclipse CDT incluye funciones avanzadas como refactorizacin
automtica de cdigo.
94

48.2. COMPILADORES E IDE


GCC: Compilador ms famoso de GNU/Linux, sumamente potente. Soporta cross-compiling.
NetBeans: IDE desarrollado en Java, entre sus plugins tiene el soporte para c/c++

95

Captulo 49

Programacin en C/Bibliografa
49.1 Bibliografa en espaol
49.2 Bibliografa en ingls
Kernighan, Brian W. y Ritchie, Dennis M.: The C Programming Language (2nd Edition), Prentice Hall, 1988.
Es conocido como Kernighan y Ritchie o como K&R. Este libro es la biblia del lenguaje C.

96

49.3. TEXT AND IMAGE SOURCES, CONTRIBUTORS, AND LICENSES

97

49.3 Text and image sources, contributors, and licenses


49.3.1

Text

Programacin en C Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C?oldid=236462 Colaboradores: Pablo.cl, Javier Carro, ManuelGR, Envite, Almorca, CaStarCo, Marsian, Gargo, H, Morfeomtx, LadyInGrey, Josemanuelmv, Valenluis, Necastro, Rafael.galvez.vizcaino, Magister Mathematicae, Ksaver, Oleinad, AlexGPL, Raulshc, Cvmontuy, MABot, Zerohours, Maxy, Margamanterola,
C1245j7414, CarsracBot, Earizon, Asele, Savh, Jcaraballo, Narutoeshacker15, Igna, Polyglottos, Dessaya, Alan, LlamaAl y Annimos: 56
Programacin en C/Introduccin Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Introducci%C3%B3n?oldid=
243091 Colaboradores: Almorca, Gargo, Tigerfenix, Rafael.galvez.vizcaino, Magister Mathematicae, Maxy, Margamanterola, C1245j7414,
Rocafort8 y Annimos: 9
Programacin en C/Historia de C Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Historia%20de%20C?oldid=
232029 Colaboradores: Javier Carro, ManuelGR, Envite, Almorca, X.Cyclop, Morza, Maxy, Margamanterola, JackPotte, Ortisa, Savh, Anndresorozco, Jcaraballo y Annimos: 15
Programacin en C/Fundamentos de programacin Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Fundamentos%
20de%20programaci%C3%B3n?oldid=205436 Colaboradores: ManuelGR, Envite, Almorca, Anakayama, Gargo, X.Cyclop, Rodrigobgcr, Rafael.galvez.vizcaino, M.estarellas, Maxy, Margamanterola, Polyglottos, Dessaya, LlamaAl y Annimos: 10
Programacin en C/Primer programa en C Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Primer%20programa%
20en%20C?oldid=225736 Colaboradores: ManuelGR, Envite, Almorca, Rutrus, X.Cyclop, Ikks, M.estarellas, Ksaver, Morza, MarcoAurelio,
Luckas Blade, Maxy, Margamanterola, Url999, Dessaya y Annimos: 13
Programacin en C/Tipos de datos Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Tipos%20de%20datos?oldid=
225259 Colaboradores: Javier Carro, ManuelGR, Gargo, Alhen, Rafael.galvez.vizcaino, M.estarellas, MarcoAurelio, Ezarate, Don Quijote,
Wutsje, Juliancolton, Maxy, Margamanterola, Savh, Igna, Dessaya, Hahc21, LlamaAl y Annimos: 46
Programacin en C/Expresiones Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Expresiones?oldid=233315 Colaboradores: Gargo, Baldur, Morza, Maxy, Savh, Dessaya y Annimos: 3
Programacin en C/Interaccin con el usuario Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Interacci%C3%
B3n%20con%20el%20usuario?oldid=199999 Colaboradores: Gargo, M.estarellas, Maxy, Dessaya y Annimos: 8
Programacin en C/Instrucciones de control Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Instrucciones%20de%
20control?oldid=243020 Colaboradores: ManuelGR, Envite, CaStarCo, Gargo, Magister Mathematicae, Luis449bp, Juanias, Zerohours, Maxy,
Margamanterola, Arpia49, Fgrvpro, Savh, TheOrlSan, Dessaya, LlamaAl y Annimos: 59
Programacin en C/Uso de funciones Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Uso%20de%20funciones?
oldid=240471 Colaboradores: Gargo, Muro de Aguas, Morza, MarcoAurelio, Rrmsjp, Luckas Blade, Zerohours, Maxy, Fgrvpro, Dessaya,
Alan, LlamaAl, Matiia y Annimos: 21
Programacin en C/Vectores Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Vectores?oldid=226053 Colaboradores: Gargo, Josemanuelmv, Magister Mathematicae, Gallaecio, Kved, Maxy, Nahuel9000 y Annimos: 10
Programacin en C/Cadenas de caracteres Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Cadenas%20de%20caracteres?
oldid=234616 Colaboradores: Maxy y Annimos: 1
Programacin en C/Manejo de archivos Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Manejo%20de%20archivos?
oldid=234069 Colaboradores: ManuelGR, Gargo, Exe, Jpag87a, Oleinad, Morza, Ezarate, Malonph, Unopresente, Zerohours, Irtusb, Mchingotto, Savh, Ruy Pugliesi, Juanhauara, LlamaAl, Godric y Annimos: 59
Programacin en C/Estructuras y Uniones Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Estructuras%20y%
20Uniones?oldid=232785 Colaboradores: Gargo, Taichi, Zerohours, Savh, LlamaAl y Annimos: 16
Programacin en C/Punteros Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Punteros?oldid=239936 Colaboradores: Jcongote, Morza, Luckas Blade, Ezarate, Jcaraballo, Frigotoni, Narutoeshacker15, Igna, Ralgisbot, Alan y Annimos: 36
Programacin en C/Manejo dinmico de memoria Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Manejo%
20din%C3%A1mico%20de%20memoria?oldid=237400 Colaboradores: CaStarCo, Gargo, Morza, Url999, Narutoeshacker15, Igna, Simeondahl, Alan, LlamaAl y Annimos: 16
Programacin en C/Matrices Dinamicas Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Matrices%20Dinamicas?
oldid=191878 Colaboradores: Narutoeshacker15
Programacin en C/Algoritmos y Estructuras de Datos Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Algoritmos%
20y%20Estructuras%20de%20Datos?oldid=237932 Colaboradores: Morza, Rrmsjp, Savh, Narutoeshacker15, Igna y Annimos: 11
Programacin en C/El proceso de compilacin Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/El%20proceso%
20de%20compilaci%C3%B3n?oldid=142589 Colaboradores: Envite y Annimos: 2
Programacin en C/Los errores Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Los%20errores?oldid=236764
Colaboradores: Gargo y Annimos: 4
Programacin en C/Herramientas externas tiles Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Herramientas%
20externas%20%C3%BAtiles?oldid=164446 Colaboradores: ManuelGR, Envite, Jespa y Annimos: 5
Programacin en C/Ejemplos Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Ejemplos?oldid=235095 Colaboradores: ManuelGR, Envite, Drinibot, Margamanterola, Savh, Ajraddatz, Igna, Ixfd64 y Annimos: 11

98

CAPTULO 49. PROGRAMACIN EN C/BIBLIOGRAFA

Programacin en C/Glib Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Glib?oldid=183036 Colaboradores: Earizon, Invadibot y Annimos: 1


Programacin en C/Referencia Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Referencia?oldid=175770 Colaboradores: ManuelGR, Almorca, Gargo, Fires, Wutsje, Drinibot y Annimos: 14
Programacin en C/Cmo compilar un programa Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/C%C3%B3mo%
20compilar%20un%20programa?oldid=171307 Colaboradores: ManuelGR, Gargo, Magister Mathematicae, Drinibot y Annimos: 2
Programacin en C/Cdigo embebido Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/C%C3%B3digo%20embebido?
oldid=146562 Colaboradores: Gargo, Vinikike, ONDIUX y Annimos: 2
Programacin en C/Recursos en la red Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Recursos%20en%20la%
20red?oldid=148592 Colaboradores: Almorca, Earizon, Lyonn y Annimos: 4
Programacin en C/Bibliografa Fuente: http://es.wikibooks.org/wiki/Programaci%C3%B3n%20en%20C/Bibliograf%C3%ADa?oldid=35363
Colaboradores: Almorca

49.3.2

Images

Archivo:100%.svg Fuente: http://upload.wikimedia.org/wikipedia/commons/c/c7/100_percents.svg Licencia: CC0 Colaboradores: File:100%


.svg Artista original: Siebrand

49.3.3

Content license

Creative Commons Attribution-Share Alike 3.0