Está en la página 1de 153

AULA POLITCNICA / ETSETB

Marco A. Pea Basurto Jos M. Cela Espn

Introduccin a la programacin en C

EDICIONS UPC

Primera edicin: septiembre de 2000

Diseo de la cubierta: Manuel Andreu

Los autores, 2000 Edicions UPC, 2000 Edicions de la Universitat Politcnica de Catalunya, SL Jordi Girona Salgado 31, 08034 Barcelona Tel.: 934 016 883 Fax: 934 015 885 Edicions Virtuals: www.edicionsupc.es E-mail: edicions-upc@upc.es

Produccin:

CPET (Centre de Publicacions del Campus Nord) La Cup. Gran Capit s/n, 08034 Barcelona

Depsito legal: B-32.449-2000 ISBN: 84-8301-429-7


Quedan rigurosamente prohibidas, sin la autorizacin escrita de los titulares del copyright, bajo las sanciones establecidas en las leyes, la reproduccin total o parcial de esta obra por cualquier medio o procedimiento, comprendidos la reprografa y el tratamiento informtico, y la distribucin de ejemplares de ella mediante alquiler o prstamo pblicos.

Introducci on a la programaci on en C
Marco A. Pe na Jos e M. Cela Departament dArquitectura de Computadors Universitat Polit` ecnica de Catalunya 08034 Barcelona, Espa na marcoa@ac.upc.es cela@ac.upc.es 19 de junio de 2000

Indice General

Indice General
Indice de Figuras Indice de Tablas Prefacio 1 Conceptos b asicos de programaci on 1.1 Ordenador y perif ericos . . . . . 1.2 Bits, bytes y palabras . . . . . . 1.3 Lenguajes de programaci on . . . 1.3.1 Lenguajes de bajo nivel . 1.3.2 Lenguajes de alto nivel . 1.4 Elaboraci on de un programa . . 1.5 Traductores . . . . . . . . . . . 1.5.1 Ensambladores . . . . . 1.5.2 Int erpretes . . . . . . . 1.5.3 Compiladores . . . . . . 2 Primer contacto con C 2.1 Un poco de historia . . . . . . 2.2 Caracter sticas del lenguaje . . 2.3 Creaci on de un programa . . . 2.4 Primeros pasos con C . . . . . 2.5 El modelo de compilaci on de C v vii ix 1 1 2 2 3 3 4 5 5 5 6 7 7 7 8 9 10 13 13 13 14 14 15 16 17 17 17

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

3 Empezando a programar 3.1 Identicadores . . . . . . . . . . . 3.2 Estructura de un programa . . . . 3.3 Variables y constantes . . . . . . . 3.3.1 Variables . . . . . . . . . 3.3.2 Constantes . . . . . . . . 3.3.3 Entrada y salida de valores 3.4 Expresiones . . . . . . . . . . . . 3.4.1 Operador de asignaci on . . 3.4.2 Operadores aritm eticos . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

Los autores, 2000; Edicions UPC, 2000.

Indice General

ii

3.5

3.4.3 Operadores relacionales 3.4.4 Operadores l ogicos . . . 3.4.5 Prioridad de operadores Ejercicios . . . . . . . . . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

18 19 19 20 23 23 25 26 27 28 31 33 33 35 36 38 38 38 39 41 41 42 43 44 44 45 45 46 47 49 49 50 50 52 53 54 54 55 55 56 57

4 Construcciones condicionales 4.1 Construcci on if . . . . . . . . 4.1.1 Variante if-else . . 4.1.2 Variante if-else-if 4.2 El operador condicional ? . . . 4.3 Construcci on switch . . . . . 4.4 Ejercicios . . . . . . . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

5 Construcciones iterativas 5.1 Construcci on while . . . . . . . . . 5.2 Construcci on do-while . . . . . . 5.3 Construcci on for . . . . . . . . . . 5.3.1 El operador coma (,) . . . . . 5.3.2 Equivalencia for-while . . 5.4 Las sentencias break y continue 5.5 Ejercicios . . . . . . . . . . . . . . . 6 Tipos de datos elementales 6.1 N umeros enteros . . . . . . . 6.1.1 Modicadores . . . . 6.1.2 Resumen . . . . . . . 6.2 Caracteres . . . . . . . . . . . 6.2.1 Caracteres especiales . 6.2.2 Enteros y el tipo char 6.2.3 Conversiones de tipos 6.3 N umeros reales . . . . . . . . 6.4 Ejercicios . . . . . . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

7 Tipos de datos estructurados: Tablas 7.1 Vectores . . . . . . . . . . . . . . 7.1.1 Consulta . . . . . . . . . 7.1.2 Asignaci on . . . . . . . . 7.1.3 Ejemplos . . . . . . . . . 7.2 Matrices . . . . . . . . . . . . . . 7.2.1 Consulta . . . . . . . . . 7.2.2 Asignaci on . . . . . . . . 7.2.3 Ejemplo . . . . . . . . . . 7.3 Tablas multidimensionales . . . . 7.3.1 Ejemplo . . . . . . . . . . 7.4 Cadenas de caracteres . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

Los autores, 2000; Edicions UPC, 2000.

iii

Indice General

7.5

7.4.1 Asignaci on . . . . . . . . . . . 7.4.2 Manejo de cadenas de caracteres 7.4.3 Ejemplos . . . . . . . . . . . . Ejercicios . . . . . . . . . . . . . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

57 59 60 61 63 63 64 65 65 66 66 67 68 69 70 70 71 71 72 75 75 76 76 77 78 79 83 84 87 87 89 89 90 91 91 91 91 92 93 94 94 95

8 Otros tipos de datos 8.1 Estructuras . . . . . . . . . . . . . . . . . . 8.1.1 Declaraci on de variables . . . . . . . 8.1.2 Acceso a los campos . . . . . . . . . 8.1.3 Asignaci on . . . . . . . . . . . . . . 8.1.4 Ejemplo . . . . . . . . . . . . . . . . 8.2 Uniones . . . . . . . . . . . . . . . . . . . . 8.2.1 Ejemplo . . . . . . . . . . . . . . . . 8.3 Tipos de datos enumerados . . . . . . . . . . 8.4 Denici on de nuevos tipos de datos . . . . . 8.5 Tiras de bits . . . . . . . . . . . . . . . . . . 8.5.1 Operador de negaci on . . . . . . . . 8.5.2 Operadores l ogicos . . . . . . . . . . 8.5.3 Operadores de desplazamiento de bits 8.6 Ejercicios . . . . . . . . . . . . . . . . . . . 9 Punteros 9.1 Declaraci on y asignaci on de direcciones 9.1.1 Declaraci on . . . . . . . . . . . 9.1.2 Asignaci on de direcciones . . . 9.2 Indirecci on . . . . . . . . . . . . . . . 9.3 Operaciones con punteros . . . . . . . . 9.4 Punteros y tablas . . . . . . . . . . . . 9.5 Punteros y estructuras . . . . . . . . . . 9.6 Ejercicios . . . . . . . . . . . . . . . .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

10 Funciones 10.1 Generalidades . . . . . . . . . . . . . . . 10.2 Denici on y llamada . . . . . . . . . . . 10.2.1 Denici on . . . . . . . . . . . . . 10.2.2 Prototipos . . . . . . . . . . . . . 10.2.3 Llamada . . . . . . . . . . . . . . 10.3 Variables y par ametros . . . . . . . . . . 10.3.1 Variables locales . . . . . . . . . 10.3.2 Variables globales . . . . . . . . 10.3.3 Par ametros formales . . . . . . . 10.4 Devoluci on de resultados . . . . . . . . . 10.5 Paso de par ametros . . . . . . . . . . . . 10.5.1 Paso de par ametros por valor . . . 10.5.2 Paso de par ametros por referencia

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Los autores, 2000; Edicions UPC, 2000.

Indice General

iv

10.5.3 Las tablas y las funciones . . . 10.5.4 Par ametros en la funci on main 10.6 Recursividad . . . . . . . . . . . . . . 10.7 Ejercicios . . . . . . . . . . . . . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. 96 . 99 . 100 . 101 105 107 109 111 111 113 113 113 116 119 119 119 120 122 123 123 124 124 124 126 127 128 129 129 129 135 135 135 136 138 141 143

11 Ficheros 11.1 Abrir y cerrar cheros . . . . . . . . . . . . . . . . 11.2 Leer y escribir en cheros . . . . . . . . . . . . . . 11.3 Otras funciones para el manejo de cheros . . . . . 11.3.1 feof . . . . . . . . . . . . . . . . . . . . 11.3.2 ferror . . . . . . . . . . . . . . . . . . 11.3.3 fflush . . . . . . . . . . . . . . . . . . 11.4 Ficheros est andar: stdin, stdout, stderr 11.5 Ejercicios . . . . . . . . . . . . . . . . . . . . . . A El preprocesador A.1 Directiva include . . . . . . A.2 Directivas define y undef . A.3 Directivas ifdef y ifndef . A.4 Macros . . . . . . . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

B La librer a est andar B.1 Manipulaci on de cadenas de caracteres . . B.2 Entrada y salida . . . . . . . . . . . . . . B.2.1 Entrada y salida b asica . . . . . . B.2.2 Entrada y salida con formato . . . B.2.3 Ficheros . . . . . . . . . . . . . . B.3 Funciones matem aticas . . . . . . . . . . B.4 Clasicaci on y manipulaci on de caracteres B.5 Conversi on de datos . . . . . . . . . . . . B.6 Manipulaci on de directorios . . . . . . . B.7 Memoria din amica . . . . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

C Sistemas de numeraci on C.1 Naturales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.2 Enteros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.3 Reales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.3.1 Problemas derivados de la representaci on en coma otante D Tabla de caracteres ASCII E Bibliograf a y recursos WEB

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

Los autores, 2000; Edicions UPC, 2000.

Indice de Figuras

Indice de Figuras
1.1 1.2 1.3 1.4 1.5 2.1 4.1 4.2 5.1 5.2 5.3 7.1 7.2 7.3 9.1 Niveles de abstracci on en los lenguajes de programaci on . . . . . Cronolog a en el desarrollo de algunos lenguajes de programaci on Ciclo de vida de un programa . . . . . . . . . . . . . . . . . . . . Fases en la interpretaci on de un programa . . . . . . . . . . . . . Fases en la compilaci on de un programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 3 4 5 6 11 24 29 34 35 36 50 54 56 82 99

Modelo de compilaci on de C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Esquema de funcionamiento de if y de if-else . . . . . . . . . . . . . . . . . . . Esquema de funcionamiento de switch . . . . . . . . . . . . . . . . . . . . . . . . . Esquema de funcionamiento de while . . . . . . . . . . . . . . . . . . . . . . . . . Esquema de funcionamiento de do-while . . . . . . . . . . . . . . . . . . . . . . . Esquema de funcionamiento de for . . . . . . . . . . . . . . . . . . . . . . . . . . . Representaci on gr aca de un vector . . . . . . . . . . . . . . . . . . . . . . . . . . . Representaci on gr aca de una matriz . . . . . . . . . . . . . . . . . . . . . . . . . . . Representaci on gr aca de una tabla de tres dimensiones . . . . . . . . . . . . . . . . . Acceso a una matriz mediante un puntero . . . . . . . . . . . . . . . . . . . . . . . .

10.1 Acceso a una matriz mediante un puntero . . . . . . . . . . . . . . . . . . . . . . . .

11.1 Almacenamiento de un chero de texto . . . . . . . . . . . . . . . . . . . . . . . . . 106

Los autores, 2000; Edicions UPC, 2000.

vii

Indice de Tablas

Indice de Tablas
3.1 3.2 3.3 3.4 3.5 6.1 6.2 6.3 6.4 8.1 C.1 C.2 C.3 C.4 Palabras reservadas de C . . . . . . . . . . . . Operadores aritm eticos en C . . . . . . . . . . Operadores relacionales y l ogicos en C . . . . . Tabla de verdad de los operadores l ogicos en C Prioridad y asociatividad de los operadores en C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 17 19 19 20 42 44 45 46 71 135 136 137 138

Representaci on de enteros en decimal, octal y hexadecimal Resumen de tipos de datos enteros . . . . . . . . . . . . . Caracteres interpretados como enteros . . . . . . . . . . . Resumen de tipos de datos reales . . . . . . . . . . . . . .

Tabla de verdad de los operadores l ogicos . . . . . . . . . . . . . . . . . . . . . . . . Representaci on de n umeros naturales en binario natural Representaci on de n umeros enteros en complemento a 2 Representaci on de n umeros enteros en exceso 2e;1 . . . Representaci on de n umeros reales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

D.1 Caracteres y sus c odigos ASCII . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

Los autores, 2000; Edicions UPC, 2000.

ix

Pr ologo

Pr ologo
Este libro surge a partir de la experiencia docente de los autores en la asignatura Introducci on a los ordenadores de la Escola T` ecnica Superior dEnginyeria de Telecomunicaci o de Barcelona, de la Universitat Polit` ecnica de Catalunya. Como su t tulo indica, se trata de un texto de introduci on a la programaci on en lenguaje C. El libro pretende ce nirse a los aspectos fundamentales del est andar ANSI C actual. Aunque hoy en d a existen otros lenguajes de programaci on muy populares como C++ o JAVA, la comprensi on de estos lenguajes exige un s olido conocimiento de las bases de programaci on en C. El texto est a concebido como un curso completo y por lo tanto debe ser le do de forma secuencial. Al nal de cada cap tulo hay un conjunto de ejercicios propuestos. El lector debe tratar de resolver el mayor n umero posible de estos ejercicos. De igual forma es una buena pr actica el programar los ejemplos resueltos en el texto. El lector debe recordar que la programaci on es una t ecnica aplicada, igual que tocar un instrumento musical, y por lo tanto requiere muchas horas de ensayo para ser dominada. Los ejercicios propuestos son lo sucientemente simples como para no requerir conocimientos adicionales de otras materias (matem aticas, f sica, contabilidad, etc). Uno de los puntos m as importantes para quien empieza a programar es adoptar desde el principio un buen estilo de programaci on. Esto es, escribir las construcciones del lenguaje de una forma clara y consistente. En este sentido, los ejemplos resueltos en el texto muestran un buen estilo b asico de programaci on, por lo que se recomienda al lector imitar dicho estilo cuando realice sus programas. Los ap endices A y B son de lectura obligada antes de comenzar a desarrollar programas de complejidad media. En dichos ap endices el lector se familiarizar a con el uso del preprocesador y de la librer a est andar. Ambas son herramientas fundamentales para desarrollar programas. El ap endice C incluye una descripci on de los formatos de datos en el computador. Este tema no es propiamente de programci on, pero la comprensi on de dichos formatos ayuda al programador a entender mejor conceptos b asicos, como las operaciones de conversi on de tipos. El lector puede leer este ap endice en cualquier momento, aunque recomendamos leerlo antes del cap tulo 6. En las referencias bibliogr acas se indican algunas direcciones web donde el lector podr a encontrar preguntas y respuestas comunes de quienes se inician en el lenguaje C. As mismo, el lector podr a encontrar materiales adicionales sobre programaci on, historia del lenguaje, etc.

Los autores, 2000; Edicions UPC, 2000.

1. Conceptos b asicos de programaci on

Cap tulo 1

Conceptos b asicos de programaci on


1.1 Ordenador y perif ericos
rdenes y operaciones muy b Un ordenador s olo es capaz de ejecutar o asicas, tales como: Aritm etica entera: sumar, restar, multiplicar, etc. Comparar valores num ericos o alfanum ericos Almacenar o recuperar informaci on Con la combinaci on de estas operaciones b asicas, y gracias a su gran potencia de c alculo, el ordenador puede llevar a cabo procesos muy complejos. Sin embargo, en cualquier caso existe una estrecha dependencia del ordenador con el programador. Es el programador quien indica a la m aquina c omo y qu e debe hacer, mediante la l ogica y el razonamiento previo, expresado en forma de un programa. En denitiva, el ordenador s olo es capaz de aceptar datos de entrada, procesarlos y facilitar otros datos o resultados de salida. Los datos se introducen u obtienen del ordenador mediante los perif ericos de entrada y salida. Estos son los encargados de facilitar la relaci on entre el coraz on del ordenador y el mundo exterior, y en particular los usuarios de ordenadores. Dependiendo de su funci on particular, los perif ericos pueden clasicarse en: rdenes al ordenador: tePerif ericos de entrada: cuya funci on es facilitar la introducci on de datos y o ptico, lector de c clado, rat on, l apiz o odigo de barras, esc aner, tableta digitalizadora, etc. Perif ericos de salida: cuya funci on es mostrar al exterior informaci on almacenada en memoria o los resultados de las operaciones realizadas por el ordenador: pantalla, impresora, plotter, etc. Perif ericos de entrada y salida: capaces tanto de introducir como de extraer informaci on del ordena pticos, etc. dor: discos y cintas magn eticos, discos o Perif ericos de comunicaci on: encargados de establecer y facilitar el intercambio de informaci on entre dos ordenadores: m odem, tarjetas de red (Ethernet, Token Ring, RDSI, . . . ), etc.

Los autores, 2000; Edicions UPC, 2000.

1.2. Bits, bytes y palabras

Programador

Lenguaje natural

Lenguaje de programacin

Lenguaje mquina

Ordenador

Figura 1.1: Niveles de abstracci on en los lenguajes de programaci on

1.2 Bits, bytes y palabras


s pequen a en un ordenador se denomina bit (del ingle s binary digit). Puede La unidad de memoria ma n intr nicamente dos posibles valores: 0 o 1. En ocasiones, debido a la relacio nseca con los tomar u ales ele ctricas en circuitos digitales, se dice que un bit esta bajo o alto, o bien descovalores en las sen n en un solo bit. nectado o conectado. Como puede verse, no es posible almacenar mucha informacio Sin embargo, un ordenador posee cantidades ingentes de ellos, por lo que podr a decirse que los bits sicos con los que se construye la memoria del ordenador. son los bloques ba El byte, compuesto por ocho bits (algunos autores se reeren a esta unidad como octeto), es una s u til. Puesto que cada bit puede tomar el valor 0 o 1, en un byte pueden represenunidad de memoria ma odigos binarios). Con estas combinaciones tarse hasta 28 = 256 combinaciones de ceros y unos (256 c pueden representarse, por ejemplo, los enteros entre 0 y 255 (0 : : : 28 ; 1), un conjunto de caracteres, etc. La unidad natural de memoria para un ordenador es la palabra. Los ordenadores de sobremesa o actuales, por ejemplo, suelen trabajar con palabras de 32 o 64 bits. En grandes ordenadores, el taman mero de bits, potencia de 2. En de la palabra puede ser mucho mayor, pero siempre formada por un nu s palabras de memoria con el n de poder almacenar cualquier caso, los ordenadores encadenan dos o ma o. datos complejos y, en general, de mayor taman

n 1.3 Lenguajes de programacio


n podr n o conjunto de s Un lenguaje de programacio a denirse como una notacio mbolos y caracteres que se combinan entre s siguiendo las reglas de una sintaxis predenida, con el n de posibilitar la n de instrucciones a un ordenador. Dichos s transmisio mbolos y caracteres son traducidos internamente ales ele ctricas representadas en sistema binario, es decir, so lo dos valores: 0 y 1. a un conjunto de sen n es necesaria porque el procesador so lo entiende ese lenguaje, al cual nos referiremos Esta traduccio como lenguaje m aquina.

Los autores, 2000; Edicions UPC, 2000.

1. Conceptos b asicos de programaci on

COBOL FORTRAN LISP Ensamblador Algol BASIC PL/I Prolog SIMULA Logo

Forth C Modula-2 Smalltalk C++ Java Ada

Pascal

1950

1955

1960

1965

1970

1975

1980

1985

1990

1995

Figura 1.2: Cronolog a en el desarrollo de algunos lenguajes de programaci on

1.3.1 Lenguajes de bajo nivel


s pro ximos Se incluyen en esta categor a aquellos lenguajes que por sus caracter sticas se encuentran ma a la arquitectura del ordenador, como el lenguaje m aquina y el lenguaje ensamblador. quina Lenguaje ma Cualquier problema que deseemos resolver se plantea en primer lugar en nuestro lenguaje natural. Sin embargo, para que la secuencia de pasos que resuelven el problema pueda ser entendida por un sico denominado lenguaje m ordenador, debe traducirse a un lenguaje muy ba aquina. quina se caracteriza por ser el u nico que es directamente inteligible por el ordenador, El lenguaje ma n de dos u nicos s s cada puesto que se basa en la combinacio mbolos (0 y 1) denominados bits. Adema quina, por lo que un programa escrito en lenguaje ma quina de procesador posee su propio lenguaje ma , en principio, ejecutarse en un procesador Y. un procesador X no podra Lenguaje ensamblador n del lenguaje ma quina. Se basa en la utilizacio n de mnemote cnicos, esto es, Constituye una evolucio abreviaturas de palabras que indican nombres de instrucciones. Para programar en lenguaje ensamblador es necesario conocer en profundidad la estructura y funcionamiento interno del ordenador, as como n, como el binario, hexadecimal, octal, etc. dominar el uso de diferentes sistemas de numeracio En general, los programas escritos en ensamblador requieren mucho menos espacio de memoria y s ra pidamente que si se hubiesen desarrollado en un lenguaje de alto nivel, puesto que se ejecutan ma n optimizados para una arquitectura espec ltimo es un inconveniente, pues esta ca. Sin embargo, esto u causa que los programas no sean portables de un ordenador a otro con un procesador distinto.

1.3.2 Lenguajes de alto nivel


n que por sus caracter s al Se engloban aqu todos los lenguajes de programacio sticas se asemejan ma s conocidos son: FORTRAN, BASIC, Pascal, lenguaje natural del programador. Algunos de los ma Modula, C, Ada, Java, etc. (ver Fig. 1.2). s importante de estos lenguajes es que son independientes de la arquitectura del La caracter stica ma ordenador, por lo que un programa escrito en un lenguaje de alto nivel puede ejecutarse sin problemas

Los autores, 2000; Edicions UPC, 2000.

1.4. Elaboraci on de un programa

Anlisis 11111111 00000000 11111111 00000000

Mantenimiento 11111111111111 00000000000000 11111111111111 00000000000000 Diseo Explotacin 0000000 1111111 11111111111 00000000000 0000000 1111111 1111111111111 11111111111 00000000000 0000000000000 Codificacin 0000000000000 1111111111111 0000000000000 1111111111111
Figura 1.3: Ciclo de vida de un programa

en otros ordenadores con procesadores distintos. Por ello, el programador no necesita conocer a fondo el funcionamiento del ordenador en el que programa, sino que el lenguaje le permite abstraerse de los n de la arquitectura de la ma quina implica que todo programa detalles de bajo nivel. Esta abstraccio traducirse a lenguaje ma quina, de forma que pueda ser escrito en un lenguaje de alto nivel debera disponer de unos entendido y ejecutado por el ordenador. Para ello cada tipo de ordenador debera n (ver Sec. 1.5). programas especiales que realicen dicha traduccio

n de un programa 1.4 Elaboracio


ticamente puede resuEl desarrollo de un programa para solucionar un determinado problema informa puede desglosarse en los siguientes pasos a seguir sico concepto de ciclo de vida. Este mirse en el ya cla lisis, disen o, codicacio n, explotacio n y mantenimiento (ver Fig. 1.3). secuencialmente: ana

lisis Ana
lisis se estudia cua l es el problema a resolver y se especican a muy alto nivel los En la fase de ana procesos y estructuras de datos necesarios, de acuerdo con las necesidades del cliente. Para realizar lisis sera necesario interaccionar con el cliente y conocer a fondo sus necesidades. Antes un buen ana o es muy importante haber comprendido correctamente los requerimientos del de proceder al disen problema.

Diseno
n Una vez bien denido el problema y las l neas generales para solucionarlo, se requiere una solucio ordenador va a funcionar la adecuada a un conjunto de recursos determinado. Tanto f sicos: en que n, de que tipo de perife ricos se dispone . . . , como lo gicos: que sistema operativo se usara , que aplicacio bases de datos . . . Finalmente se disen ara un conjunto de algoritmos herramientas de desarrollo, que que resuelvan los distintos subproblemas en que se haya dividido el desarrollo.

n Codicacio
n de los algoritmos disen ados previamente, utilizando el lenguaje y entorno de Consiste en la traduccio necesario realizar pruebas que garanticen al ma ximo la desarrollo escogidos en la fase anterior. Sera n libres de errores. calidad de los programas desarrollados. Entre otras cosas, que este n generada en esta fase junto con la de las fases anteriores sera muy u til en el La documentacio futuro para las eventuales actuaciones de mantenimiento.

Los autores, 2000; Edicions UPC, 2000.

1. Conceptos b asicos de programaci on

Instruccin 1 Instruccin 2 Instruccin 3 ...

Intrprete Intrprete Intrprete

Ejecucin 1 Ejecucin 2 Ejecucin 3

Figura 1.4: Fases en la interpretaci on de un programa

n Explotacio
Los diferentes programas desarrollados en la fase anterior se instalan en el entorno nal de trabajo. Si n tambie n otras herramientas de utilidad, necesarias para el correcto funcionaes necesario se instalara n, manuales de usuario, formacio n, etc. miento del sistema. Se debe proporcionar documentacio

Mantenimiento
n correcciones al sistema desarrollado, bien para solventar errores no depuraEn esta fase se realizara adir nuevas funcionalidades requeridas por el cliente. Dependiendo de la dos, bien para cambiar o an necesario retomar el ciclo de vida a nivel de codicacio n, disen o o incluso importancia del caso, sera lisis (ver Fig. 1.3). ana Cuanto mejor se haya documentado el desarrollo en las primeras fases del ciclo de vida, menor sera el tiempo necesario para llevar a cabo los distintos tipos de mantenimiento.

1.5 Traductores
nico lenguaje directamente inteligible por el ordenador es el lenguaje Como ya se ha comentado, el u quina. Por ello, si se programa usando lenguajes de alto nivel sera necesario algu n programa traducma el encargado de comprobar que los programas este n escritos correctamente, de tor. Este, a su vez, sera n del lenguaje de programacio n empleado. Pueden distinguirse varios tipos de acuerdo con la denicio traductores:

1.5.1 Ensambladores
quina los programas escritos Los programas ensambladores son los encargados de traducir a lenguaje ma en lenguaje ensamblador. La correspondencia entre ambos lenguajes es muy directa, por lo que los ensambladores suelen ser programas relativamente sencillos.

rpretes 1.5.2 Inte


rprete es procesar una a una las instrucciones de un programa escrito en un lenguaje El objetivo de un inte n se verica la sintaxis, se traduce a co digo ma quina y nalmente se de alto nivel. Para cada instruccio n y la ejecucio n se realizan como una sola operacio n (ver Fig. 1.4). ejecuta. Es decir, que la traduccio

Los autores, 2000; Edicions UPC, 2000.

1.5. Traductores

ERRORES Edicin Compilacin Montaje Fuente Ejecucin Objeto Ejecutable

Figura 1.5: Fases en la compilaci on de un programa rpretes es su lentitud para ejecutar los programas, pues es neceLa principal desventaja de los inte n en cada ejecucio n. sario vericar la sintaxis y realizar la traduccio

1.5.3 Compiladores
n de un compilador consiste en traducir un programa fuente escrito en un lenguaje de alto La funcio digo ma quina (tambie n llamado c nivel a su equivalente en co odigo objeto). rprete traduce y ejecuta al mismo tiempo cada una de las instrucciones, un Mientras que un inte compilador analiza, traduce y posteriormente ejecuta todo el programa en fases completamente separadas (ver Fig. 1.5). As pues, una vez se ha compilado un programa, no es necesario volverlo a compilar n de un programa compilado sea mucho ma s ra pida que la de uno cada vez. Esto hace que la ejecucio interpretado. n El proceso de compilacio n Consiste en escribir el programa fuente usando el lenguaje de programacio n seleccionado y su Edicio n en un chero. Para ello es necesario usar un programa editor, que puede o no formar grabacio parte del entorno de desarrollo. n En esta fase se verica la sintaxis del programa fuente y se traduce el programa a co digo Compilacio quina (objeto). Si se producen errores, el compilador muestra informacio n del tipo de error y ma nde se ha producido. do n de los diferentes mo dulos objeto y librer Montaje Consistente en la combinacio as del lenguaje para n como linkado. crear un programa ejecutable. Esta fase se conoce tambie n En esta fase se invoca al programa de la manera adecuada dependiendo del sistema operativo Ejecucio sobre el que vaya a funcionar. n puede ser tanto interpretado como Como nota nal, cabe decir que todo lenguaje de programacio compilado. Sin embargo, dependiendo del las caracter sticas del lenguaje y del uso mayoritario a que destinado, es normal asociar a cada lenguaje una forma de traduccio n particular. Por ejemplo, el este lenguaje BASIC es mayoritariamente interpretado, mientras que C es compilado.

Los autores, 2000; Edicions UPC, 2000.

2. Primer contacto con C

Cap tulo 2

Primer contacto con C


2.1 Un poco de historia
n C fue desarrollado por Dennis Ritchie en los Laboratorios Bell de la El lenguaje de programacio sito muy concreto: empresa de comunicaciones AT&T, en 1972. C fue creado inicialmente con un propo o del sistema operativo UNIX. Sin embargo, pronto se revelo como un lenguaje muy potente y el disen que su uso se extendiese ra pidamente, incluso fuera de los Laboratorios Bell. exible, lo que provoco De esta forma, programadores de todo el mundo empezaron a usar el lenguaje C para escribir programas de todo tipo. os, el esta ndar de facto del lenguaje C fue el denido en el libro El lenguaje de proDurante an gramaci on C, escrito por Brian Kernighan y Dennis Ritchie en 1978. Sin embargo, con el tiempo proliferaron distintas versiones de C, que con sutiles diferencias entre ellas, empezaron a causar proble n, el Instituto Nacional mas de incompatibilidad a los programadores. Con el n de cambiar esta situacio ndares Americano (ma s conocido como ANSI) creo un comite en 1983 para establecer una dede Esta n esta ndar de C que fuese no ambigua e independiente de la arquitectura interna de cualquier nicio el esta ndar ANSI C. Actualmente, cualquier compilador ordenador. Finalmente, en 1989 se establecio n por moderno soporta ANSI C. Sin embargo, probablemente debido a razones comerciales, la opcio n propia del desarrollador del compilador. Dicha defecto en muchos compiladores de C es una versio ndar ANSI C. version suele ser ligeramente diferente e incompatible con el esta El lenguaje C debe su nombre a su predecesor, el lenguaje B desarrollado por Ken Thompson, n en los Laboratorios Bell. tambie

2.2 Caracter sticas del lenguaje


n de alto nivel entre los que elegir, como Actualmente existe gran variedad de lenguajes de programacio BASIC, Pascal, C, C++, Java, etc. Todos ellos pueden usarse para resolver la mayor a de proyectos de n. Sin embargo, existen algunas razones que hacen de C el preferido de muchos programaprogramacio dores: Potencia y exibilidad. Se ha usado en contextos tan dispares como el desarrollo de sistemas cos, bases de datos, compiladores de otros lenguajes, etc. operativos, procesadores de texto, gra

Los autores, 2000; Edicions UPC, 2000.

2.3. Creaci on de un programa

Popularidad. Existe una gran variedad de compiladores, librer as, herramientas de apoyo a la n, etc. Es el lenguaje predominante en el entorno UNIX. programacio cticamente Portabilidad. El mismo programa escrito en C puede compilarse y ejecutarse sin pra n cambio en diferentes ordenadores. Esto se debe en gran parte al esta ndar ANSI C. ningu cilmente. Sencillez. C utiliza pocas palabras clave, por lo que puede aprenderse fa digo en funcioEstructura y modularidad. Los programas en C pueden escribirse agrupando el co dulos. De esta forma, el co digo puede reutilizarse. nes que a su vez se agrupan en distintos mo n como lenguaje de programacio n. Sin emDe acuerdo con esto, C representa una buena eleccio n orientada a bargo, seguro que el lector ha o do hablar de los lenguajes C++, Java y de la programacio s de preguntarse sobre las diferencias entre C y C++. Pues bien, C++ puede verse como objetos, adema lido en C++ un superconjunto de C, lo que signica que casi cualquier aspecto de C es perfectamente va s). Java por su parte, al igual que C++, tambie n se basa en la sintaxis de C. (pero no al reve Finalmente, diremos que aunque C es considerado como un lenguaje de alto nivel, mantiene muchas caracter sticas de los lenguajes de bajo nivel, por lo que podr a clasicarse como de nivel bajo-medio.

n de un programa 2.3 Creacio


n de un programa de ordenador consta generalmente de una serie de pasos claramente difeLa creacio renciados.

n Edicio
digo del El primer paso consiste en usar un editor de textos y crear un chero que contenga el co digo, normalmente llamado c para dar instrucciones precisas programa en C. Este co odigo fuente, servira digo fuente en C indica al ordenador que debe mostrar al ordenador. Por ejemplo, la siguiente linea de co el mensaje entre comillas en la pantalla: printf( "Esto es un mensaje" ); digo Esta ndar AmeriEl formato del texto admitido por la mayor a de compiladores se basa en el Co n (ASCII). La mayor parte de los procesadores de texto utilizan cano para el Intercambio de Informacio digos especiales para dar formato a los documentos, por lo que normalmente no pueden ser usados co como editores de programas. n incluyen un editor, sin embargo, otros no. Hoy en d a, la mayor a de los entornos de programacio ricos de edicio n de textos ASCII proporcionados por En estos casos pueden usarse otros programas gene el sistema. Por ejemplo, en UNIX pueden usarse editores como ed, ex, edit, vi, emacs, o nedit, entre otros. En MS-Windows puede usarse el Bloc de Notas. En MS-DOS puede usarse edit. En OS/2, pueden usarse E y EPM. El chero fuente de un programa debe grabarse con un nombre. Normalmente, el nombre del hace el programa. Adicionalmente, los cheros fuente en C suelen chero debe permitir intuir que n .c para identicarlos fa cilmente. tener la extensio

Los autores, 2000; Edicions UPC, 2000.

2. Primer contacto con C

n Compilacio
Puesto que el ordenador es incapaz de entender directamente un lenguaje de alto nivel como C, antes de quina. Esta traduccio n que un programa pueda ejecutarse en el ordenador debe traducirse a lenguaje ma la realiza un programa llamado compilador que, dado un chero fuente, produce un chero con las quina correspondientes al programa fuente original. El nuevo chero instrucciones de lenguaje ma recibe el nombre de chero objeto. n .OBJ (o El chero objeto suele tener el mismo nombre que el chero fuente, pero con la extensio .o en UNIX).

Montaje
digo compilado se combinan para crear el programa ejecuEn el tercer paso, las diferentes partes del co table. digo objeto. Parte del lenguaje C consiste en una librer a de funciones precompiladas que contiene co Las funciones en esta librer a realizan operaciones de uso frecuente, como mostrar datos en pantalla o n printf del ejemplo anterior es una funcio n de dicha librer leer datos de un chero. La funcio a. As digo objeto de pues, el chero objeto producido al compilar el chero fuente debe combinarse con el co la librer a para crear el chero del programa ejecutable. Cabe destacar que en la mayor a de compiladores actuales, como los que funcionan en MS-DOS o n. MS-Windows, compilacion y montaje se realizan como si fuesen una sola accio

2.4 Primeros pasos con C


n se muestra el programa ma s sencillo posible en C: A continuacio void main()

f g

lo una funcio n main(). Esta funcio n debera constar de una Todo programa en C debe tener una y so serie de sentencias (en este caso vac a) delimitada por los s mbolos f g. Dichas sentencias especican llevar a cabo. la secuencia de acciones que el programa debera En C pueden ponerse comentarios en cualquier lugar del programa, utilizando los s mbolos /* */. El compilador de C ignora todo el texto entre el inicio del comentario (/*) y el nal del mismo (*/). adir comentarios a un programa en C no incrementa el taman o de los cheros objeto ni ejecutable, An n del programa. Veamos un ejemplo de programa con comentarios: ni tampoco ralentiza la ejecucio /* Mi primer programa en C */ void main()

f g

/* Otro comentario */ y otro comentario */

/* ...

Sin embargo, no es posible poner un comentario dentro de otro. Por ejemplo ser a ilegal:

Los autores, 2000; Edicions UPC, 2000.

2.5. El modelo de compilaci on de C

10

/* Mi primer programa en C */ void main()

f g

/* Otro comentario /* Comentario ilegal */ */ y otro comentario */

/* ...

n Pero veamos un programa no tan simple. Por ejemplo, el siguiente programa usa la funcio ndar stdio.h, para mostrar un mensaje en la pantalla. printf, predenida en la librer a esta /* Mi primer programa en C */ #include <stdio.h> void main()

f g

printf( "Mi primer mensaje en pantalla

nn"

);

n de C 2.5 El modelo de compilacio


n se describe el modelo de compilacio n de C y los distintos procesos implicados: preproA continuacio cesador, compilador y montador (ver Fig. 2.1).

Preprocesador
ndice A se vera en detalle esta parte del proceso de compilacio n, seguidamente se Aunque en el ape sicos. describen algunos aspectos ba digo fuente y es el responsable de eliminar los comenEl preprocesador toma como entrada el co n) y de interpretar las directivas especiales tarios (ya que en realidad no representan ninguna instruccio lamente dos de las del preprocesador, denotadas por el s mbolo #. Por el momento destacaremos so s utilizadas: directivas ma n los s #include, que incluye un chero externo dentro del chero fuente. Se usara mbolos n, dife< > para indicar que el chero se encuentra en un directorio del entorno de compilacio n los s rente del directorio de trabajo actual. Por el contrario, se usara mbolos " " para indicar chero locales. Por ejemplo: #include <math.h> incluye el chero con las deniciones de las funciones ma ticas de la librer ndar. tema a esta #include <stdio.h> incluye el chero con las deniciones de las funciones de ndar. entrada y salida de la librer a esta #include "funciones.h" incluye el chero funciones.h del directorio actual. lico. Cuando el preprocesador encuentra un nombre #define, que dene un nombre simbo lico en el programa lo substituye por el valor que se le haya asociado con la directiva simbo #define. #define NUM ELEMENTOS 100 dene la constante NUM ELEMENTOS con valor 100. #define PI 3.1416 dene la constante PI.

Los autores, 2000; Edicions UPC, 2000.

11

2. Primer contacto con C

Cdigo fuente

Preprocesador

Compilador Cdigo objeto Libreras Montador Cdigo ejecutable

Figura 2.1: Modelo de compilaci on de C

Compilador
digo fuente producido por el preprocesador y lo traduce a c El compilador de C recibe el co odigo objeto n .OBJ en MS-Windows, o extensio n .o en UNIX). (cheros con extensio

Montador
ndar) o a funciones Si un chero fuente hace referencia a funciones de una librer a (como la librer a esta denidas en otros cheros fuente, el montador se encarga de: combinar todos los cheros objeto correspondientes, lo uno de ellos contenga la funcio n principal main() y vericar que so crear el chero nalmente ejecutable.

Los autores, 2000; Edicions UPC, 2000.

2.5. El modelo de compilaci on de C

12

Los autores, 2000; Edicions UPC, 2000.

13

3. Empezando a programar

Cap tulo 3

Empezando a programar
3.1 Identicadores
n es un nombre utilizado para referir un valor constante, Un identicador en un lenguaje de programacio n, dentro de un programa. Todo identicauna variable, una estructura de datos compleja, o una funcio formado por una secuencia de letras, nu meros y caracteres de subrayado, con la restriccio n de dor esta que siempre debe comenzar por una letra o un subrayado y que no puede contener espacios en blanco. ximo para la longitud de los identicadores, siendo habitual un ma ximo de Cada compilador ja un ma 32 caracteres. sculas y minu sculas, segu n lo cual C considerara los identicadores contador, C diferencia entre mayu Contador y CONTADOR, por ejemplo, como diferentes. n En cualquier caso, nunca pueden utilizarse las palabras reservadas del lenguaje para la construccio ndar ANSI, C consta u nicamente de 32 palabras reservadas de identicadores. De acuerdo con el esta (ver Tab. 3.1). Tabla 3.1: Palabras reservadas de C auto break case char const continue default do double else enum extern oat for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while

3.2 Estructura de un programa


sicamente de los siguientes elementos: Todo programa en C consta ba Directivas del preprocesador Deniciones de tipos de datos Declaraciones de funciones

Los autores, 2000; Edicions UPC, 2000.

3.3. Variables y constantes

14

u nicamente la declaracio n de la funcio n main() que corresponde al Por el momento se tratara n de un programa escrito en C siempre comienza por dicha funcio n. programa principal. La ejecucio n, en un programa so lo puede haber una funcio n con dicho nombre. La denicio n de tipos Por esta razo de datos se deja para el cap tulo 8. n en C, y en particular la funcio n main(), tiene la siguiente estructura: Toda funcio tipo datos nombre funci on ( par ametros )

f g

variables locales; secuencia de sentencias;

metros y la deNo entraremos aqu en las particularidades de las funciones como el paso de para n de resultados de un tipo de datos determinado (ver Cap. 10). Comentaremos simplemente volucio n de resultados como los para metros son opcionales, y que en la mayor que tanto la devolucio a de n del programa principal. programas sencillos no se usan en la denicio n se muestra, como ejemplo, un programa para evaluar la expresio n 3 A continuacio /* Evaluando una expresi on */ #include <stdio.h> void main()
5

; =

32 4

int a, b, c = 5; a = 3 * c; b = 32 / 4; c = a - b; printf( "El valor de la expresi on es:

%dnn", c );

El cuerpo del programa principal lo constituyen todas las l neas de programa comprendidas entre s sentencias. Una sentencia es neas puede haber una o ma los s mbolos f y g. En cada una de dichas l una orden completa para el ordenador. Toda sentencia debe acabar con un punto y coma (;).

3.3 Variables y constantes


n mecanismo Los programas de ordenador utilizan diferentes tipos de datos, por lo que requieren de algu para almacenar el conjunto de valores usado. C ofrece dos posibilidades: variables y constantes. Una variable es un objeto donde se guarda un valor, el cual puede ser consultado y modicado durante la n del programa. Por el contrario, una constante tiene un valor jo que no puede ser modicado. ejecucio

3.3.1 Variables
Toda variable debe declararse antes de ser usada por primera vez en el programa. Las sentencias de n de variables indican al compilador que debe reservar cierto espacio en la memoria del ordeclaracio denador con el n de almacenar un dato de tipo elemental o estructurado. Por ejemplo, la siguiente

Los autores, 2000; Edicions UPC, 2000.

15

3. Empezando a programar

n de variables indica al compilador que debe reservar espacio en la memoria para tres variadeclaracio bles de tipo entero, a las que nos referiremos con los nombres a, b y c: int a, b, c; n consiste en dar un nombre signicativo a la variable e indicar el tipo de datos a que La declaracio . A continuacio n se muestra la sintaxis ma s sencilla de una corresponden los valores que almacenara n para una sola variable. sentencia de declaracio tipo datos nombre variable; s, en una sola sentencia pueden declararse varias variables de un mismo tipo de datos, sepaAdema rando los nombres de las variables mediante comas: tipo datos nombre variable1, ..., nombre variableN; n. Opcionalmente, es posible asignar un valor inicial a las variables en la propia declaracio tipo datos nombre variable = valor inicial;

3.3.2 Constantes
licas. C admite dos tipos diferentes de constantes: literales y simbo Constantes literales digo fuente cada vez que es necesario para una operacio n Todo valor que aparece directamente en el co constituye una constante literal. En el siguiente ejemplo, los valores 20 y 3 son constantes literales del tipo de datos entero: int cont = 20; cont = cont + 3; rica contiene un punto decimal, el compilador considera dicha constante Si una constante nume n utilizando alguna como un valor real de coma otante. Este tipo de constantes puede escribirse tambie nmente aceptadas (ver Sec. 6.3). de las notaciones cient cas comu ricas son consideradas por el compilador, como valores Por el contrario, el resto de constantes nume enteros. Pueden usarse tres formatos alternativos: Toda constante que comience por un d gito distinto de 0 es interpretada como un entero decimal (esto es, en base 10). Se especican mediante los d gitos del 0 al 9 y el signo positivo o negativo. Si una constante comienza con el d gito 0, se interpreta como un entero octal (base 8). Se especican mediante los d gitos del 0 al 7 y el signo positivo o negativo. Finalmente, las constantes que comienzan por 0x o 0X se interpretan como enteros en base hexadecimal (base 16). Se especican mediante los d gitos del 0 al 9, las letras de la A a la F, y el signo positivo o negativo. s sobre los distintos sistemas de numeracio n, ver el ape ndice C. Para saber ma

Los autores, 2000; Edicions UPC, 2000.

3.3. Variables y constantes

16

licas Constantes simbo Una constante simb olica es una constante representada mediante un nombre (s mbolo) en el programa. Al igual que las constantes literales, no pueden cambiar su valor. Sin embargo para usar el valor lico, de la misma forma que lo har constante, se utiliza su nombre simbo amos con una variable. Una lica se declara una sola vez, indicando el nombre y el valor que representa. constante simbo licas tienen dos ventajas claras respecto a las literales. Supongamos el siguienLas constantes simbo digo para calcular el per rea del c te co metro de una circunferencia y el a rculo que dene: perimetro = 2 * 3.14 * radio; area = 3.14 * radio * radio; lica de nombre PI y valor 3.14, podr Si por el contrario se hubiese denido una constante simbo amos digo mucho ma s claro: escribir un co perimetro = 2 * PI * radio; area = PI * radio * radio; s, imaginemos ahora que para incrementar la precisio n del ca lculo se desea usar un valor ma s Es ma a substituirse uno a uno el valor preciso de la constante , como 3.14159. En el primer caso deber n de la constante PI con 3.14 en todo el programa. En el segundo caso, bastar a cambiar la denicio el nuevo valor. todo ma s habitual para denir constantes en C es la directiva del preprocesador #define. El me Por ejemplo, en el caso anterior podr amos haber escrito: #define PI 3.14159 lico y a continuacio n el valor constante que representa. Es decir, el nombre simbo

3.3.3 Entrada y salida de valores


ndice B se vera n con ma s detalle las funciones de la librer ndar printf y Aunque en el ape a esta scanf, se introducen en este punto con el n de poder realizar algunos programas sencillos. n printf usa como C utiliza operaciones de entrada y salida con formato. Por ejemplo, la funcio cter especial de formato el s cter que sigue a este s cara mbolo de porcentaje (%). El cara mbolo dene el n). Por ejemplo, %c para valores de tipo cara cter o formato de un valor (constante, variable o expresio %d para valores de tipo entero. El siguiente ejemplo muestra por pantalla el contenido de una variable cter (ch), y una variable entera (num). de tipo cara char ch; int num; . . . printf( "Esto es un car acter: %cnn", ch ); printf( "Y esto un entero: %dnn", num ); El formato es todo aquello especicado entre las comillas, al que le sigue una lista de variables, constantes o expresiones separadas por comas. Es responsabilidad del programador asegurar la perfecta

Los autores, 2000; Edicions UPC, 2000.

17

3. Empezando a programar

Tabla 3.2: Operadores aritm eticos en C Unarios Signo negativo Incremento Decremento Suma Resta n Multiplicacio n Divisio dulo Mo

;
++

;; ;
=
% +

Binarios

mero como en el tipo de los mismos. correspondencia entre el formato y la lista de valores, tanto en nu nea. Finalmente, la secuencia especial nn indica un salto de l n para la entrada de valores a una estructura de datos, y en Por su parte, scanf es una funcio particular a una variable. Su formato es similar al de printf. Por ejemplo: char ch; int num; . . . scanf( "%c%d", &ch, &num ); cter en la variable ch y seguidamente un valor entero en Permite introducir desde el teclado un cara tese que en el caso de scanf se antepone el s la variable num. No mbolo & a las variables. Por el momento, no debemos olvidar utilizarlo, y tengamos en mente que el uso de & tiene que ver con direcciones de memoria y punteros (ver Cap. 9).

3.4 Expresiones
n es una fo rmula matema tica cuya evaluacio n especica un valor. Los elementos que Una expresio n son: constantes, variables y operadores. constituyen una expresio

n 3.4.1 Operador de asignacio


n permite asignar valores a las variables. Su s El operador de asignacio mbolo es un signo igual =. Este a la izquierda del operador el valor que esta a la derecha. Un operador asigna a la variable que esta lidas con el operador de asignacio n son: x = 1; z = 1.35; . ejemplo de expresiones va

ticos 3.4.2 Operadores aritme


s de los operadores aritme ticos tradicionales, C proporciona algunos operadores adicionales (ver Adema Tab. 3.2). n, x++; equivale a x = x+1;, y x--; equivale a x = x-1;. Aunque en el La expresio digo ma s eciente si se usaba los operadores ++, -- en pasado algunos compiladores generaban co lugar de sus expresiones equivalentes, esto ya no es cierto en los compiladores modernos. Los opera s habitual) como preja, indicando en cada dores ++ y -- pueden usarse tanto de manera postja (ma

Los autores, 2000; Edicions UPC, 2000.

3.4. Expresiones

18

s o antes de la evaluacio n de la expresio n en la que caso si el valor de la variable se modica despue digo: aparece. Por ejemplo, la siguiente l nea de co x = ((++z) - (w--)) % 100; es equivalente al siguiente grupo de sentencias: z = z + 1; x = (z - w) % 100; w = w - 1; tese que en C no existe ningu n operador especial para la divisio n entera, de forma que cuando No n son enteros, el cociente que se obtiene es el correspondiente a la los dos operandos de la divisio n entera (el cociente no se redondea, sino que se trunca). Si alguno de los operandos es un valor divisio n sera tambie n real. Por ejemplo, x = 3/2; asigna el valor 1 a la real, el resultado de la divisio variable x (que debe ser entera), mientras que x = 3.0/2; o x = 3/2.0; asigna el valor dulo (%) permite obtener 1.5 a la variable x (que debe ser real). Finalmente, el operador de mo n entera, por lo que sus operandos deben ser tambie n enteros. Por ejemplo, el resto de una divisio x = 8 % 5; asigna el valor 3 a la variable entera x. s una manera abreviada de expresar ciertos ca lculos en C. Es muy comu n tener exExiste adema presiones del estilo de i = i + 5; o x = x * (y + 2);. Este tipo de expresiones puede escribirse en C de forma compacta como: expresi on1 que es equivalente a: expresi on1 = expresi on1 op expresi on2 op = expresi on2

n esto, la asignacio n i = i + 5; puede reescribirse como i += 5; y la asignacio n Segu tese que esta u ltima expresio n no signica en x = x * (y + 2); como x *= y + 2;. No n caso x = (x * y) + 2;. ningu Como puede verse, un uso abusivo de los operadores abreviados de C puede hacer dif cil de leer un n al ser programa. C permite escribir expresiones muy compactas, pero que pueden generar confusio le das. Hay que recordar siempre que la legibilidad (mantenimiento) de un programa es tan importante como su correcto funcionamiento.

3.4.3 Operadores relacionales


Los operadores relacionales se utilizan principalmente para elaborar condiciones en las sentencias condicionales e iterativas (ver Cap. 4 y Cap. 5). n en C. Al relacionar (comparar) dos expreLa tabla 3.3 resume los distintos operadores de relacio gico, es decir: CIERTO o FALSO. siones mediante uno de estos operadores se obtiene un resultado lo n 4 > 8 da como resultado el valor falso, la expresio n num == num da Por ejemplo, la expresio n 8 <= 4 da como resultado falso, etc. como resultado cierto, la expresio Es interesante destacar que a diferencia de otros lenguajes, C no dispone de un tipo de datos es gicos o booleanos. En su lugar, C representa un resultado FALSO como pec co para los valores lo

Los autores, 2000; Edicions UPC, 2000.

19

3. Empezando a programar

Tabla 3.3: Operadores relacionales (izquierda) y l ogicos (derecha) en C Menor que Mayor que Menor o igual que Mayor o igual que Igual que Distinto que

< > < >

= =

== ! =

n o Y lo gico Conjuncio n u O lo gico Disyuncio n o NO lo gico Negacio

&&

jj
!

Tabla 3.4: Tabla de verdad de los operadores l ogicos en C A Cierto Cierto Falso Falso B Cierto Falso Cierto Falso !A Falso Falso Cierto Cierto A && B Cierto Falso Falso Falso A jj B Cierto Cierto Cierto Falso

rico entero cero, y un resultado CIERTO como cualquier valor entero diferente de cero. el valor nume Es muy importante recordar este hecho de ahora en adelante. n Un error habitual es confundir el operador relacional de igualdad == con el operador de asignacio = . Por ejemplo, la sentencia x = 3 asigna el valor 3 a la variable x, mientras que x == 3 compara el valor de x con la constante 3.

gicos 3.4.4 Operadores lo


gicos (ver Tab. 3.3) se utilizan principalmente en conjuncio n con los relacionales para Los operadores lo elaborar condiciones complejas en las sentencias condicionales e iterativas (ver Cap. 4 y Cap. 5). gicos && y Es importante no confundir los operadores lo n 8.5. & y j que veremos en la seccio

jj

con los operadores de manejo de bits

gicos. De acuerdo con dicha tabla, La tabla 3.4 muestra la tabla de verdad para los operadores lo las expresiones 4 && 0, !(4 > 1) y 5 <= 0 dan como resultado 0 (falso), mientras que las expresiones 4 jj 9, (8 == 4*2) && (5 > 2) y 2 && (4 < 9) dan como resultado 1 (cierto).

3.4.5 Prioridad de operadores


La tabla 3.5 muestra los operadores vistos anteriormente, as como la prioridad entre ellos. La prioridad n se muestra la asociatividad para operadores con el mismo desciende al descender en la tabla. Tambie nivel de prioridad. n dicha tabla, la expresio n (a < 10 && 2 * b < c) se interpretara como Por ejemplo, segu (a < 10) && ((2 * b) < c).

Los autores, 2000; Edicions UPC, 2000.

3.5. Ejercicios

20

Tabla 3.5: Prioridad y asociatividad de los operadores en C Operador ntesis Pare gico NO lo Signo negativo Incremento Decremento n Multiplicacio n Divisio dulo Mo Suma Resta Menor que Menor o igual que Mayor que Mayor o igual que Igual que Distinto que gico Y lo gico O lo Asignaciones S mbolo
()

;
++

Asociatividad Izquierda a derecha Derecha a izquierda

;;
=
% Izquierda a derecha Izquierda a derecha Izquierda a derecha

< < > >

== ! =

Izquierda a derecha Izquierda a derecha Izquierda a derecha Derecha a izquierda

&&

jj

= =

+ =

%=

3.5 Ejercicios
Escribir un programa para cada uno de los siguientes ejercicios: ngulo, calcular su a rea y su per 1. Pedir la base y la altura de un recta metro, y mostrar los resultados por pantalla. ntas horas, minutos y segundos 2. Pedir una cantidad de segundos y mostrar por pantalla a cua corresponden. n int x = 7, y; , calcular el 3. Suponiendo que previamente se ha realizado la declaracio n: valor de la variable y tras evaluar cada una de las siguientes sentencias de asignacio (a) y (b) y (c) y (d) y
=

;2
(y

;;x;
x); x;

+ = = =

2;
==

y++

4. Evaluar las siguientes expresiones: (a) 5 (b) 4

2 6

20 % 6 2

15

Los autores, 2000; Edicions UPC, 2000.

21

3. Empezando a programar

(c) 5 (d) 8 (e) (4

15
==

= <

16 3

jj

2 6

(4 3

;
>

2) 5

7 != 4 && 4

jj

<

1
+

2) && 3

<

12

Los autores, 2000; Edicions UPC, 2000.

3.5. Ejercicios

22

Los autores, 2000; Edicions UPC, 2000.

23

4. Construcciones condicionales

Cap tulo 4

Construcciones condicionales
Una de las construcciones importantes que pueden especicarse en un programa es el hecho de realizar n de ciertas condiciones. Esto es, ejecutar una parte del co digo u otra, condiferentes tareas en funcio necesario especicar dichas condiciones (ver Sec. 3.4) y disponer de un dicionalmente. Para ello sera acciones tomar dependiendo de co mo se evalu e una determinada condicio n mecanismo para indicar que n del programa. en un momento dado de la ejecucio en la seccio n 3.4.3, C no dispone de Antes de empezar, un recordatorio. Como ya de comento gicos, que podr n de condiciones. En su defecto, C valores booleanos o lo an usarse en la evaluacio rico cero, y cualquier valor no cero (incluyendo simula los valores falso y cierto, como el valor nume negativos), respectivamente. As pues, en este cap tulo veremos las distintas maneras que C ofrece para controlar el ujo de n de un programa de forma condicional, que son: ejecucio n if, la construccio el operador condicional ?, y n switch. la construccio

n if 4.1 Construccio
n if es similar a la existente en otros lenguajes de programacio n, aunque en C poLa construccio n para decidir si una determinada see ciertas peculiaridades. El formato general de esta construccio sentencia debe ejecutarse o no (alternativa simple) es el siguiente: if (condici on) sentencia; n if puede escribirse tambie n de forma ma s general para controlar la ejecucio n de un La construccio grupo de sentencias, de la siguiente manera:

Los autores, 2000; Edicions UPC, 2000.

4.1. Construcci on if

24

Cierto Condicin Grupo de sentencias

Cierto

Condicin

Falso

Grupo de sentencias 1

Grupo de sentencias 2

(a)

(b)

Figura 4.1: Esquema de funcionamiento de if y de if-else if (condici on)

sentencia 1; sentencia 2; . . . sentencia N;

n if es muy simple. En primer lugar se evalu a la condicio n, El funcionamiento de la construccio n de tipo entero. A continuacio n, si la expresio n se ha evaluado que no es otra cosa que una expresio n del programa como cierta, se ejecuta la sentencia o grupo de sentencias. En caso contrario la ejecucio a por la siguiente sentencia en orden secuencial (ver Fig. 4.1 (a)). continu n if. El programa lee un nu mero entero y lo El siguiente ejemplo muestra el uso de la construccio transforma en el impar inmediatamente mayor, si es que no era ya impar. #include <stdio.h> void main()

int a; scanf("%d", &a); if (a % 2 == 0) /* Comprobar si a es par. a = a + 1; printf( "Ahora es impar: %dnn", a );

*/

tese que despue s de la condicio n no se escribe ;. Escribir ; detra s de la condicio n equivaldr No a n if ejectutase un conjunto vac n sentido. a que la construccio o de sentencias, lo cual no tiene ningu tese, sin embargo, que tal hecho es va lido sinta cticamente (no produce ningu n error de compilacio n), No tenerse cuidado al escribir esta construccio n. Algo similar ocurre con los bucles por lo que debera for y while (ver Cap. 5).

Los autores, 2000; Edicions UPC, 2000.

25

4. Construcciones condicionales

4.1.1 Variante if-else


s general, denominada alternativa doble, que ofrece dos alternativas de ejecucio n, Existe otra forma ma n de si la condicio n se evalu a cierta o falsa. en funcio if (condici on) sentencia 1; else sentencia 2; Y para un grupo de sentencias: if (condici on)

f g f g

grupo de sentencias 1;

else grupo de sentencias 2;

n es cierta se ejecutara la primera sentencia (el primer grupo de sentencias), y si As pues, si la condicio la segunda sentencia (el segundo grupo). Ver gura 4.1 (b). es falsa se ejecutara n. El programa calcula el ma ximo de dos El siguiente programa muestra el uso de esta construccio meros enteros: nu #include <stdio.h> void main() int a, b, max; scanf( "%d %d", &a, &b ); if (a > b) max = a; else max = b; prinf( "El m aximo es: %dnn", max );

n else es opcional, es decir, puede ser Es importante destacar que la sentencia en la construccio moslo en el siguiente ejemplo que determina si un nu mero es par: nula. Vea #include <stdio.h> void main()

int x;

Los autores, 2000; Edicions UPC, 2000.

4.1. Construcci on if

26

scanf( "%d", &x ); if (x % 2 == 0) printf( "Es par.nn" ); else ;

n else sea opcional puede causar problemas de ambigu edad al El hecho de que la construccio compilador cuando se utilizan construcciones if o if-else anidadas. Para solventar el problema se ha establecido una regla muy sencilla que todo compilador de C tiene en cuenta. La regla consiste s cercano siempre y cuando e ste no en que una sentencia else se asocia con el if precedente ma tenga ya asociada otra sentencia else. n se muestran dos porciones de programa pra cticamente iguales, pero con comportaA continuacio lisis de ambos casos. mientos completamente diferentes. Se deja para el lector el ana . . . if (n > 0) if (a > b) z = a; else z = b; . . . . . . if (n > 0)

f g

if (a > b) z = a;

else z = b; . . .

4.1.2 Variante if-else-if


n alternativa muy comu n, conocida como if-else-if o simpleExiste nalmente otra construccio n, donde las condiciones se plantean de forma escalonada, se muestra mente else-if. Su construccio n: a continuacio if (condici on 1)

f g f g f g f g

grupo de sentencias 1;

else if (condici on 2) grupo de sentencias 2;

. . . else if (condici on N) grupo de sentencias N;

else grupo de sentencias por defecto;

Los autores, 2000; Edicions UPC, 2000.

27

4. Construcciones condicionales

an secuencialmente de arriba hacia abajo hasta encontrar una que de como Las condiciones se evalu n. El resultado cierto. En ese punto, se ejecuta el grupo de sentencias correspondiente a dicha condicio resto de condiciones y sentencias asociadas se ignoran. En caso de que ninguna de las condiciones se e cierta, se ejecutar evalu a el grupo de sentencias por defecto. Como en todos los casos anteriores, el ltimo else es opcional. u n se muestra un ejemplo del uso de esta construccio n: A continuacio #include <stdio.h> void main()

int hora; scanf( "%d", &hora ); if ((hora >= 0) && (hora < 12)) printf( "Buenos d as" ); else if ((hora >= 12) && (hora < 18)) printf( "Buenas tardes" ); else if ((hora >= 18) && (hora < 24)) printf( "Buenas noches" ); else printf( "Hora no v alida" );

4.2 El operador condicional ?


nico operador ternario de C. La forma general de las expresiones El operador condicional ? es el u construidas con este operador es la siguiente: expresi on 1 ? expresi on 2 : expresi on 3;

n se evalu a cierta, toda la expresio n toma el valor de la segunda De manera que si la primera expresio n. En cambio, si la primera expresio n se evalu a falsa, toda la expresio n toma el valor de la expresio n. tercera expresio lculo del ma ximo de dos valores. En la siguiente Un ejemplo t pico del uso de este operador es el ca ximo entre la variable a y b. sentencia, c toma el valor del ma c = (a > b) ? a : b;

n if-else como: Esto mismo podr a haberse escrito usando la construccio if (a > b) c = a; else c = b;

Los autores, 2000; Edicions UPC, 2000.

4.3. Construcci on switch

28

De esta manera, algunas sentencias if-else sencillas pueden escribirse de manera muy compacta mediante el operador ?. Finalmente, el operador condicional, por ser en realidad un operador para expresiones, puede usarse n: en lugares donde no puede usarse un if-else, como se muestra a continuacio printf("El m nimo es %d

nn",

((x < y) ?

x :

y) );

n switch 4.3 Construccio


n permite especicar mu ltiples sentencias al estilo if-else-if, pero de manera Esta construccio s compacta, legible y elegante. Su forma general es la siguiente: ma switch ( expresi on )

case constante 1 : grupo de sentencias break; case constante 2 : grupo de sentencias break; . . . case constante N : grupo de sentencias break; default : grupo de sentencias break;

1;

2;

N;

por defecto;

n debe ser de tipo entero o cara cter, al igual que todas las constantes asociadas a cada donde la expresio etiqueta case. Es importante resaltar que no pueden usarse variables o expresiones en los distintos lo constantes. case, sino so n switch es como sigue. En primer lugar se evalu a la El funcionamiento de la construccio n. Seguidamente su valor es comparado secuencialmente con el de las diferentes constantes en expresio n coincide con alguna de ellas, se ejecuta el grupo de sentencias los case. Si el valor de la expresio correspondiente y switch concluye gracias a la sentencia break. En caso contrario, y si existe el caso default (que es opcional), se ejecutar a el grupo de sentencias por defecto (ver Fig. 4.2). Cabe mencionar de forma especial, la sentencia break que volveremos a ver en cap tulos sucesi n dentro de un bloque de vos. En general, break se utiliza para nalizar de forma forzada la ejecucio digo, de manera que la siguiente sentencia a ejecutar sera la primera sentencia justo despue s de dicho co n switch, break es necesario para concluir la ejecucio n del grupo de bloque. En la construccio n. As sentencias asociado al caso cuya constante coincide con el valor de la expresio pues, la sentencia s de break en un switch, sera la primera sentencia posterior a la llave g que a ejecutar despue cierra el switch.

Los autores, 2000; Edicions UPC, 2000.

29

4. Construcciones condicionales

Expresin

Grupo de sentencias 1

Grupo de sentencias 2

...

Grupo de sentencias N

Grupo de sentencias por defecto

Figura 4.2: Esquema de funcionamiento de switch n switch tambie n podr La construccio a escribirse de forma equivalente mediante sentencias del tipo if-else-if, de la siguiente forma: if (expresi on == constante 1)

f g f f g f g

grupo de sentencias 1;

else if (expresi on == constante 2) grupo de sentencias 2; g. . . else if (expresi on == constante N) grupo de sentencias N;

else grupo de sentencias por defecto;

s ineciente en tiempo de ejecucio n, puesto que la expresio n debe que, como puede verse, es mucho ma n. evaluarse repetidas veces, una para cada condicio El siguiente ejemplo muestra un programa que hace uso de switch para traducir a caracteres un d gito entre 1 y 5. #include <stdio.h> void main() int num; scanf( "%d", &num ); switch ( num )

Los autores, 2000; Edicions UPC, 2000.

4.3. Construcci on switch

30

f
case 1 : printf( "Uno.nn" ); break; case 2 : printf( "Dos.nn" ); break; . . . case 5 : printf( "Cinco.nn" ); break; default : printf( "El d gito est a fuera de rango.nn" ); break;

Finalmente, cabe decir que el grupo de sentencias asociado a un case puede ser vac o. Este caso particular tiene su utilidad cuando se desea que varias etiquetas case ejecuten un mismo grupo de sentencias. Por ejemplo: #include <stdio.h> void main() int num; scanf( "%d", &num ); switch ( num )

case 1: case 3: case 7: printf( "Es un uno, un tres o un siete.nn" ); break; case 4: case 8: printf( "Es un cuatro, o un ocho.nn" ); break; default: printf( "D gito no controlado.nn" ); break;

Los autores, 2000; Edicions UPC, 2000.

31

4. Construcciones condicionales

4.4 Ejercicios
ximo y el m 1. Escribir un programa que lea tres valores enteros y muestre por pantalla el ma nimo de ellos. n en los siguientes supuestos: 2. Dado el siguiente programa, realizar un seguimiento de la ejecucio (a) a = 0, b = 0, c = 5, d = 3 (b) a = 2, b = 1, c = 5, d = 3 (c) a = 2, b = 1, c = 2, d = 2 (d) a = 2, b = 1, c = 0, d = 0 #include <stdio.h> void main() int a, b, c, d; scanf( "%d %d %d %d", &a, &b, &c, &d ); if ( ((a > 0) || (b > a)) && (c != d) )

f g f g g

a = c; b = 0;

else c += d; c = (c == 0) ? b = a + c + d;

(c + b) :

(c - a);

printf( "%d %d %d %dnn", a, b, c, d );

ltiplo de 2 y de 5. 3. Escribir un programa que lea un valor entero y determine si es mu n de una recta en un plano, Ax + By + 4. Escribir un programa que muestre por pantalla la ecuacio C = 0, leyendo previamente las coordenadas de dos de sus puntos (x1 , y1) y (x2 , y2). Recordar que:

A y ;y
=
2

y B y
=

x ;x ;x
2 1)

y ;y
2

1)

Los autores, 2000; Edicions UPC, 2000.

4.4. Ejercicios

32

Los autores, 2000; Edicions UPC, 2000.

33

5. Construcciones iterativas

Cap tulo 5

Construcciones iterativas
sicos del control del ujo de ejecucio n de un programa en Hasta ahora hemos visto algunos aspectos ba n repetida de sentencias, bien C. Este cap tulo presenta los mecanismos que C ofrece para la ejecucio mero prejado de veces, bien dependiendo de cierta condicio n. Es decir, mecanismos para la un nu n de bucles de ejecucio n. creacio C proporciona las siguientes construcciones iterativas: n while, la construccio n do-while, y la construccio n for. la construccio

n while 5.1 Construccio


n while es similar a la existente en otros lenguajes de programacio n. Sin embargo, La construccio n, la construccio n while de debido a que en C toda sentencia puede considerarse como una expresio adida. C ofrece cierta potencia an s general para la ejecucio n repetida de una sola sentencia es: La forma ma while (condici on) sentencia; n repetida de un grupo de sentencias: O para la ejecucio while (condici on)

f g

grupo de sentencias;

n es bastante simple. El cuerpo del bucle, es decir, la senEl funcionamiento de esta construccio n que actu a de tencia o grupo de sentencias dentro del bucle, se ejecuta mientras el valor de la expresio n sea cierto. En el momento en que la condicio n sea falsa, la ejecucio n del programa continu a condicio n tras el bucle (ver Fig. 5.1). secuencialmente con la siguiente instruccio

Los autores, 2000; Edicions UPC, 2000.

5.1. Construcci on while

34

Falso Condicin Cierto Grupo de sentencias

Figura 5.1: Esquema de funcionamiento de while meros enteros le El siguiente ejemplo calcula la media de una secuencia de nu dos por teclado acabada en ;1: #include <stdio.h> void main()

int num, cont, suma; cont = 0; suma = 0; scanf( "%d", &num ); while (num != -1)

f g

cont++; suma = suma + num; scanf( "%d", &num );

if (cont != 0) printf( "La media es %dnn", sum/cont ); else printf( "La secuencia es vac a.nn" );

n while la condicio n se evalu a al principio del bucle. Por ello, si cuando se alEn la construccio n es falsa, el cuerpo del bucle no se ejecuta nunca (imag canza el bucle por primera vez, la condicio nese mero de la secuencia sea ;1). Como consecuencia, el caso, en el ejemplo anterior, en que el primer nu n. el cuerpo de un bucle while puede ejecutarse entre 0 y N veces, donde N depende de la condicio tese tambie n que si la condicio n permanece cierta, el bucle puede no terminar nunca (imag No nese ocurrir que a si se elimina la sentencia scanf del cuerpo del bucle del ejemplo anterior). Por ello, n, habitualmente las sentencias del cuerpo del bucle modican las variables que aparecen en la condicio sta sea falsa en algu n momento. de forma que e n del bucle (y esto es extensible a las diferentes construcciones repetitivas) Por otra parte, la condicio

Los autores, 2000; Edicions UPC, 2000.

35

5. Construcciones iterativas

Grupo de sentencias

Condicin Falso

Cierto

Figura 5.2: Esquema de funcionamiento de do-while ser simplemente una expresio n lo gica, sino que puede ser cualquier expresio n. Por no tiene por que ejemplo, los siguiente bucles while (x--)

...

while (x = x+1); lidos. En ambos casos el cuerpo del bucle se repetira mientras el valor de x sea son perfectamente va tese que en el segundo caso el cuerpo del bucle es nulo, lo cual tambie n es posible. distinto de 0. No

n do-while 5.2 Construccio


n do-while es la siguiente: La forma general de la construccio do

f g

sentencia; o grupo de sentencias; while (condici on);

tese que tanto para ejecutar una sola sentencia como para ejecutar un grupo de ellas, las llaves No f g son igualmente necesarias. n funciona de manera muy similar a la construccio n while. Sin embargo, al Esta construccio sta, do-while ejecuta primero el cuerpo del bucle y despue s evalu a la condicio n. Por contrario que e lo cual, el cuerpo del bucle se ejecuta como m nimo 1 vez (ver Fig. 5.2). mero de veces que aparece el nu mero El siguiente ejemplo cuenta el nu meros enteros acabada en ;1: nu #include <stdio.h> void main() int num, cont;
3

en una secuencia de

Los autores, 2000; Edicions UPC, 2000.

5.3. Construcci on for

36

Sentencia inicial

Falso

Condicin Cierto

Grupo de sentencias

Incremento / Decremento

Figura 5.3: Esquema de funcionamiento de for cont = 0;

do

scanf( "%d", &num ); if (num == 3) cont++; g while (num != -1); printf( "El 3 ha aparecido %d vecesnn", cont );

s de la condicio n, a diferencia de en la construccio n Es importante destacar el uso de ; despue while , donde no se utiliza. n while como la construccio n Finalmente, cabe decir que tradicionalmente, tanto la construccio mero exacto de iteraciones. do-while se utilizan en bucles donde se desconoce a priori el nu

n for 5.3 Construccio


n iterativa no presenta un formato jo estricto, sino que admite numerosas variantes, lo Esta construccio que la dota de gran potencia y exibilidad. s general para la ejecucio n repetida de una sola sentencia es: Su forma ma for (sentencia inicial ; condici on ; incremento/decremento) sentencia; n repetida de un grupo de sentencias: o para la ejecucio

Los autores, 2000; Edicions UPC, 2000.

37

5. Construcciones iterativas

for (sentencia inicial ; condici on ; incremento/decremento)

f g

grupo de sentencias;

n for acostumbra a ser una sentencia de asignacio n donde se La primera parte de la construccio mero de veces que debe ejecutarse el cuerpo del bucle. Esta inicializa alguna variable que controla el nu n, antes de entrar por primera vez al cuerpo del bucle. sentencia se ejecuta una sola ocasio n que indica cua ndo naliza el bucle, de la misma forma La segunda parte corresponde a la condicio n se evalu a antes de ejecutar el que en las construcciones iterativas anteriores. En este caso, la condicio n while, el cuerpo puede ejecutarse entre 0 cuerpo del bucle, por lo que al igual que en la construccio n. y N veces, donde N depende de la condicio La tercera parte corresponde normalmente a una sentencia de incremento o decremento sobre la s de la ejecucio n del cuerpo del variable de control del bucle. Esta sentencia se ejecuta siempre despue bucle. ticamente el funcionamiento del bucle for. La gura 5.3 muestra esquema n for para calcular el sumatorio El programa del siguiente ejemplo utiliza la construccio #include <stdio.h> void main()

X
10

=1

int i, cubo, suma; suma = 0; for (i = 0 ; i <= 10 ; i++)

f g g

cubo = i * i * i; suma += cubo; printf( "El sumatorio es %dnn", suma );

n for son opcionales, por lo que es posible omitir alguna o todas Las tres partes de la construccio sico ellas. En cualquier caso, los punto y coma (;) separadores son siempre necesarios. Un ejemplo cla n): de este tipo de bucle for es el bucle innito (nunca concluye la ejecucio for ( ; 1 ; )

f g

/* Grupo de sentencias */

n for se utiliza en bucles donde el nu mero exacto de iteraciones Tradicionalmente la construccio a como contador. es conocido a priori, y puede controlarse mediante una variable que actu

Los autores, 2000; Edicions UPC, 2000.

5.4. Las sentencias break y continue

38

5.3.1 El operador coma (,)


n de ma s de una sentencia en la primera y tercera partes de la construccio n for, C permite la utilizacio s de una condicio n en la segunda parte. Por ejemplo, el siguiente bucle es va lido en C: as como de ma for (i = 0, j = 10 ; i < 10, j > 0 ; i++, j-=2)

f g

/* Grupo de sentencias */

n As pues, las variables i y j se inicializan a 0 y 10, respectivamente, antes de comenzar la ejecucio n, aparecen dos condiciones, i < 10 y j > 0. Si del bucle. En la segunda parte de la construccio n del bucle se detiene. Finalmente, tras ejecutarse el cuerpo del bucle, alguna de ellas es falsa, la ejecucio i se incrementa en 1 y j se decrementa en 2, tras lo cual vuelven a comprobarse las condiciones, y as sucesivamente.

5.3.2 Equivalencia for-while


Como se ha podido ver, C trata el bucle for de manera muy similar al bucle while, usando una n para decidir cua ndo concluye la ejecucio n. De hecho, todo bucle for puede escribirse de condicio forma equivalente mediante un bucle while de la siguiente forma: sentencia inicial; while (condici on)

f g

sentencia; incremento/decremento;

5.4 Las sentencias break y continue


n de las construcciones iterativas: las sentencias C proporciona dos mecanismos para alterar la ejecucio break y continue.

break
n Esta sentencia tiene una doble nalidad. Por un lado, indica el nal de un case en la construccio en la seccio n 4.3. Y por otro, para forzar la terminacio n inmediata de la ejecuswitch, como ya se vio n de un bucle. De esta forma, se permite salir de la construccio n repetitiva ignorando la evaluacio n cio n. Si bien su uso esta reconocido como no muy elegante, permite en ocasiones escribir de la condicio s legibles y compactos. programas ma

continue
nicamente en las construcciones repetitivas. Su funcio n es la de evitar que se Esta sentencia se utiliza u digo a continuacio n de ella y hasta el nal del cuerpo del bucle, durante una iteracio n ejecute todo el co determinada. El siguiente ejemplo pretende ilustrar el uso de estas sentencias:

Los autores, 2000; Edicions UPC, 2000.

39

5. Construcciones iterativas

do

scanf("%d", &num); if (num < 0)

f g f g

printf( "Valor ilegalnn" ); break; /* Abandonar el bucle.

*/

if (num > 100) printf( "Valor demasiado grandenn" ); continue; /* No ejecutar el resto de sentencias e ir al final del bucle. */

/* Procesar el valor le do */ . . . g while (num != 0 ); . . .

5.5 Ejercicios
Se recomienda realizar los siguientes ejercicios utilizando las diferentes construcciones iterativas presentadas. meros mu ltiplos de 5 o de 7. 1. Escribir un programa que calcule la suma de los 20 primeros nu mero entero, dado su valor y el del expo2. Escribir un programa que calcule la potencia de un nu nente. meros enteros y muestre el mayor y el menor de todos ellos. 3. Escribir un programa que lea N nu mero le 4. Escribir un programa que escriba la tabla de multiplicar de un nu do por teclado. 5. Escribir un programa que muestre la serie de Fibonacci hasta un l mite dado. Recordar que la serie de Fibonacci se dene como

= 1

= 1

Fi Fi;
=

Fi;

mero entero positivo a cualquier base de numeracio n 6. Escribir un programa que convierta un nu dada, igual o inferior a 10. mero entero dado es primo o no. 7. Escribir un programa que determine si un nu mero entero le 8. Escribir un programa que calcule el factorial de un nu do por teclado. meros mu ltiplos de 5 comprendidos 9. Escribir un programa que calcule la suma de todos los nu entre dos enteros le dos por teclado. meros de la serie de Fibonacci. 10. Escribir un programa que muestre los 15 primeros nu

Los autores, 2000; Edicions UPC, 2000.

5.5. Ejercicios

40

Los autores, 2000; Edicions UPC, 2000.

41

6. Tipos de datos elementales

Cap tulo 6

Tipos de datos elementales


Hasta el momento se ha usado impl citamente el tipo de datos entero en todos los ejemplos presentados. En este cap tulo entraremos en los detalles de este tipo de datos, as como de otros tipos de datos predenidos en C. C proporciona los siguientes tipos de datos elementales: meros enteros, nu caracteres, y meros de coma otante (reales). nu

6.1 Numeros enteros


ndice C se describe el formato usado para almacenar nu meros enteros en memoria. Es imporEn el ape n de esta seccio n. tante que el lector se familiarice con este formato para obtener una mejor compresio La palabra clave utilizada para especicar el tipo de datos entero es int. Dependiendo del orde o de un entero en memoria var nador, del sistema operativo y el compilador utilizados, el taman a. Sin embargo, hoy en da la mayora de los computadores almacenan las variables del tipo int en 32 bits (4 meros enteros va desde ;2147483648 hasta 2147483647 bytes), por lo que el rango representable de nu n existen compiladores en (esto es, desde ;231 hasta 231 ; 1). Por otro lado, en el entorno IBM-PC au lo ocupa 16 bits (2 bytes), con un rango entre ;32768 y 32767 (desde ;215 hasta donde un entero so 15 2 ; 1). Por ejemplo, Turbo C 2.0, Visual C++ 1.5, etc. Aunque ya se ha visto previamente, el formato para declarar variables enteras es: int lista de variables;

Donde se especica una lista de nombres de variables separados por comas. meros enteros en C se expresan mediante una serie de d Los nu gitos, precedidos o no por un signo mero es positivo, el signo + es opcional. Habitualmente se utiliza la notacio n decimal, o ;. Si el nu n es posible usar notacio n octal y hexadecimal. En los nu meros expresados en octal, se aunque tambie meros expresados en hexadecimal, el nu mero utiliza un 0 como primer d gito, mientras que en los nu scula o minu scula (0x o 0X). La tabla 6.1 muestra algunos es precedido por un 0 y una equis mayu n de constantes enteras en los distintos formatos. ejemplos de representacio
+

Los autores, 2000; Edicions UPC, 2000.

6.1. N umeros enteros

42

Tabla 6.1: Representaci on de enteros en decimal, octal y hexadecimal Decimal 27 4026 -149 Octal 033 07672 -0225 Hexadecimal 0X1B 0xFBA -0x95

6.1.1 Modicadores
C dene una serie de modicadores para el tipo de datos entero. El modicador short meros enteros de 16 bits, independientemente del proEste modicador se emplea para representar nu n donde el pues, hay entornos de programacio cesador, por lo que su rango es ;32768 32767]. As o y rango de una variable short int coincide con el de int. Mientras que en otros entortaman nos, una variable de tipo short int ocupa la mitad de espacio y tiene un rango mucho menor. La n de variables de este tipo tiene la forma: declaracio short int O simplemente: short lista de variables; lista de variables;

No existe ninguna manera de especicar expl citamente constantes de tipo short int. El modicador long meros enteros con un rango mayor al permitido por Este modicador se emplea para representar nu n ocupan ma s espacio en memoria. Por lo tanto las variables del tipo long int, por lo que tambie n el entorno. Habitualmente son 64 bits, lo que da un rango de int pueden ocupar 32 o 64 bits segu representacion de ;9223372036854775808 9223372036854775807], esto es ;263 ;263 ; 1]. La n de variables es como sigue: declaracio long int O simplemente: long lista de variables; lista de variables;

Para especicar expl citamente que una constante es de tipo long int, debe escribirse una letra scula o minu scula), justo detra s del valor constante. Cabe decir, que esto so lo es necesario ele (mayu dentro del rango de int. Es reen caso que el valor de la constante que se desea especicar este n se muestra un comendable el uso de L, pues l puede confundirse con el d gito 1. A continuacio ejemplo:

Los autores, 2000; Edicions UPC, 2000.

43

6. Tipos de datos elementales

long x; . . . x = -554L; x = 187387632; El modicador signed Es el modicador usado por defecto para todo dato de tipo int, por lo que no suele utilizarse de forma expl cita. En cualquier caso, las declaraciones tiene la forma: signed int O simplemente: int lista de variables; lista de variables;

El modicador unsigned meros enteros sin signo. Como consecuencia de eliminar el Este modicador permite especicar nu n, el rango de valores positivos se amplia hasta 0 65535] si se emplean 16 signo de la representacio n de variables se realiza como: bits, o 0 4294967295] si se emplean 32 bits. La declaracio unsigned int O simplemente: unsigned lista de variables; lista de variables;

scula justo detra s Pueden especicarse constantes de tipo unsigned, escribiendo una letra u mayu del valor constante, como en: unsigned x; . . . x = 45728; x = 345U; Finalmente, cabe comentar que el modicador unsigned puede combinarse con short y lido de 0 264 ; 1], es long. Por ejemplo, los datos de tipo unsigned long tienen un rango va decir 0 18446744073709551615].

6.1.2 Resumen
La tabla 6.2 resume los distintos tipos de datos enteros que se han presentado, mostrando su rango, n de memoria en bits y el modicador de formato para printf y scanf. ocupacio

Los autores, 2000; Edicions UPC, 2000.

6.2. Caracteres

44

Tabla 6.2: Resumen de tipos de datos enteros Tipo int unsigned int short int unsigned short int long int unsigned long int

Rango

2147483648 2147483647]

0 4294967295] 32768 32767] 0 65535]


63

2
64

63

0 2

;
1]

1]

Tamano 32 bits 32 bits 16 bits 16 bits 64 bits 64 bits

Formato %d %u %d %u %ld %lu

6.2 Caracteres
Este tipo de datos se identica con la palabra reservada char. Comprende un conjunto ordenado y digos nume ricos. La codicacio n ma s extendida es el nito de caracteres, representados mediante co ndar ASCII que utiliza 8 bits. As esta pues, el tipo de datos char es internamente tratado como cter propiamente. El ape ndice D muestra la tabla un entero, aunque puede manipularse como un cara digos ASCII y los caracteres asociados. La declaracio n de variables se realiza como: completa de co char lista de variables;

cter correspondiente La forma habitual de expresar una constante de tipo char es mediante el cara entre comillas: char x, y; . . . x = f; y = ?; x = 5; n interna de los caracteres mediante nu meros enteros, pueden realizarse Debido a la representacio ticas como: F+5 , o lo que es lo mismo, 70 + 53 = 123, que equivale al operaciones aritme cter K. cter f; o como F+5, esto es 70 + 5 = 75 que equivale al cara cara n tambie n se establece un orden entre los caracteres, lo que permite usar los Por la misma razo n a <= h da como resultado el operadores relacionales habituales. As pues, la comparacio n K > V da como resultado el valor falso. valor cierto, o la comparacio

6.2.1 Caracteres especiales


ndar ASCII no son directamente imprimibles, por lo que Algunos de los caracteres denidos por el esta para utilizarlos en un programa es necesario un mecanismo especial. En realidad, C ofrece dos: digo ASCII asociado al cara cter, que puede representarse tanto en decimal, Puede usarse el co digo cter n9 representa un tabulador mediante su co octal o hexadecimal. Por ejemplo, el cara digo cter n040 corresponde al espacio en blanco mediante su co ASCII en decimal; el cara ASCII en octal, etc. O bien, pueden usarse secuencias de escape especiales, como nn , para forzar un salto de s utilizados: l nea, que hemos utilizado en ejemplos anteriores. La siguiente tabla muestra los ma

Los autores, 2000; Edicions UPC, 2000.

45

6. Tipos de datos elementales

Tabla 6.3: Caracteres interpretados como enteros Tipo char signed char unsigned char

; ;

Rango
128 127] 128 127] 0 255]

Tamano 1 byte 1 byte 1 byte

Formato %c %d %u

na nn nf nr nt n n" n0
6.2.2 Enteros y el tipo char

digo Co

Signicado pitido salto de l nea gina salto de pa principio de la misma l nea tabulador strofe apo comillas cter nulo cara

internamente representado mediante co digos nume ricos de 8 bits, una Puesto que el tipo char esta n como una variable entera. As variable de este tipo puede interpretarse tambie pues, pueden utilizarse n los modicadores signed y unsigned. Los rangos de valores se muestran en la tabla 6.3. tambie

6.2.3 Conversiones de tipos


En general, en C puede convertirse el tipo de una variable o constante a otro tipo cualquiera. Para ello, ntesis. Aunque no profundizaremos basta con escribir delante de dicha variable el nuevo tipo entre pare n de tipos en C, veremos su utilidad en este caso, para obtener el co digo ASCII de un en la conversio cter y viceversa. cara digo ASCII del cara cter A alEn el ejemplo de la izquierda, se asigna a la variable cod el co cter macenado en la variable c, que es 65. En el ejemplo de la derecha, se asigna a la variable c el cara digo ASCII 98 almacenado en la variable cod, que es el caracter b. correspondiente al co int cod; char c; . . . c = A; cod = (int) c; . . . cticos: Para concluir, un par de aspectos pra n cara cter del rango 0...9, puede obtenerse su valor Si la variable c almacena algu rico equivalente (no confundir con el co digo ASCII) mediante la sentencia: nume i = (int)c - (int)0; int cod; char c; . . . cod = 98; c = (char) cod; . . .

Los autores, 2000; Edicions UPC, 2000.

6.3. N umeros reales

46

Tabla 6.4: Resumen de tipos de datos reales Tipo float double long double

1 1754945

2 225073858507202

1 797693134862312 8 4

: :

3 4028232

: :

Rango

5 9

: :::E ; : :::E

E; E E; E
38 + 38 4932

Tamano 4 bytes
308

Formato %f, %e, %g %f, %e, %g %f, %e, %g

8 bytes 16 bytes

+ 308

+ 4932

Si i es una variable entera con un valor en el rango pondiente de la siguiente forma: c = (char)((int)0 + i);

0 9]

cter corres, puede obtenerse el cara

6.3 Numeros reales


ndice C se describe el formato de coma otante usado para almacenar nu meros Nuevamente, en el ape n reales. Es importante que el lector se familiarice con este formato para obtener una mejor comprensio n. de esta seccio sicamente dos tipos de nu meros reales, los de precisio n simple (float) y los de En C existen ba n doble (double). Un valor de tipo float ocupa 4 bytes (32 bits) y permite representar precisio meros reales con 8 d n. Un valor de tipo double ocupa 8 bytes (64 bits) y permite nu gitos de precisio meros reales con 16 d n (ver Tab. 6.4). representar nu gitos de precisio Las constantes reales pueden representarse mediante dos notaciones: la decimal, constituida por una a detra s de un punto, por ejemplo -5.034 o 443.43; serie de d gitos donde la parte decimal se situ n cient n decimal que representa la y la notacio ca o exponencial, formada por una parte en notacio cter E o e y un nu mero entero que representa el exponente, como por mantisa, seguida del cara ejemplo: -3.56E67 o 7.9e-15. Por defecto, las constantes reales se consideran de tipo double. Para especicar expl citamente scula tras la constante, como en el siconstantes de tipo float, debe escribirse una letra efe mayu guiente ejemplo: double x; float y; . . . x = 34E23; y = 2.3E12F; Algunos compiladores admiten el uso del modicador long para el tipo double. Este tipo de n cua druple (32 d variables se almacenan en 16 bytes y proporcionan precisio gitos). meros reales en un programa que calcula el sumaPara concluir, veamos un ejemplo de uso de nu torio

1 X
i
=1

con un error inferior a un valor

, mientras que

1000

. Expresando el error

Los autores, 2000; Edicions UPC, 2000.

47

6. Tipos de datos elementales

ticamente tenemos: matema

k X i
=1

i ;

k ; X i
=1

i j<

n se muestra un programa que realiza dicho ca lculo: A continuacio #include <stdio.h> #define LIMITE 1000 void main ()

int i, fin; float suma, t, epsilon; suma = 0.0F; fin = 0; i = 1; scanf( "%f", &epsilon ); while (!fin)

g g

t = 1.0F / (float)i; suma = suma + t; i++; fin = ((t < epsilon) || (i > LIMITE));

printf( "La suma es %fnn", suma );

rvese el uso del modicador de formato %f para la entrada y salida de valores de coma otante, Obse n del bucle. y el uso de la variable fin para controlar la terminacio ndar En el chero de cabeceras math.h (#include <math.h>), perteneciente a la librer a esta ticas para operar con valores reales, como: (ver Ap. B), se denen una serie de funciones matema sqrt para la ra z cuadrada, sin y cos para senos y cosenos, etc.

6.4 Ejercicios
mero de veces que aparece una letra en una secuencia de 1. Escribir un programa que cuente el nu caracteres acabada en . . cter de teclado e informe de si es alfabe tico, nume rico, 2. Escribir un programa que lea un cara n. blanco o un signo de puntuacio mero ente3. Escribir un programa que convierta una secuencia de d gitos entrados por teclado al nu ngase que el primer d rvese tambie n ro correspondiente. Supo gito le do es el de mayor peso. Obse n de que el peso efectivo de cada d gito le do es desconocido hasta haber concluido la introduccio la secuencia.

Los autores, 2000; Edicions UPC, 2000.

6.4. Ejercicios

48

4. Sean las variables enteras i y j con valores 5 y 7, respectivamente. Y las variables de l sera el resultado de las coma otante f y g con valores 5:5 y ;3:25, respectivamente. Cua siguientes asignaciones? (a) i = i % 5; (b) f = (f - g) / 2; (c) j = j * (i - 3); (d) f = f % g; (e) i = i / (j - 2); n de segundo 5. Escribir un programa que calcule y muestre por pantalla las ra ces de una ecuacio 2 grado, leyendo previamente los coecientes A, B y C de la misma: Ax + Bx + C = 0. 6. Escribir un programa que calcule el per metro de una circunferencia y que lo muestre por pantalla n. Si el radio introducido por el usuario es negativo, el per con cuatro decimales de precisio metro 0. resultante sera mero e. Recordar que 7. Escribir un programa para calcular de forma aproximada el nu

1 X
i
=0

1 !

Los autores, 2000; Edicions UPC, 2000.

49

7. Tipos de datos estructurados: Tablas

Cap tulo 7

Tipos de datos estructurados: Tablas


n de tipos de datos En este cap tulo veremos algunos de los mecanismos que C ofrece para la creacio complejos. Estos se construyen, en un principio, a partir de los tipos de datos elementales predenidos por el lenguaje (ver Cap. 6). Comenzaremos hablando del tipo abstracto de datos tabla, tanto de una (vectores), dos (matrices) o ltiples dimensiones. En C existe un tratamiento especial para los vectores de caracteres, por lo que mu dedicaremos una parte de este cap tulo a su estudio. Se deja para el cap tulo 8 el estudio de otros tipos de datos estructurados, como las estructuras, las uniones, y los tipos de datos enumerados. n. Las tablas en C son similares a las que podemos encontrar en otros lenguajes de programacio Sin embargo, se denen de forma diferente y poseen algunas peculiaridades derivadas de la estrecha n con los punteros. Volveremos a esto ma s adelante en el cap relacio tulo 9.

7.1 Vectores
n llamados tablas unidimensionales, son estructuras de datos caracterizadas por: Los vectores, tambie n de datos del mismo tipo. Una coleccio Referenciados mediante un mismo nombre. n de Almacenados en posiciones de memoria f sicamente contiguas, de forma que, la direccio s baja corresponde a la del primer elemento, y la direccio n de memoria ma s alta memoria ma ltimo elemento. corresponde a la del u n de una variable de tipo vector es el siguiente: El formato general para la declaracio tipo de datos nombre tabla [tama no]; donde: tipo de datos indica el tipo de los datos almacenados por el vector. Recordemos que todos los elementos del vector son forzosamente del mismo tipo. Debe aparecer necesariamente en la n, puesto que de ella depende el espacio de memoria que se reservara para almacenar declaracio el vector.

Los autores, 2000; Edicions UPC, 2000.

7.1. Vectores

50

N-1

...
Primer elemento del vector ltimo elemento del vector

Figura 7.1: Representaci on gr aca de un vector de N elementos nombre tabla es un identicador que usaremos para referiremos tanto al vector como un todo, como a cada uno de sus elementos. n entera constante que indica el nu mero de elementos que contendra el tama no es una expresio vector. El espacio ocupado por un vector en memoria se obtiene como el producto del numero de o de cada uno de e stos. elementos que lo componen y el taman

7.1.1 Consulta
ste y un El acceso a un elemento de un vector se realiza mediante el nombre de e ndice entre corche n relativa que ocupa dicho elemento dentro del vector y se tes ([ ]). El ndice representa la posicio n entera (normalmente una constante o una variable). Formalmente: especica mediante una expresio nombre vector[ ndice]; n se muestran algunas formas va lidas de acceso a los elementos de un vector: A continuacio int contador[10]; int i, j, x; . . . x = contador[1]; x = contador[i]; x = contador[i * 2 + j]; . . . a en la posicio n 0, mientras Como muestra la gura 7.1, el primer elemento de un vector en C se situ mero de elementos del vector). Por esta ltimo lo hace en la posicio n N ; 1 (N indica el nu que el u n, el razo ndice para acceder a los elementos del vector debe permanecer entre estos dos valores. Es responsabilidad del programador garantizar este hecho, para no acceder a posiciones de memoria fuera del vector, lo cual producir a errores imprevisibles en el programa.

n 7.1.2 Asignacio
n de valores a los elementos de un vector se realiza de forma similar a como se consultan. La asignacio moslo en un ejemplo: Vea

Los autores, 2000; Edicions UPC, 2000.

51

7. Tipos de datos estructurados: Tablas

int contador[3]; . . . contador[0] = 24; contador[1] = 12; contador[2] = 6; En muchas ocasiones, antes de usar un vector (una tabla en general) por primera vez, es necesario s habitual de inicializar un vector en tiempo de dar a sus elementos un valor inicial. La manera ma n consiste en recorrer secuencialmente todos sus elementos y darles el valor inicial que les ejecucio moslo en el siguiente ejemplo, donde todos los elementos de un vector de nu meros corresponda. Vea enteros toman el valor 0: #define TAM 100 void main()

int vector[TAM], i; for (i= 0; i< TAM; i++) vector[i] = 0;

tese que el bucle recorre los elementos del vector empezando por el elemento 0 (i=0) y hasta el No n i<TAM). elemento TAM-1 (condicio n un mecanismo que permite asignar un valor a todos los elementos de un tabla con Existe tambie n de la tabla. La forma general de inicializar una sola sentencia. Concretamente en la propia declaracio mero de dimensiones es la siguiente: una tabla de cualquier nu tipo de datos nombre tabla [tam1]...[tamN] =

lista valores

g;

contener nunca ma s valores de los que puedan almacenarse en la tabla. La lista de valores no debera Veamos algunos ejemplos: int contador[3] = f24, 12, 6g; /* Correcto */ char vocales[5] = fa, e, i, o, ug; /* Correcto */ int v[4] = f2, 6, 8, 9, 10, 38g; /* Incorrecto */ permitido en ningu n caso comparar dos vectores (en general Finalmente, cabe destacar que no esta mero de dimensiones) utilizando los operadores relacionales que vimos en la dos tablas de cualquier nu n 3.4.3. Tampoco esta permitida la copia de toda una tabla en otra con una simple asignacio n. Si seccio n almacenada en dos tablas, debera hacerse elemento a se desea comparar o copiar toda la informacio elemento. n son ide nticos para las matrices y las tablas mulLos mecanismos de acceso descritos en esta seccio nica diferencia es que sera necesario especicar tantos tidimensionales. La u ndices como dimensiones posea la tabla a la que se desea acceder. Esto lo veremos en las siguientes secciones.

Los autores, 2000; Edicions UPC, 2000.

7.1. Vectores

52

7.1.3 Ejemplos
n se muestra un programa que cuenta el nu mero de apariciones de los nu meros 0, 1, 2 y A continuacio 3 en una secuencia de enteros acabada en ;1.

#include <stdio.h> void main () int num, c0=0, c1=0, c2=0, c3=0; scanf("%d", &num); while (num != -1)

g g

if (num == 0) c0++; if (num == 1) c1++; if (num == 2) c2++; if (num == 3) c3++; scanf( "%d", &num );

printf( "Contadores:%d, %d, %d, %dnn", c0, c1, c2, c3 );

ocurrir semos que contar las apariciones de los cien primeros nu meros enteros? Que a si tuvie Deber amos declarar cien contadores y escribir cien construcciones if para cada caso? La respuesta, moslo en el siguiente programa: como era de esperar, se halla en el uso de vectores. Vea #include <stdio.h> #define MAX 100 void main () int i, num, cont[MAX]; for (i= 0; i< MAX; i++) cont[i] = 0; scanf("%d", &num); while (num != -1) f if ((num >= 0) && (num <= MAX)) cont[num]++; scanf( "%d", &num );

g g

for (i= 0; i< MAX; i++) printf( "Contador [%d] = %dnn", i, cont[i] );

mo normalizar un vector de nu meros reales. Veamos nalmente otro ejemplo en el que se muestra co n consiste en dividir todos los elementos del vector por la ra La normalizacio z cuadrada de la suma de mero de elementos del vector y sus cuadrados. Destaca el uso de la constante MAX para denir el nu n sqrt para el ca lculo de ra de la funcio ces cuadradas.

Los autores, 2000; Edicions UPC, 2000.

53

7. Tipos de datos estructurados: Tablas

#include <math.h> #include <stdio.h> #define MAX 10 void main()

float vector[MAX], modulo; int i; /* Lectura del vector. */ for (i= 0; i< MAX; i++) scanf("%f", &vector[i]); /* Calcular m odulo. */ modulo = 0.0; for (i= 0; i< MAX; i++) modulo = modulo + (vector[i] * vector[i]); modulo = sqrt(modulo); /* Normalizar */ for (i= 0; i< MAX; i++) vector[i] /= modulo; /* Escritura del vector. */ for (i= 0; i< MAX; i++ ) printf( "%f ", vector[i] );

7.2 Matrices
n llamadas tablas bidimensionales, no son otra cosa que vectores con dos dimenLas matrices, tambie n, etc. son similares. siones. Por lo que los conceptos de acceso, inicializacio n de una variable matriz tiene la forma siguiente: La declaracio tipo de datos nombre tabla [tama no dim1][tama no dim2]; mero de las y de Donde tama no dim1 y tama no dim2 indican, respectivamente, el nu n gra ca habitual de una columnas que componen la matriz. La gura 7.2 muestra la representacio matriz de datos. Otro hecho importante es que las matrices en C se almacenan por las. Es decir, que los elementos an en memoria de forma contigua. As de cada la se situ pues, en la matriz de la gura anterior, el primer elemento almacenado en memoria es el (0,0), el segundo el (0,1), el tercero el (0,2), . . . , s (1,0), y as ltimo elemento, es decir (N-1,M-1). (0,M-1), despue sucesivamente hasta el u

Los autores, 2000; Edicions UPC, 2000.

7.2. Matrices

54

0 0 1 Primer elemento de la matriz 2 3

M-1

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


ltimo elemento de la matriz

N-1

Figura 7.2: Representaci on gr aca de una matriz de N las y M columnas

7.2.1 Consulta
sta y dos El acceso a un elemento de una matriz se realiza mediante el nombre de e ndices (uno para n) entre corchetes. El primer cada dimensio ndice representa la la y el segundo la columna en que se valores entre 0 y encuentra dicho elemento. Tal como muestra la gura 7.2, el ndice de las las tomara valores entre 0 y el nu mero mero de las menos 1, mientras que el ndice de las columnas tomara el nu de columnas menos 1. Es responsabilidad del programador garantizar este hecho. nombre matriz[ ndice 1][ ndice 2];

n 7.2.2 Asignacio
nicamente la inicializacio n de una matriz en la propia declaracio n. El siguiente ejemComentaremos u n plo declara una matriz de tres las y cuatro columnas y la inicializa. Por claridad, se ha usado identacio en los datos, aunque hubiesen podido escribirse todos en una sola l nea. int mat[3][4] =

24, 12, 6, 17, 15, 28, 78, 32, 0, 44, 3200 , -34 g;

n de matrices, y en general de tablas multidimensionales, puede expresarse de forma La inicializacio s clara agrupando los valores mediante llaves (f g), siguiendo la estructura de la matriz. As pues, ma n podr el ejemplo anterior tambie a escribirse como: int mat[3][4] =

ff f f g;

24, 12, 6, 17 g, 15, 28, 78, 32 g, 0, 44, 3200 , -34

Los autores, 2000; Edicions UPC, 2000.

55

7. Tipos de datos estructurados: Tablas

7.2.3 Ejemplo
unas El siguiente ejemplo calcula la matriz traspuesta de una matriz de enteros. La matriz tendra ximas segu n la constante MAX. dimensiones ma #include <stdio.h> #define MAX 20 void main()

int filas, columnas, i, j; int matriz[MAX][MAX], matrizT[MAX][MAX]; /* Lectura matriz */ printf( "Num. filas, Num. columnas: " ); scanf( "%d%d", &filas, &columnas ); printf ("Introducir matriz por filas:" ); for (i= 0; i< filas; i++) for (j= 0; j< columnas; j++)

f g

printf( "nnmatriz[%d][%d] = ", i, j ); scanf( "%d", &matriz[i][j] );

/* Traspuesta */ for (i= 0; i< filas; i++) for (j= 0; j< columnas; j++) matrizT[j][i] = matriz[i][j]; /* Escritura del resultado */ for (i= 0; i< filas; i++) for (j= 0; j< columnas; j++) printf( "nnmatrizT[%d][%d] = %d ", i, j, matrizT[i][j] );

rvese que para recorrer todos los elementos de una matriz es necesario el empleo de dos bucles Obse mero de las o columnas anidados que controlen los ndices de las y columnas (siempre entre 0 y el nu menos 1). En este ejemplo todos los recorridos se realizan por las, es decir, que primero se visitan todos los elementos de una la, luego los de la siguiente, etc. Finalmente, cabe comentar que para el necesario el empleo de tantos bucles como dimensiones recorrido de tablas multidimensionales sera tenga la tabla.

7.3 Tablas multidimensionales


s dimensiones. Al igual que vectores y matrices, Este tipo de tablas se caracteriza por tener tres o ma todos los elementos almacenados en ellas son del mismo tipo de datos. n de una tabla multidimensional tiene la forma siguiente: La declaracio

Los autores, 2000; Edicions UPC, 2000.

7.3. Tablas multidimensionales

56

M-1

... ... ...


Primer elemento de la tabla

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

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


2

0 1 2 3

...
ltimo elemento de la tabla 0

N-1

Figura 7.3: Representaci on gr aca de una tabla de tres dimensiones: N

tipo de datos nombre tabla [tama no dim1] ...[tama no dimN]; necesario usar tantos Para acceder a un elemento en particular sera ndices como dimensiones: nombre vector[ ndice 1] ...[ ndice N]; s de tres dimensiones, no es muy habitual hacerlo. La guAunque pueden denirse tablas de ma n gra ca habitual de una tabla de tres dimensiones. ra 7.3 muestra como ejemplo la representacio

7.3.1 Ejemplo
El siguiente ejemplo muestra el empleo de una tabla multidimensional. Concretamente, el programa meros aleatorios. Para generar nu meros utiliza una tabla de 3 dimensiones para almacenar 1000 nu n rand de la librer ndar stdlib.h. Tambie n se ha usado la funcio n aleatorios se usa la funcio a esta getchar (stdio.h), que interrumpe el programa y espera a que el usuario presione una tecla. #include <stdio.h> #include <stdlib.h> #define DIM 10 void main()

int tabla random [DIM][DIM][DIM], a, b, c; for (a= 0; a< DIM; a++)

Los autores, 2000; Edicions UPC, 2000.

57

7. Tipos de datos estructurados: Tablas

for (b= 0; b< DIM; b++) for (c= 0; c< DIM; c++) tabla random[a][b][c] = rand(); /* Muestra series de DIM en DIM elementos. for (a= 0; a< DIM; a++) for (b= 0; b < DIM; b++) */

for (c= 0; c < DIM; c++)

f g g g

printf( "nn tabla[%d][%d][%d] = ", a, b, c ); printf( "%d", tabla random[a][b][c] );

printf( "nnPulse ENTER para seguir" ); getchar();

7.4 Cadenas de caracteres


cter (char) que reciben un tratamiento especial para Las cadenas de caracteres son vectores de tipo cara n. simular el tipo de datos string, presente en otros lenguajes de programacio ltimo Para que un vector de caracteres pueda ser considerado como una cadena de caracteres, el u n esto, si se quiere tiles del vector debe ser el cara cter nulo (co digo ASCII 0). Segu de los elementos u declararse un vector con N + 1 elementos de declarar una cadena formada por N caracteres, debera cter. Por ejemplo, la declaracio n char cadena[6]; reserva suciente espacio en memoria tipo cara para almacenar una cadena de 5 caracteres, como la palabra "casco":

c a s

c o \0

En C pueden denirse constantes correspondientes a cadenas de caracteres. Se usan comillas dobles para delimitar el principio y el nal de la cadena, a diferencia de las comillas simples empleadas con cter. Por ejemplo, la cadena constante "H" tiene muy poco que ver con el las constantes de tipo cara cter constante H, si observamos la representacio n interna de ambos: cara

"H"

H \0

n 7.4.1 Asignacio
Mientras que la consulta de elementos de una cadena de caracteres se realiza de la misma forma que con los vectores, las asignaciones tienen ciertas peculiaridades.

Los autores, 2000; Edicions UPC, 2000.

7.4. Cadenas de caracteres

58

cter de la cadena individualmente. No debera olviComo en toda tabla, puede asignarse cada cara n caso que el u ltimo cara cter va lido de la misma debe ser el cara cter nulo (n0). El darse en ningu tese que siguiente ejemplo inicializa la cadena de caracteres cadena con la palabra "casco". No ltimas posiciones del vector no se han usado. Es ma s, aunque se les hubiese asignado algu n las tres u cter, su contenido ser cara a ignorado. Esto es, el contenido del vector en las posiciones posteriores al cter nulo es ignorado. cara char cadena[10]; . . . cadena[0] cadena[1] cadena[2] cadena[3] cadena[4] cadena[5]

= = = = = =

c; a; s; c; o; n0;

n de una cadena de caracteres durante la declaracio n puede hacerse del mismo modo La inicializacio cter nulo al nal de la cadena. Sin embargo, que en los vectores, aunque no debe olvidarse incluir el cara todo de inicializacio n propio de las cadena de caracteres, cuyo formato general es: existe un me char nombre [tama no] = "cadena"; n, el cara cter nulo es an adido automa ticamente al nal de la cadena. Usando este tipo de inicializacio n t As pues, una inicializacio pica de vectores como la siguiente: char nombre[10] =

N, U, R, I, A, n0

g;

n de forma equivalente como: puede hacerse tambie char nombre[10] = "NURIA"; n anterior puede hacerse sin necesidad de especicar el taman o del vecFinalmente, la inicializacio ticamente, reservando tor correspondiente. En este caso, el compilador se encarga de calcularlo automa cter nulo al nal. As espacio de memoria suciente para almacenar la cadena, incluyendo el cara pues, n reserva memoria para almacenar 6 caracteres y los inicializa adecuadamente la siguiente declaracio con las letras de la palabra NURIA: char nombre[] = "NURIA"; La cadena vac a nicamente Otra curiosidad de las cadenas de caracteres se reere a la cadena vac a, " " , que consta u del caracter nulo. Puesto que los caracteres posteriores al caracter nulo son ignorados, convertir una cter nulo a cadena con cualquier valor almacenado a la cadena vac a es tan simple como asignar el cara n 0 de dicha cadena. He aqu un ejemplo: la posicio char cadena [12] = "Una frase"; . . . a */ cadena[0] = n0; /* Ahora es una cadena vac

Los autores, 2000; Edicions UPC, 2000.

59

7. Tipos de datos estructurados: Tablas

10

11

"Una frase" U n a

\0

cadena[0] = \0;
0 1 2 3 4 5 6 7 8 9 10 11

"" \0 n a

\0

7.4.2 Manejo de cadenas de caracteres


n operadores para el manejo de cadenas de caracteres, todo comAunque C no incorpora en su denicio ndar (string.h) con funciones para facilitar su utilizacio n. pilador de C proporciona una librer a esta Destacar algunas de ellas: cter nulo, strlen para obtener la longitud de la cadena, sin contar el cara strcpy para copiar una cadena en otra, strcat para concatenar dos cadenas, strcmp para comparar dos cadenas, etc. s informacio n sobre estas y otras funciones, consultar el ape ndice B. Para ma Entrada y salida En cuanto a la entrada y salida de cadenas de caracteres, existe un formato especial %s que puede una cadena de utilizarse en las funciones scanf y printf. Por ejemplo, la siguiente sentencia leera lo se asignara n caracteres mientras no sean caracteres blancos, tabucaracteres en la variable cad. So lo tendra sentido para la lectura de palabras. ladores o saltos de l nea. Por lo tanto, el empleo de %s so s del formato %s existen los formatos %[abc] y %[abc], que permiten leer respectivamente Adema n cara cter del conjunto fa, b, cg, o bien hasta no encontrar una cadena de caracteres hasta encontrar algu cter del conjunto fa, b, cg no es le do. Ver un caracter del conjunto fa, b, cg. En cualquier caso el cara ndice B para ma s informacio n sobre el empleo de scanf y la lectura de cadenas de caracteres. el ape char cad[20]; . . . scanf("%s", cad); tese que, en el ejemplo, no se ha antepuesto el s No mbolo & a la variable cad. Por el momento, moslo en mente y esperemos hasta el cap se debe este hecho. tenga tulo 9 para comprender a que ndar de entrada y salida (stdio.h) proporciona adema s las funciones gets y La librer a esta puts, que permiten leer de teclado y mostrar por pantalla una cadena de caracteres completa, respec ndice B para ma s detalles). tivamente (ver el ape

Los autores, 2000; Edicions UPC, 2000.

7.4. Cadenas de caracteres

60

7.4.3 Ejemplos
Para nalizar, veamos un par de ejemplos de manejo de cadenas de caracteres. mero de veces que se repite una palabra en una frase. El programa El siguiente programa cuenta el nu n de comparacio n de cadenas strcmp. Dicha funcio n devuelve 0 en caso de que las emplea la funcio cadenas comparadas sean iguales (ver Sec. B.1). #include <stdio.h> #include <string.h> #define MAXLIN 100 void main() char pal[MAXLIN]; char palfrase[MAXLIN]; char c; int total = 0; printf( "nnPALABRA:" ); scanf( "%s", pal ); printf( "nnFRASE:" ); c = ; while (c != nn) /* La que buscamos. */ /* Una palabra de la frase.

*/

f g g

scanf( "%s%c", palfrase, &c ); if (strcmp(pal, palfrase) == 0) total++;

printf( "nnLa palabra %s aparece %d veces.", pal, total );

n se muestra otro ejemplo que hace uso de las cadenas de caracteres. El programa lee A continuacio sculas en mayu sculas y viceversa, y dos cadenas de caracteres, las concatena, convierte las letras minu nalmente escribe la cadena resultante. #include <stdio.h> #include <string.h> void main() char cad1[80], cad2[80], cad3[160]; int i, delta; printf( "Introduzca la primera cadena:nn" ); gets(cad1); printf( "Introduzca la segunda cadena:nn" ); gets( cad2 ); /* cad3 = cad1 + cad2 */ strcpy( cad3, cad1 );

Los autores, 2000; Edicions UPC, 2000.

61

7. Tipos de datos estructurados: Tablas

strcat( cad3, cad2 ); i = 0; delta = a - A; while (cad3[i] != n0)

g g

if ((cad3[i] >= a) cad3[i] -= delta; else if ((cad3[i] >= cad3[i] += delta; i++;

&& (cad3[i] <= z)) /* Convierte a may uscula */ A) && (cad3[i] <= Z)) /* Convierte a min uscula */

printf( "La cadena resultante es:

%s

nn",

cad3 );

7.5 Ejercicios
nde esta el error en el siguiente programa? 1. Do void main()

int vector [10]; int x = 1; for (x= 1; x<= 10; x++) vector[x] = 23;

meros enteros, lo invierta y nalmente 2. Escribir un programa que lea del teclado un vector de 10 nu lo muestre de nuevo. mero de palabras de ma s de cuatro caracteres en una frase. 3. Escribir un programa que cuente el nu ltimo elemento es el cara cter .. Esta se almacena en forma de vector cuyo u meros enteros de hasta 20 d 4. Escribir un programa que lea del teclado dos nu gitos y los sume. mero. Usar vectores para almacenar los d gitos de cada nu 5. Escribir un programa que decida si una palabra es pal ndroma o no. La palabra se almacena en un vector de caracteres acabado en .. meros enteros. La moda es el 6. Escribir un programa para calcular la moda de un conjunto de nu s veces. valor que se repite ma nde esta el error en el siguiente programa? 7. Do void main()

int matriz [10][3], x, y;

Los autores, 2000; Edicions UPC, 2000.

7.5. Ejercicios

62

for (x= 0; x< 3; x++) for (y= 0; y< 10; y++) matrix[x][y] = 0;

8. Escribir un programa que inicialice cada elemento de una matriz de enteros con el valor de la mero de la y columna en que esta situado. suma del nu 9. Escribir un programa que calcule la suma de dos matrices de enteros. 10. Escribir un programa que calcule los puntos de silla de una matriz de enteros. Un elemento de ximo de su columna. una matriz es un punto de silla si es el m nimo de su la y el ma trica. 11. Escribir un programa que determine si una matriz es sime 12. Escribir un programa que multiplique dos matrices. 13. Escribir un programa que lea una frase del teclado y cuente los espacios en blanco. 14. Escribir un programa que, dada una cadena de caracteres y un entero correspondiente a una n va lida dentro de ella, genere una nueva cadena de caracteres que contenga todos los posicio n, pero en orden inverso. caracteres a la izquierda de dicha posicio 15. Escribir un programa que, dada una cadena de caracteres, la limpie de caracteres blancos. Por transformarse en "Estoesunafrase". ejemplo, la cadena "Esto es una frase" debera n que realice los cambios Escribir dos versiones, una utilizando una cadena auxiliar y otra versio sobre la misma cadena. 16. Escribir un programa que lea dos cadenas de caracteres, las compare e informe de si son iguales n de la librer ndar strcmp. o diferentes. No usar la funcio a esta

Los autores, 2000; Edicions UPC, 2000.

63

8. Otros tipos de datos

Cap tulo 8

Otros tipos de datos


n y manejo de tipo de En este cap tulo veremos los restantes mecanismos que C ofrece para la creacio n un datos complejos. Concretamente las estructuras y las uniones. Por otra parte, se incluye tambie n de nuevos tipos apartado que estudia los tipos de datos enumerados y otro donde se trata la denicio de datos por parte del programador.

8.1 Estructuras
En el cap tulo 7 hemos estudiado el tipo abstracto de datos tabla, formado por un conjunto de elementos todos ellos del mismo tipo de datos. En una estructura, sin embargo, los elementos que la componen cter, enteros, pueden ser de distintos tipos. As pues, una estructura puede agrupar datos de tipo cara meros . . . , e incluso otras estructuras. En cualquier caso, es cadenas de caracteres, matrices de nu n entre ellos. En habitual que todos los elementos agrupados en una estructura tengan alguna relacio adelante nos referiremos a los elementos que componen una estructura como campos. n de una estructura requiere especicar un nombre y el tipo de datos de todos los campos La denicio n. Para que la componen, as como un nombre mediante el cual pueda identicarse toda la agrupacio ello se utiliza la palabra reservada struct de la forma siguiente: struct nombre estructura

g;

tipo campo 1 tipo campo 2 . . . tipo campo N

nombre campo 1; nombre campo 2; nombre campo N;

El siguiente ejemplo dene una estructura denominada cliente en la que puede almacenarse la cha bancaria de una persona. El signicado de los diferentes campos es obvio:

struct cliente char long int nombre[100]; dni;

Los autores, 2000; Edicions UPC, 2000.

8.1. Estructuras

64

char long int float

domicilio[200]; no cuenta; saldo;

n de una estructura corresponde a la denicio n de una plantilla Puede decirse que la denicio rica que se utilizara posteriormente para declarar variables. Por tanto la denicio n de una estructura gene n espacio de memoria. no representa la reserva de ningu

n de variables 8.1.1 Declaracio


n de variables del tipo denido por una estructura puede hacerse de dos maneras diferenLa declaracio n de la estructura, bien posteriormente. La forma gene rica para el primer tes. Bien en la misma denicio caso es la siguiente: struct nombre estructura

tipo campo 1 nombre campo 1; nombre campo 2; tipo campo 2 . . . nombre campo N; tipo campo N lista de variables;

tese que al declararse las variables al mismo tiempo que se dene la estructura, el nombre de e sta No junto a la palabra reservada struct se hace innecesario y puede omitirse. Por otra parte, suponiendo que la estructura nombre estructura se haya denido previamen n de variables en el segundo caso ser te, la declaracio a: struct nombre estructura lista de variables; n la primera variante de declaracio n, podr Siguiendo con el ejemplo anterior, segu amos escribir:

struct char nombre[100]; long int dni; char domicilio[200]; long int no cuenta; float saldo; antiguo cliente, nuevo cliente;

O bien, de acuerdo con la segunda variante donde se asume que la estructura cliente se ha denido previamente: struct cliente antiguo cliente, nuevo cliente;

Los autores, 2000; Edicions UPC, 2000.

65

8. Otros tipos de datos

8.1.2 Acceso a los campos


Los campos de una estructura de manejan habitualmente de forma individual. El mecanismo que C proporciona para ello es el operador punto (.). La forma general para acceder a un campo en una variable de tipo estructura es el siguiente: variable.nombre campo As pues, podr amos acceder a los campos de la variable nuevo cliente como el nombre, mero de dni o el saldo de la siguiente forma: nu nuevo cliente.nombre nuevo cliente.dni nuevo cliente.saldo

n 8.1.3 Asignacio
n de valores a los campos de una variable estructura puede realizarse de dos formas difeLa asignacio rentes. Por un lado, accediendo campo a campo, y por otro, asignando valores para todos los campos n de la variable. en el momento de la declaracio n se muestran algunas posibles maneras de asignar datos a los campos individuales A continuacio de la variable nuevo cliente declarada previamente. Como puede verse, cada campo es tratado como si de una variable se tratase, con lo que pueden usarse funciones como strcpy para copiar una cadena de caracteres sobre un campo de ese tipo, o gets para leerla del teclado, etc. strcpy( nuevo cliente.nombre, "Federico Sancho Buch" ); nuevo cliente.dni = 23347098; gets( nuevo cliente.domicilio ); scanf( "%ld",&nuevo cliente.no cuenta ); nuevo cliente.saldo += 10000.0; n completa de todos los campos de una Por otra parte, el siguiente ejemplo muestra la inicializacio n: variable de tipo estructura en el momento de su declaracio struct cliente nuevo cliente =

f
"Federico Sancho Buch", 23347098, "Rue del Percebe 13 - Madrid", 7897894, 1023459.34

g;

n es posible copiar todos los datos de una variable estructura a otra variable Finalmente, tambie n: estructura del mismo tipo mediante una simple asignacio nuevo cliente = antiguo cliente; permitido en ningu n caso, comparar dos estructuras utilizando los operadores relacionales que No esta n 3.4.3. vimos en la seccio

Los autores, 2000; Edicions UPC, 2000.

8.2. Uniones

66

8.1.4 Ejemplo
El siguiente programa dene las estructuras de datos para gestionar un conjunto de chas personales. tese el uso de estructuras anidadas, as tese tambie n el uso No como el uso de tablas de estructuras. No n gets para leer cadenas de caracteres. Se deja como ejercicio para el lector escribir este de la funcio mismo programa usando scanf en lugar de gets para leer dichas cadenas. #include <stdio.h> struct datos char nombre[20]; char apellido[20]; long int dni;

g; f

struct tablapersonas int numpersonas; struct datos persona[100];

g; f

void main() int i; struct tablapersonas tabla; printf( "N umero de personas: " ); scanf( "%d", &tabla.numpersonas ); for (i= 0; i< tabla.numpersonas; i++)

printf( "nnNombre: " ); gets( tabla.persona[i].nombre ); printf( "nnApellido: " ); gets( tabla.persona[i].apellido ); printf( "nnDNI: " ); scanf( "%ld", &tabla.persona[i].dni );

8.2 Uniones
n pueden contener mu ltiples campos de diferentes tipos Al igual que las estructuras, las uniones tambie rea de almacenade datos. Sin embargo, mientras que cada campo en una estructura posee su propia a n, todos los campos que la componen se hallan almacenados en la misma a rea de miento, en una unio n memoria. El espacio de memoria reservado por el compilador corresponde al del campo de la unio que requiere mayor espacio de almacenamiento. El resto de campos comparten dicho espacio. n esta n solapados en memoria, por lo que, en un momento dado de As pues, los campos de una unio n del programa, so lo podra haber almacenado un dato en uno de los campos. Es responsabilila ejecucio

Los autores, 2000; Edicions UPC, 2000.

67

8. Otros tipos de datos

campo contiene la informacio n dad del programador hacer que el programa mantenga control sobre que n en cada momento. Intentar acceder al tipo de informacio n equivocado puede almacenada en la unio producir resultados sin sentido. n de una unio n es muy similar a la de una estructura, excepto por el uso de la palabra La denicio reservada union: union nombre union

g;

tipo campo 1 nombre campo 1; tipo campo 2 nombre campo 2; . . . tipo campo N nombre campo N;

n de variables de tipo unio n como el acceso a los campos se expresa de forma Tanto la declaracio en las estructuras. similar a como se mostro n y viceversa. Igualmente, Finalmente, diremos que una estructura puede ser el campo de una unio pueden denirse tablas de uniones, etc.

8.2.1 Ejemplo
n asociada a tres tipos diferenEl siguiente ejemplo dene tres estructuras para almacenar la informacio quinas voladoras (jet, helicoptero y carguero). Finalmente dene una estructura tes de ma rica que puede contener, alternativamente, los datos de cualquiera de ellos (un aeroplano). gene tipo es el objeto almacenado en la unio n datos, se utiliza la variable tipo. Para controlar de que

struct jet int num pasajeros; . . .

g; f

struct helicoptero int capacidad elevador; . . .

g; f

struct carguero int carga maxima; . . .

g; f

union aeroplano struct jet jet u; struct helicoptero helicopter u; struct carguero carguero u;

g;

Los autores, 2000; Edicions UPC, 2000.

8.3. Tipos de datos enumerados

68

struct un aeroplano

g;

/* 0:jet, 1:helicoptero, 2:carguero */ int tipo; union aeroplano datos;

8.3 Tipos de datos enumerados


Un objeto enumerado consiste en un conjunto ordenado de constantes enteras cuyos nombres indican todos los posibles valores que se le pueden asignar a dicho objeto. n de una plantilla de un objeto enumerado requiere especicar un nombre mediante La denicio el cual pueda identicarse, as como la lista de constantes de los posibles valores que puede tomar. Para ello se utiliza la palabra reservada enum de la forma siguiente: enum nombre enumeraci on

constante 1, constante 2, . . . constante N; g;

n denominada dia semana, cuyo signicado es obEl siguiente ejemplo dene una enumeracio vio. enum dia semana

LUNES, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO g;

n son representadas internamente Las constantes que denen los posibles valores de la enumeracio n del orden como constantes enteras. El compilador asigna a cada una de ellas un valor en funcio n. As pues, en el ejemplo anterior tenemos que (empezando por 0) en que aparecen en la denicio s modicar dicha asignacio n por a ser de intere LUNES es 0, MARTES es 1, etc. Sin embargo, podr rico. Ver el siguiente ejemplo: defecto, asignando a las constantes otro valor nume enum dia semana

LUNES=2, MARTES=3, MIERCOLES=4, JUEVES=5, VIERNES=6, SABADO=7, DOMINGO=1 g;

n puede asignarse el mismo valor nume rico a diferentes constantes, as Tambie como dejar que el compilador numere algunas por defecto. Ver el siguiente ejemplo: enum dia semana

LUNES=1, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO=10, FESTIVO=10 g;

donde los valores asociados a las constantes son, respectivamente: 1, 2, 3, 4, 5, 6, 10 y 10.

Los autores, 2000; Edicions UPC, 2000.

69

8. Otros tipos de datos

n de variables puede hacerse de dos formas diferentes. Bien en la misma denicio n La declaracio n, bien posteriormente. Por su similitud con la declaracio n de variables en el caso de de la enumeracio digo muestra estructuras y uniones, veremos simplemente un ejemplo del segundo caso. El mismo co n de las constantes denidas en un tipo enumerado. algunos ejemplos de utilizacio enum dia semana

LUNES=1, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO=10, FESTIVO=10 g;

void main() enum dia semana dia; . . . if (dia <= VIERNES) printf( "Es laborable" ); . . . dia = MARTES; /* Muestra el valor de dia */ printf( "Hoy es: %d", dia ); . . .

n de nuevos tipos de datos 8.4 Denicio


C ofrece al programador la posibilidad de denir nuevos tipos de datos mediante la palabra reservada typedef. Los nuevos tipos denidos pueden utilizarse de la misma forma que los tipos de datos pren denidos por el lenguaje. Es importante destacar que typedef tiene especial utilidad en la denicio de nuevos tipos de datos estructurados, basados en tablas, estructuras, uniones o enumeraciones. La sintaxis general para denir un nuevo tipo de datos es la siguiente: typedef tipo de datos nombre nuevo tipo; De esta forma se ha denido un nuevo tipo de datos de nombre nombre nuevo tipo cuya estructura interna viene dada por tipo de datos. n se muestran algunos ejemplos de denicio n de nuevos tipos de datos, as A continuacio como su n en un programa: utilizacio

typedef float Testatura; typedef char Tstring [30]; typedef enum Tsexo =

HOMBRE, MUJER

g;

Los autores, 2000; Edicions UPC, 2000.

8.5. Tiras de bits

70

typedef struct

f g f

Tstring nombre, apellido; Testatura alt; Tsexo sex; Tpersona;

void main() Tpersona paciente; . . . scanf( "%f", &paciente.alt ); gets( paciente.nombre ); printf( "%s", paciente.apellido ); paciente.sex = MUJER;

8.5 Tiras de bits


til que permite programar con un alto nivel de abstraccion. Sin embarco, C C es un lenguaje muy versa n permite programar a muy bajo nivel. Esta caracter til, por ejemplo, para tambie stica es especialmente u programas que manipulan dispositivos hardware, como el programa que controla el funcionamiento de un modem, etc. Este tipo de programas manipulan tiras de bits. En C, una tira de bits se debe almacenar como una variable entera con o sin signo. Es decir, como una variable de tipo char, short, int, long, unsigned, etc. Seguidamente veremos las n tiras de bits. operaciones que C ofrece para la manipulacio

n 8.5.1 Operador de negacio


n recibe el nombre de operador de complemento a 1, y se representa mediante el Este operador tambie s mbolo . La funcion de este operador consiste en cambiar los 1 por 0 y viceversa. Por ejemplo, el siguiente programa: #include <stdio.h> void main()

unsigned short a; a= 0x5b3c; /* a = /* b = b= a; printf( " a= %x b= printf( " a= %u b= printf( " a= %d b= 0101 1011 1010 0100 %xnn", a, %unn", a, %dnn", a, 0011 1100 */ 1100 0011 */ b ); b ); b );

Los autores, 2000; Edicions UPC, 2000.

71

8. Otros tipos de datos

Tabla 8.1: Tabla de verdad de los operadores l ogicos x 0 0 1 1 y 0 1 0 1 AND (&) 0 0 0 1 OR ( j ) 0 1 1 1 XOR (b) 0 1 1 0

mostrar a en pantalla los siguientes mensajes: a= 0x5b3c a= 23356 a= 23356 b= 0xa4c3 b= 42179 b= -23357

como resultado de intercambiar por sus complementarios los bits de la variable a.

gicos 8.5.2 Operadores lo


gicas AND (&), OR ( j ) y XOR (b), tambie n llamadas respectivaC permite realizar las operaciones lo mente Y, O y O exclusivo. La tabla 8.1 muestra la tabla de verdad de estas operaciones, donde x e y son bits. n lo gica se realiza bit a bit. Vea moslo Cuando aplicamos estos operadores a dos variables la operacio en el siguiente ejemplo: a= b= c= d= e= 0x5b3c; 0xa4c3; a & b; a j b; a b b; /* /* /* /* /* a b c d e = = = = = 1101 1010 1000 1111 0111 1011 0101 0001 1111 1110 0001 1100 0000 1101 1101 1101 1011 1001 1111 0110 */ */ */ */ */

8.5.3 Operadores de desplazamiento de bits


Existen dos operadores de desplazamiento que permiten desplazar a derecha o izquierda una tira de bits. El operador de desplazamiento a la dercha se denota como >> y el operador de desplazamiento a la izquierda se denota como <<. Su uso es como sigue: var1 << var2 var1 >> var2 mero de bits desplazados. En el desplazadonde var1 es la tira de bits desplazada y var2 es el nu s a la izquierda de var1, y se introducen ceros por la miento a la izquierda se pierden los bits de ma s a la derecha de derecha. De forma similar, en el desplazamiento a la derecha se pierden los bits de ma var1, y por la izquierda se introducen, o bien ceros (si la variable es de tipo unsigned, o bien se ltimo bit (si la variable es de tipo signed). repite el u El siguiente ejemplo muestra el resultado de aplicar los operadores de desplazamiento de bits:

Los autores, 2000; Edicions UPC, 2000.

8.6. Ejercicios

72

unsigned short a, d, e; short b, c, f, g; a= b= c= d= e= f= g= 28; -28; 3; a << a >> b << b >> /* /* /* /* /* /* /* a b c d e f g = = = = = = = 0000 1111 0000 0000 0000 1111 1111 0000 1111 0000 0000 0000 1111 1111 0001 1110 0000 1110 0000 0010 1111 1100 0100 0011 0000 0011 0000 1100 */ */ */ = 224 */ = 3 */ = -224 */ = -3 */

c; c; c; c;

alar que los operadores de desplazamiento tienen un signicado aritme tico en Es importante sen ndose el cociente base 10. El desplazamiento a la derecha de 1 bit es equivalente a dividir por 2, obtenie de la division entera. El desplazamiento a la izquierda de 1 bit es equivalente a multiplicar por 2. Por lo tanto, cuando trabajemos con variables enteras: var << n equivale a var * 2n , y var >> n equivale a var / 2n .

8.6 Ejercicios
l de las dos es anterior a la otra. Para 1. Escribir un programa que, dadas dos fechas, indique cua denir una estructura para el tipo de datos fecha (d o). ello, el programa debera a, mes y an 2. Denir una estructura de datos para representar polinomios de hasta grado 10. Escribir un programa capaz de sumar dos polinomios expresados con dicha estructura. n de tipos de datos: 3. Dada la siguiente denicio typedef char Tstring [50]; typedef struct

f g

Tstring nombre; Tstring area; long int ventas[4]; Tagente;

n de los datos por Escribir un programa que dena un vector de N agentes, permita la introduccio xima media de ventas. teclado y, nalmente, muestre los datos del agente con la ma n de tipo de datos: 4. Dada la siguiente denicio typedef struct

f g

Tstring pais; int temp max; int temp min; Ttemp;

Los autores, 2000; Edicions UPC, 2000.

73

8. Otros tipos de datos

escribir un programa que dena un vector con los datos de N pa ses y permita introducirlos mostrar el nombre de los pa por teclado. Finalmente, el programa debera ses cuya temperatura m nima sea inferior a la media de las temperaturas m nimas. n de tipos de datos: 5. Dada la siguiente denicio typedef char Tstring [50]; typedef struct

f g f

long int num; char letra; Tnif;

typedef struct Tnif nif; Tstring nombre; Tstring direc; long int telf; Tempresa;

escribir un programa que dena un vector con los datos de N empresas y permita introducirlos permitir mostrar los datos de la por teclado. Dado el NIF de una empresa, el programa debera ndolo para no dejar espacios vac misma, as como eliminarla del vector, reorganiza os.

Los autores, 2000; Edicions UPC, 2000.

75

9. Punteros

Cap tulo 9

Punteros
n de memoria. Dicha direccio n corresUn puntero es una variable que contiene como valor una direccio n que ocupa otra variable en memoria. Se dice entonces que el puntero ponde habitualmente a la direccio apunta a dicha variable. La variable apuntada puede ser de cualquier tipo elemental, estructurado o incluso otro puntero. sicos para comprender toda Los punteros constituyen una parte fundamental del lenguaje C y son ba n la potencia y exibilidad que ofrece el lenguaje. Son especialmente importantes en la programacio a bajo nivel, donde se manipula directamente la memoria del ordenador. Algunas de las ventajas que aporta el uso de punteros en C son: nica forma de expresar algunas operaciones. Constituyen la u digo compacto y eciente. Su uso produce co metros por referencia a funciones. Son imprescindibles para el paso de para n con el manejo eciente de tablas y estructuras. Tienen una fuerte relacio n dina mica de memoria y manipular estructuras de Permiten realizar operaciones de asignacio micas. datos dina s dif Finalmente, cabe advertir al lector que los punteros son tradicionalmente la parte de C ma cil de s deben usarse con gran precaucio n, puesto que al permitir manipular directamente comprender. Adema la memoria del ordenador, pueden provocar fallos en el programa. Estos fallos suelen ser bastante dif ciles de localizar y de solucionar.

n y asignacio n de direcciones 9.1 Declaracio


n de punteros y la posterior asignacio n de direcciones de memoria a los mismos, se En la declaracio utilizan respectivamente los operadores unarios * y &. El operador & permite obtener la direcci on que ocupa una variable en memoria. Por su parte, el operador de indirecci on * permite obtener el contenido de un objeto apuntado por un puntero.

Los autores, 2000; Edicions UPC, 2000.

9.1. Declaraci on y asignaci on de direcciones

76

n 9.1.1 Declaracio
n de variables puntero se usa tambie n el operador * , que se aplica directamente a la En la declaracio n de variables puntero es el siguiente: variable a la cual precede. El formato para la declaracio tipo de datos * nombre variable puntero; tese que un puntero debe estar asociado a un tipo de datos determinado. Es decir, no puede asignarse No n de un short int a un puntero a long int. Por ejemplo: la direccio int *ip; declara una variable de nombre ip que es un puntero a un objeto de tipo int. Es decir, ip contendra direcciones de memoria donde se almacenaran valores enteros. No debe cometerse el error de declarar varios punteros utilizando un solo *. Por ejemplo: int *ip, x; declara la variable ip como un puntero a entero y la variable x como un entero (no un puntero a un entero). n de un puntero debe ser del mismo tipo de datos que El tipo de datos utilizado en la declaracio las posibles variables a las que dicho puntero puede apuntar. Si el tipo de datos es void, se dene rico de forma que su tipo de datos impl el de la variable cuya direccio n se le un puntero gene cito sera digo, ip es un puntero gene rico que a lo largo del programa asigne. Por ejemplo, en el siguiente co cter. apunta a objetos de tipos distintos, primero a un entero y posteriormente a un cara void *ip; int x; char car; . . . ip = &x; ip = &car;

/* ip apunta a un entero */ /* ip apunta a un car acter */

denido, pues es el corresAl igual que cualquier variable, al declarar un puntero, su valor no esta n. Para evitar el uso pondiente al contenido aleatorio de la memoria en el momento de la declaracio n no se le ha asignado una direccio n, es conveniente inicializarlo con indebido de un puntero cuando au ndar stdio.h. El siguiente ejemplo el valor nulo NULL, denido en el chero de la librer a esta n: muestra dicha inicializacio int *ip = NULL; De esta forma, si se intentase acceder al valor apuntado por el puntero ip antes de asignarle una n va lida, se producir n que interrumpir direccio a un error de ejecucio a el programa.

n de direcciones 9.1.2 Asignacio


n que ocupa una variable en memoria. Para que un puntero El operador & permite obtener la direccio n de dicha variable al puntero. El tipo de datos de apunte a una variable es necesario asignar la direccio puntero debe coincidir con el tipo de datos de la variable apuntada (excepto en el caso de un puntero n de memoria contenida en un puntero, puede usarse el de tipo void). Para visualizar la direccio n printf: modicador de formato %p con la funcio

Los autores, 2000; Edicions UPC, 2000.

77

9. Punteros

double num; double *pnum = NULL; . . . pnum = &num; printf( "La direcci on contenida en pnum es:

%p", pnum );

n 9.2 Indireccio
s de un puntero que Llamaremos indirecci on a la forma de referenciar el valor de una variable a trave rmino indireccio n para referirnos al hecho de reapunta a dicha variable. En general usaremos el te n de memoria apuntada por un puntero. La indireccio n se ferenciar el valor contenido en la posicio realiza mediante el operador *, que precediendo al nombre de un puntero indica el valor de la variable n esta contenida en dicho puntero. A continuacio n se muestra un ejemplo del uso de la cuya direccio n: indireccio int x, y; int *p; . . . x = 20; p = &x; *p = 5498; y = *p;

/* Se usa * para declarar un puntero */

/* Se usa * variable /* Se usa * variable

para indicar el valor de la apuntada */ para indicar el valor de la apuntada */

s de ejecutar la sentencia *p = 5498; la variable x, apuntada por p , toma por valor 5498. Despue s de ejecutar la sentencia y = *p; la variable y toma por valor el de la variable Finalmente, despue x, apuntada por p. n la indireccio n mu ltiple, en que un puntero contiene la direccio n de Para concluir, existe tambie n es el siguiente: otro puntero que a su vez apunta a una variable. El formato de la declaracio tipo de datos ** nombre variable puntero; En el siguiente ejemplo, pnum apunta a num, mientras que ppnum apunta a pnum. As pues, la sentencia **ppnum = 24; asigna 24 a la variable num. int num; int *pnum; int **ppnum; . . . pnum = &num; ppnum = &pnum; **ppnum = 24; printf( "%d", num );

Los autores, 2000; Edicions UPC, 2000.

9.3. Operaciones con punteros

78

n mu ltiple puede extenderse a ma s de dos niveles, aunque no es recomendable por la La indireccio digo resultante. dicultad que supone en la legibilidad del co n de punteros debe hacerse con gran precaucio n, puesto que permiten manipular direcLa utilizacio tamente la memoria. Este hecho puede provocar fallos inesperados en el programa, que normalmente n va lida a un puntero son dif ciles de localizar. Un error frecuente consiste en no asignar una direccio antes de usarlo. Veamos el siguiente ejemplo: int *x; . . . *x = 100; n de memoria El puntero x no ha sido inicializado por el programador, por lo tanto contiene una direccio digo aleatoria, con lo que es posible escribir involuntariamente en zonas de memoria que contengan co n error de compilacio n, por lo que puede ser o datos del programa. Este tipo de error no provoca ningu n controlada de memoria, dif cil de detectar. Para corregirlo es necesario que x apunte a una posicio por ejemplo: int y; int *x; . . . x = &y; *x = 100;

9.3 Operaciones con punteros


n, comparacio n y En C pueden manipularse punteros mediante diversas operaciones como asignacio ticas. operaciones aritme

n de punteros Asignacio
Es posible asignar un puntero a otro puntero, siempre y cuando ambos apunten a un mismo tipo de s de una asignacio n de punteros, ambos apuntan a la misma variable, pues contienen la datos. Despue n de memoria. En el siguiente ejemplo, el puntero p2 toma por valor la direccio n de misma direccio memoria contenida en p1. As pues, tanto y como z toman el mismo valor, que corresponde al valor de la variable x, apuntada tanto por p1 como por p2. int x, y, z; int *p1, *p2; . . . x = 4; p1 = &x; p2 = p1; y = *p1; z = *p2;

Los autores, 2000; Edicions UPC, 2000.

79

9. Punteros

n de punteros Comparacio
n de punteros para conocer las posiciones relativas que ocupan Normalmente se utiliza la comparacio en memoria las variables apuntadas por los punteros. Por ejemplo, dadas las siguientes declaraciones, int *p1, *p2, precio, cantidad; *p1 = &precio; *p2 = &cantidad; n p1 > p2 permite saber cua l de las dos variables (precio o cantidad) ocupa una la comparacio n de memoria mayor. Es importante no confundir esta comparacio n con la de los valores de las posicio variables apuntadas, es decir, *p1 > *p2 .

tica de punteros Aritme


mero entero a un puntero, lo que se produce impl Si se suma o resta un nu citamente es un incremento n de memoria contenida por dicho puntero. El nu mero de posiciones de o decremento de la direccio lo del nu mero sumado o restado, sino tambie n memoria incrementadas o decrementadas depende, no so o del tipo de datos apuntado por el puntero. Es decir, una sentencia como: del taman nombre puntero = nombre puntero + N; se interpreta internamente como: nombre puntero = direcci on + N * tama no tipo de datos; o de un float es de 4 bytes, y que la variable Por ejemplo, teniendo en cuenta que el taman l es el valor de pnum al nal del siguiente co digo? a en la direccio n de memoria 2088, cua num se situ float num, *punt, *pnum; . . . punt = &num; pnum = punt + 3; La respuesta es 2100. Es decir, 2088 + 3
4

tica de punteros, esto constituye una Es importante advertir que aunque C permite utilizar aritme ctica no recomemdable. Las expresiones aritme ticas que manejan punteros son dif pra ciles de entender n, por ello son una fuente inagotable de errores en los programas. Como veremos y generan confusio n, no es necesario usar expresiones aritme ticas con punteros, pues C proporciona en la siguiente seccio n alternativa mucho ma s clara. una notacio

9.4 Punteros y tablas


n entre los punteros y las estructuras de datos de tipo tabla En el lenguaje C existe una fuerte relacio (vectores, matrices, etc.). n del En C, el nombre de una tabla se trata internamente como un puntero que contiene la direccio primer elemento de dicha tabla. De hecho, el nombre de la tabla es una constante de tipo puntero, por

Los autores, 2000; Edicions UPC, 2000.

9.4. Punteros y tablas

80

que las instrucciones del programa modiquen la direccio n contenida lo que el compilador no permitira n como char tab[15] , el empleo de tab es en dicho nombre. As pues, dada una declaracio n tab = tab + 1 generara un error equivalente al empleo de &tab[0]. Por otro lado, la operacio n, pues representa un intento de modicar la direccio n del primer elemento de la tabla. de compilacio C permite el uso de punteros que contengan direcciones de los elementos de una tabla para acceder a ellos. En el siguiente ejemplo, se usa el puntero ptab para asignar a car el tercer elemento de cimo elemento del vector tab, leer de teclado el quinto elemento de tab y escribir por pantalla el de tab. char car; char tab[15]; char *ptab; . . . ptab = &tab; ptab = ptab + 3; car = *(ptab); /* Equivale a car = tab[3]; */ scanf( "%c", ptab+5 ); printf( "%c", ptab+10 ); n entre punteros y tablas en C va au n ma s alla . Una vez declarado un puntero que Pero la relacio apunta a los elementos de una tabla, pueden usarse los corchetes para indexar dichos elementos, como si de una tabla se tratase. As , siguiendo con el ejemplo anterior, ser a correcto escribir: scanf( "%c", ptab[0] );/* ptab[0] equivale a tab[0] */ ptab[7] = R; /* ptab[7] equivale a *(ptab +7) */ Por lo tanto, vemos que no es necesario usar expresiones aritm eticas con punteros; en su lugar lo usaremos la sintaxis de acceso a una tabla. Es importante subrayar que este tipo de indexaciones so lidas si el puntero utilizado apunta a los elementos de una tabla. Adema s, no existe ningu n tipo son va n al respecto, por lo que es responsabilidad del programador saber en todo momento si de vericacio accediendo a una posicio n de memoria dentro de una tabla o ha ido a parar fuera de ella y esta esta sobreescribiendo otras posiciones de memoria. l de entre dos vecEl siguiente ejemplo muestra el uso de los punteros a tablas para determinar cua s fuerte. La fuerza de un vector se calcula como la suma de todos sus elementos. tores de enteros es ma #include <stdio.h> #define DIM 10 void main()

int v1[DIM], v2[DIM]; int i, fuerza1, fuerza2; int *fuerte; /* Lectura de los vectores. for (i= 0; i< DIM; i++) scanf( "%d ", &v1[i] ); */

Los autores, 2000; Edicions UPC, 2000.

81

9. Punteros

for (i= 0; i< DIM; i++) scanf( "%d ", &v2[i] ); /* C alculo de la fuerza de los vectores. fuerza1 = 0; fuerza2 = 0; for (i= 0; i< DIM; i++) */

f g

fuerza1 = fuerza1 + v1[i]; fuerza2 = fuerza2 + v2[i];

if (fuerza1 > fuerza2) fuerte = v1; else fuerte = v2; /* Escritura del vector m as fuerte. for (i= 0; i< DIM; i++) printf( "%d ", fuerte[i] ); */

rmulas En el caso de usar punteros para manipular tablas multidimensionales, es necesario usar fo n para el acceso a los elementos. Por ejemplo, en el caso de una matriz de n las y de transformacio m columnas, el elemento que ocupa la la i y la columna j se referencia por medio de un puntero como puntero[i*m+j]. En el siguiente ejemplo se muestra el acceso a una matriz mediante un puntero. float mat[3][5]; float *pt; pt = mat; pt[i*5+j] = 4.6; /* Equivale a mat[i][j]=4.6 */

n pt[k] signica acceder al elemento Cuando usamos el puntero para acceder a la matriz, la expresio k elementos por debajo del elemento apuntado por pt . Dado que en C las de tipo float que esta matrices se almacenan por las, para acceder al elemento de la la i columna j deberemos contar n cuantos elementos hay entre el primer elemento de la matriz y el elemento [i][j ]. Como la numeracio comienza en cero, antes de la la i hay exactamente i las, y cada una tiene m columnas. Por lo tanto hasta el primer elemento de la la i tenemos i m elementos. Dentro de la la i, por delante del elemento j , hay j elementos. Por lo tanto tenemos que entre mat[0][0] y mat[i][j] hay dispuesta en memoria la matriz de este ejemplo i m j elementos. La gura 9.1 muestra como esta n gra ca del ca lculo descrito. y una explicacio

Los autores, 2000; Edicions UPC, 2000.

9.4. Punteros y tablas

82

Puntero pt A[0][0] Fila 0

...

i*m elementos

A[0][m-1]

A[i][0]

...

i*m+j elementos

Fila i

A[i][j]

A[i][m-1]

A[n-1][0] Fila n-1

A[n-1][m-1]

Figura 9.1: Acceso a una matriz mediante un puntero

Punteros y cadenas de caracteres


Una cadena de caracteres puede declararse e inicializarse sin necesidad de especicar expl citamente n es un ejemplo: su longitud. La siguiente declaracio char mensaje[] = "Reiniciando sistema"; s el cara cter nulo n0). El La cadena de caracteres mensaje ocupa en memoria 20 bytes (19 ma n del primer cara cter de la cadena. En esta declaracio n, nombre mensaje corresponde a la direccio cter dismensaje es un puntero constante, por lo que no puede modicarse para que apunte a otro cara cter de la cadena. Sin embargo, puede usarse mensaje para acceder a caracteres tinto del primer cara individuales dentro de la cadena, mediante sentencias como mensaje[13]=S, etc. n puede hacerse usando un puntero: La misma declaracio char *pmens = "Reiniciando sistema"; n, pmens es una variable puntero inicializada para apuntar a una cadena constante, En esta declaracio que como tal no puede modicarse. Sin embargo, el puntero pmens puede volver a utilizarse para apuntar a otra cadena.

...

...

...

...

j elementos

Los autores, 2000; Edicions UPC, 2000.

83

9. Punteros

Puede decirse que en general a una tabla puede accederse tanto con ndices como con punteros tica de punteros). Habitualmente es ma s co modo el uso de (usando la aritme ndices, sin embargo en el metros a una funcio n (ver Cap. 10) donde se recibe la direccio n de una tabla, es necesario paso de para n usarse como tales o usando la indexacio n utilizar punteros. Como veremos, dichos punteros podra t pica de las tablas.

9.5 Punteros y estructuras


Los punteros a estructuras funcionan de forma similar a los punteros a variables de tipos elementales, con la salvedad de que en las estructuras se emplea un operador espec co para el acceso a los campos. n de comienzo de una variable estructura en memoria mediante el Puede accederse a la direccio n &. As empleo del operador de direccio pues, si var es una variable estructura, entonces &var re n de comienzo de dicha variable en memoria. Del mismo modo, puede declararse presenta la direccio una variable puntero a una estructura como: tipo estructura *pvar; donde tipo estructura es el tipo de datos de las estructuras a las que pvar puede apuntar. n de comienzo de una variable estructura al puntero de la forma As pues, puede asignarse la direccio habitual: pvar = &var; n se dene, entre otros, el tipo de datos Tnif como: Veamos un ejemplo. A continuacio typedef char Tstring [50];

f g f

typedef struct long int num; char letra; Tnif;

typedef struct Tnif nif; Tstring nombre; Tstring direc; long int telf; Tempresa;

De forma que en el programa puede declararse una variable cliente de tipo Tnif y un puntero n de inicio de la variable estructura cliente : pc a dicho tipo, as como asignar a pc la direccio Tnif cliente; Tnif *pc; . . . pc = &cliente;

Los autores, 2000; Edicions UPC, 2000.

9.6. Ejercicios

84

Para acceder a un campo individual en una estructura apuntada por un puntero puede usarse el n * junto con el operador punto (.) habitual de las estructuras. Vemos un operador de indireccio ejemplo: (*pc).letra = Z; scanf( "%ld", &(*pc).num ); s prioridad que el operador *. Los par entesis son necesarios ya que el operador punto (.) tiene ma tese que el operador de direccio n & en la llamada a scanf se reere al campo num y no al No puntero pc. ntesis en esta notacio n hace que se generen errores debido El hecho de que sea obligatorio usar pare ntesis adecuados. Para evitar estos errores, C posee otra notacio n para acceder a al olvido de los pare los campos de una estructura apuntada por un puntero. n mediante el operador especial de los punEl acceso a campos individuales puede hacerse tambie n seguido del s teros a estructuras -> (guio mbolo de mayor que). As pues, puede escribirse el mismo ejemplo anterior como: pc->letra = Z; scanf( "%ld", &pc->num ); El operador -> tiene la misma prioridad que el operador punto (.). Es recomendable usar el operador -> al manejar structs apuntados por punteros. El acceso a los campos de una estructura anidada a partir de un puntero puede hacerse combinando los operadores de punteros con el punto (.). Veamos el siguiente ejemplo: Tempresa emp; Tempresa *pe; char inicial; . . . pe = &emp; pe->nif.letra = Z; scanf( "%ld", &pe->nif.num ); gets( pe->nombre ); inicial = pe->nombre[0]; . . .

9.6 Ejercicios
sculas la inicial de todas las palabras en una cadena de 1. Escribir un programa que pase a mayu caracteres. Usar un puntero a dicha cadena para acceder a los elementos de la misma. ximo de un vector de nu meros enteros, utilizando un 2. Escribir un programa que calcule el ma puntero para acceder a los elementos del vector. 3. Escribir un programa que, usando punteros, copie en orden inverso una cadena de caracteres en otra.

Los autores, 2000; Edicions UPC, 2000.

85

9. Punteros

4. Un programa en C contiene las siguientes instrucciones: char u, v; char *pu, *pv; . . . v = A; pv = &v; *pv = v + 1; u = *pv + 1; pu = &u; cter ocupa 1 byte de memoria y la variable u se situ a en la direccio n FC8 (hexadeSi cada cara cimal), responder a las siguientes preguntas: valor representa &v ? (a) Que valor se asigna a pv ? (b) Que valor representa *pv ? (c) Que valor se asigna a u ? (d) Que valor representa &u ? (e) Que valor se asigna a pu ? (f) Que valor representa *pu ? (g) Que 5. Un programa en C contiene las siguientes instrucciones: float a = 0.1, b = 0.2; float c, *pa, *pb; . . . pa = &a; *pa = 2 * a; pb = &b; c = 5 * (*pb - *pa); a en la Si cada variable de tipo float ocupa 4 bytes de memoria y la variable a se situ n 1230 (hexadecimal), responder a las siguientes preguntas: direccio valor representa &a ? (a) Que valor representa &c ? (b) Que valor representa &pb ? (c) Que valor se asigna a pa ? (d) Que valor representa *pa ? (e) Que valor representa &(*pa) ? (f) Que valor se asigna a pb ? (g) Que valor representa *pb ? (h) Que

Los autores, 2000; Edicions UPC, 2000.

9.6. Ejercicios

86

valor se asigna a c ? (i) Que 6. Un programa de C contiene las siguientes sentencias: int i, j = 25; int *pi, *pj = &j; . . . *pj = j + 5; i = *pj + 5; pi = pj; *pi = i + j; a en la Suponiendo que cada variable entera ocupa 2 bytes de memoria. Si la variable i se situ n 1002, entonces: n 1000 y la variable j en la direccio direccio valor representan &i y por &j ? (a) Que valor se asigna a pj , *pj y a i ? (b) Que valor representa pi ? (c) Que valor se asigna a *pi ? (d) Que valor representa pi + 2 ? (e) Que valor representa la expresio n (*pi + 2) ? (f) Que valor representa la expresio n *(pi + 2) ? (g) Que

Los autores, 2000; Edicions UPC, 2000.

87

10. Funciones

Cap tulo 10

Funciones
ndar Hasta ahora hemos visto como el programa principal (main( )) utiliza funciones de la librer a esta n la dede C para realizar algunas tareas comunes (printf( ), scanf( ), . . . ). C permite tambie n de funciones por parte del programador. Como veremos, al usar funciones denidas por el nicio s pequen as y sencillas. Cada una de esprogramador, los programas pueden estructurarse en partes ma sito u nico e identicable, pudiendo adema s utilizarse en distintos tas partes debe responder a un propo n del co digo de un programa usando funciones se conoce como lugares del programa. La distribucio modularizaci on. o modular de programas ofrece diversas ventajas. Por ejemplo, muchos programas requieEl disen n de un mismo grupo de instrucciones en distintas partes del programa. Este grupo de ren la ejecucio n, a la que se puede llamar cuando sea necesario. instrucciones puede incluirse dentro de una sola funcio s, puede proporcionarse un conjunto de datos (par n cada vez que Adema ametros) diferente a la funcio se la llama. n la claridad en la lo gica del programa resultante de la descomposicio n del Es importante tambie s fa cil de escribir y mismo en partes bien denidas. Un programa concebido de esta forma es mucho ma lo por el propio programador, sino tambie n (y ma s importante) por otros programadode depurar, no so res que posteriormente deban mantener el programa. Este hecho es especialmente cierto en programas grandes donde participan muchos programadores. n de funciones permite tambie n la construccio n a medida de librer La utilizacio as de funciones de ticos uso frecuente. Por ejemplo, un programador especializado en el desarrollo de programas matema meros complejos, etc. De esta podr a crear una librer a con funciones para el manejo de matrices, nu digo repetidas veces para distintos programas. forma se evita la reescritura del mismo co

10.1 Generalidades
n es una porcio n de programa, identicable mediante un nombre, que realiza determinadas Una funcio tareas bien denidas por un grupo de sentencias sobre un conjunto de datos. Las operaciones que realiza n son siempre las mismas, pero los datos pueden variar cada vez que se llame a la funcio n. la funcio s funciones, una (y so lo una) de la cuales debe llamarse Todo programa en C consta de una o ma n del programa comienza siempre en dicha funcio n, desde donde puede llamarse main. La ejecucio ndar o denidas por el programador. Al llamar a una funcio n se a otras funciones de la librer a esta

Los autores, 2000; Edicions UPC, 2000.

10.1. Generalidades

88

n de la funcio n, la ejecucio n ejecutan las sentencias que la componen y, una vez completada la ejecucio a desde el punto en que se hizo la llamada a la funcio n. del programa continu n se le proporciona un conjunto de datos (para metros) que Generalmente, al llamar a una funcio n devuelve un solo valor mediante se procesan ejecutando las sentencias que la componen. La funcio metros, pero no devuelven nada (como la funla sentencia return. Algunas funciones reciben para n printf), mientras que otras no reciben para metros pero s n cio devuelven un valor (como la funcio rand). mero combinatorio El programa del siguiente ejemplo calcula el nu

m n

m n m;n
! ! (

)!

, donde

mero diferentes. Una posible realizacio n de este programa, es necesario calcular el factorial de tres nu si no se tuviese en cuenta el uso de funciones, ser a la siguiente: #include <stdio.h> void main() long int m, n, fm = 1, fn = 1, fdif = 1; float res; int i; printf( "Introduzca m y n: " ); scanf( "%d %d", &m, &n ); for (i= 2; i<= m; i++) fm = fm * i; for (i= 2; i<= n; i++) fn = fn * i; for (i= 2; i<= m-n; i++) fdif = fdif * i; res = (float) fm / ((float)fn* (float)fdif); printf( "m sobre n = %fnn", res );

digo para el ca lculo del factorial se halla triplicado. Una solucio n ma s clara y Como puede verse, el co elegante puede obtenerse usando funciones: #include <stdio.h> long int fact ( int x )

int i; long int f = 1; for (i= 2; i<= x; i++) f = f * i; return(f);

void main()

Los autores, 2000; Edicions UPC, 2000.

89

10. Funciones

f
long int m, n; float res; printf( "Introduzca m y n: " ); scanf( "%d %d", &m, &n ); res = (float) fact(m) / ((float)fact(n)*(float)fact(m-n)); printf( "m sobre n = %fnn", res );

n fact, que recibe como para metro un valor de tipo int, al que En el ejemplo se ha denido la funcio digo en el interior de la funcio n se ha llamado x, y devuelve un resultado de tipo long int. El co ndolo sobre la variable local f. Finalmente la funcio n devuelve el calcula el factorial de x acumula lculo mediante la sentencia return. Obse rvese que la denicio n de una funcio n se resultado del ca n. asemeja a la del programa principal. De hecho, el programa principal main es una funcio s formalmente co mo denir funciones, co mo llamarlas, las distintas vaSeguidamente veremos ma metros, etc. riantes del paso de para

n y llamada 10.2 Denicio


n 10.2.1 Denicio
n se hace de forma similar a la de la funcio n main. Su forma ma s gene rica La denici on de una funcio sicamente de dos partes: un l consta ba nea llamada cabecera donde se especica el nombre de la n, el tipo del resultado que devuelve y los para metros que recibe; y un conjunto de sentencias funcio encerrado entre llaves formando el cuerpo. tipo nombre funci on(tipo1 param1, ..., tipoN paramN)

f g

cuerpo

n. Si no se especica ninguno, C asume tipo: es el tipo de datos del valor que devuelve la funcio n devuelve un valor de tipo entero. que la funcio posteriormente para llamar a la funcio n. nombre funci on: identicador que se usara metros que recibe la funcio n. Se espetipoi parami: tipo y nombre de cada uno de los para ntesis y separados por comas. Algunas funciones pueden no tener para metros. cican entre pare metros de la declaracio n se denominan par Los para ametros formales, ya que representan los n a los datos que se transeren a e sta desde la parte nombres con que referirse dentro de la funcio del programa que hace la llamada. n de variables y sentencias de ejecucio n (incluyendo llamadas a cuerpo: conjunto de declaracio n de la tarea especicada por la funcio n. Debe incluir una funciones) necesarias para la realizacio s sentencias return para devolver un valor al punto de llamada. o ma

Los autores, 2000; Edicions UPC, 2000.

10.2. Denici on y llamada

90

10.2.2 Prototipos
n, dicha funcio n ya ha sido Si en el punto del programa donde se va a realizar una llamada a una funcio mero y tipo de denida previamente, entonces ya se conocen sus caracter sticas (tipo del resultado, nu metros, etc.), por lo que la llamada puede realizarse sin problemas. Sin embargo, si la funcio n los para que se va a llamar se halla denida posteriormente al punto desde donde se realiza la llamada, entonces n a la cual se desea llamar. Dicho prototipo debera colocarse debe crearse un prototipo de la funcio n, y consta u nicamente de la cabecera de antes del punto donde se haga la primera llamada a la funcio n. dicha funcio n puede interpretarse como un aviso al compilador, para que cuando El prototipo de una funcio n pueda conocer el tipo del resultado que devuelve y la informacio n encuentre una llamada a dicha funcio metros que recibe. sobre los para n se muestra el formato general de un prototipo, que corresponde a la cabecera de la A continuacio n seguida de un punto y coma: funcio tipo nombre funci on(tipo1 param1, ..., tipoN paramN); De acuerdo con esto, el programa del ejemplo anterior podr a haberse escrito de otro modo, de n fact con posterioridad a main y usando un prototipo: niendo la funcio #include <stdio.h> long int fact ( int x ); /* Prototipo */

void main() long int m, n; float res; printf( "Introduzca m y n: " ); scanf( "%d %d", &m, &n ); res = (float) fact(m) / ((float)fact(n)*(float)fact(m-n)); printf( "m sobre n = %fnn", res );

g f

long int fact ( int x ) int i; long int f = 1; for (i= 2; i<= x; i++) f = f * i; return(f);

n de prototipos de funciones no es obligatorio en C. Sin embargo, es aconsejable, ya La utilizacio n y deteccio n de errores entre las llamadas a funciones y las deniciones que facilitan la comprobacio correspondientes.

Los autores, 2000; Edicions UPC, 2000.

91

10. Funciones

10.2.3 Llamada
n se realiza con el nombre de la misma y una lista de para metros Finalmente, la llamada a una funcio ntesis. El nu mero y tipo de los para metros empleados en la llamada a (si es que los requiere) entre pare n debe coincidir con el nu mero y tipo de los para metros formales de la denicio n o prototipo. la funcio n devuelve algu n valor (es decir, no es de tipo void) la llamada a la Adicionalmente, si la funcio n debe estar incluida en una expresio n que recoja el valor devuelto. Siguiendo con el ejemplo del funcio factorial: fm = fact(m); prod = fact(n)*fact(m-n); n reciben el nombre de par Los datos empleados en la llamada a una funcio ametros reales, ya que n que se transere a la funcio n para que e sta se ejecute. Como veremos ma s se reeren a la informacio metros formales son locales a la funcio n, en el sentido de que adelante, los identicadores de los para sta. Por tanto, los nombres de los para metros formales no tienen no son reconocidos desde fuera de e coincidir con los nombres de la variables usadas como para metros reales en el momento de la por que llamada.

metros 10.3 Variables y para


n del a Las variables de un programa pueden clasicarse en funcio mbito en el cual son conocidas y por mbito de las variables, as tanto accesibles. El a como su tiempo de vida, depende del lugar donde se hallen declaradas dentro del programa. As pues, se distinguen los siguientes tipos: variables locales, metros formales. variables globales y para

10.3.1 Variables locales


n (esto incluye a la funcio n Una variable local se halla declarada al comienzo del cuerpo de una funcio mbito se circunscribe al bloque de sentencias que componen el cuerpo de la funcio n, por main). Su a lo son conocidas dentro de e l. Por otra parte, su tiempo de vida va desde que se entra en la lo que so n hasta que se sale de ella, por lo que las variables locales se crean al comenzar la ejecucio n de funcio n y se destruyen al concluir dicha ejecucio n. la funcio lculo de En el ejemplo del ca

m n

n fact, por , las variables i y f son locales a la funcio

lo que no son accesibles fuera de ella. De forma similar, las variables m, n y res son locales a la n main. funcio

10.3.2 Variables globales


n del programa al principio del chero Una variable global se halla declarada fuera de toda funcio mbito se extiende a lo largo de todas las funciones del programa. Su tiempo de vida esta principal. Su a n del programa, por lo que las variables globales se crean al limitado por el tiempo que dura la ejecucio ste concluye la ejecucio n. comenzar a ejecutar el programa y se destruyen cuando e n incluidas en un mismo chero, basta con escribir una Si todas las funciones del programa esta n de las variables globales. Sin embargo, si tenemos las sola vez al principio del chero la declaracio

Los autores, 2000; Edicions UPC, 2000.

10.3. Variables y par ametros

92

n y funciones repertidas en diferentes cheros, deberemos incluir en uno de los cheros la declaracio s cheros la declaracio n precedida de la palabra extern. Tambie n es posible repetir en los dema nicamente dentro de un chero. Para ello antepondremos en la declaracio n denir variables globales u la palabra static. El siguiente ejemplo muestra las declaraciones de tres variables globales. La variable A es accesible declarada en este chero. La variable B es accesible en todo el programa, en todo el programa y esta declarada en otro chero, es decir, hay otras funciones adema s de las de este chero que pero esta lo es accesible por las funciones de este chero. pueden acceder a ella. Finalmente, la variable C so int A; extern int B; static int C; void main ()

f g f g f g

int func1() . . .

int func2() . . .

n, puesto que al poderse modicar desde El uso de variables globales debe hacerse con precaucio n del programa donde sean accesibles, pueden producirse efectos laterales dif cualquier funcio ciles de detectar y corregir. Es una buena pr actica de programaci on no emplear variables globales salvo en casos muy excepcionales. En general, el uso de una variable global puede substituirse por una varia metros a todas las funciones que requieran ble local al programa principal y el adecuado paso de para acceder a dicha variable.

metros formales 10.3.3 Para


mbito y el tiempo de vida de un para metro formal en una funcio n son los mismos que los de una El a n. Es decir, que el a mbito es toda la funcio n y que la variable se crea al variable local a dicha funcio n y se destruye al salir de la misma. entrar en la funcio mbito de las variables locales y los para metros de una funcio n se Como hemos comentado, el a nicamente al interior de la misma. Es decir, que ni las variables ni los para metros formales circunscribe u n son accesibles desde fuera de ella. Incluso en el caso de que el programa use el mismo de una funcio nombre para variables de distintas funciones, el compilador es capaz de diferenciarlas. Para demostrar sto usaremos el operador de direccio n & en un ejemplo muy sencillo: e

Los autores, 2000; Edicions UPC, 2000.

93

10. Funciones

void func( int par )

f g f

int loc = 10; printf( "En func(), loc=%d y &loc=%pnn", loc, &loc ); printf( "En func(), par=%d y &par=%pnn", par, &par );

void main() int loc = 24, par = 5; printf( "En main(), loc=%d y &loc=%pnn", loc, &loc ); printf( "En main(), par=%d y &par=%pnn", par, &par ); func(loc);

an en direcAl compilar y ejecutar este ejemplo, observaremos que las variables loc y par se situ n o ciones de memoria diferentes (y por tanto, son variables diferentes) si estamos dentro de la funcio en el programa principal.

n de resultados 10.4 Devolucio


n termina de realizar la tarea para la que fue disen ada, devuelve el control de la Cuando una funcio n a la parte del programa desde donde se hizo la llamada. Para concluir la ejecucio n de una ejecucio n se utiliza la sentencia return, que fuerza la salida de la funcio n en el punto donde se ha funcio n termina con la llave especicado dicha sentencia. Si no existe ninguna sentencia return, la funcio que cierra el cuerpo. n para el ca lculo del ma ximo El siguiente ejemplo muestra dos maneras de escribir la misma funcio meros enteros: de dos nu void maximo( int x, int y )

void maximo( int x, int y )

f f

int max; if (x > y) max = x; else max = y; printf( "MAX=%d", max );

if (x > y) printf( "MAX=%d", x ); return;

g g

printf( "MAX=%d", y );

n no es de tipo void, la sentencia return, adema s de especicar la terminacio n Si la funcio n, puede especicar la devolucio n de un valor para que pueda ser utilizado en el punto de la funcio n, puede ser cualquiera de donde se hizo la llamada. El valor devuelto, y por ende el tipo de la funcio los tipos elementales, estructurados o denidos por el programador, excepto tablas. Aunque en C es n retorne cualquier tipo de estructura, por cuestiones de eciencia en la ejecucio n legal que una funcio o. Por ejemplo, estructuras del programa no es conveniente retornar estructuras muy grandes en taman n devuelva tipos de datos complejos, se en cuyo interior haya tablas. Cuando se desea que una funcio metros por referencia que veremos en la seccio n 10.5. utiliza el paso de para

Los autores, 2000; Edicions UPC, 2000.

10.5. Paso de par ametros

94

n maximo para que devuelva el ma ximo de dos En el siguiente programa se ha rescrito la funcio enteros, en lugar de mostrarlo por pantalla.

int maximo( int x, int y ) if (x > y) return(x); else return(y);

n dentro de En la parte del programa que hace la llamada puede usarse el valor devuelto por la funcio n va lida (en particular una sentencia de escritura): cualquier expresio printf( "MAX(%d,%d)=%d", a, b, maximo(a,b) );

metros 10.5 Paso de para


metros de una funcio n no son ma s que variables que actu an de Como ya hemos comentado, los para n. As enlace entre la parte del programa donde se realiza la llamada y el cuerpo de la funcio pues, metros formales de una funcio n son variables locales a e sta. Como tales, se crean y reciben los para n, y se destruyen al salir de la misma. El paso de para metros puede sus valores al entrar en la funcio realizarse de dos formas: por valor o por referencia.

metros por valor 10.5.1 Paso de para


n, los para metros formales reciben una copia del valor de los para metros reales. Por Al entrar a la funcio metros formales son locales y no afectan a los para metros reales tanto las modicaciones sobre los para n. Veamos un ejemplo: de la parte del programa que hace la llamada a la funcio #include <stdio.h> void cuadrado ( int x )

f g f

x = x * x; printf( "Dentro x = %dnn", x );

void main() int x = 5; printf( "Antes x = %dnn", x ); cuadrado( x ); printf( "Despu es x = %dnn", x );

: El resultado de ejecutarlo sera

Los autores, 2000; Edicions UPC, 2000.

95

10. Funciones

Antes x = 5 Dentro x = 25 Despu es x = 5 n sobre el para metro formal no afecta a la variable del programa Como puede verse, la modicacio principal. metros por valor, la transferencia de informacio n es so lo en un sentido, es decir, En el paso de para n, pero no al reve s. desde la parte del programa donde se hace la llamada hacia el interior de la funcio metros reales, en lugar de necesariamente Gracias a ello, es posible utilizar expresiones como para metro formal es el resultado de la evaluacio n variables. Esto es as puesto que el valor asignado al para n. Es ma s, si el para metro real es una variable, su valor es protegido de posibles de dicha expresio n. modicaciones por parte de la funcio

metros por referencia 10.5.2 Paso de para


mo proporcionar datos a una funcio n (paso de para metros por valor) Hasta este punto hemos visto co mo hacer que la funcio n devuelva resultados con la sentencia return. Sin embargo, co mo o co n devolviese ma s de un valor? O bien, co mo podr podr amos hacer que una funcio amos conseguir que metros formales afectasen tambie n a los para metros reales? Es decir, las modicaciones sobre los para mo podr mbito en el que se realizo la llamada desde el interior de una co amos modicar variables del a n? funcio n del paso de para metros por referencia. Este La respuesta a estas cuestiones se halla en la utilizacio metros se conoce tambie n en C como paso por direcci tipo de paso de para on o paso por puntero. metros reales son una referencia (puntero) a las variables de la parte del proEn este caso los para metros formales, grama que realiza la llamada y no las variables en s . La referencia se copia en los para n puede usarse dicha referencia para modicar una variable que, de de forma que dentro de la funcio n (modicar el valor referenciado). otra forma, no ser a accesible desde el interior de la funcio n ( & ) y puntero El paso de parametros por referencia implica el uso de los operadores de direccio ( * ) de C: n de memoria en que se halla ubicada. & , que antepuesto a una variable permite obtener la direccio en los para metros reales de la llamada a una funcio n para pasarle por referencia dicha Se usara metro que se pasa a la funcio n es un puntero a una variable. variable. En otras palabras, el para n scanf, donde las variables Ya hemos utilizado esto anteriormente en las llamadas a la funcio en que se almacenan los valores le dos del teclado se pasan por referencia. n de los para metros formales de la funcio n como en el * , que se utiliza tanto en la declaracio precediendo al nombre de un para metro formal en la cabecera cuerpo de la misma. Aparecera metro sera pasado por referencia (sera un puntero). Aparecera en el para indicar que dicho para n, antepuesto al nombre de un para metro formal, para acceder al valor de la cuerpo de la funcio n y referenciada por el para metro formal. variable externa a la funcio n swap que intercambia el valor de sus dos para metros. En el siguiente ejemplo se muestra la funcio metros formales x e y se han declarado de paso por referencia usando * en la Para ello los para n se ha usado & para pasar a la funcio n cabecera. De forma complementaria, en la llamada a la funcio n usamos nuevamente una referencia a las variables a y b del programa principal. Dentro de la funcio

Los autores, 2000; Edicions UPC, 2000.

10.5. Paso de par ametros

96

metro real. Por ejemplo, la sentencia aux = *x; asigna a la * para referenciar el valor del para metro formal variable local aux el valor de la variable a del programa principal, puesto que el para x contiene una referencia a la variable a. #include <stdio.h> void swap(int *x, int *y) int aux; /* Se asigna a aux el valor referenciado por x */ aux = *x; /* Se asigna el valor referenciado por y al valor referenciado por x */ *x = *y; /* El valor referenciado por y pasa a ser el valor de aux */ *y = aux;

g f

void main() int a, b; scanf( "%d %d", &a, &b ); swap( &a, &b ); printf( "Los nuevos valores son a=%d y b=%dnn", a, b );

metros por referencia tiene una estrecha relacio n con el uso de Como puede verse, el paso de para punteros y direcciones de memoria que vimos en el cap tulo 9. De hecho un purista del lenguaje dir a metros se hace por valor. El paso por que en C no existe el paso por referencia y que todo paso de para n y referencia se simula mediante el paso (por valor) de punteros a las variables externas a la funcio que se desean modicar desde el interior de la misma.

10.5.3 Las tablas y las funciones


Los elementos individuales de una tabla (vector, matriz, etc.) se pasan a las funciones como si de variables individuales se tratase, tanto por valor como por referencia. meros enteros. Para ello utiliza la El siguiente ejemplo busca el elemento mayor en un vector de nu n maximo que vimos anteriormente. Obse rvese el paso por referencia del elemento i-e simo de funcio n scanf y, por valor, a la funcio n maximo. un vector, a la funcio #include <stdio.h> void main() int max, v[20], i; printf( "Introducir elementos del vector:nn" ); for (i= 0; i< 20; i++)

Los autores, 2000; Edicions UPC, 2000.

97

10. Funciones

scanf( "%d", &v[i] ); max = v[0]; for (i= 1; i< 20; i++) max = maximo( max, v[i] ); printf( "El elemento mayor es:

%dnn", max );

n. La u nica manera que C ofrece para ello Algo muy diferente es el paso de una tabla a una funcio n. Sin embargo, al contrario que en el paso por es el paso por referencia de toda la tabla en cuestio referencia habitual, no se usan los s mbolos & y * . En su lugar se utiliza directamente el nombre de la tabla, que constituye de por s una referencia al primer elemento de la tabla, tal como vimos en el metro formal de la funcio n debe ser un puntero para poder recoger la cap tulo 9. Por lo tanto, el para n de inicio de la tabla. direccio n para el ca lculo de la media de los elementos de un vector El siguiente ejemplo dene una funcio meros de coma otante: de nu #include <stdio.h> #define DIM 20 float media( float vec[], int n )

int j; float sum; sum = 0.0; for (j= 0; j< n; j++) sum = sum + vec[j]; return (sum/(float)n);

g f

void main() float med, v[DIM]; int i; printf( "Introducir elementos del vector:nn" ); for (i= 0; i< DIM; i++) scanf( "%f", &v[i] ); med = media( v, DIM ); printf( "La media es: %fnn", med );

n media hubiese podido escribirse tambie n como: La cabecera de la funcio float media( float *vec, int n ) n del para metro vec en la funcio n media es una declaracio n Es importante notar que la denicio de un puntero. Es decir, no existe diferencia alguna entre float *vec y float vec[]. El mo n es dar mayor claridad al programa. Por lo tanto, cuando un para metro tivo de usar esta nueva notacio

Los autores, 2000; Edicions UPC, 2000.

10.5. Paso de par ametros

98

n tipo nombrePuntero[], mientras que cuansea un puntero a una tabla usaremos la notacio do tengamos un puntero a cualquier otro tipo de datos (tanto tipos elementales como estructurados) n tipo *nombrePuntero. usaremos la notacio n media tambie n pudiera haberse escrito como: Finalmente, la cabecera de la funcio float media( float vec[DIM], int n ) metro vec es un puntero a una tabla, pero ahora adema s indicamos el En este caso de nuevo el para o de la tabla, lo que clarica au n ma s el programa. Notar que esto so lo es posible hacerlo si las taman nes de la tabla son constantes. Es decir, una expresio n como dimensio float media( float vec[n], int n ) ser a incorrecta. n que multiplique una matriz Vemos ahora un ejemplo con una matriz. Deseamos hacer una funcio n propuesta es la siguiente: por un vector. La solucio #include <stdio.h> #define MAXFIL 3 #define MAXCOL MAXFIL void matXvec( int nfil, int ncol, float A[], float x[], float y[] ) f /*Calcula y = A*x */ int i, j; for (i= 0; i< nfil; i++)

f g

y[i] = 0.0; for (i= 0; i< ncol; i++) y[i] = y[i] + A[i*MAXCOL+j] * x[j];

g f

void main() int nfil, ncol; float v1[MAXCOL], v2[MAXFIL], M[MAXFIL][MAXCOL]; ... /* Leer los nfil, ncol, A, x */ matXvec( nfil, ncol, M, v1, v2 ); ... /* Mostrar y */

tese que los para metros formales A, x e y son todos punteros. Se accede a los elementos de No s de un puntero que sen ala al primer elemento ([0][0]). En la seccio n 9.4 vimos la matriz a trave tese tambie n que en la fo rmula que da el nu mero de la forma de realizar un acceso de este tipo. No elementos entre el primero y el elemento [i][j], se debe usar MAXCOL y no ncol. Es decir,

Los autores, 2000; Edicions UPC, 2000.

99

10. Funciones

A A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] M[0][0] ncol=2 M[0][1] M[0][2] MAXCOL = 3 M[1][0] M[1][1] M[1][2] M[2][0] M[2][1] M[2][2]
Figura 10.1: Acceso a una matriz mediante un puntero debemos contar todos los elementos que hay en memoria entre el primero y el elemento [i][j], camente incluyendo los que no son usados por el algoritmo. La gura 10.1 muestra este ejemplo gra suponiendo que ncol vale 2, MAXCOL vale 3, y que queremos acceder el elemento [2][1] de la matriz.

i*MAXCOL+j = 2*3+1=7

metros en la funcio n main 10.5.4 Para


n main sin para metros. Sin embargo, es posible pasar Hasta el momento hemos empleado la funcio metros a la funcio n principal del programa, desde la l rdenes del sistema operativo. Los para nea de o metros de la funcio n main son dos; se conocen tradicionalmente como argc y argv, aunque para pueden tomar cualquier nombre. metro argc es un valor entero que contiene el nu mero de para metros dados al programa El para rdenes del sistema operativo. El nombre del programa se considera al ser ejecutado desde la l nea de o metro, por lo que el valor m como el primer para nimo de argc es 1. metro argv es un vector de punteros a cadenas de caracteres. Estas cadenas toman el valor El para metros dados al programa al ejecutarlo. Cada para metro de la l rdenes de cada uno de los para nea de o debe estar separado por un espacio o un tabulador.

Los autores, 2000; Edicions UPC, 2000.

10.6. Recursividad

100

n main con para metros es el siguiente: As pues, el formato de la funcio

f g

void main( int argc, char *argv[] ) /* Cuerpo de la funci on. */

El siguiente programa de ejemplo permite introducir el nombre del usuario del programa al ejecutarlo y mostrar un mensaje que lo incluya. #include <stdio.h> void main( int argc, char *argv[] ) if (argc > 2)

f g f g f g g

printf( "Demasiados par ametrosnn" );

else if (argc < 2) printf( "Faltan par ametrosnn" );

else printf( "Yo te saludo %snn", argv[1] );

rdenes As pues, si hemos llamado al programa ejecutable saludo y se escribe en la l nea de o : del sistema operativo saludo Pepe, la salida del programa sera Yo te saludo Pepe metros que se pasan al programa contiene espacios en blanco o tabuladores, Si alguno de los para n del programa. deben usarse comillas en la ejecucio L nea de o erez" rdenes del sistema operativo: saludo "Pepe P Salida del programa: Yo te saludo Pepe P erez

10.6 Recursividad
n se llama a s Se llama recursividad a un proceso en el que una funcio misma repetidamente hasta n. Este proceso se emplea para ca lculos repetitivos en los que el que se satisface una cierta condicio n se determina a partir del resultado de alguna iteracio n anterior. resultado de cada iteracio Frecuentemente un mismo problema puede expresarse tanto de forma recursiva como de forma ite n recursiva requiere de numerosas llamadas a funciones, rativa. En estos casos, debido a que la ejecucio n no recursiva. Sin embargo, en otros casos, la escritura de una solues preferible utilizar una solucio n no recursiva puede resultar extraordinariamente compleja. Es entonces cuando es apropiada una cio n recursiva. solucio

Los autores, 2000; Edicions UPC, 2000.

101

10. Funciones

n se presentan dos funciones recursivas para el ca lculo del factorial y el ca lculo de A continuacio valores de la serie de Fibonacci:

f g f g

int fact( int x ) if (x <= 1) return (1); return (x * fact(x-1));

int fibo( int n ) if ((n==0) || (n==1)) return (1); return (fibo(n-1)+fibo(n-2));

n recursiva es este programa para invertir los elementos de un vector usando Otro ejemplo de solucio n swap: la funcio #define N 10 void invert( int v[], int i, int j ) swap( &v[i], &v[j] ); i++; j--; if (i < j) invert( v, i, j );

g f

void main() int i, vector[N]; for(i= 0; i< N; i++) scanf( "%d", &vector[i] ); invert( v, 0, N-1 ); for(i= 0; i< N; i++) printf( "%dnn", vector[i] );

10.7 Ejercicios
lculo de 1. El ca

ex

lculo de puede aproximarse mediante el ca

n pot grande. Escribir una funcio metros enteros de la funcio n. Usando esta funcio n y la funcio n fact del donde i y x son para

n sucientemente sima de un nu mero x, que permita calcular la potencia i-e


=0

n xi X i i
!

para

Los autores, 2000; Edicions UPC, 2000.

10.7. Ejercicios

102

principio del cap tulo, escribir un programa que calcule ex de forma aproximada para un valor de n dado. 2. Escribir un programa para calcular frac del problema anterior. 3. Escribir un programa para calcular frac. 4. Se dispone de las dos funciones siguientes:

sen x
(

) =

1 xi X i i
=0

2 +1

(2

+ 1)!

1)

i . Utilizar las funciones pot y

cos x
(

) =

1 xi X i ; i
2 =0

(2 )!

1)

i . Utilizar las funciones pot y

void f1( int x, int *y, int a, int b ) x = x + *y = *y x = x + *y = *y printf( 1; + 1; a; + b; "%d %dnn", x, *y );

g f

void f2( int a, int *b ) a = a + *b = *b a = a + *b = *b printf( 1; + 1; a; + *b; "%d %dnn", a, *b );

Y del programa principal: #include <stdio.h> void main() int a = 0, b = 0; llamada printf( "%d %dnn", a, b );

Indicar el resultado de ejecutar este programa en caso de que llamada se substituya por: f1( a, &b, a, b ); o bien por f2( a, &b ); n se muestra el esqueleto de un programa en C: 5. A continuacio

Los autores, 2000; Edicions UPC, 2000.

103

10. Funciones

int f1( char a, char b )

f g f g f

a = P; b = Q; return ((a<b)?(int)a:(int)b);

int f2( char *c1, char *c2 ) *c1 = R; *c2 = S; return ((*c1==*c2)?(int)*c1:(int)*c2);

void main() char a, b; int i, j; . . . a = X; b = Y; i = f1( a, b ); printf( "a=%c,b=%cnn", a, b ); . . . j = f2( &a, &b ); printf( "a=%c,b=%cnn", a, b );

valores se asignan a i y j en main? (a) Que valores escribe la primera llamada a printf? (b) Que valores escribe la segunda llamada a printf? (c) Que valor calcula el siguiente programa? 6. Que

void func( int p[] ) int i, sum = 0; for(i= 3; i< 7; ++i) sum = sum + p[i]; printf( "suma = %d", sum );

g f g

void main() int v[10] = f1,2,3,4,5,6,7,8,9,10g; func( &v[2] );

Los autores, 2000; Edicions UPC, 2000.

10.7. Ejercicios

104

mero no negativo es perfecto o tiene algu n amigo. Dos nu meros son amigos 7. Determinar si un nu mero. Por ejemplo: 220 y 284 cuando la suma de los divisores de uno de ellos es igual al otro nu mero es perfecto cuando la suma de sus divisores es e l mismo. son amigos. Por otra parte, un nu Por ejemplo 6 = 3 + 2 + 1 es perfecto. 8. Dado el siguiente tipo de datos: #include <stdio.h> typedef struct

f g

char a[10]; char b[10]; char c[10]; Tcolores;

describir la salida generada por cada uno de los siguientes programas: (a) void func( Tcolores X )

g f

X.a = "cian"; X.b = "magenta"; X.c = "amarillo"; printf( "%s%s%snn", X.a, X.b ,X.c ); return();

void main() Tcolores col = f "rojo", "verde", "azul" g; printf( "%s%s%snn", col.a, col.b, col.c ); func( col ); printf( "%s%s%snn", col.a, col.b, col.c );

g
(b)

void func(Tcolores *X)

g f

X->a = "cian"; X->b = "magenta"; X->c = "amarillo"; printf( "%s%s%snn", X->a, X->b, X->c ); return();

void main() Tcolores col = f "rojo", "verde", "azul" g; printf( "%s%s%snn", col.a, col.b, col.c ); func( & col ); printf( "%s%s%snn", col.a, col.b, col.c );

Los autores, 2000; Edicions UPC, 2000.

105

11. Ficheros

Cap tulo 11

Ficheros
n mecanismo que permita almacenar de forma permamente ciertos datos de los proEs preciso algu gramas. Por ejemplo, un programa que gestione la contabilidad de una empresa necesita una serie de informaciones iniciales (balance hasta ese momento, lista de compras, lista de ventas, etc ). De igual forma, genera una serie de informaciones que deben ser almacenadas cuando el programa naliza. n de Desde el punto de vista del hardware, hay diferentes dispositivos para almacenar informacio forma permanente: discos duros, unidades de cinta, CDs, disquetes, etc. Para un programador, el dispon sitivo f sico que se use carece de importancia. Los programas deben funcionar tanto si la informacio en un disco duro como en un CD como en una cinta. Por lo tanto, es preciso un conjunto de funcioesta n, pero omitiendo los nes (una librer a) que permita realizar almacenamiento permamente de informacio detalles espec cos de cada dispositivo hardware. Esta librer a de funciones la proporciona el sistema operativo. Para ocultarle al programador los detalles espec cos de cada dispositivo hardware, se usa el con n. cepto de chero. Un chero es un objeto abstracto sobre el cual se puede leer y escribir informacio Existen dos tipos fundamentales de cheros: cheros de texto y cheros binarios. En los cheros n se almacena usando caracteres (co digos ASCII). Por ejemplo, una variable de de texto la informacio tipo int se almacena en la memoria como una secuencia de bits que debe ser interpretada como digo complemento a dos. Sin embargo, cuando escribimos dicha variable en un chero de texto, un co lo que almacenamos es un conjunto de caracteres que representan el valor de la variable en base 10. Una variable tipo de int que en memoria se almacenase como 1 0 0 en un chero de texto se n se almacena de igual forma que escribir a como ;2147483648. En los cheros binarios la informacio en la memoria, mediante la misma secuencia de unos y ceros. n almacenada puede ser visualizada y Usar cheros de texto tiene la ventaja de que la informacio comprendida por un ser humano. Pero tiene el inconveniente de ocupar aproximadamente tres veces s espacio que los cheros binarios. Por ejemplo, la variable de tipo int mostrada anteriormente, ma ocupa 4 bytes en un chero binario (lo mismo que ocupa en memoria), y ocupa 11 bytes (signo y 10 cifras) en un chero de texto. Existen diferentes funciones para trabajar con cheros de texto y con cheros binarios. En este nicamente de los cheros de texto. libro nos ocuparemos u n como una secuencia de co digos ASCII. La gura 11.1 Un chero de texto almacena la informacio muestra un ejemplo de almacenamiento de un chero de texto. En esta gura se muestra el aspecto que

z }| {
31

Los autores, 2000; Edicions UPC, 2000.

106

Esto es un ejemplo de cmo se almacena un chero de texto.

Ventana de acceso

69 115 116 111 32 101 115 10 ... 130 116 111 EOF

Cdigo del carcter E Cdigo del carcter s Cdigo del carcter t Cdigo del carcter o Cdigo del carcter Espacio en blanco Cdigo del carcter e Cdigo del carcter s Cdigo del carcter \n Cdigo del carcter t Cdigo del carcter o Cdigo del carcter .

Figura 11.1: Almacenamiento de un chero de texto tendr a un chero de texto al mostrarse en pantalla, as como la secuencia de bytes que se almacenar an cter especial que indica el nal del chero. en disco. Todos los cheros de texto nalizan com un cara cter lo representamos mediante la constante EOF (End Of File) que se halla denida en el Este cara chero stdio.h. n en un chero de texto deberemos hacerlo de forma Cuando queramos leer o escribir informacio secuencial. Por ejemplo, si queremos leer el chero de la gura 11.1, deberemos leer en primer lugar el cter y as lo primer cara sucesivamente. Esto se debe a que existe una ventana asociada al chero que so puede avanzar secuencialmente, nunca a saltos. El sistema operativo usa variables del tipo FILE para manejar los dispositivos hardware asociados n del tipo FILE se encuentra en el chero stdio.h. Todos los programas a cheros. La denicio n incluir stdio.h. Una variable del tipo FILE es una estructura cuyo que manejen cheros debera lo puede ser entendido y manejado por funciones del sistema operativo. Dicha estructura contenido so n, por ejemplo, de la pista y el sector del disco donde comienza el chero, etc. contiene informacio Dado que las variables de tipo FILE pertenecen al sistema operativo, nunca tendremos una variable nico que necesitamos son punteros a dichas variables. Esto de este tipo en nuestros programas. Lo u n como la es, si queremos manejar un chero dentro de un programa, deberemos tener una declaracio siguiente: FILE *fp; n fopen, de forma que apunte a una El puntero fp debe ser inicializado mediante la funcio variable del sistema operativo que contenga los datos del chero concreto que usemos. Las funciones nicamente necesitan conocer dicho puntero para saber la variable de lectura y escritura en el chero u que deben usar. Para utilizar un chero se debe realizar una secuencia ja de acciones:

Los autores, 2000; Edicions UPC, 2000.

107

11. Ficheros

1. Abrir el chero. Esto signica decirle al sistema operativo que inicialice una variable de tipo FILE, de forma que a partir de ese momento, las acciones de lectura/escritura que utilicen dicha variable se realicen realmente en el dispositivo hardware correspondiente. Esto se hace llamando n fopen. a una funcio 2. Leer o Escribir en el chero. Para ello usaremos las funciones fscanf y fprintf. Estas lo necesitan dos datos: la variable de tipo FILE asociada al chero y la informacio n funciones so que queremos leer o escribir en dicho chero. 3. Cerrar el chero. Esto signica indicar al sistema operativo que ya no necesitamos la variable n fclose. tipo FILE asociada al chero. Para ello se usa la funcio

11.1 Abrir y cerrar cheros


n fopen es la siguiente: La cabecera de la funcio FILE * fopen( char nombreFichero[], char modoAcceso[] ) donde nombreFichero es una cadena de caracteres con el nombre del chero f sico que se quiere n que realizaremos sobre el usar, y modoAcceso es una cadena de caracteres que indica la accio chero. sicos para abrir cheros: Existen tres modos ba "r": Abrir un chero ya existente para lectura. destruido y creado de "w": Abrir un chero nuevo para escritura. Si el chero ya exist a, sera nuevo. adir informacio n; esto es, escribir al nal del mismo. "a": Abrir un chero ya existente para an uno nuevo. Si el chero no exist a se creara s de estos modos existen otros de uso menos frecuente: Adema "r+": Abrir un chero ya existente tanto para lectura como escritura. "w+": Abrir un chero nuevo tanto para lectura como escritura. Si el chero ya exist a sera destruido y creado de nuevo. adir. Si el chero no exist uno "a+": Abrir un chero ya existente para leer y an a se creara nuevo. n fopen retorna la constante NULL si no ha podido abrir el chero. Esta condicio n de La funcio n fopen. La constante NULL esta denida error debe ser comprobada siempre que se use la funcio en stdio.h. rselo al sistema operativo mediante Cuando ya hemos acabado de utilizar el chero, debemos indica n fclose, que libera la variable de tipo FILE asociada al chero. La cabecera de la funcio n la funcio fclose es la siguiente:

Los autores, 2000; Edicions UPC, 2000.

11.1. Abrir y cerrar cheros

108

int fclose( FILE *fp ) n error al cerrar el chero fclose retorna 0. En caso contrario retorna la Si no se produce ningu denida en stdio.h). Veamos algunos ejemplos constante EOF (recordemos que esta constante esta del uso de fopen y fclose. n En el siguiente ejemplo abrimos un chero llamado miFichero.txt para leer la informacio l. En caso de error al abrir el chero mostramos un mensaje en pantalla y nalizamos la contenida en e n del programa mediante la funcio n exit. Finalmente cerramos el chero. ejecucio #include <stdio.h> void main( ) FILE *fp; fp = fopen( "miFichero.txt", "r" ); if (fp == NULL)

f g

printf( "Error abriendo miFichero.txtnn" ); exit(0);

. . . /* Aqu podemos leer datos del fichero */ . . . fclose( fp );

n se muestra otro ejemplo para el caso en que abrimos un chero para escritura. A continuacio s del teclado. Si el chero ya existe, sera El nombre del chero es introducido por el usuario a trave n la realiza de forma automa tica la funcio n fopen. Finalmente destruido y creado de nuevo. Esta accio cerramos el chero. #include <stdio.h> #define N 256 void main( )

FILE *fp; char nombreFichero[N]; printf( " Nombre del fichero (< %d caracteres): scanf( "%s%*c", nombreFichero ); fp = fopen( nombreFichero, "w" ); if (fp == NULL) ", N );

f g

printf( "Error abriendo %snn", nombreFichero ); exit(0); . .

Los autores, 2000; Edicions UPC, 2000.

109

11. Ficheros

/* Aqu podemos escribir datos en el fichero */ . . . fclose( fp );

11.2 Leer y escribir en cheros


l mediante las funciones fscanf y fprint. Una vez abierto un chero, podemos leer y escribir en e Las cabeceras de estas funciones son: int fscanf( FILE *fp, char formato[], <lista variables> ) int fprintf( FILE *fp, char formato[], <lista variables> ) n fscanf permite leer del chero apuntado por fp, mientras que la funcio n fprintf perLa funcio logo al de scanf y mite escribir en el chero apuntado por fp. El uso de estas funciones es ana printf, que permiten leer variables desde el teclado y escribir variables en pantalla, respectivamente. Por tanto, formato es una cadena de caracteres que describe el formato de las variables a leer/escribir. Por su parte, <lista variables> contiene las direcciones de memoria de todas las variables en el caso de fscanf y las variables propiamente dichas en el caso de fprintf. Los operadores de ndice B. formato se hallan descritos en el ape n fprintf retorna el nu mero de bytes (caracteres) escritos en el chero, o un nu mero La funcio n error en la escritura. La funcio n fscanf retorna el nu mero de negativo en caso de que ocurra algu variables correctamente le das, o la constante EOF en caso de error. Veamos algunos ejemplo de uso de fscanf y fprintf. En el siguiente ejemplo leemos un vector de enteros de un chero de entrada. El chero contiene en mero de elementos del vector. El resto de l la primera l nea el nu neas del chero contienen un elemento del vector en cada l nea. Finalmente, el programa escribe el vector en un chero de salida usando el mismo formato que en el chero de entrada. #include <stdio.h> #define N 256 #define MAXELE 100 void main( )

FILE *fp; char nombreFichero[N]; int lon = 0; int vec[MAXELE]; printf( "Fichero de entrada(< %d caracteres): scanf( "%s%*c", nombreFichero ); fp = fopen( nombreFichero, "r" ); if (fp == NULL) ", N );

printf( "Error abriendo %snn", nombreFichero );

Los autores, 2000; Edicions UPC, 2000.

11.2. Leer y escribir en cheros

110

g f g

exit(0);

fscanf( fp, "%d", &lon ); if (lon < MAXELE) for (i= 0; i< lon; i= i+1) fscanf( fp, "%d", &vec[i] );

else printf( "El vector tiene demasiados elementosnn" ); fclose( fp ); . . . /* Aqu podemos modificar vec */ . . . printf( "Fichero de salida(< %d caracteres): ", N ); scanf( "%s%*c", nombreFichero ); fp = fopen( nombreFichero, "w" ); if (fp == NULL)

f g

printf( "Error abriendo %snn", nombreFichero ); exit(0);

fprintf( fp, "%dnn", lon ); for (i= 0; i< lon; i= i+1) fprintf( fp, "%dnn", vec[i] ); fclose( fp );

En el ejemplo anterior, si el nombre del chero de salida es el mismo que el nombre del chero de n, ya que al abrir el chero en modo "w", el chero que ya exist entrada, los datos iniciales se perdera a es destruido y creado de nuevo. En este ejemplo, sin embargo, leemos de un chero y el resultado del adido al nal del mismo chero. programa es an #include <stdio.h> #define N 256 #define MAXELE 100 void main( )

FILE *fp; char nombreFichero[N]; int lon; int vec[MAXELE]; printf( "Nombre del fichero(< %d caracteres): scanf( "%s%*c", nombreFichero ); fp = fopen( nombreFichero, "r" ); if (fp == NULL) ", N );

Los autores, 2000; Edicions UPC, 2000.

111

11. Ficheros

f g f g

printf( "Error abriendo %snn", nombreFichero ); exit(0);

fscanf( fp, "%d", &lon ); if (lon < MAXELE) for (i= 0; i< lon; i= i+1) fscanf( fp, "%d", &vec[i] );

else printf( "El vector tiene demasiados elementosnn" ); fclose( fp ); . . . /* Aqu trabajamos con vec */ . . . fp = fopen( nombreFichero, "a" ); if (fp == NULL)

f g

printf( "Error abriendo %snn", nombreFichero ); exit(0);

fprintf( fp, "%dnn", lon ); for (i= 0; i< lon; i= i+1) fprintf( fp, "%dnn", vec[i] ); fclose( fp );

11.3 Otras funciones para el manejo de cheros


11.3.1 feof
o a priori y, por lo tanto, sin En la mayor a de ocasiones debemos leer un chero sin saber su taman n se hace necesaria una funcio n que nos saber la cantidad de datos que debemos leer. En esta situacio ndo se alcanza el nal de chero. Esta funcio n es feof, cuya cabecera es la siguiente: indique cua int feof( FILE *fp ) n feof retorna un nu mero diferente de 0 (cierto) cuando el cara cter especial EOF ha La funcio alado por fp. En caso contrario, retorna 0 (falso). sido alcanzado en una lectura previa del chero sen n feof so lo indica n de chero si previamente hemos Es muy importante notar que la funcio cter realizado una lectura mediante fscanf que no ha podido leer nada (que ha alcanzado el cara EOF). Veamos algunos ejemplos del uso de feof. El programa del siguiente ejemplo lee de un chero los elementos de un vector de enteros. El tese que en el bucle while se controlan dos chero contiene un elemento del vector en cada l nea. No condiciones: alcanzar el n del chero y llenar completamente el vector.

Los autores, 2000; Edicions UPC, 2000.

11.3. Otras funciones para el manejo de cheros

112

#include <stdio.h> #define N 256 #define MAXELE 100 void main( )

FILE *fp; char nombreFichero[N]; int lon; int vec[MAXELE]; printf( " Nombre del fichero(< %d caracteres): scanf( "%s%*c", nombreFichero ); fp = fopen( nombreFichero, "r" ); if (fp == NULL) ", N );

f g f

printf( "Error abriendo %snn", nombreFichero ); exit(0);

lon = 0; while (!feof(fp) && (lon < MAXELE)) kk = fscanf( fp, if (kk == 1) lon++; if (!feof(fp) && printf( "Todo cabe "%d", &vec[lon] );

g g

(lon == MAXELE)) el contenido del fichero no en el vectornn" );

fclose( fp ); . . .

lo tres l Supongamos que el chero contiene so neas como las siguientes: 123 254 -35 cuatro iteraciones. En la tercera iteracio n se leera Al ejecutar el programa, el bucle while realizara mero -35 y se almacenara en vec[2]. Sin embargo, la funcio n feof au n no del chero el nu el nal del chero, es decir, retornara 0. En la cuarta iteracio n, la funcio n fscanf detectara indicara cter EOF y por lo tanto no podra leer ningu n valor va lido. As el cara pues, en vec[3] no alma n ha cenamos nada (se queda como estaba, con un valor aleatorio). Podremos saber que esta situacio n fscanf. En este ejemplo, como so lo leemos ocurrido consultando el valor retornado por la funcio tese que el prouna variable, fscanf debe retornar 1 si ha podido realizar una lectura correcta. No lo incrementa el valor de lon si la lectura ha sido correcta. Despue s de la cuarta iteracio n, grama so un valor diferente de 0 (cierto). feof retornara

Los autores, 2000; Edicions UPC, 2000.

113

11. Ficheros

11.3.2 ferror
n es la siguiente: La cabecera de esta funcio int ferror( FILE *fp ) n ferror retorna un valor diferente de 0 si ha ocurrido algu n error en una lectuLa funcio alado por fp. En caso contrario retorna 0. ra/escritura previa en el chero sen

11.3.3 fflush
n es la siguiente: La cabecera de esta funcio int fflush( FILE *fp ) Cuando escribimos en un chero, en realidad la escritura no se produce en el mismo momento n fprintf. Sin embargo, esta funcio n deja la informacio n a escribir en un de ejecutar la funcio s tarde, cuando el sistema operativo lo decida (este libre buffer temporal del sistema operativo. Ma de otras tareas, por ejemplo), se vuelca el contenido de dicho buffer sobre el chero f sico. De esta s eciente el acceso a las forma en un computador con varios usuarios se puede organizar de forma ma n. La funcio n fflush puede utilizarse para forzar en unidades de almacenamiento de informacio n error, la funcio n el instante deseado el volcado del buffer sobre el chero. Si no se produce ningu fflush retorna 0, en caso contrario retorna EOF. n de programas. Supongamos que tenemos Un ejemplo t pico del uso de fflush es la depuracio un error en un programa y para encontrarlo ponemos diversos fprintf, que muestran valores de s de cada fprintf una llamada a fflush, no veremos el algunas variables. Si no ponemos despue valor que queremos en el momento en que realmente se produce, lo que nos puede llevar a conclusiones neas sobre el comportamiento del programa. erro

ndar: stdin, stdout, stderr 11.4 Ficheros esta


En C existen tres constantes del tipo FILE *, denidas en stdio.h, llamadas stdin, stdout y lo para lectura. Los punteros stdout y stderr. El puntero stdin apuntan a un chero abierto so lo para escritura. stderr apuntan a cheros abiertos so n inicializados por el sistema operativo de forma que una lectura de stdin sea Estos punteros esta en realidad una lectura del teclado. Es decir, que una llamada como fscanf( stdin, "%d", &i ) es equivalente a scanf( "%d", &i ) . n inicialmente redirigidos a la De igual forma, los cheros asignados a stdout y stderr esta pantalla, de forma que fprintf( stdout, "Holann" ) o fprintf( stderr, "Holann" ) tienen el mismo efecto que printf( "Holann" ) . Las constantes stdin, stdout y stderr pueden ser usadas para inicializar varibles del tipo s de teclado/pantalla. FILE * de forma que la entrada/salida sea a trave

Los autores, 2000; Edicions UPC, 2000.

11.4. Ficheros est andar: stdin, stdout, stderr

114

El siguiente ejemplo muestra un programa para multiplicar una matriz por un vector. Los datos de entrada se leen de stdin, es decir, del teclado. Por otra parte, los datos de salida se escriben n la pantalla). No tese que stdin, en stdout (pantalla), y los mensajes de error en stderr (tambie n declaradas en el programa, puesto que ya lo esta n en stdio.h. Cuando stdout y stderr no esta el programa funciona usando teclado/pantalla, muestra una serie de mensajes en pantalla explicando al usuario los datos que debe introducir. Sin embargo, cuando se usan cheros, estos mensajes no tienen sentido, por lo que no son mostrados. #include <stdio.h> #define MAXFILAS 10 #define MAXCOLUMNAS MAXFILAS void main( )

int i, j, k, Nfilas, Ncolumnas; double x[MAXCOLUMNAS], y[MAXFILAS]; double A[MAXFILAS][MAXCOLUMNAS]; char car; FILE *fi = stdin; FILE *fo = stdout; FILE *fe = stderr; printf( "Entrada/Salida por ficheros? scanf( "%c", &car ); if (car == s|| car == S) (s/n)" );

fi = fopen( "Entrada.txt", "r" ); if (fi == NULL)

f g f g f g g

printf( "Error abriendo Entrada.txtnn" ); exit(0);

fo = fopen( "Salida.txt", "w" ); if (fo == NULL) printf( "Error abriendo Salida.txtnn" ); exit(0);

fe = fopen( "Errores.txt", "w" ); if (fe == NULL) printf( "Error abriendo Errores.txtnn" ); exit(0);

if (fo == stdout) fprintf( fo, " N. filas = " );

Los autores, 2000; Edicions UPC, 2000.

115

11. Ficheros

fscanf( fi, "%d", &Nfilas ); if (Nfilas > MAXFILAS)

f g

fprintf( fe, "Demasiadas filasnn" ); exit (0);

if (fo == stdout) fprintf( fo, " N. columnas = " ); fscanf( fi, "%d", &Ncolumnas ); if (Ncolumnas > MAXCOLUMNAS)

f g

fprintf( fe, "Demasiadas columnasnn" ); exit (0);

for (i= 0; i< Nfilas; i++) for (j= 0; j< Ncolumnas; j++)

if (fo == stdout) fprintf( fo, "A[%d][%d] = ", i, j ); k = fscanf( fi, "%lf", &A[i][j] ); if (k != 1)

f g f g

fprintf( fe, "Error leyendo la matriznn" ); exit (0);

for (i= 0; i< Nfilas; i++) if (fo == stdout) fprintf( fo, "x[%d] = ", i ); k = fscanf( fi, "%lf", &x[i] ); if (k != 1)

f g f g

fprintf( fe, "Error leyendo el vectornn" ); exit (0);

for (i= 0; i< Nfilas; i++) y[i] = 0.0; for (j= 0; j< Ncolumnas; j++) y[i] = y[i] + A[i][j] * x[j];

Los autores, 2000; Edicions UPC, 2000.

11.5. Ejercicios

116

g
for (i= 0; i< Nfilas; i++) fprintf( fo, "y[%d] = %lfnn", i, y[i] ); if (fi != stdin) fclose( fi ); if (fo != stdout) fclose( fo ); if (fe != stderr) fclose( fe );

11.5 Ejercicios
meros enteros ordenados de menor a mayor. Escribir los si1. Se dispone de dos cheros con nu meros ordenados de mayor guientes programas de forma que el chero resultante contenga los nu a menor. meros que esta n en ambos cheros Un programa que construya un chero con todos los nu neamente (AND de cheros). simulta meros que esta n en cualquiera de Un programa que construya un chero con todos los nu meros repetidos. los dos cheros (OR de cheros). En el chero resultante no debe haber nu meros que esta n en cualquiera de los dos Un programa que construya un chero con los nu neamente (XOR de cheros). cheros, pero no en los dos simulta n del mismo. 2. Se dispone de un chero que contiene texto y se pretende realizar una compactacio s caracteres blancos por la secuencia #n# Para ello se substituyen las secuencias de cuatro o ma mero de caracteres blancos que se han substituido. Para evitar confucio n, , donde n indica el nu cter # se sustituye por ##. Disen ar una funcio n que lea de un chero un texto no el cara n los criterios expuestos. Disen ar tambie n otra funcio n que lea compactado y lo compacte segu n previa y lo descompacte. un chero de texto resultado de una compactacio mero no determinado de etiquetas. Cada etiqueta 3. Se dispone de un chero que contiene un nu n, tele fono, etc). La es un conjunto de datos sobre un determinado individuo (nombre, direccio formada por 3 l etiqueta esta neas consecutivas de texto. Cada l nea de texto tiene 15 caracteres ximo. Las etiquetas esta n separadas por una l nicamente el cara cter *. como ma nea que contiene u ar un programa que permita construir un nuevo chero que contenga las etiquetas Se desea disen n respectivamente del chero original pero organizadas en columnas de 3 etiquetas (que empezara ximo de en las columnas 0, 20 y 40). Supondremos que las l neas de un chero pueden tener un ma 80 caracteres. Las las de etiquetas deben estar separadas por una l nea en blanco. Por ejemplo: Fichero de Entrada Juan P erez c/ Arag on Tlf. 932 491 134

Los autores, 2000; Edicions UPC, 2000.

117

11. Ficheros

Pedro L opez Avd. Europa Tlf. 931 113 456 Juan Garc a c/ Gracia L erida Andr es Villa Tlf. 931 113 457 Badalona Pedro Cubero Tlf. 971 456 789 Mallorca

Fichero de Salida Juan P erez c/ Arag on Tlf. 932 491 134 Andr es Villa Tlf. 931 113 457 Badalona

Pedro L opez Avd. Europa Tlf. 931 113 456 Pedro Cubero Tlf. 971 456 789 Mallorca

Juan Garc a c/ Gracia L erida

nicamente por letras mayu sculas, espacios en blanco, comas 4. Se dispone de un chero compuesto u y puntos. El contenido de este chero tiene las siguientes caracter sticas: mero de espacios en blanco. Entre palabra y palabra puede haber cualquier nu n puede haber cualquier nu mero de espacios en Entre una palabra y un signo de puntuacio blanco. n y una palabra puede haber cualquier nu mero de espacios en Entre un signo de puntuacio blanco. ltimo cara cter del texto de entrada es una letra. El primer y u Debemos realizar un algoritmo que escriba en un chero de caracteres el contenido del chero de entrada formateado de tal manera que en el texto resultante se cumplan los siguientes requisitos: n escritas con letras minu sculas excepto la primera letra despue s Todas las palabras estara de un punto y la primera letra del texto. lo puede haber un blanco. Entre palabra y palabra so ltima letra de una palabra y un signo de puntuacio n no debe haber ningu n blanco. Entre la u

Los autores, 2000; Edicions UPC, 2000.

11.5. Ejercicios

118

n y la primera letra de una palabra debe haber un espacio en Entre un signo de puntuacio blanco. ltimo cara cter debe ser un punto. El u

Los autores, 2000; Edicions UPC, 2000.

119

A. El preprocesador

ndice A Ape

El preprocesador
til para el programador. Las directivas del preprocesador El preprocesador es una herramienta muy u n, es decir, comandos que modican el chero con co digo son en realidad simples comandos de edicio fuente del programa, de igual forma que lo har amos mediante un editor de textos. El chero modicado por el preprocesador sigue siendo un chero de texto. digo C porque empiezan con el Las directivas del preprocesador se distinguen de las l neas de co s mbolo # en la primera columna. Es importante hacer notar que es obligatorio que el s mbolo # este un error de compilacio n. en la primera columna, ya que en caso contrario se genera ndice veremos las directivas ma s importantes del preprocesador. En este ape

A.1 Directiva include


digo fuente otros cheros de texto. Esta La directiva include permite incluir en el chero de co directiva puede usarse dos formas distintas: #include <fichero.h> #include "miFichero.h" Cuando el chero incluido pertenece al sistema operativo se usan los s mbolos < > para delimitar el nombre del chero. Si el chero no forma parte del sistema operativo se usan los s mbolos " ". En cualquier caso, el efecto de un include es el mismo: se sustituye la l nea donde aparece la directiva por el contenido del chero indicado.

A.2 Directivas define y undef


Como su nombre indica, la directiva define permite denir s mbolos. Por su parte, la directiva undef permite eliminar s mbolos previamente denidos. El uso de estas directivas es el siguente: #define nombreS mbolo valorS mbolo #undef nombreS mbolo donde nombreS mbolo es el nombre del s mbolo que denimos/eliminamos y valorS mbolo es el valor que damos a dicho s mbolo. Dar valor al s mbolo es optativo.

Los autores, 2000; Edicions UPC, 2000.

A.3. Directivas ifdef y ifndef

120

El principal uso de la directiva define es substituir un texto por otro texto. Por ejemplo: #define N 100 el s signica que el preprocesador sustituira mbolo N por el texto 100 dentro del programa. A n se muestra un fragmento de co digo antes y despue s de ser tratado por el preprocesador: continuacio Antes del preprocesador ... for (i= 0; i< N; i++) Numeros[i] = i; ... s del preprocesador Despue ... for (i= 0; i< 100; i++) Numeros[i] = i; ... tese que la palabra Numeros no ha sido substituida por 100umeros. So lo se ha substituido el No cticas de C indican que dicho texto es el nombre de un s texto N all donde las reglas sinta mbolo. n de constantes. Normalmente estas constantes son las dimenEsto se aprovecha para la denicio ximas de tablas del programa. De esta forma, cuando deseemos modicar estas dimensiones, siones ma modicar la l digo que contiene el define, sin tener que buscar por el programa bastara nea de co todas las apariciones de las constantes. La directiva define tiene otros usos importantes que veremos en las secciones A.3 y A.4.

A.3 Directivas ifdef y ifndef


digo fuente so lo se compilen si se cumplen En ocasiones es preciso que determinados fragmentos de co ciertas condiciones. A este hecho se le denomina compilaci on condicional. Las directivas ifdef y n. El uso de estas directivas es el siguiente: ifndef sirven para realizar dicho tipo de compilacio #ifdef nombre c odigo1 #else c odigo2 #endif #ifndef nombre c odigo1 #else c odigo2 #endif donde nombre es un s mbolo denido mediante la directiva define. Los textos indicados por digo fuente en C. En la directiva ifdef, si c odigo1 y c odigo2 representan fragmentos de co

Los autores, 2000; Edicions UPC, 2000.

121

A. El preprocesador

digo que nalmente se complia corresponde al existe un define que dena el s mbolo nombre el co digo compilado corresponde a c fragmento indicado por c odigo1. En caso contrario, el co odigo2. Por otra parte, en la directiva ifndef, si no existe un define para el s mbolo nombre, el digo compilado es el correspondiente a c digo compilado es el co odigo1. En caso contrario, el co correspondiente a c odigo2. En ambas directivas el uso de else es optativo. Veamos algunos ejemplos. Supongamos que un programa debe mostrar ciertos valores en pantalla para estar seguros de su lo es necesario hacerlo mientras el programa esta en la fase de desarrollo. funcionamiento. Pero esto so n. Una solucio n consistira Una vez nalizada esta fase, no es necesario que muestre toda esa informacio digo pertinentes, pero si el programa es grande (miles o millones en borrar manualmente las l neas de co digo) podemos cometer errores fa cilmente al eliminar dichas l de l neas de co neas. En el siguiente digo, el s tese que la directiva #define co mbolo DEBUG controla si se compila o no el printf. No DEBUG no le asigna valor a la constante DEBUG, s mplemente la dene como s mbolo. #define DEBUG ... for (i= 0; i< Nfilas; i++) y[i] = 0.0; for (j= 0; j< Ncolumnas; j++)

#ifdef DEBUG printf( "y[%d]= %lf, x[%d]= %lf, A[%d][%d]= %lfnn", i, y[i], j, x[j], i, j, A[i][j] ); #endif y[i] = y[i] + A[i][j] * x[j];

Supongamos ahora que necesitamos mostrar en pantalla los recursos que usa un programa (memo n, etc). Para ello debemos llamar a una funcio n del sistema operativo. Pero en ria, tiempo de ejecucio n puede ser diferente, o puede que incluso no exista cada sistema operativo el nombre de dicha funcio n. El siguiente co digo muestra una solucio n para que, en cualquier caso, el programa se dicha funcio pueda compilar sin problemas: ... printf( "Recursos usados por el programann" ); #ifdef WINDOWS printf( "Funcion no disponible en sistema WINDOWSnn" ); #else getrusage( RUSAGE SELF, &rusage ); ... #endif ...

Los autores, 2000; Edicions UPC, 2000.

A.4. Macros

122

A.4 Macros
n permite denir macros. La sintaxis de una macro es la siguiente: La directiva define tambie #define nombreMacro( param1, param2, ... ) c odigo

lido de sentencias en C, y param1, etc. son s donde c odigo es un conjunto va mbolos que aparecen en c odigo. Cuando el preprocesador se ejecuta, substituye cada llamada a la macro por el texto escrito en c odigo, substituyendo dentro de c odigo los s mbolos param1, etc. por los valores que tengan en la llamada a la macro. Veamos un ejemplo: #define SWAP( p1, p2, p3 ) p3=p1; p1=p2; p2=p3;

digo anterior hemos denido la macro SWAP. Esta macro tiene tres para metros p1, p2 y En el co la macro por el co digo indicado. Esta p3. Donde esta macro sea invocada, el preprocesador susbtituira metros p1 y p2, usando el para metro p3 como macro sirve para intercambiar los valores de los para n que har una variable temporal. Veamos a continuacio a el preprocesador con dos llamas a la macro SWAP en el siguente programa: Antes del preprocesador double x, y, z; int a, b, c; ... SWAP ( x, y, z ); SWAP ( a, b, c ); ... s del preprocesador Despue double x, y, z; int a, b, c; ... z=x; x=y; y=z; c=a; a=b; b=c; ... n. Pero si las sentencias de la macro son muy Una macro siempre se puede substituir por una funcio s tiempo llamando y retornando de la funcio n que ejecutando su co digo. simples, podemos gastar ma s, en un ejemplo como el anterior vemos que la misma macro sirve para valores enteros, reales, Adema n diferente para cada tipo de datos caracteres, estructuras, etc. Sin embargo necesitar amos una funcio distinto.

Los autores, 2000; Edicions UPC, 2000.

123

B. La librer a est andar

ndice B Ape

ndar La librer a esta


Como se ha visto, una de las caracter sticas de C es que su sintaxis se basa en un conjunto muy reducido n, las operaciones de entrada y salida, el manejo de de palabras reservadas (ver Tab. 3.1). Por esta razo ticas, etc. no forman parte propiamente del lenguaje C. cadenas de caracteres, las funciones matema s, se hallan implementadas en una librer Todas estas funcionalidades, y muchas otras ma a de funciones y tipos de datos especiales que se conoce como la librer a est andar. ndar mediante un conjunto de cheros de cabeceras El programador puede acceder a la librer a esta n .h). As (con extensio pues, si un programa utiliza alguna de las funciones de la librer a, dicho incluir el chero de cabeceras correspondiente donde se halle denida dicha funcio n. programa debera n de entrada y salida como printf, debera incluir el Por ejemplo, si el programa utiliza una funcio chero stdio.h de la siguiente forma: #include <stdio.h>. ndice resume algunas de las funciones disponibles en dicha librer ndolas segu n Este ape a agrupa n, se proporciona su nombre, el chero de cabeceras donde se hallan denidas. Para cada funcio metros y resultado devuelto, as n. Cabe decir que alguno estos datos para como una breve descripcio puede diferir de un sistema a otro, por lo que es recomendable consultar los manuales correspondientes para mayor seguridad.

n de cadenas de caracteres B.1 Manipulacio


Las siguientes funciones se hallan denidas en el chero de cabeceras string.h: int strcasecmp( char s1[], char s2[] ) Compara las dos cadenas s1 y s2, sculas y minu sculas. Devuelve un entero menor, igual o mayor que 0, si s1 es ignorando mayu camente que s2, respectivamente. menor, igual o mayor lexicogra char *strcat( char dest[], char src[] ) Concatena la cadena src al nal de la cadena dest. La cadena dest debe tener suciente espacio para albergar la cadena resultante. n de la primera char *strchr( char s[], int c ) Devuelve un puntero a la posicio cter c en la cadena s. ocurrencia del cara int strcmp( char s1[], char s2[] ) Compara las dos cadenas s1 y s2. De camente vuelve un entero menor, igual o mayor que 0, si s1 es menor, igual o mayor lexicogra

Los autores, 2000; Edicions UPC, 2000.

B.2. Entrada y salida

124

que s2, respectivamente. char *strcpy( char dest[], char src[] ) Copia la cadena scr en la cadena dest. La cadena dest debe tener suciente espacio para albergar la cadena src. char *strdup( char s[] ) Devuelve un puntero a una nueva cadena que es un duplicado de la cadena s. cter int strlen( char s[] ) Devuelve la longitud de la cadena s, sin contar el cara n0. char *strncat( char dest[], char src[], int n ) Similar a strcat, a ex n de que so lo se concatenan al nal de dest, los n primeros caracteres de la cadena cepcio src. n int strncmp( char s1[], char s2[], int n ) Similar a strcmp, a excepcio lo se comparan los n primeros caracteres de ambas cadenas. de que so char *strncpy( char dest[], char src[], int n ) Similar a strcpy, a ex n de que so lo se copian en dest los n primeros caracteres de la cadena src. cepcio int strncasecmp( char s1[], char s2[], int n ) Similar a strcasecmp, n de que so lo se comparan los n primeros caracteres de ambas cadenas. a excepcio n de la u ltima char *strrchr( char s[], int c ) Devuelve un puntero a la posicio cter c en la cadena s. ocurrencia del cara n de la char *strstr( char s1[], char s2[] ) Devuelve un puntero a la posicio primera ocurrencia de la cadena s2 en la cadena s1.

B.2 Entrada y salida


Las siguientes funciones se hallan denidas en el chero de cabeceras stdio.h.

sica B.2.1 Entrada y salida ba


sica. Probablemente las ma s conocidas sean: Hay varias funciones que proporcionan entrada y salida ba cter del teclado. int getchar() Lee un cara char *gets( char string[] ) Lee una cadena de caracteres del teclado. cter por pantalla. Devuelve el cara cter escrito. int putchar( char ch ) Escribe un cara int puts( char string[] ) Escribe una cadena de caracteres por pantalla. Devuelve mero de caracteres escritos. el nu

B.2.2 Entrada y salida con formato


Ya hemos visto el uso de la entrada y salida con formato mediante las funciones printf y scanf. moslas ahora con ma s detalle: Vea

Los autores, 2000; Edicions UPC, 2000.

125

B. La librer a est andar

int printf( char format[], ...

Escribe en pantalla la lista de argumentos de acuerdo con el formato especicado para cada uno de ellos, mero de caracteres escritos. El formato consta de caracteres ordinarios (que se escriben y devuelve el nu cter %. Debe haber directamente en pantalla) y de especicadores de formato denotados por el cara tantos especicadores de formato como argumentos. La forma general de uno de estos especicadores es la siguiente: %[-|+][ancho][.prec][h|l|L]tipo donde: n la tabla: tipo especica el tipo de datos del argumento segu tipo c i, d o x, X u s f e, E g, G p % Argumento char int char * double/oat puntero ninguno Formato de salida cter cara entero decimal: d gitos 0, . . . , 9 entero octal: d gitos 0, . . . , 7 entero hexadecimal: d gitos 0, . . . , 9, A, . . . , F entero decimal sin signo cadena de caracteres hasta n0 [-]dddd.dddd n cient notacio ca: [-]d.dddd[e/E][+/-]ddd s compacta entre %f y %e la forma ma n de memoria direccio cter % cara

sico. Se usa h para short int, l para [h|l|L] como modicador del tipo de datos ba long int y double, y L para long double. mero de decimales al escribir un nu mero de coma otante, o nu mero de caracteres [.prec] nu al escribir una cadena de caracteres. mero de espacios empleados para la escritura. Si es inferior al necesario se ignora. [ancho] nu ancho puede tomar dos valores: n Se emplean n espacios rellenando con blancos el espacio sobrante. 0n Se emplean n espacios rellenando con 0s el espacio sobrante. [-|+] Se usa - para justicar a la izquierda rellenando con blancos, y + para forzar la meros. escritura del signo en los nu Veamos algunos ejemplos ilustrativos: printf( printf( printf( printf( printf( "%030.5f", 1.5236558 ); "%+30.5f", 1.5236558 ); "%+-030.5f", 1.5236558 ); "%8.3s", "hola" ); "%-08.3s", "hola" ); 000000000000000000000001.52326 +1.52326 +1.523260000000000000000000000 hol hol00000

Los autores, 2000; Edicions UPC, 2000.

B.2. Entrada y salida

126

int scanf( char format[], ...

cter a cara cter) y los coloca en las direcciones de memoria especicadas en la Lee datos del teclado (cara mero de argumentos le lista de argumentos de acuerdo con el formato. Devuelve el nu dos. El formato consta de caracteres ordinarios (que se espera se tecleen) y de especicadores de formato denotados por cter %. Debe haber tantos especicadores de formato como direcciones de argumentos donde el cara almacenar los datos le dos. La forma general de uno de estos especicadores es la siguiente: %[*][ancho][h|l|L]tipo donde: n la tabla: tipo especica el tipo de datos del argumento segu tipo c i d o x u I D O X U s f e, E g, G p % Argumento char * int * long int * char [] double/oat puntero ninguno Entrada esperada cter cara entero decimal, octal o hexadecimal entero decimal entero octal entero hexadecimal entero decimal sin signo entero decimal, octal o hexadecimal entero decimal entero octal entero hexadecimal entero decimal sin signo cadena de caracteres hasta blanco, tabulador o salto de l nea mero en coma otante nu n de memoria hexadecimal: YYYY:ZZZZ o ZZZZ direccio cter % cara

* no asigna el argumento le do a ninguna variable de los argumentos. nticos al caso de printf. Sin embargo existen un par El resto de campos del modicador son ide de convenciones especiales que merece la pena destacar: cter que no pertenezca %[set] que permite leer una cadena de caracteres hasta encontrar un cara cter no se lee. al conjunto set especicado. Dicho cara cter que pertenezca %[set] que permite leer una cadena de caracteres hasta encontrar un cara cter no se lee. al conjunto set especicado. Dicho cara

B.2.3 Ficheros
digo de error. int fclose( FILE *fich ) Cierra el chero fich y devuelve un co int feof( FILE *fich ) Comprueba si se ha llegado al nal del chero fich.

Los autores, 2000; Edicions UPC, 2000.

127

B. La librer a est andar

n error en alguna operaint ferror( FILE *fich ) Comprueba si se ha producido algu n sobre el chero fich. cio int fflush( FILE *fich ) Fuerza la escritura en disco de las escrituras diferidas realizadas sobre fich. cter de fich. int fgetc( FILE *fich ) Lee un cara char *fgets( char string[], int max, FILE *fich ) Lee una cadena de hasta max caracteres de fich. FILE *fopen( char nombre[], char modo[] ) Abre el chero con el nombre y modo de apertura especicados. modo puede ser: "r" para lectura, "w" para escritura y adir informacio n al nal del chero. "a" para an int fprintf( FILE *fich, char formato[], ... fich. Ver printf. ) Escritura con formato en

cter c en fich. int fputc( int c, FILE *fich ) Escribe el cara int fputs( char string[], FILE *fich ) Escribe una cadena de caracteres en fich. int fscanf( FILE *fich, char formato[], ... fich. Ver scanf. cter de fich. int getc( FILE *fich ) Lee un cara cter c en fich. int putc( int c, FILE *fich ) Escribe el cara a el cursor para lecturas/escrituras de fich al prinvoid rewind( FILE *fich ) Situ cipio del mismo. int sprintf( char string[], char formato[], ... mato en una cadena caracteres. Ver printf. int sscanf( char buffer[], char formato[], ... de una cadena de caracteres. Ver scanf. ) Escritura con for) Lectura con formato de

) Lectura con formato

cter c, le int ungetc( int c, FILE *fich ) Devuelve el cara do previamente, al chero fich de donde fue le do.

ticas B.3 Funciones matema


Las siguientes funciones se hallan denidas en el chero de cabeceras math.h: double acos( double x ) Calcula el arco coseno de x. double asin( double x ) Calcula el arco seno de x. double atan( double x ) Calcula el arco tangente de x.

Los autores, 2000; Edicions UPC, 2000.

B.4. Clasicaci on y manipulaci on de caracteres

128

double atan2( double y, double x ) Calcula el arco tangente de y/x. s pequen o que es mayor que x. double ceil( double x ) Calcula el entero ma double cos( double x ) Calcula el coseno de x en radianes. lico de x. double cosh( double x ) Calcula el coseno hiperbo double exp( double x ) Calcula ex . double fabs( double x ) Calcula el valor absoluto de x. s grande que es menor que x. double floor( double x ) Calcula el entero ma labs( long n ) Calcula el valor absoluto de n. double log( double x ) Calcula el logaritmo natural de x. double log10( double x ) Calcula el logaritmo en base 10 de x. double pow( double x, double y ) Calcula xy . double sin( double x ) Calcula el seno de x en radianes. lico de x. double sinh( double x ) Calcula el seno hiperbo double sqrt( double x ) Calcula la ra z cuadrada de x. meros void srand( unsigned seed ) Fija un nuevo germen para el generador de nu aleatorios (rand). double tan( double x ) Calcula la tangente de x en radianes. lica de x. double tanh( double x ) Calcula la tangente hiperbo

n y manipulacio n de caracteres B.4 Clasicacio


Las siguientes funciones se hallan denidas en el chero de cabeceras ctype.h: cter alfanume rico. int isalnum( int c ) Devuelve cierto si c es un cara int isalpha( int c ) Devuelve cierto si c es una letra. digo ASCII. int isascii( int c ) Devuelve cierto si c corresponde a un co cter de control. int iscntrl( int c ) Devuelve cierto si c es un cara int isdigit( int c ) Devuelve cierto si c es un d gito decimal. cter gra co. int isgraph( int c ) Devuelve cierto si c es un cara scula. int islower( int c ) Devuelve cierto si c es una letra minu cter imprimible. int isprint( int c ) Devuelve cierto si c es un cara

Los autores, 2000; Edicions UPC, 2000.

129

B. La librer a est andar

n. int ispunct( int c ) Devuelve cierto si c es un s mbolo de puntuacio cter de espaciado. int isspace( int c ) Devuelve cierto si c es un cara scula. int isupper( int c ) Devuelve cierto si c es una letra mayu int isxdigit( int c ) Devuelve cierto si c es un d gito hexadecimal. digo ASCII de c. int toascii( int c ) Obtiene el co scula. tolower( int c ) Convierte c a minu scula. int toupper( int c ) Convierte c a mayu

n de datos B.5 Conversio


Las siguientes funciones se hallan denidas en el chero de cabeceras stdlib.h: mero de double atof( char string[] ) Convierte una cadena de caracteres en un nu coma otante. mero entero. int atoi( char string[] ) Convierte una cadena de caracteres en un nu mero entero int atol( char string[] ) Convierte una cadena de caracteres en un nu n. de doble precisio

n de directorios B.6 Manipulacio


Las siguientes funciones se hallan denidas en el chero de cabeceras dir.h: int chdir( char path[] ) Cambia el directorio de trabajo actual de acuerdo con el path especicado. char *getcwd( char path[], int numchars ) Devuelve el nombre del directorio de trabajo actual. int mkdir( char path[] ) Crea un nuevo directorio con el nombre especicado en path. int rmdir( char path[] ) Borra el directorio con el nombre especicado en path.

mica B.7 Memoria dina


s importantes de un programa es la cantidad de memoria que necesita para Una de las caracter sticas ma ejecutarse. Es importante que un programa no desperdicie memoria. Esto plantea un serio problema cuando declaramos las variables, esencialmente las tablas, ya que deberemos dimensionar el espacio de memoria para el peor caso posible. n din Para evitar este problema existen funciones que permiten una gestio amica de la memoria, es n la necesite, y la vaya libera ndola cuando deje decir, permiten que un programa adquiera memoria segu

Los autores, 2000; Edicions UPC, 2000.

B.7. Memoria din amica

130

mica la memoria, todas de necesitarla. C dispone de las siguiente funciones para gestionar de forma dina n denidas en el chero stdlib.h: ellas esta void *malloc( size t num bytes ) Reserva un bloque de memoria de num bytes bytes. Devuelve un puntero al primer byte del bloque de memoria reservado, o NULL si no hay suciente memoria disponible. void *calloc( size t num elems, size t tam elem ) Reserva un bloque de memoria capaz de almacenar num elems de tam elem bytes cada uno. Este espacio de memoria es inicializado con ceros. Devuelve un puntero al primer byte del bloque de memoria reservado, o NULL si no hay suciente memoria disponible. void *realloc( void *ptr, size t num bytes ) o del bloque de memoria apuntado por ptr para que tenga num bytes bytes. Cambia el taman Devuelve un puntero al primer byte del nuevo bloque de memoria reservado, o NULL si no hay suciente memoria disponible. void free( void *ptr ) Libera el bloque de memoria apuntado por ptr. Dicho bloque debe haber sido previamente obtenido mediante malloc, calloc o realloc. Si ptr es NULL, no se hace nada. mero natural (sin signo). Cuando llamamos a estas funciones y El tipo de datos size t es un nu metros varibles de tipo entero (short, int o long), se realiza una conversio n les pasamos como para tica. de tipo de forma automa Junto con estas funciones usaremos el operador de C sizeof(tipo de datos). Este operador mero de bytes que ocupa una variable del tipo tipo de datos, tanto si este tipo esta retorna el nu predenido en C (int, float, etc.) como si es un tipo denido por el programador. mica. Veamos algunos ejemplos que ilustran el empleo de memoria dina mica dos vectores. El siguiente ejemplo gestiona de forma dina #include <stdio.h> #include <stdlib.h> typedef struct

f g

long DNI; char nom[256]; Tpersona;

void main( ) int i, lon; double *nota; Tpersona *alumno;

Los autores, 2000; Edicions UPC, 2000.

131

B. La librer a est andar

do

f g

printf( "Cu antos alumnos hay?nn" ); scanf( "%d", &lon ); while( lon < 0 );

nota = malloc( lon*sizeof(double) ); alumno = malloc( lon*sizeof(Tpersona) ); if ((nota == NULL) || (alumno == NULL))

f g

printf( " No hay memoria suficientenn" ); exit(0);

... /* Introducci on de datos y notas de cada alumno. ...

*/

for (i= 0; i< lon; i++) printf( "Alumno:%d nombre:%s DNI:%ld nota:%lfnn", i, alumno[i].nom, alumno[i].DNI, nota[i] ); free( alumno ); free( nota );

Hay varios puntos a destacar: n de variables no declaramos ningu n vector. En su lugar declaramos Notar que en la declaracio punteros. En este caso un puntero al tipo double y otro al tipo Tpersona. En estos punteros almacenamos las direcciones de memoria que devuelve malloc. n malloc que cantidad de bytes de memoria necesitamos, hemos Para indicarle a la funcio mero de elementos multiplicado por usado el operador sizeof. Los bytes requeridos son el nu o en bytes de cada elemento. Cabe notar que sizeof se puede usar tambie n con tipos el taman denidos por el programador como el tipo Tpersona. s de llamar a malloc comprobamos que los punteros no sean NULL. Si lon es muy Despue grande, puede ocurrir que el computador no tenga memoria suciente. Esta comprobaci on de error siempre debe hacerse. s de los Cuando tenemos los bloques de memoria ya reservados, podemos acceder a ellos a trave n para acceder a trave s de los punteros es ide ntica a la que se punteros. En este caso, la notacio usa con vectores. Pero no debemos olvidar que alumno y nota son punteros. En el momento en que los bloques de memoria ya no son necesarios, debemos liberarlos. Para n free. Cualquier intento de acceder a los bloques de memoria despue s ello usamos la funcio n. de la llamada a free generar a un error de ejecucio

Los autores, 2000; Edicions UPC, 2000.

B.7. Memoria din amica

132

En este ejemplo multiplicamos la matriz A por el vector x dejando el resultado en el vector y. #include <stdio.h> #include <stdlib.h>

void main( ) int i, j, nfil, ncol; double *x, *y, *A; do

f g f g

printf( " N umero de filas?nn" ); scanf( "%d", &nfil ); while( nfil < 0 );

do printf( " N umero de columnas?nn" ); scanf( "%d", &ncol ); while( ncol < 0 );

A = malloc( nfil*ncol*sizeof(double) ); x = malloc( ncol*sizeof(double) ); y = calloc( nfil, sizeof(double) ); if ((x == NULL) || (y == NULL) || (A == NULL))

f g

printf( " No hay memoria suficientenn" ); exit(0);

... /* Introducci on del vector x y la matrix A */ ... for (i= 0; i< nfil; i++)

f g

for (j= 0; j< ncol; j++) y[i] = y[i] + A[i*ncol+j] * x[j];

for (i= 0; i< nfil; i++) printf( "y[%d] = %lfnn", i, y[i] ); free( A );

Los autores, 2000; Edicions UPC, 2000.

133

B. La librer a est andar

free( x ); free( y );

s destacables son los siguientes: Los puntos ma n calloc. De esta forma el bloque Para reservar memoria para el vector y utilizamos la funcio de memoria queda inicializado a cero y no es necesario inicializar cada componente de y en el n. algoritmo de multiplicacio n para acceder a los bloques de memoria x e y a trave s de los punteros coincide con La notacio tica. Pero no pasa lo mismo con la la que usar amos si fuesen vectores declarados de forma esta matriz. o de un bloque de memoria, que previamnete Finalmente, en este ejemplo modicamos el taman n malloc. hab a sido reservado mediante la funcio #include <stdio.h> #include <stdlib.h>

void main( ) int lon1, lon2; double *vec; do

f g

printf( "Longitud del vector?nn" ); scanf( "%d", &lon1 ); while( lon1 < 0 );

vec = malloc( lon1*sizeof(double) ); if (vec == NULL)

f g

printf( " No hay memoria suficientenn" ); exit(0);

... /* Aqu trabajamos con vec */ ... do

printf( " Nueva longitud del vector?nn" ); scanf( "%d", &lon2 );

Los autores, 2000; Edicions UPC, 2000.

B.7. Memoria din amica

134

while( lon2 < 0 );

vec = realloc( vec, lon2*sizeof(double) ); if (vec == NULL)

f g

printf( " No hay memoria suficientenn" ); exit(0);

... /* Aqu trabajamos con vec */ ...

free( vec );

n realloc nos permite modicar el taman o del bloque de memoria reservado, pero no La funcio modica los datos almacenados en dicho bloque. Es decir: s pequen o, pero los lon2 valores Si lon2 < lon1, tendremos un bloque de memoria ma n siendo los mismos. almacenados seguira s grande. Los primeros lon1 vaSi lon2 > lon1, tendremos un bloque de memoria ma n los mismos que hab lores sera a antes de la llamada a realloc, mientras que los lon2 n aleatorios (no estara n inicializados). lon1 valores nales sera

Los autores, 2000; Edicions UPC, 2000.

135

C. Sistemas de numeraci on

ndice C Ape

n Sistemas de numeracio
n en base 2 debido a co mo funcionan los dispositivos Un computador usa el sistema de numeracio nicos ba sicos (los transistores) que lo forman. En el sistema de numeracio n en base dos so lo electro mero en base 2 se las denomina bits. A un grupo de 8 existen 2 cifras el 0 y el 1. A las cifras de un nu bits se le denomina byte.

C.1 Naturales
meros naturales se representan mediante un co digo llamado binario natural, que consiste simLos nu meros naturales mero en base 2. Si disponemos n bits para representar nu plemente en expresar el nu n tendremos las 2 combinaciones que se muestran en la tabla C.1.

C.2 Enteros
meros enteros se representan mediante un co digo llamado complemento a 2. Este co digo se usa Los nu n de los circuitos electro nicos necesarios para realizar porque simplica notablemente la construccio ticas, fundamentalmente sumas y restas. operaciones aritme mero se calcula de la siguiente forma: si el nu mero es positivo su El complemento a 2 de un nu n en binario natural; si el nu mero es negativo se debe escribir complemento a 2 coincide con su expresio n en binario natural de su mo dulo (valor absoluto), complementar a 1 dicha expresio n la representacio Tabla C.1: Representaci on de n umeros naturales en binario natural Valor Decimal
0 1 2 3 4

n;1

...

Binario Natural 0.....0 0....01 0...010 0...010 0...100 ... 1.....1

Los autores, 2000; Edicions UPC, 2000.

C.3. Reales

136

Tabla C.2: Representaci on de n umeros enteros en complemento a 2 Valor Decimal

;2n; ;
n;
...
1 0 1

...
1

+2

Complemento a 2 10....0 ... 1.....1 0.....0 0....01 ... 01....1

(cambiar los 0 por 1 y viceversa), y nalmente sumarle 1. Por ejemplo si disponemos de 4 bits para meros enteros y deseamos representar el nu mero ;3, tendr amos que: representar nu 3 = 0011 1100 + 1 -3 = 1101 En general, si disponemos de muestran en la tabla C.2. Complemento a 1 Complemento a 2 meros en complemento a 2 que se n bits, podemos representrar los nu

n en complemento a 2 tiene algunas propiedades interesantes como las siguientes: La codicacio nica representacion: 0...0 = 1...1 + 1 El cero tiene una u meros del mismo signo empiezan por el mismo bit: 1 para los negativos, 0 para los Todos los nu positivos La suma/resta de numeros en complemento a 2 se puede realizar mediante la suma binaria bit a ltimo acarreo. Por ejemplo: bit, despreciando el u -2 - 1 = -3 2 - 1 = 1 1....10 0...010 + + 1...1 1...1 = = 1...10 0...01

C.3 Reales
meros reales se representan mediante un co digo llamado coma otante. Este co digo es simpleLos nu n en notacio n cient mente la representacio ca normalizada y en base 2. n cient n: Recordemos que un numero en notacio ca se representa mediante la siguiente expresio mero real con la coma decimal colocada Donde la mantisa es un nu n por la derecha o por la a la derecha o a la izquierda de la primera cifra signicativa (normalizacio n usada para representar mantisa y exponente; izquierda); la base es la misma que la base de numeracio mero entero. Los siguientes ejemplos muestran nu meros representados en y el exponente es un nu n cient notacio ca en base 10, normalizados por la derecha y por la izquierda:

mantisa baseexponente.

Los autores, 2000; Edicions UPC, 2000.

137

C. Sistemas de numeraci on

Tabla C.3: Representaci on de n umeros enteros en exceso 2e;1 Valor Decimal

;2e; ;
e;
...
1 0 1

...
1

+2

Complemento a 2 10....0 ... 1.....1 0.....0 0....01 ... 01....1


1

exceso 2e;1 0.....0 ... 01....1 10....0 10...01 ... 11....1

3 141592

2 53547

10

10
3

= =

0 3141592 10

0 253547

10
2

n cient La notacio ca usada por los computadores tiene algunos detalles especiales debidos a que usa la base 2. 1. En la memoria unicamente se almacena: una secuencia de m bits que representa la mantisa, una secuencia de e bits que representa el exponente, el signo de la mantisa se almacena usando 1 bit (0 signica positivo y 1 signica negativo). semos ver un nu mero real La base no es necesario almacenarla, ya que siempre es 2. Si pudie almacenado en la memoria del computador ver amos una secuencia de bits como la siguiente:

signo

bit z m}| bits { ze }| bits{ z}|{ : : } | {z } |{z} | :{z


1

101

010

mantisa

exponente

10010

lo existen 2 cifras, el 0 y el 1. As un 1, 2. En base 2 so pues, el primer bit signicativo siempre sera nicos que operan por lo que este primer bit no se almacena en la memoria. Los circuitos electro con datos en coma otante ya tienen en cuenta que delante de todos los bits de la mantisa siempre hay un 1. A este bit que no se almacena se le denomina bit oculto o impl cito. mero digo llamado exceso 2e;1 , donde e es el nu 3. El exponente se almacena usando un co digo proviene de rotar de forma c de bits usados para almacenar el exponente. Este co clica e ; 1 2 posiciones la tabla del complemento a 2 (ver Tab. C.3). digo en exceso podemos usar la siguiente fo rmula: Para calcular un co Valor decimal
=

Valor en binario natural

e;

digo en exceso todos los nu meros negativos comienzan por 0 y todos los Notar que en el co meros positivos comienzan por 1. Adema s, a valores crecientes les corresponden co digos que nu n son crecientes. Es decir: ;2 < 1 , 01 : : : 10 < 10 : : : 01. le dos en binario natural tambie meros de un co digo en exceso usando un simple comparador De esta forma podemos comparar nu meros en binario natural. Sin embargo, los circuitos para sumar/restar nu meros codicados de nu n un simple sumador binario. Por razones histo ricas se decidio usar el en exceso, ya no sera digo en exceso en vez del co digo en complemento a 2 para representar los exponentes. co

Los autores, 2000; Edicions UPC, 2000.

C.3. Reales

138

Tabla C.4: Representaci on de n umeros reales Valor Decimal Signo

NAN M nimo ::: M aximo

x x x ::: x

Mantisa

::: x:::x ::: ::: :::


0 0 0 0 1 1

Exponente
0 0 0

::: ::: ::: ::: :::

0 0 1

mero cero no se puede representar, ya que sea cual sea la man4. Debido al uso del bit oculto, el nu sta nunca sera cero. Dado que el nu mero cero es un nu mero importante, que es necesario tisa, e n a la regla de representacio n. De forma arbitraria se poder representar, se hace una excepcio mero cero se representa mediante la combinacio n en que todos los bits de la decide que el nu mantisa y el exponente son ceros. s, las diferentes combinaciones de mantisa con el exponente cuyo co digo son todo ceros 5. Adema meros. Estos co digos se reservan como co digos de error, generados tampoco se usan como nu ticos cuando se producen condiciones de error como: una divisio n en que por los circuitos aritme mero negativo, etc. A estos co digos de error se les el divisor es cero, la ra z cuadrada de un nu denomina NAN (del ingles, Not A Number). Por lo tanto:

mero representable ma s cercano a cero es 1:0 El nu n toda su mantisa con ceros y el exponente es la combinacio

e; ximo es +(2e; El exponente ma


El exponente m nimo es

(2

1 1

; ;

1) 1)

n y se representa mediante la combinacio n , y se representa mediante la combinacio


0

Exp:M nimo . Este nu mero tiene 2

::: :::

01 1

mero representable ma s grande es El nu ) n tiene toda su mantisa con unos y el exponente es la combinacio

;m 2(1 ; 2
(

:::

+1)

Exp:M aximo . Este nu mero 2


1

01

:::

digos de un formato de coma otante. El s En la tabla C.4 se muestran ordenados los co mbolo x signica cualquier bit 0 o 1. s bits se usen para representar la mantisa, mayor precisio n se tiene en 6. Cabe notar que cuantos ma n (menor error relativo). Cuantos ma s bits usemos para representar el exponente la representacio rico abarcaremos. mayor rango nume n en coma otante, podr Si cada computador usase su propio sistema de representacio amos tener valores diferentes al ejecutar el mismo programa en computadores diferentes. Para evitar este problema, n en coma otante esta estandarizada por la organizacio n IEEE (Institute of Electrical la representacio ndar IEEE-754. Actualmente todos los computadores cumplen and Electronics Engineers) bajo el esta ndar. con dicho esta

n en coma otante C.3.1 Problemas derivados de la representacio


meros reales en un computador siempre usaremos una secuencia nita de bits. En Para representar nu meros. Al subconjunto de nu meros que podeconsecuencia, nunca podremos representar todos los nu mos representar en un formato coma otante se le denomina rango de representaci on.

Los autores, 2000; Edicions UPC, 2000.

139

C. Sistemas de numeraci on

n es nito, las operaciones aritme ticas no tienen las propieDebido a que el rango de representacio dades habituales. Por ejemplo, la suma ya no es asociativa. Supongamos un formato de coma otante mero ma ximo representable es el 8:0. Entonces tendremos que: donde el nu
(8 0 + 2 0)

8 0 + (2 0

: ; : 6 : : ; : : ; : : ; : ) ERROR : ; : : ; : : ) CORRECTO
(8 0 + 2 0)

4 0 = 8 0 + (2 0 4 0

4 0)

4 0 = 10 0

4 0) = 8 0

2 0 = 6 0

n se la denomina overow (desbordamiento por arriba), y ocurre cuando una operaA esta situacio n genera un nu mero mayor que el ma ximo representable. Adema s del overow puede producirse el cio n cae en la zona de nu meros underow (desbordamiento por abajo) cuando el resultado de una operacio mero m situados entre 0 y el nu nimo representable. n, al realizar ca lculos en coma otante deberemos tener en cuenta el orden en el que En conclusio se realizan las operaciones, para evitar las citadas situaciones de error.

Los autores, 2000; Edicions UPC, 2000.

C.3. Reales

140

Los autores, 2000; Edicions UPC, 2000.

141

D. Tabla de caracteres ASCII

ndice D Ape

Tabla de caracteres ASCII


s de poder representar valores nume ricos, es preciso que un ordenador sea capaz de almacenar Adema ricos que usamos normalmente en el lenguaje humano. Para ello se usa un co digo de los signos alfanume digo ASCII. Cada combinacio n de este co digo representa un cara cter. Los perife ricos, 8 bits llamado co digos y mostrar/imprimir el s como la pantalla o una impresora, son capaces de reconocer estos co mbolo correspondiente. s de los s Entre los caracteres representados adema mbolos que usamos para escribir (letras, cifras, n, etc) tambie n hay caracteres de control, necesarios para el funcionamiento de los signos de puntuacio ricos. Por ejemplo, el cara cter nn provoca un salto de l nea cuando es mostrado en una pantalla. perife digo ASCII so lo usaba 7 bits para codicar caracteres, el octavo bit (bit de paOriginalmente el co digo ASCII original so lo pod ridad) se usaba para control de errores. Por lo tanto, el co a representar 7 128 = 2 caracteres diferentes. Actualmente, este control de errores no es necesario debido al perfec n para codicar caracteres. A cionamiento de los equipos, por ello el octavo bit puede ser usado tambie digo se le conoce como ASCII extendido y codica 256 = 28 caracteres. este co n esta ndar ASCII. La tabla D.1 muestra los primeros 128 caracteres de acuerdo con la codicacio

Los autores, 2000; Edicions UPC, 2000.

142

Tabla D.1: Caracteres y sus c odigos ASCII ASCII 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 char NUL n0 SOH STX ETX EOT ENQ ACK BEL na BS nb HT nt LF nn VT nv FF nf CR nr SO SI DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US ASCII 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 char SP ! # $ % & ASCII 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 char @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ ASCII 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 char a b c d e f g h i j k l m n o p q r s t u v w x y z

( )
+

;
. / 0 1 2 3 4 5 6 7 8 9 : ; = ?

n
]

DEL

Los autores, 2000; Edicions UPC, 2000.

143

E. Bibliograf a y recursos WEB

ndice E Ape

Bibliograf a y recursos WEB


n C El Lenguaje de programacio Brian W. Kernighan y Dennis M. Ritchie n. Prentice Hall, 1992, segunda edicio http://cm.bell-labs.com/cm/cs/cbook/index.html De obligada referencia, es el primer libro sobre lenguaje C. Uno de los autores, Dennis n ocial de C y un M. Ritchie, es uno de los creadores del lenguaje. Incluye la denicio mero de ejemplos interesantes, aunque en algunos aspectos el material presentado gran nu familiarizado con la programacio n de sistemas. es obsoleto. Presupone que el lector esta n en C Programacio Byron Gottfried n. Mc Graw Hill, 1997, segunda edicio estructurado como Extenso y eshaustivo libro con multitud de ejemplos detallados. Esta un libro de texto, por lo que contiene gran cantidad de ejercicios, cuestiones de repaso, etc. Para principiantes. The Annotated ANSI C Standard Herbert Schildt Osborne - Mc Graw Hill, 1993. ndar ANCI C comentado y anotado por Herbert Shildt, miembro observador del El esta encargado de desarrollar el esta ndar. ANSI C determina las reglas fundamentales comite que todo programador en C deber a observar para crear programas funcionales y portables. Para lectores avanzados. C by example Greg M. Perry Que Corporation, 1993. a a programar en C, construyendo programas paso a paso, desde Interesante libro que ensen el primer momento. Separa los conceptos complicados del lenguaje en varios cap tulos cil asimilacio n. Incluye gran cantidad de ejercicios. Para principiantes. cortos, de fa

Los autores, 2000; Edicions UPC, 2000.

144

The Development of the C Language Dennis M. Ritchie History of Programming Languages Conference (HOPL-II), 1993. http://cm.bell-labs.com/cm/cs/who/dmr/chist.html n que describe la historia de la creacio n del lenguaje C, Interesante art culo de divulgacio por los an os 70. alla WEB: Programming in C http://www.lysator.liu.se/c/index.html Un sitio WEB muy interesante. Incluye multitud de enlaces a recursos en Internet sobre n en C, historia del lenguaje, curiosidades, etc. programacio WEB: Frequently Asked Questions about C http://www.eskimo.com/ scs/C-faq/top.html n de las preguntas ma s habituales sobre En este sitio WEB encontraremos una recopilacio n en lenguaje C del grupo de noticias en Internet comp.lang.c . programacio

Los autores, 2000; Edicions UPC, 2000.

También podría gustarte