Programacion en C
Programacion en C
Programacion en C
PROGRAMACIÓN EN LENGUAJE C
c
Pedro María Alcover Garau
“Eso desean quienes viven estos tiempos, pero no les toca a ellos
decidir. Sólo tú puedes decidir qué hacer con el tiempo que se te
ha dado.” (Gandalf)
Presentación
V
VI Capítulo 0. Presentación
Muchas gracias.
Cartagena, 15 de agosto de 2013 (20 de Septiembre, 2015)
Índice general
Presentación V
2 Codificación numérica 17
2.1 Concepto de Código . . . . . . . . . . . . . . . . . . . 18
2.2 Los números y las cantidades . . . . . . . . . . . . . 20
2.3 Bases, dígitos y cifras . . . . . . . . . . . . . . . . . . 21
2.4 Bases más habituales . . . . . . . . . . . . . . . . . 25
2.5 Sistema binario . . . . . . . . . . . . . . . . . . . . . 26
2.6 Cambio de Base . . . . . . . . . . . . . . . . . . . . . 28
2.7 Complemento a la Base . . . . . . . . . . . . . . . . 31
2.8 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 34
3 Codificación interna 37
3.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . 38
3.2 Códigos de Entrada/Salida . . . . . . . . . . . . . . 40
3.3 Representación o Codificación Interna de la Infor-
mación. . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.4 Enteros sin signo . . . . . . . . . . . . . . . . . . . . 43
3.5 Enteros con signo . . . . . . . . . . . . . . . . . . . . 44
VII
VIII ÍNDICE GENERAL
3.6 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 46
4 Lenguaje C 51
4.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . 52
4.2 Entorno de programación . . . . . . . . . . . . . . . 54
4.3 Estructura básica de un programa en C . . . . . . . 57
4.4 Elementos léxicos . . . . . . . . . . . . . . . . . . . . 60
4.5 Sentencias simples y compuestas . . . . . . . . . . 62
4.6 Errores de depuración . . . . . . . . . . . . . . . . . 62
4.7 Evolución y estándares . . . . . . . . . . . . . . . . . 64
5 Algoritmia 67
5.1 Concepto de Algoritmo . . . . . . . . . . . . . . . . . 69
5.2 Creación y expresión de algoritmos . . . . . . . . . . 71
5.3 Diagramas de flujo . . . . . . . . . . . . . . . . . . . 73
5.4 Símbolos utilizados en un flujograma . . . . . . . . 74
5.5 Estructuras básicas . . . . . . . . . . . . . . . . . . 77
5.6 Estructuras derivadas . . . . . . . . . . . . . . . . . 79
5.7 Flujogramas: Ventajas y limitaciones . . . . . . . . . 82
5.8 Flujogramas estructurados y no estructurados . . . 83
5.9 Pseudocódigo . . . . . . . . . . . . . . . . . . . . . . 86
5.10 Pseudocódigo: Ventajas y limitaciones . . . . . . . . 89
5.11 Ejemplo de Algoritmo . . . . . . . . . . . . . . . . . . 90
5.12 Más ejemplos de algoritmos . . . . . . . . . . . . . . 91
5.13 Recapitulación . . . . . . . . . . . . . . . . . . . . . . 104
12 Funciones 311
12.1 Definiciones . . . . . . . . . . . . . . . . . . . . . . . 313
12.2 Funciones en C . . . . . . . . . . . . . . . . . . . . . 316
12.3 Declaración de una función . . . . . . . . . . . . . . 317
12.4 Definición de una función . . . . . . . . . . . . . . . 319
12.5 Llamada a una función . . . . . . . . . . . . . . . . . 322
12.6 return . . . . . . . . . . . . . . . . . . . . . . . . . . 323
12.7 Ámbito y Vida . . . . . . . . . . . . . . . . . . . . . . 327
12.8 Recapitulación . . . . . . . . . . . . . . . . . . . . . . 330
12.9 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 330
15 Punteros 389
15.1 Definición y declaración . . . . . . . . . . . . . . . . 390
15.2 Dominio y operadores . . . . . . . . . . . . . . . . . 391
15.3 Punteros y vectores . . . . . . . . . . . . . . . . . . . 396
15.4 Operatoria de punteros y de índices . . . . . . . . . 402
15.5 Puntero a puntero . . . . . . . . . . . . . . . . . . . . 405
15.6 Modificador de tipo const . . . . . . . . . . . . . . . 409
15.7 Distintos usos de const . . . . . . . . . . . . . . . . 410
15.8 Punteros fuera de ámbito . . . . . . . . . . . . . . . 414
15.9 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 415
17 Recursividad 443
17.1 Ejercicio inicial . . . . . . . . . . . . . . . . . . . . . 444
17.2 Concepto de Recursividad . . . . . . . . . . . . . . . 448
17.3 Árbol de recursión . . . . . . . . . . . . . . . . . . . 455
17.4 Recursión e iteración . . . . . . . . . . . . . . . . . . 456
17.5 Las torres de Hanoi . . . . . . . . . . . . . . . . . . . 462
17.6 Algoritmo de Ackermann . . . . . . . . . . . . . . . . 467
17.7 Recapitulación . . . . . . . . . . . . . . . . . . . . . . 470
17.8 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 471
Introducción y conceptos
generales.
En este capítulo...
1.1 Estructura funcional de las computadoras . . . . . . . . . 3
1
2 Capítulo 1. Introducción y conceptos generales
SECCIÓN 1.1
Dispositivos Dispositivos
PROCESADOR de Salida
de Entrada
MEMORIA
CPU
PRINCIPAL
ctrl_1 unidad_1
UC datos
... ...
ALU instrucciones ctrl_N unidad_N
SECCIÓN 1.2
Tanto las instrucciones, como los datos a manipular con esas ins-
trucciones, se almacenan en la memoria principal, en lugares dis-
tintos de esa memoria.
go, no lo entiende una máquina que sólo sabe codificar con ceros y
unos.
SECCIÓN 1.3
Codificación numérica.
En este capítulo...
2.1 Concepto de Código . . . . . . . . . . . . . . . . . . . . . . 18
2.8 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
17
18 Capítulo 2. Codificación numérica
SECCIÓN 2.1
Concepto de Código.
SECCIÓN 2.2
SECCIÓN 2.3
Se deduce que estas propiedades exigidas que toda base debe te-
ner, al menos, dos elementos: el cero y la unidad.
La base B = 10, por ejemplo, está formada por los siguientes ele-
mentos: B = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
0 ≤ ai ≤ B − 1, para i = 1, 2, . . . , k, y ak 6= 0 (2.2)
Cuanto más larga pueda ser la serie de dígitos que se emplean para
codificar, mayor será el rango de números que podrán ser represen-
tados. Por ejemplo, en base B = 10, si disponemos de tres dígitos
podremos codificar 1.000 valores diferentes (desde el 000 hasta el
999); si disponemos de cinco dígitos podremos codificar 100.000 va-
lores (desde el 00.000 hasta el 99.999). Desde luego, en un sistema
de numeración como el que conocemos y usamos nosotros nor-
24 Capítulo 2. Codificación numérica
SECCIÓN 2.4
Por eso, porque los ordenadores “sólo tienen dos dedos”, es por lo
que ellos trabajan mejor en base dos. Es decir, sólo disponen de
dos elementos para codificar cantidades. El primer elemento, por
definición de base, es el valor cero. El segundo (y último) es igual
al cardinal de la base menos uno y es igual al primer elemento
más uno. Esa base está formada, por tanto, por dos elementos:
B = {0, 1}.
B = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F }.
SECCIÓN 2.5
Sistema binario.
¡No!: cien.
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 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
y... ¿en base dos?: después de cero el uno. Y después del uno... ¡el
diez!
0 1 10 11 100
101 110 111 1000 1001
1010 1011 1100 1101 1110
1111 10000 10001 10010 10011
10100 10101 10110 10111 11000
11001 11010 11011 11100 11101
En ambos cuadros están codificadas las mismas cantidades. En
base diez el primero, en base dos o base binaria el segundo.
Las reglas básicas para esas dos operaciones (suma y resta) son:
28 Capítulo 2. Codificación numérica
0 + 0 = 0 0 - 0 = 0
0 + 1 = 1 0 - 1 = 1 “y debo 1”
1 + 0 = 1 1 - 0 = 1
1 + 1 = 0 “y llevo 1” 1 - 1 = 0
Y así, se puede practicar con sumas de enteros de más o menos
dígitos:
Al final del capítulo se recoge una sugerencia útil para practicar las
operaciones aritméticas: realizarlas en la calculadora de Windows
y probar luego a realizar esas mismas operaciones a mano.
SECCIÓN 2.6
Cambio de Base.
Paso de base dos a base diez: Para este cambio de base es sufi-
ciente con desarrollar la expansión del número. Por ejemplo:
Sección 2.6. Cambio de Base 29
Paso de base diez a base dos: Para este cambio se divide el entero
por dos (división entera), y se repite sucesivamente esta división
hasta llegar a un cociente menor que la base. Simplemente vamos
dividiendo por la base el número original y vamos repitiendo el
procedimiento para los cocientes que vamos obteniendo.
157 2
1 78 2
0 39 2
1 19 2
1 9 2
1 4 2
0 2 2
0 1
Las bases octal y hexadecimal, a las que antes hemos hecho re-
ferencia, facilitan el manejo de las cifras codificadas en base dos,
que enseguida acumulan gran cantidad de dígitos, todos ellos ce-
ros o unos. Para pasar de base dos a base dieciséis es suficiente
con separar la cifra binaria en bloques de cuatro en cuatro dígitos,
comenzando por el dígito menos significativo. Al último bloque, si
no tiene cuatro dígitos, se le añaden tantos ceros a la izquierda
como sean necesarios.
30 Capítulo 2. Codificación numérica
B D Hx B D Hx
0000 0 0 1000 8 8
0001 1 1 1001 9 9
0010 2 2 1010 10 A
0011 3 3 1011 11 B
0100 4 4 1100 12 C
0101 5 5 1101 13 D
0110 6 6 1110 14 E
0111 7 7 1111 15 F
SECCIÓN 2.7
Complemento a la Base.
k
CB (N ) = B k − N (2.4)
k
CB−1 (N ) = B k − N − 1 (2.5)
menos 1.
k k
CB−1 (N ) = CB (N ) − 1 (2.6)
619 619
El complemento a la base de
-492 508
492 es 508
127 [1]127
Donde si, como se ha dicho, despreciamos el último acarreo, tene-
mos que se llega al mismo resultado: 127.
N C2 (N ) C1 (N )
SECCIÓN 2.8
Ejercicios.
Las divisiones realizadas para estas dos conversiones son las si-
guientes:
810 8 810 5
2 101 8 0 162 5
5 12 8 2 32 5
4 1 2 6 5
1 1
N1 N2 C2 (N2 ) N1 − N2
N C2 (N ) C1 (N )
Codificación interna de la
información.
En este capítulo...
3.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.6 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
37
38 Capítulo 3. Codificación interna
SECCIÓN 3.1
Introducción.
1. De TEXTO:
a) Alfanuméricos:
SECCIÓN 3.2
Es fácil encontrar una tabla con los valores del código ASCII. Quizá
puede usted hacer la sencilla tarea de buscar esa tabla y comparar
las codificaciones de las letras mayúsculas y minúsculas. ¿Advierte
alguna relación entre ellas? ¿En qué se diferencian las mayúsculas
42 Capítulo 3. Codificación interna
SECCIÓN 3.3
SECCIÓN 3.4
SECCIÓN 3.5
Si, por ejemplo, queremos saber cómo queda codificado, con un by-
te, el valor numérico −75, debemos hacer los siguientes cálculos:
El bit más significativo será 1, porque el entero a codificar es nega-
tivo. El código binario del valor absoluto del número es 100 1011
(siete dígitos, que son los que nos quedan disponibles). El comple-
mento a la base menos uno de ese valor es 011 0100 (se calcula
invirtiendo todos los dígitos: de 0 a 1 y de 1 a 0), y el complemento
a la base será entonces 011 0101 (recuérdese la igualdad 2.6). Por
46 Capítulo 3. Codificación interna
SECCIÓN 3.6
Ejercicios.
Lenguaje C.
En este capítulo...
4.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . 52
4.2 Entorno de programación . . . . . . . . . . . . . . . . . . . 54
4.3 Estructura básica de un programa en C . . . . . . . . . . 57
4.4 Elementos léxicos . . . . . . . . . . . . . . . . . . . . . . . 60
4.5 Sentencias simples y compuestas . . . . . . . . . . . . . . 62
4.6 Errores de depuración . . . . . . . . . . . . . . . . . . . . . 62
4.7 Evolución y estándares . . . . . . . . . . . . . . . . . . . . 64
51
52 Capítulo 4. Lenguaje C
SECCIÓN 4.1
Introducción.
SECCIÓN 4.2
Entorno de programación.
SECCIÓN 4.3
SECCIÓN 4.4
Elementos léxicos.
SECCIÓN 4.5
SECCIÓN 4.6
Errores de depuración.
SECCIÓN 4.7
estándar C11 hay que tener en cuenta que al ser reciente es posible
que muchos compiladores disponibles en la red no hayan incluido
sus nuevas incorporaciones. Quizá, en una manual de introduc-
ción, no sea necesario ahondar en sus novedades.
CAPÍTULO 5
Algoritmia. Diagramas de
flujo. Pseudocódigo.
En este capítulo...
5.1 Concepto de Algoritmo . . . . . . . . . . . . . . . . . . . . 69
5.2 Creación y expresión de algoritmos . . . . . . . . . . . . . 71
5.3 Diagramas de flujo . . . . . . . . . . . . . . . . . . . . . . . 73
5.4 Símbolos utilizados en un flujograma . . . . . . . . . . . . 74
5.5 Estructuras básicas . . . . . . . . . . . . . . . . . . . . . . 77
5.6 Estructuras derivadas . . . . . . . . . . . . . . . . . . . . . 79
5.7 Flujogramas: Ventajas y limitaciones . . . . . . . . . . . . 82
5.8 Flujogramas estructurados y no estructurados . . . . . . 83
5.9 Pseudocódigo . . . . . . . . . . . . . . . . . . . . . . . . . . 86
5.10 Pseudocódigo: Ventajas y limitaciones . . . . . . . . . . . 89
5.11 Ejemplo de Algoritmo . . . . . . . . . . . . . . . . . . . . . 90
5.12 Más ejemplos de algoritmos . . . . . . . . . . . . . . . . . 91
5.13 Recapitulación . . . . . . . . . . . . . . . . . . . . . . . . . 104
67
68 Capítulo 5. Algoritmia
SECCIÓN 5.1
Concepto de Algoritmo.
SECCIÓN 5.2
SECCIÓN 5.3
SECCIÓN 5.4
Son varios los símbolos que se han definido para expresar median-
te flujograma la secuencia de instrucciones de un programa. No
los vamos a ver aquí todos, sino simplemente aquellos que usare-
mos en este manual para crear flujogramas acordes con la llamada
programación estructurada. Pueden verse esos símbolos en la Fi-
gura 5.1.
SECCIÓN 5.5
SECCIÓN 5.6
Estructuras derivadas.
SECCIÓN 5.7
SECCIÓN 5.8
SECCIÓN 5.9
Pseudocódigo.
Instr. 1
Instr. 2
Instr. 3
IF Cond
Instr. 1
ELSE
Instr. 2
END IF
IF Cond
Instr. 1
END IF
WHILE Cond.
Instr. 1
END WHILE
Y la segunda así:
DO
Instr. 1
WHILE Cond.
END DO
SECCIÓN 5.10
SECCIÓN 5.11
Acciones:
1. Inicializar Variables
1.1. Fact = 1
1.2. Lectura por teclado valor de n
2. WHILE n distinto de 0
2.1. Fact = Fact * n
2.2. n = n - 1
END WHILE
3. Devolver Resultado: Fact
SECCIÓN 5.12
m: Entero
Acciones:
1. Inicializar Variables
1.1. Lectura por teclado de los valores de a, b y c
2. m = a
3. IF m > b
m=b
END IF
4. IF m > c
m=c
END IF
5. Devolver Resultado: m
IF b < c
m=b
ELSE
m=c
END IF
3. Devolver Resultado: m
Veamos el pseudocódigo:
1. Inicializar Variables
Lectura por teclado del valor de n
2. WHILE n >= 2
n=n-2
END WHILE
3. IF n = 0
Mostrar que el entero introducido es PAR
ELSE
Mostrar que el entero introducido es IMPAR
END IF
SECCIÓN 5.13
Recapitulación.
Modelo de representación.
En este capítulo...
6.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . 108
6.2 Abstracción . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
6.3 Modularidad . . . . . . . . . . . . . . . . . . . . . . . . . . 110
6.4 Los Datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
6.5 Tipo de dato . . . . . . . . . . . . . . . . . . . . . . . . . . 123
6.6 Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
6.7 Variable - Tipo de Dato - Valor . . . . . . . . . . . . . . . . 126
6.8 Paradigmas programación estructurada . . . . . . . . . . 127
6.9 Recapitulación . . . . . . . . . . . . . . . . . . . . . . . . . 129
107
108 Capítulo 6. Modelo de representación
SECCIÓN 6.1
Introducción.
SECCIÓN 6.2
Abstracción.
SECCIÓN 6.3
Modularidad.
0
1:
0
1 1
2:
0 1
2 2 2
3:
0 1 2
...
k−1 k−1 k−1 k−1
k:
0 1 ... k−2 k−1
Variables:
i, fila, b: ENTEROS
Sección 6.3. Modularidad 113
Acciones:
1. Inicializar Variables:
1.1. Entrada valor fila
1.2. i = 0
2. WHILE i <= fila - 1
2.1. Calcular b = binomio(fila - 1, i)
2.2. Mostrar b
END WHILE
Variables:
m, k: ENTEROS
Acciones:
1. Inicializar variables:
114 Capítulo 6. Modelo de representación
Recibir valores de m y de k
2. B = Factorial(m)
3. B = B / Factorial(k)
4. B = B / Factorial(m - k)
5. Resultado: B
Con este ejemplo hemos visto que para afrontar y resolver satis-
factoriamente un problema es conveniente descomponerlo en par-
Sección 6.3. Modularidad 115
Cuadro de Código 6.1: Programa que muestra una fila del Triángulo
de Tartaglia
1 #include <stdio.h>
2
3 /* Declaracion de modulos o funciones definidas. -- */
4 void Tartaglia(unsigned short);
5 unsigned long Binomio(unsigned short, unsigned short);
6 unsigned long Factorial(unsigned short);
7
8 /* Funcion Principal. --- */
9 int main(void)
10 {
11 unsigned short fila;
12 printf("Aplicacion que muestra una fila");
13 printf(" del triangulo de Tartaglia.\n\n");
14 printf("Indique numero de la fila a visualizar ... "
);
15 scanf(" %hu", &fila);
16
17 Tartaglia(fila);
18 return 0;
19 }
20 /* Funcion Tartaglia. --- */
21 void Tartaglia(unsigned short f)
22 {
23 unsigned short i;
24
25 for(i = 0 ; i < f ; i++)
26 printf(" %lu\t", Binomio(f - 1 , i ));
27 }
28 /* Funcion Binomio. --- */
29 unsigned long Binomio(unsigned short m, unsigned short k)
30 {
Sección 6.3. Modularidad 117
Figura 6.4: Operaciones con números complejos: (a) Suma; (b) Res-
ta; (c) Producto.
Variables:
a, b: DECIMALES (primer valor complejo)
c, c: DECIMALES (segundo valor complejo)
re, im: DECIMALES (valor complejo calculado)
op: CARÁCTER (recogerá la operación seleccionada)
Acciones:
1. Inicializar variables:
1.1. Ingreso de los valores de a, b.
1.2. Ingreso de los valores de c, d.
1.3. Ingreso del valor de op (+ , - , *).
2. IF op = ‘+’
Sección 6.3. Modularidad 119
SECCIÓN 6.4
Un dato puede ser tanto una constante definida dentro del progra-
ma y que no altera su valor durante su ejecución; o dato variable,
que puede cambiar su valor a lo largo de la ejecución el programa.
SECCIÓN 6.5
Tipo de dato.
SECCIÓN 6.6
Variable.
Por ejemplo, mediante <x, entero, Rx , 7> nos referimos a una varia-
ble que se ha llamado x, creada para reservar datos de tipo entero,
que está posicionada en la dirección de memoria Rx (ya verá en su
momento qué forma tienen esas referencias de memoria) y que en
este preciso instante tiene codificado el valor entero 7. Al hacer la
asignación x ←− 3, se altera el estado de esa memoria, de forma
que ahora x pasa a codificar el valor entero 3.
SECCIÓN 6.7
SECCIÓN 6.8
1. Entrada N.
2. Inicializar Variables.
3. Calcular F, término N de la serie de Fibonacci.
4. mostrar valor de F.
2.1. fib1 = 1
2.2. fib2 = 1
2.3. Fib = 1
2.4. i = 3
SECCIÓN 6.9
Recapitulación.
En este capítulo...
7.1 Declaración de variables . . . . . . . . . . . . . . . . . . . 133
7.2 Dominios . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
7.3 Literales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
7.4 Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
7.5 Asignación . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
7.6 Aritméticos . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
7.7 Cociente de enteros . . . . . . . . . . . . . . . . . . . . . . 148
7.8 Relacionales y Lógicos . . . . . . . . . . . . . . . . . . . . . 150
7.9 A nivel de bit . . . . . . . . . . . . . . . . . . . . . . . . . . 153
7.10 Operadores compuestos . . . . . . . . . . . . . . . . . . . . 159
7.11 Intercambio de valores . . . . . . . . . . . . . . . . . . . . 161
7.12 Operador sizeof . . . . . . . . . . . . . . . . . . . . . . . 162
7.13 Promoción entre tipos de dato . . . . . . . . . . . . . . . . 164
7.14 Cast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
7.15 Propiedades de los operadores . . . . . . . . . . . . . . . . 168
7.16 Fuera de Rango . . . . . . . . . . . . . . . . . . . . . . . . 171
131
132 Capítulo 7. Tipos de Dato y Variables en C
SECCIÓN 7.1
Declaración de variables.
SECCIÓN 7.2
RANGO DE VALORES
SIGNO TIPOS MENOR MAYOR
float ±3.402923E+38
double ±1.7976931E+308
long double Depende del compilador
SECCIÓN 7.3
Formación de literales.
VALORES ENTEROS
SECCIÓN 7.4
SECCIÓN 7.5
Operador asignación.
nombre_variable = expresion;
a = a + 1;
LValue = RValue;
SECCIÓN 7.6
Operadores aritméticos.
Supongamos la expresión
Sección 7.6. Aritméticos 145
a = b + ++c;
signed short a = 5, b = 2, c;
c = ++a + b + a++;
SECCIÓN 7.7
Por ejemplo:
short a = -3 , b = 2, c = a / b;
La verdad es que cada una de las dos definiciones tiene una jus-
tificación inteligente. El estándar C99 no viene a corregir un error
absurdo introducido en los estándares previos. Más adelante com-
prenderá por qué el C90 había propuesto su definición, y verá que
con el cambio de definición se pierden propiedades computaciona-
les que eran útiles con la definición del C90.
SECCIÓN 7.8
int a = 1 , b = 3 , x = 30 , y = 10;
int resultado;
resultado = a * x == b * y;
a b a && b a || b !a
F F F F V
F V F V V
V F F V F
V V V V F
SECCIÓN 7.9
and or xor
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0
Tabla 7.4: Valores que adoptan los tres operadores a nivel de bit.
SECCIÓN 7.10
Operadores compuestos.
F = F * n;
n = n - 1;
SECCIÓN 7.11
SECCIÓN 7.12
Operador sizeof.
sizeof(nombre_var); ó sizeof(nombre_tipo_dato);
Cuadro de Código 7.7: Para ver el tamaño de los tipos de dato pri-
mitivos.
1 #include <stdio.h>
2 main()
3 {
4 printf("int => %d\n",sizeof(int));
5 printf("char => %d\n",sizeof(char));
6 printf("short => %d\n",sizeof(short));
7 printf("long => %d\n",sizeof(long));
8 printf("float => %d\n",sizeof(float));
9 printf("double => %d\n",sizeof(double));
10 }
11 //La funcion printf se presenta en el proximo capitulo.
164 Capítulo 7. Tipos de Dato y Variables en C
SECCIÓN 7.13
char ch = 7;
short sh = 2;
long ln = 100, ln2;
double x = 12.4, y;
y = (ch * ln) / sh - x;
El resultado final será pues un valor del tipo de dato double. Y así
será almacenado en la posición de memoria de la variable y de tipo
double.
SECCIÓN 7.14
(tipo)nombre_variable;
short a = 1, b = 2;
double c = (double)a / b;
SECCIÓN 7.15
1 () [] -> . I-D
2 ! ˜ ++ -- + - * & (cast) sizeof D-I
3 .* ->* I-D
4 * / % I-D
5 + - I-D
6 << >> I-D
7 > >= < <= I-D
8 == != I-D
9 & I-D
10 ^ I-D
11 | I-D
12 && I-D
13 || I-D
14 ?: D-I
15 = += -= *= /= %= &= |= ^= <<= >>= D-I
16 , I-D
SECCIÓN 7.16
SECCIÓN 7.17
SECCIÓN 7.18
C99 ofrece cinco tipos de dato enteros diferentes: char, short int,
int, long int y long long int. El tamaño de una variable int
dependerá de la arquitectura del entorno de ejecución. Su rango
de valores, como se verá en breve, queda definido como cualquier
valor entre INT_MIN e INT_MAX. Se ha introducido un nuevo tipo
de dato entero, de mayor longitud que el que hasta este momento
se tenía: el tipo long long, de 64 bits (8 bytes). Para indicar que
un literal expresa un valor de tipo long long se coloca el sufijo ll,
ó LL, ó llu, ó LLU.
Los tipos enteros más rápidos que tienen, al menos, una an-
chura (en bytes) determinada. Con este tipo de dato el com-
pilador trata de establecer, dentro de las condiciones del tipo
(anchura y signo) cuál es el óptimo en relación a su velocidad
dentro del sistema en que se compila el programa.
Los límites para los valores del tipo de dato entero de tamaño
exacto:
Sección 7.18. Enteros en C90 y C99 179
Los límites para los valores del tipo de dato de tamaño “al
menos” dependerán evidentemente del sistema para el que se
haya definido el compilador. Si suponemos un sistema que
soporta todos los tamaños: 8, 16, 32 y 64, esos valores serán:
Los límites para los valores del tipo de dato de tamaño “los
más rápidos” también dependerán evidentemente del sistema
para el que se haya definido el compilador. Si suponemos un
sistema que soporta todos los tamaños: 8, 16, 32 y 64, esos
valores serán:
Los límites para los valores del tipo de dato de tamaño mayor:
SECCIÓN 7.19
Ayudas On line.
SECCIÓN 7.20
Recapitulación.
SECCIÓN 7.21
La salida que se obtiene con este código es... -128. Intente justificar
por qué ocurre. No se preocupe si aún no conoce el funcionamien-
to de la función printf. Verdaderamente la variable a ahora vale
-128. ¿Por qué?
Sección 7.21. Ejercicios 189
SOLUCIÓN: -12 12 1.
¡Explíquelo!
short a = 0xFFFF;
long b = 0xFFFF;
Funciones de entrada y
salida por consola.
En este capítulo...
8.1 printf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
195
196 Capítulo 8. Entrada y Salida por Consola
SECCIÓN 8.1
int printf
(const char *cadena_control[, argumento, ...]);
printf("Otro texto");
Para poder escribir este carácter de salto de línea, y otros que lla-
mamos caracteres de control, se escribe, en el lugar de la cadena
donde queremos que se imprima ese carácter especial, una barra
invertida (‘
’) seguida de una letra. Cuál letra es la que se debe poner depen-
derá de qué carácter especial se desea introducir. Esos caracteres
de control son caracteres no imprimibles, o caracteres que tienen
ya un significado especial en la función printf.
Ahora c vale 15
y b vale ahora 11
A. 2345
B. -2345
C. +2345
D. -2345
E. 2345
F. -2345
SECCIÓN 8.2
int scanf
(const char *cadena_control[,direcciones,...]);
SECCIÓN 8.3
SECCIÓN 8.4
Caracter a ... g
Caracter b ... Caracter c ... q
Caracter d ...
Caracter c ... q
Caracter d ...
SECCIÓN 8.5
Recapitulación.
SECCIÓN 8.6
Ejercicios.
Que muestran los números tal y como los tiene codificados el orde-
nador: al ser enteros con signo, y ser negativos, codifica el bit más
significativo (el bit 31 en el caso de sli, el bit 15 en el caso de ssi)
a uno porque es el bit del signo; y codifica el resto de los bits (desde
el bit 30 al bit 0 en el caso de sli, desde el bit 14 hasta el bit 0 en
el caso de ssi) como el complemento a la base del valor absoluto
del número codificado.
En este capítulo...
9.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . 222
9.2 Transferencia condicionada . . . . . . . . . . . . . . . . . 224
9.3 Bifurcación Abierta . . . . . . . . . . . . . . . . . . . . . . 225
9.4 Bifurcación Cerrada . . . . . . . . . . . . . . . . . . . . . . 226
9.5 Anidamiento . . . . . . . . . . . . . . . . . . . . . . . . . . 227
9.6 Escala if - else . . . . . . . . . . . . . . . . . . . . . . . . . 230
9.7 Operador Condicional . . . . . . . . . . . . . . . . . . . . . 234
9.8 Estructura switch . . . . . . . . . . . . . . . . . . . . . . . 236
9.9 Recapitulación . . . . . . . . . . . . . . . . . . . . . . . . . 241
9.10 Ejercicios: secuencialidad . . . . . . . . . . . . . . . . . . . 242
9.11 Ejercicios: secuencia de condicionales . . . . . . . . . . . 243
9.12 Ejercicios: árboles de Condicionalidad . . . . . . . . . . . 244
9.13 Ejercicios: anidamiento de condicionales . . . . . . . . . . 245
221
222 Capítulo 9. Estructuras de Control Condicionales
SECCIÓN 9.1
SECCIÓN 9.2
SECCIÓN 9.3
if(condición) sentencia;
226 Capítulo 9. Estructuras de Control Condicionales
SECCIÓN 9.4
if(condición) sentencia1;
else sentencia2;
SECCIÓN 9.5
SECCIÓN 9.6
Escala if – else.
Como se ve, una estructura así anidada se escribe con mayor faci-
lidad y expresa también más claramente las distintas alternativas.
No es necesario que, en un anidamiento de sentencias condiciona-
Sección 9.6. Escala if - else 233
SECCIÓN 9.7
es equivalente a:
if(a < b) c = a;
else c = b;
c = a < b ? a : b;
236 Capítulo 9. Estructuras de Control Condicionales
SECCIÓN 9.8
Figura 9.3: Flujograma del programa ejemplo con switch sin sen-
tencias break.
Una sola sentencia puede venir marcada por más de una etiqueta
case. El ejemplo recogido en el Cuadro de Código 9.12 resuelve,
de nuevo, el programa que indica, a partir de la nota numérica,
la calificación textual. En este ejemplo, los valores 0, 1, 2, 3, y 4,
etiquetan la misma línea de código.
Figura 9.4: Flujograma del programa ejemplo con switch y con sen-
tencias break.
Cuadro de Código 9.12: Uso del switch donde varios valores sirven
para indicar el inicio de ejecución en el bloque de sentencias.
1 #include <stdio.h>
2 int main(void)
3 {
4 short int nota;
5 printf("Nota del examen ... ");
6 scanf(" %hd",¬a);
7 switch(nota)
8 {
9 case 0: case 1: case 2: case 3: case 4:
10 printf("SUSPENSO");
11 break;
12 case 5: case 6:
13 printf("APROBADO");
14 break;
15 case 7: case 8:
16 printf("NOTABLE");
17 break;
18 case 9: printf("SOBRESALIENTE");
19 break;
20 case 10: printf("MATRICULA DE HONOR");
21 break;
22 default: printf("Nota introducida erronea");
23 }
24 return 0;
25 }
SECCIÓN 9.9
Recapitulación.
SECCIÓN 9.10
SECCIÓN 9.11
SECCIÓN 9.12
SECCIÓN 9.13
1 #include <stdio.h>
2 int main(void) {
3 unsigned short D , mm , aaaa;
4 unsigned short M , A , C , d;
5
6 printf("Introduzca la fecha ... \n");
7 printf("Dia ... "); scanf(" %hu", &D);
8 printf("Mes ... "); scanf(" %hu", &mm);
9 printf("Anyo ... "); scanf(" %hu", &aaaa);
10 // Valores de las variables:
11 // El valor de D ya ha quedado introducido por el usuario
.
12 // Valor de M:
13 if(mm < 3) {
14 M = mm + 10;
15 A = (aaaa - 1) % 100;
16 C = (aaaa - 1) / 100;
17 }
18 else {
19 M = mm - 2;
20 A = aaaa % 100;
21 C = aaaa / 100;
22 }
23 printf("El dia %2hu / %2hu / %4hu fue ",D, mm, aaaa)
;
24 d = (70 + /26 + M - 2) / 10 + D + A + A / 4 + C / 4
- C * 2) % 7;
25 switch(d) {
26 case 0: printf("DOMINGO"); break;
27 case 1: printf("LUNES"); break;
28 case 2: printf("MARTES"); break;
29 case 3: printf("MIERCOLES"); break;
30 case 4: printf("JUEVES"); break;
250 Capítulo 9. Estructuras de Control Condicionales
En este capítulo...
10.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . 252
10.2 Estructura while . . . . . . . . . . . . . . . . . . . . . . . 252
10.3 Estructura do – while . . . . . . . . . . . . . . . . . . . . 258
10.4 Estructura for . . . . . . . . . . . . . . . . . . . . . . . . . 261
10.5 Programación estructurada . . . . . . . . . . . . . . . . . . 265
10.6 Sentencias de salto . . . . . . . . . . . . . . . . . . . . . . 270
10.7 break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
10.8 continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
10.9 goto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
10.10 Variables de control . . . . . . . . . . . . . . . . . . . . . . 280
10.11 Recapitulación . . . . . . . . . . . . . . . . . . . . . . . . . 281
10.12 Ejercicios: iterar determinadas veces . . . . . . . . . . . . 282
10.13 Ejercicios: iterar indeterminadas veces . . . . . . . . . . . 284
10.14 Ejercicios: iterar hasta encontrar ‘contraejemplo’ . . . . . 286
251
252 Capítulo 10. Estructuras de Control Iteradas
SECCIÓN 10.1
Introducción.
SECCIÓN 10.2
Estructura while.
while(condición) sentencia;
Este último ejemplo ha sido sencillo. Veamos otro ejemplo que re-
quiere un poco más de imaginación. Supongamos que queremos
hacer un programa que solicite al usuario la entrada de un entero
y que entonces muestre por pantalla el factorial de ese número. Ya
se sabe la definición de factorial: n! = n × (n − 1) × (n − 2) × . . . × 2 × 1.
Sección 10.2. Estructura while 255
n 5 4 3 2 1 0
Fact 5 20 60 120 120 120
Hemos tenido que emplear una variable auxiliar, que hemos llama-
do aux, para poder hacer el intercambio de variables: que a pase a
valer el valor de b y b el del resto de dividir a por b.
SECCIÓN 10.3
Estructura do – while.
do sentencia; while(condición);
SECCIÓN 10.4
Estructura for.
5. Vuelta al paso 2.
6. Fin de la iteración.
SECCIÓN 10.5
SECCIÓN 10.6
Sentencias de salto.
SECCIÓN 10.7
SECCIÓN 10.8
SECCIÓN 10.9
esa breve carta deja clara su postura. Reza así: “Go To Statement
Considered Harmful”. Siempre hay programadores que la usan, e
incluso hay autoridades indiscutidas del mundo de la programa-
ción que aceptan su uso en determinadas condiciones excepciona-
les. Pero en términos generales se puede afirmar que la sentencia
goto no debe ser usada.
SECCIÓN 10.10
SECCIÓN 10.11
Recapitulación.
SECCIÓN 10.12
SECCIÓN 10.13
SECCIÓN 10.14
SECCIÓN 10.15
SECCIÓN 10.16
SECCIÓN 10.17
π 2 2 4 4 6 6 8 8
= × × × × × × × ×
2 1 3 3 5 5 7 7 9
π2 1 1 1 1 1 1
= 2 + 2 + 2 + 2 + 2 + 2 + ...
6 1 2 3 4 5 6
6 1 1 1 1
= 1− 2 × 1− 2 × 1− 2 × 1− 2 ×
π2 2 3 5 7
1 1 1
1 − 2 × 1 − 2 × 1 − 2 × ...
11 13 17
En este capítulo...
11.1 Ámbito y Vida . . . . . . . . . . . . . . . . . . . . . . . . . . 294
293
294 Capítulo 11. Ámbito y Vida de las Variables
SECCIÓN 11.1
Ámbito y Vida.
Además del ámbito, existe otro concepto, que podríamos llamar ex-
tensión o tiempo de vida, que define el intervalo de tiempo en el
que el espacio de memoria reservado por una variable sigue en re-
serva; cuando la variable “muere”, ese espacio de memoria vuelve
a estar disponible para otros usos que el ordenador requiera. Tam-
bién este concepto quedará más aclarado a medida que avancemos
en este breve capítulo.
SECCIÓN 11.2
SECCIÓN 11.3
Hay una palabra en C, que rara vez se usa, para indicar que la
variable es local. Es la palabra reservada auto. El compilador des-
cubre siempre el ámbito de una variable gracias al lugar donde ésta
se declara.
¿Cuál es la salida que ofrecerá por pantalla este código? Por lo que
respecta a la variable b no hay ninguna duda: se ha incrementado
Sección 11.4. Estáticas y Dinámicas 301
El valor de b es 10 y el de c es 0.
SECCIÓN 11.4
a = 5. b = 5.
a = 10. b = 5.
a = 15. b = 5.
a = 20. b = 5.
a = 25. b = 5.
a = 30. b = 5.
a = 35. b = 5.
a = 40. b = 5.
a = 45. b = 5.
a = 50. b = 5.
a = 55. b = 5.
a = 60. b = 5.
SECCIÓN 11.5
Variables en registro.
También puede ocurrir que no se desee que una variable sea alma-
cenada en un registro de la ALU. Y quizá se desea indicar al com-
pilador que, sea cual sea su opinión, una determinada variable no
debe ser almacenada allí sino en la memoria, como una variable
Sección 11.6. extern 305
SECCIÓN 11.6
Variables extern.
Para evitar ese problema, las variable globales que deben perma-
necer en todos o varios de los módulos de un programa se decla-
306 Capítulo 11. Ámbito y Vida de las Variables
SECCIÓN 11.7
En resumen...
SECCIÓN 11.8
Un ejercicio propuesto.
1 #include <stdio.h>
2 int main(void)
3 {
4 unsigned short a, b, mcd;
5 do
6 {
7 printf("Valor de a ... "); scanf(" %hu",&a);
8 printf("Valor de b ... "); scanf(" %hu",&b);
9 if(a == 0 && b == 0) break;
10 while(b)
11 {
12 static unsigned short cont = 0;
13 mcd = b;
14 b = a % b;
15 a = mcd;
16 printf("\ncont = %hu", ++cont);
17 }
18 printf("\n\nEl mcd es %hu.", mcd);
19 }while(1);
20 return 0;
21 }
310 Capítulo 11. Ámbito y Vida de las Variables
CAPÍTULO 12
Funciones.
En este capítulo...
12.1 Definiciones . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
12.2 Funciones en C . . . . . . . . . . . . . . . . . . . . . . . . . 316
12.3 Declaración de una función . . . . . . . . . . . . . . . . . 317
12.4 Definición de una función . . . . . . . . . . . . . . . . . . 319
12.5 Llamada a una función . . . . . . . . . . . . . . . . . . . . 322
12.6 return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
12.7 Ámbito y Vida . . . . . . . . . . . . . . . . . . . . . . . . . . 327
12.8 Recapitulación . . . . . . . . . . . . . . . . . . . . . . . . . 330
12.9 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
311
312 Capítulo 12. Funciones
SECCIÓN 12.1
Definiciones.
Tanto los procedimientos como las funciones pueden ser vistos co-
mo cajas negras: un código del que desconocemos sus sentencias,
al que se le puede suministrar unos datos de entrada y obtener
modificaciones para esos valores de entrada y/o el cálculo de un
nuevo valor, deducido a partir de los valores que ha recibido como
entrada.
Con eso se consigue programas más cortos; que el código pueda ser
usado más de una vez; mayor facilidad para gestionar un correcto
orden de ejecución de sentencias; que las variables tengan mayor
316 Capítulo 12. Funciones
SECCIÓN 12.2
Funciones en C.
SECCIÓN 12.3
Declaración de la función.
tipo_funcion nombre_funcion
([tipo1 [var1][,... tipoN [varN]]);
Toda función que quiera ser definida e invocada debe haber sido
previamente declarada. El prototipo de la función presenta el modo
en que esa función debe ser empleada. Es como la definición de
su interface, de su forma de comunicación: qué valores, de qué
tipo y en qué orden debe recibir la función como argumentos al
ser invocada. El prototipo permite localizar cualquier conversión
ilegal de tipos entre los argumentos utilizados en la llamada de la
función y los tipos definidos en los parámetros, entre los parénte-
sis del prototipo. Además, controla que el número de argumentos
Sección 12.4. Definición de una función 319
SECCIÓN 12.4
tipo_funcion nombre_funcion
([tipo1 var1],... tipoN varN])
{
[declaración de variables locales]
320 Capítulo 12. Funciones
tipo_funcion nombre_funcion(void);
// declaración prototipo
SECCIÓN 12.5
variable = nombre_funcion
([argumento1][, ..., argumentoN]);
SECCIÓN 12.6
La sentencia return.
return [expresión];
Sección 12.6. return 325
mostrar(10);
A = mayor(a , b);
SECCIÓN 12.7
SECCIÓN 12.8
Recapitulación.
Hemos visto cómo crear bloques de código, que pueden luego ser
invocados, mediante un nombre para que realicen una determina-
da función. Gracias a la llamada a uno de estos bloques de códi-
go, que hemos llamado funciones, podemos obtener un resultado
calculado a partir de valores iniciales que la función recibe como
parámetros. La función termina su ejecución entregando un valor
concreto de un tipo de dato predeterminado y establecido en su
prototipo.
SECCIÓN 12.9
Ejercicios propuestos.
n!
(k!×(n−k)!) .
Sugerencias:
2. Será útil definir una función que realice el cálculo del facto-
rial.
En este capítulo...
13.1 Noción y declaración de Vector . . . . . . . . . . . . . . . . 340
339
340 Capítulo 13. Vectores y Matrices
SECCIÓN 13.1
tipo nombre_vector[dimension];
Sección 13.1. Noción y declaración de Vector 341
short mi_vector[1000], i;
for(i = 0 ; i < 1000 ; i++)
mi_vector[i] = 0;
Tenga cuidado, por ejemplo, con el recorrido del vector, que va des-
de el elemento 0 hasta el elemento 999. Un error habitual es escri-
bir:
short mi_vector[1000], i;
for(i = 0 ; i <= 1000 ; i++) // Debería ser i < 1000
mi_vector[i] = 0; // ERROR !!!
short mi_vector[10] =
{10,20,30,40,50,60,70,80,90,100};
short mi_vector[10], i;
for(i = 0 ; i < 10 ; i++)
mi_vector[i] = 10 * (i + 1);
short mi_vector[] =
{10,20,30,40,50,60,70,80,90,100};
SECCIÓN 13.2
float matriz[3][3];
que reserva 9 bloques de cuatro bytes cada uno para poder alma-
cenar valores tipo float. Esas variables se llaman también con
índices, en este caso dos índices (uno para cada dimensión) que
van desde el 0 hasta el valor de cada dimensión menos uno.
Por ejemplo:
long matriz[5][2], i, j;
for(i = 0 ; i < 5 ; i++)
for(j = 0 ; j < 2 ; j++)
matriz[i][j] = 0;
donde tenemos una matriz de cinco filas y dos columnas, toda ella
con los valores iniciales a cero. También se puede inicializar la
matriz mediante el operador asignación y llaves. En este caso se
haría lo siguiente:
long matriz[5][2], i, j, k;
for(i = 0 , k = 1; i < 5 ; i++)
{
for(j = 0 ; j < 2 ; j++)
{
matriz[i][j] = k;
k++;
}
}
SECCIÓN 13.3
int main(void)
{
short size;
printf("Dimension del array ... ");
scanf(" %hd", &size);
double m[size];
// ...
return 0;
}
short dimensión;
printf("dimensión ... ");
scanf(" %hd", &dimension);
double array[dimension] = {0}; // ERROR!!!
SECCIÓN 13.4
SECCIÓN 13.5
SECCIÓN 13.6
SECCIÓN 13.7
SECCIÓN 13.8
SECCIÓN 13.9
SECCIÓN 13.10
SECCIÓN 13.11
grama que calcule los valores de un segundo array q que sean los
correspondientes al polinomio derivado de p.
SECCIÓN 13.12
SECCIÓN 13.13
SECCIÓN 13.14
Caracteres y Cadenas de
caracteres.
En este capítulo...
14.1 Operaciones con caracteres . . . . . . . . . . . . . . . . . 358
14.2 Entrada de caracteres . . . . . . . . . . . . . . . . . . . . . 361
14.3 Cadena de caracteres . . . . . . . . . . . . . . . . . . . . . 362
14.4 Dar valor a una cadena . . . . . . . . . . . . . . . . . . . . 364
14.5 Operaciones con cadenas . . . . . . . . . . . . . . . . . . . 371
14.6 Otras funciones . . . . . . . . . . . . . . . . . . . . . . . . 376
14.7 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
357
358 Capítulo 14. Caracteres y Cadenas de caracteres
SECCIÓN 14.1
Ejemplo de uso:
Sección 14.1. Operaciones con caracteres 359
if(isalnum(‘@’)) printf("Alfanumerico");
else printf("No alfanumerico");
Ejemplo de uso:
if(isalnum(‘2’)) printf("Alfabetico");
else printf("No alfabetico");
Ejemplo de uso:
SECCIÓN 14.2
Entrada de caracteres.
SECCIÓN 14.3
Cadena de caracteres.
char mi_cadena[dimensión];
SECCIÓN 14.4
"buenas tardes.
este texto sigue siendo parte de la entrada.
12345: se incluyen los dígitos.
FIN"
Otra función, quizá más cómoda (pero que no goza de tantas po-
sibilidades de control en el valor de la cadena de entrada), es la
función gets. La función gets está también definida en la biblio-
teca stdio.h, y su prototipo es el siguiente:
Hay que hacer una advertencia grave sobre el uso de estas funcio-
nes de entrada de cadenas de texto: puede ocurrir que la cadena
introducida por teclado sea de mayor longitud que el número de
bytes que se han reservado. Esa incidencia no es vigilada por la
función gets. Y si ocurre, entonces, además de grabar informa-
ción de la cadena en los bytes reservados para ello, se hará uso de
los bytes, inmediatamente consecutivos a los de la cadena, hasta
almacenar toda la información tecleada más su carácter nulo final.
Esa violación de memoria puede tener —y de hecho habitualmente
tiene— consecuencias desastrosas para el programa.
Por todo ello, está recomendado que NO se haga uso de esta fun-
ción.
SECCIÓN 14.5
char *strncat
(char *dest, const char *src, size_t maxlen);
int strncmp
( const char *s1, const char *s2, size_t maxlen);
SECCIÓN 14.6
SECCIÓN 14.7
Ejercicios.
Esta segunda forma (Cuadro de Código 14.12) es, desde luego, más
sencilla. Una observación conviene hacer aquí: en la segunda so-
lución, al acabar de hacer la copia, hemos cerrado la cadena copia
Sección 14.7. Ejercicios 381
Punteros.
En este capítulo...
15.1 Definición y declaración . . . . . . . . . . . . . . . . . . . . 390
15.2 Dominio y operadores . . . . . . . . . . . . . . . . . . . . . 391
15.3 Punteros y vectores . . . . . . . . . . . . . . . . . . . . . . 396
15.4 Operatoria de punteros y de índices . . . . . . . . . . . . . 402
15.5 Puntero a puntero . . . . . . . . . . . . . . . . . . . . . . . 405
15.6 Modificador de tipo const . . . . . . . . . . . . . . . . . . 409
15.7 Distintos usos de const . . . . . . . . . . . . . . . . . . . 410
15.8 Punteros fuera de ámbito . . . . . . . . . . . . . . . . . . . 414
15.9 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
389
390 Capítulo 15. Punteros
SECCIÓN 15.1
Definición y declaración.
Y como tipos de dato que son, habrá que definir para ellos un do-
minio y unos operadores.
tipo *nombre_puntero;
Por ejemplo:
long a, b, *c;
SECCIÓN 15.2
*pt = 3.141596;
Sección 15.2. Dominio y operadores 395
float x, *px;
long y;
px = &y;
float x, *px;
char y;
px = &y;
4. Operadores relacionales (<, <=, >, >=, ==, !=): los veremos
más adelante.
SECCIÓN 15.3
Punteros y vectores.
long a[10];
long *pa;
pa = &a[0];
ph2(0012FF62) - ph1(0012FF50) = 9
pd2(0012FF20) - pd1(0012FED8) = 9
(long)ph2 - (long)ph1 = 18
(long)pd2 - (long)pd1 = 72
Operadores relacionales (<, <=, >, >=, ==, !=): De nuevo estos
operadores se aplican únicamente sobre punteros que apunten a
posiciones de memoria de variables ubicadas dentro de un array.
Estos operadores comparan las ubicaciones de las variables a las
que apuntan, y no, desde luego, los valores de las variables a las
que apuntan. Si, por ejemplo, el puntero pa0 apunta a la posición
primera del array a (posición de a[0]) y el puntero pa1 apunta a la
segunda posición del mismo array (posición de a[1]), entonces la
expresión pa0 < pa1 se evalúa como verdadera (distinta de cero).
402 Capítulo 15. Punteros
SECCIÓN 15.4
tipo nombre_array[dimensión];
SECCIÓN 15.5
Puntero a puntero.
Y así como antes hemos visto que hay una relación directa entre
punteros a un tipo de dato y vectores de este tipo de dato, tam-
bién veremos ahora que hay una relación directa entre punteros a
punteros y matrices de dimensión 2. Y entre punteros a punteros
a punteros y matrices de dimensión 3. Y si trabajamos con matri-
ces de dimensión n, entonces también lo haremos con punteros a
punteros a punteros...
double m[4][6];
406 Capítulo 15. Punteros
m = 0012FECC
*(m + 0) = 0012FECC &m[0][0] = 0012FECC
*(m + 1) = 0012FEFC &m[1][0] = 0012FEFC
Sección 15.5. Puntero a puntero 407
SECCIÓN 15.6
SECCIÓN 15.7
Por ejemplo:
double x = 5, y = 2;
const double *ptrx = &x;
double const *ptry = &y;
x *= 2; // operación permitida.
y /= 2; // operación permitida.
ptrx = &y; // operación permitida.
Sección 15.7. Distintos usos de const 411
double x = 5, y = 2;
double* const ptrx = &x;
double* const ptry = &y;
x *= 2; // operación permitida.
y /= 2; // operación permitida.
ptrx = &y; // operación PROHIBIDA.
ptry = &x; // operación PROHIBIDA.
*ptrx *= 2; // operación permitida.
*ptry /= 2; // operación permitida.
412 Capítulo 15. Punteros
double x = 5;
const double * const ptrx = &x;
double x = 5, y = 2, z = 7;
const double xx = 25;
const double *ptrx = &x; // a constante
double* const ptry = &y; // constante
const double* const ptrz = &z; // constante a constante.
x = 1; // OK: x no es const.
*ptrx = 1; // MAL: ptrx es puntero a constante.
ptrx = &xx; // OK: ptrx no es puntero constante.
= 1; // OK: y no es const.
*ptry = 1; // OK: ptry no es puntero a constante.
ptry = &x; // MAL: ptry es puntero constante.
z = 1; // OK: z no es const.
ptrz = &x; // MAL: ptrz es puntero constante.
*ptrz = 1; // MAL: ptrz es puntero a constante.
SECCIÓN 15.8
SECCIÓN 15.9
Ejercicios.
Recuerde:
En este capítulo...
16.1 Por valor y por referencia . . . . . . . . . . . . . . . . . . . 418
16.2 Vectores con C89 y C90 . . . . . . . . . . . . . . . . . . . . 421
16.3 Matrices con C89 y C90 . . . . . . . . . . . . . . . . . . . . 425
16.4 Matrices con C99 . . . . . . . . . . . . . . . . . . . . . . . 427
16.5 Argumentos de puntero constantes . . . . . . . . . . . . . 429
16.6 Recapitulación . . . . . . . . . . . . . . . . . . . . . . . . . 433
16.7 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
417
418 Capítulo 16. Funciones: llamada por Referencia
SECCIÓN 16.1
intercambio(&x,&y);
Por otro lado, siempre que deseemos que una función nos devuelva
más de un valor también será necesario utilizar llamadas por re-
ferencia: uno de los valores deseamos podremos recibirlo gracias a
la sentencia return de la función llamada; los demás podrán que-
dar en los argumentos pasados como referencia: entregamos a la
función sus direcciones, y ella, al terminar, deja en esas posiciones
de memoria los resultados deseados.
SECCIÓN 16.2
long a[100];
funcion(a);
void funcion(long*);
ó también
void funcion(long*arg);
SECCIÓN 16.3
Así las cosas veamos entonces cómo podemos recibir esa matriz
antes declarada como parámetro de una función.
Pero estas formas son erróneas. ¿Por qué? Pues porque el com-
pilador de C necesita conocer el tipo de dato del array que recibe
como parámetro: hemos dicho antes que una matriz hay que con-
siderarla aquí como un array de elementos de tipo array de una
determinada cantidad de variables. El compilador necesita cono-
cer el tamaño de los elementos del array. No le basta saber que es
una estructura de doble indirección o de matriz. Cuando se trata
de una matriz (de nuevo, por ejemplo, double a[4][9]), debemos
indicarle al compilador el tipo de cada uno de los 4 elementos del
array: en este caso, tipo array de 9 elementos de tipo double.
SECCIÓN 16.4
SECCIÓN 16.5
SECCIÓN 16.6
Recapitulación.
SECCIÓN 16.7
Ejercicios.
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #define TAM 100
5 // Declaracion de las funciones ...
6 void asignar(short d, long a[d]);
434 Capítulo 16. Funciones: llamada por Referencia
42 v[i] ^= v[j];
43 }
44 }
45 /* Funcion q recibe vector y lo muestra. */
46 void mostrar(short d, long a[d])
47 {
48 short i;
49 printf("\n\n");
50 for(i = 0 ; i < d ; i++)
51 printf(" %5ld", v[i]);
52 }
1 #include <stdio.h>
2 // Declaracion de la funcion ...
3 short divisores(long N, short dim, long divisores[dim]);
4 // Definicion de la funcion ...
5 short divisores(long N, short dim, long divisores[dim])
6 {
7 short cont = 1;
8 long div;
9 divisores[0] = 1;
10 for(div = 2 ; div <= N / 2 ; div++)
11 if(N % div == 0)
12 {
13 divisores[cont++] = div;
14 // Si no caben mas divisores, se aborta la operacion.
15 if(cont >= dim) return -1;
16 }
17 divisores[cont++] = N;
18 return cont;
19 }
que reciba como único parámetro una cadena de texto, y que de-
vuelva un valor verdadero (distinto de cero) si la cadena contiene
Sección 16.7. Ejercicios 439
1 #include <ctype.h>
2
3 short isNumero(char* c)
4 {
5 int i;
6 for(i = 0 ; c[i] ; i++)
7 if(!isdigit(c[i])) return 0;
8 return 1;
9 }
1 #include <ctype.h>
2 short isNumero(short dim, char cad[dim])
3 {
4 int i;
5 for(i = 0 ; i < dim && c[i] ; i++)
6 if(!isdigit(c[i])) return 0;
7 if(i == d) return -1;
8 return 1;
9 }
short IndiceArray
(short dim, long array[dim], long valorBuscado);
Los parámetros son (1) la dimensión del array, (2) la dirección del
array, y (3) el valor buscado. Devuelve el índice donde se ubica la
primera ocurrencia del valor buscado, o el valor -1 si ese valor no
se encuentra en el array.
442 Capítulo 16. Funciones: llamada por Referencia
1 short IndiceArray
2 (short dim , long array[dim], long valorBuscado)
3 {
4 int i;
5 for(i = 0 ; i < dim ; i++)
6 {
7 if(array[i] == valorBuscado)
8 {
9 return i;
10 }
11 }
12 return -1;
13 }
CAPÍTULO 17
Recursividad (Recurrencia).
En este capítulo...
17.1 Ejercicio inicial . . . . . . . . . . . . . . . . . . . . . . . . . 444
443
444 Capítulo 17. Recursividad
SECCIÓN 17.1
Resolviendo un ejercicio.
Su prototipo será:
Su prototipo será:
int main(void)
{
unsigned long a;
do
{
printf("Entrada entero ... ");
scanf(" %lu", &a);
printf("Valor introducido ... %lu\n", a);
}while(esCompuesto(a));
return 0;
}
SECCIÓN 17.2
El concepto de recursividad.
Quizá todos nos hemos planteado alguna vez una imagen recursi-
va: una fotografía que muestra a una persona que sostiene entre
sus manos esa fotografía, que muestra a esa persona que sostie-
ne entre sus manos esa fotografía, que muestra a esa persona que
sostiene entre sus manos esa fotografía, que muestra...
(a) (b)
Figura 17.1: (a) Edificio construido al abrigo de la Geometría Eu-
clídea. (b) Edificio que comprende que la realidad es recursiva, y no
todo está formado por círculos, triángulos y paralelepípedos.
cas euclideas, solo logra crear obras frías y casi inhumanas... Vea,
por ejemplo, la espantosa imagen recogida en la Figura 17.1(a). Y
cuando el hombre se atreve con una matemática más recursiva,
más real por tanto, más pegada a la verdad intrínseca de las cosas
creadas (plantas, animales, personas, etc., que en nada se pueden
modelizar mediante círculos, triángulos y paralelepípedos), enton-
ces construye obras como la mostrada en la Figura 17.1(b). ¿No se
parece esta imagen del techo de la Sagrada Familia (Barcelona) a
las imágenes del conjunto de Mandelbrot, que son sencillamente
recursivas?
Y así tenemos que para calcular una fila del triángulo de Tartaglia
no es necesario acudir al cálculo de binomios ni de factoriales, y
basta con conocer la fila anterior, que se calcula si se conoce la fila
anterior, que se calcula si se conoce la fila anterior... hasta llegar a
las dos primeras filas, que están formadas todo por valores uno. Te-
nemos, por tanto, y de nuevo, un camino recurrente hecho a base
de simples sumas para encontrar la solución que antes habíamos
buscado mediante el cálculo de tres factoriales, dos productos y un
cociente para cada elemento.
Nivel de
Recursión N devuelve recibe resultado
1 5 5 * Factorial(4) 24 120
2 4 4 * Factorial(3) 6 24
3 3 3 * Factorial(2) 2 6
4 2 2 * Factorial(1) 1 2
5 1 1 * Factorial(0) 1 1
6 0 1 - 1
SECCIÓN 17.3
Árbol de recursión.
SECCIÓN 17.4
Recursión e iteración.
El factorial de 3 es 6.
ELSE
fibonacciR(N) = fibonacciR(N – 1) + fibonacciR(N – 2)
END IF
SECCIÓN 17.5
Función hanoi
Variables: N, X, Y, Z: Enteros
Acciones:
IF (N = 1)
Trasladar disco de X a Z.
ELSE
1. Trasladar discos desde 1 hasta N – 1 de X a Y, tomando
como auxiliar a Z.
2. Trasladar disco N de X a Z.
3. Trasladar discos desde 1 hasta N – 1 de Y a Z, tomando
como auxiliar a X.
END IF
Podemos definir una función que muestre por pantalla los movi-
mientos necesarios para hacer el traslado de una torre a otra. A
esa función la llamaremos hanoi, y recibe como parámetros los
siguientes valores:
Sección 17.5. Las torres de Hanoi 465
Una variable que indique la torre donde están los discos que
trasladamos.
i j 6 - i - j
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
ELSE
1. hanoi(D1, D2 – 1, i, 6 – i – j)
2. hanoi(D1, D2, i, j)
3. hanoi(D1, D2 – 1, 6 – i – j, j)
END IF
Disco 1 de 1 a 2 Disco 1 de 2 a 3
Disco 2 de 1 a 3 Disco 2 de 2 a 1
Disco 1 de 2 a 3 Disco 1 de 3 a 1
Disco 3 de 1 a 2 Disco 3 de 2 a 3
Sección 17.6. Algoritmo de Ackermann 467
Disco 1 de 3 a 1 Disco 1 de 1 a 2
Disco 2 de 3 a 2 Disco 2 de 1 a 3
Disco 1 de 1 a 2 Disco 1 de 2 a 3
Disco 4 de 1 a 3
SECCIÓN 17.6
n+1 si m = 0
A(m, n) = A(m − 1, 1) si m > 0 y n = 0 (17.1)
A(m − 1, A(m, n − 1)) si M > 0 y n > 0
468 Capítulo 17. Recursividad
A(m , n) n = 0 n = 1 n = 2 n = 3 n = 4 n = 5
m = 0 1 2 3 4 5 6
m = 1 2 3 4 5 6 7
m = 2 3 5 7 9 11 13
m = 3 5 13 29 61 125 253
m = 4 13 ¿? ¿? ¿? ¿? ¿?
SECCIÓN 17.7
Recapitulación.
SECCIÓN 17.8
Ejercicios.
Para resolver este problema es fácil buscar los casos más sencillos,
que forman la Base de la recurrencia: El código binario de 0 en ba-
se 10 es 0; el código binario de 1 en base 10 es 1. Un posible código
de la función podría ser el recogido en el Cuadro de Código 17.10.
f("EXAMEN", 0);
Asignación Dinámica de
Memoria.
En este capítulo...
18.1 Memorias estática y dinámica . . . . . . . . . . . . . . . . 482
481
482 Capítulo 18. Asignación Dinámica de Memoria
ese array fue creado. Esa dos operaciones no son posibles con la
memoria llamada estática, que es la parte de la memoria donde
se alojan las variables de un array, pero sí se pueden realizar en la
llamada memoria dinámica. Disponemos de algunas funciones que
nos permiten reservar y liberar esa memoria dinámica en tiempo
de ejecución.
SECCIÓN 18.1
SECCIÓN 18.2
Función malloc.
Veamos un ejemplo:
long dim;
float *vector;
printf("Dimensión de su vector ... ");
scanf(" %ld",&dim);
vector = (float*)malloc(4 * dim);
SECCIÓN 18.3
Función calloc.
SECCIÓN 18.4
Función realloc.
vector =
(float*)realloc(vector, new_dim * sizeof(float));
SECCIÓN 18.5
Función free.
SECCIÓN 18.6
1 #include <stdlib.h>
2 #include <stdio.h>
3
4 int main(void)
5 {
6 float **p;
7 short f, c;
8 short i, j;
9 // Introducir las dimensiones ...
10 printf("Filas del vector ... ");
11 scanf(" %hd",&f);
12 printf("Columnas del vector ");
13 scanf(" %hd",&c);
14 // Creacion de las filas ...
15 p = (float**)malloc(f * sizeof(float*));
16
17 if(p == NULL)
18 {
19 printf("Memoria insuficiente.\n");
20 getchar();
21 exit(0);
22 }
23 // Creacion de las columnas ...
24 for( i = 0 ; i < f ; i++)
25 {
26 *(p + i) = (float*)malloc(c * sizeof(float));
27
490 Capítulo 18. Asignación Dinámica de Memoria
28 if(*(p + i) == NULL)
29 {
30 printf("Memoria insuficiente.\n");
31 getchar();
32 exit(0);
33 }
34 }
35 // Asignacion de valores ...
36 for(i = 0 ; i < f ; i++)
37 for(j = 0 ; j < c ; j++)
38 {
39 printf("matriz[ %2hd][ %2hd] = " , i, j);
40 scanf(" %f" , *(p + i) + j);
41 }
42 // Mostrar la matriz por pantalla ...
43 for(i = 0 ; i < f ; i++)
44 {
45 printf("\n");
46 for(j = 0 ; j < c ; j++)
47 printf(" %6.2f\t" , *(*(p + i) + j));
48 }
49 // Liberar la memoria ...
50 for(i = 0 ; i < f ; i++)
51 free(*(p + i));
52 free(p);
53 return 0;
54 }
Luego, para ver cómo se puede hacer uso de esa matriz creada
mediante memoria dinámica, solicitamos al usuario que dé valor a
cada elemento de la matriz y, finalmente, mostramos por pantalla
todos los elementos de la matriz.
Decíamos que había dos formas de crear una matriz por asignación
dinámica de memoria. La segunda es crear un solo array, de longi-
tud igual al producto de filas por columnas. Y si la matriz tiene f
filas y c columnas, considerar los f primeros elementos del vector
como la primera fila de la matriz; y los segundos f elementos, como
la segunda fila, y así, hasta llegar a la última fila. El código de esta
otra forma de manejar matrices queda ejemplificado en el Cuadro
de Código 18.2.
1 #include <stdlib.h>
2 #include <stdio.h>
3 int main(void)
4 {
5 float *p;
6 short f, c;
7 short i, j;
8 // Introducir las dimensiones ...
9 printf("Filas del vector ... ");
10 scanf(" %hd",&f);
11 printf("Columnas del vector ");
12 scanf(" %hd",&c);
13 // Creacion de la matriz ...
492 Capítulo 18. Asignación Dinámica de Memoria
14 p = (float*)malloc(f * c * sizeof(float*));
15 if(p == NULL)
16 {
17 printf("Memoria insuficiente.\n");
18 printf("Pulse 1 tecla para terminar ... ");
19 getchar();
20 exit(0);
21 }
22 // Asignacion de valores ...
23 for(i = 0 ; i < f ; i++)
24 for(j = 0 ; j < c ; j++)
25 {
26 printf("matriz[ %2hd][ %2hd] = " , i, j);
27 scanf(" %f" , p + (i * c + j));
28 }
29 // Mostrar la matriz por pantalla ...
30 for(i = 0 ; i < f ; i++)
31 {
32 printf("\n");
33 for(j = 0 ; j < c ; j++)
34 printf(" %6.2f\t" , *(p + (i * c + j)));
35 }
36 // Mostrar los datos como vector lineal ...
37 printf("\n\n");
38 for(i = 0 ; i < f * c ; i++)
39 printf(" %6.2f\t",*(p + i));
40 // Liberar la memoria ...
41 free(p);
42 return 0;
43 }
En este capítulo...
19.1 Funciones de escape . . . . . . . . . . . . . . . . . . . . . . 496
19.2 Punteros a funciones . . . . . . . . . . . . . . . . . . . . . 497
19.3 Vectores de punteros a funciones . . . . . . . . . . . . . . 500
19.4 Funciones como argumentos . . . . . . . . . . . . . . . . . 503
19.5 la función qsort . . . . . . . . . . . . . . . . . . . . . . . . 506
19.6 Estudio de tiempos . . . . . . . . . . . . . . . . . . . . . . 509
19.7 Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513
19.8 Número variable de argumentos . . . . . . . . . . . . . . . 514
19.9 Línea de órdenes . . . . . . . . . . . . . . . . . . . . . . . . 520
495
496 Capítulo 19. Algunos usos con funciones
SECCIÓN 19.1
Funciones de escape.
El prototipo de la función es
void abort(void);
SECCIÓN 19.2
Punteros a funciones.
puntero_a_funcion = nombre_funcion_1;
SECCIÓN 19.3
tipo_funcion
(*ptr_funcion[dimensión])(tipo1, ..., tipoN);
float(*operacion[4])(float,float)
= {suma, resta, producto, cociente};
Con esto hemos declarado cuatro punteros, cada uno de ellos apun-
tando a cada una de las cuatro funciones definidas. A partir de
ahora será lo mismo invocar a la función sum que invocar a la
función apuntada por el primer puntero del vector.
switch(op)
{
case ’+’: i = 0; break;
case ’-’: i = 1; break;
case ’*’: i = 2; break;
case ’/’: i = 3;
}
printf("\n\n %f %c %f = %f",
a, op, b, (*operación[i])(a,b));
Sección 19.4. Funciones como argumentos 503
SECCIÓN 19.4
1 #include <stdio.h>
2 #include <conio.h>
3 float suma (float, float);
4 float resta (float, float);
5 float producto (float, float);
6 float cociente (float, float);
7 void mostrar(float, char, float, float(*f)(float, float))
;
8
9 int main(void)
10 {
11 float a, b;
12 unsigned char op;
13 float (*f_op[4])(float, float) =
14 {suma,resta,producto,cociente};
15 printf("\n1er operador: ");
16 scanf(" %f",&a);
17 printf("2do operador ... ");
18 scanf(" %f",&b);
19 printf("Operacion ... \n)");
20 printf("\n\n1. Suma\n2. Resta");
21 printf("\n3. Producto\n4. Cociente");
22 printf("\n\n\tSu opcion (1 , 2 , 3 , 4) ... ");
23 do
24 {
25 op = ’0’ - getche();
26 }
27 while(op < 1 || op > 4 );
28 mostrar(a, op, b, f_op[(short)(op - ’1’)]);
Sección 19.4. Funciones como argumentos 505
29 return 0;
30 }
31 float suma(float x, float y) { return x + y; }
32 float resta(float x, float y) { return x - y; }
33 float producto(float x, float y) { return x * y; }
34 float cociente(float x, float y) { return y ? x / y : 0;
}
35
36 void mostrar(float x,char c,float y,float(*f)(float,float
))
37 {
38 if(c == ’1’) c = ’+’;
39 else if(c == ’2’) c = ’-’;
40 else if(c == ’3’) c = ’*’;
41 else c = ’/’;
42 printf("\n\n %f %c %f = %f.\n", x, c, y, (*f)(x,y));
43 }
SECCIÓN 19.5
Hay que explicar porqué los tipos que recoge el prototipo son siem-
pre void. El motivo es porque la función qsort está definida para
ser capaz de ordenar un array de cualquier tipo. Puede ordenar
enteros, reales, letras, u otros tipos de dato mucho más comple-
jos, que se pueden crear y que veremos en un capítulo posterior.
La función no tiene en cuenta el tipo de dato: simplemente quiere
saber dos cosas:
SECCIÓN 19.6
Estudio de tiempos.
clock_t clock(void);
510 Capítulo 19. Algunos usos con funciones
nación de los elementos del vector. Pero ahora el valor que saldrá
por pantalla es del orden de 500 veces más bajo.
SECCIÓN 19.7
Creación de MACROS.
#define cuadrado(x) x * x
#define circulo(r) 3.141596 * cuadrado(r)
SECCIÓN 19.8
Sin embargo no todas las funciones que hemos utilizado son real-
mente así de rígidas. Por ejemplo, la función printf, tantas veces
invocada en nuestros programas, no tiene un número prefijado de
parámetros:
Sección 19.8. Número variable de argumentos 515
Existen una serie de macros que permiten definir una función co-
mo si tuviera una lista variable de parámetros. Esas macros, que
ahora veremos, están definidas en la biblioteca stdarg.h.
Lo primero que habrá que hacer con esta variable de tipo va_list
será inicializarla con la lista de argumentos variables recibida en
la llamada a la función. Para inicializar esa variable se emplea una
de las tres macros definidas en la biblioteca stdarg.h: la macro
va_start, que tiene la siguiente sintaxis:
Su sintaxis es:
SECCIÓN 19.9
Nombre: Isabel
Edad: 21
Profesion: estudiante
522 Capítulo 19. Algunos usos con funciones
En este capítulo...
20.1 enum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524
523
524 Capítulo 20. Estructuras y Definición de Tipos
SECCIÓN 20.1
Veamos un ejemplo:
SECCIÓN 20.2
Así, se pueden definir los tipos de dato estándar con otros nombres,
que quizá convengan por la ubicación en la que se va a hacer uso
de esos valores definidos por el tipo de dato. Y así tenemos:
O también:
SECCIÓN 20.3
SECCIÓN 20.4
Estructuras de datos en C.
variable_estructura.id_1
variable_estructura.id_1 = valor_1;
nombre_estructura nombre_variable;
typedef struct
{
double real;
double imag;
}complejo;
1 #include <stdio.h>
2 typedef struct
3 {
4 double real;
Sección 20.4. struct 533
5 double imag;
6 }complejo;
7 complejo sumac(complejo, complejo);
8 complejo restc(complejo, complejo);
9 complejo prodc(complejo, complejo);
10 void mostrar(complejo);
11
12 int main (void)
13 {
14 complejo A, B, C;
15 printf("Introduccion de datos ... \n");
16 printf("Parte real de A: ");
17 scanf(" %lf",&A.real);
18 printf("Parte imag de A: ");
19 scanf(" %lf",&A.imag);
20 printf("Parte real de B: ");
21 scanf(" %lf",&B.real);
22 printf("Parte imag de B: ");
23 scanf(" %lf",&B.imag);
24 // SUMA ...
25 printf("\n\n"); mostrar(A);
26 printf(" + "); mostrar(B);
27 C = sumac(A,B); mostrar(C);
28 // RESTA ...
29 printf("\n\n"); mostrar(A);
30 printf(" - "); mostrar(B);
31 C = restc(A,B); mostrar(C);
32 // PRODUCTO ...
33 printf("\n\n"); mostrar(A);
34 printf(" * "); mostrar(B);
35 C = prodc(A,B); mostrar(C);
36 return 0;
37 }
38 complejo sumac(complejo c1, complejo c2)
39 {
534 Capítulo 20. Estructuras y Definición de Tipos
40 c1.real += c2.real;
41 c1.imag += c2.imag;
42 return c1;
43 }
44 complejo restc(complejo c1, complejo c2)
45 {
46 c1.real -= c2.real;
47 c1.imag -= c2.imag;
48 return c1;
49 }
50 complejo prodc(complejo c1, complejo c2)
51 {
52 complejo S;
53 S.real = c1.real + c2.real; - c1.imag * c2.imag;
54 S.imag = c1.real + c2.imag + c1.imag * c2.real;
55 return S;
56 }
57 void mostrar(complejo X)
58 {
59 printf("( % .2f %s %.2f * i) ",
60 X.real, X.imag > 0 ? " +" : " " , X.imag);
61 }
como el Rvalue) sean variables objeto del mismo tipo. Por ejemplo,
se puede hacer la asignación:
complejo A, B;
A.real = 2;
A.imag = 3;
B = A;
typedef struct
{
long clave;
char descripcion[50];
float creditos;
}asignatura;
SECCIÓN 20.5
asignatura curricula[100];
1 #include <stdio.h>
2 #include <stdlib.h>
3 typedef struct
4 {
5 long clave;
6 char descr[50];
7 float cred;
8 }asig;
9
10 int main(void)
Sección 20.5. Vectores y punteros a estructuras 537
11 {
12 asig *curr;
13 short n, i;
14
15 printf("Indique numero de asignaturas de su CV ... "
);
16 scanf(" %hd",&n);
17 /* La variable n recoge el numero de elementos de tipo
18 asignatura que debe tener nuestro array. */
19 curr = (asig*)malloc(n * sizeof(asig));
20 if(curr == NULL)
21 {
22 printf("Memoria insuficiente.\n");
23 printf("Pulse una tecla para terminar ... ");
24 getchar();
25 exit(0);
26 }
27 for(i = 0 ; i < n ; i++)
28 {
29 printf("\n\nAsignatura %hd ... \n",i + 1);
30 printf("clave ......... ");
31 scanf(" %ld",&(curr + i)->clave);
32 printf("Descripcion ... ");
33 gets((curr + i)->descr);
34 printf("creditos ...... ");
35 scanf(" %f",&(curr + i)->cred);
36 }
37 // Listado ...
38 for(i = 0 ; i < n ; i++)
39 {
40 printf("( %10ld)\t",(curr + i)->clave);
41 printf(" %s\t",(curr + i)->descr);
42 printf(" %4.1f creditos\n",(curr + i)->cred);
43 }
44 return 0;
538 Capítulo 20. Estructuras y Definición de Tipos
45 }
SECCIÓN 20.6
Anidamiento de estructuras.
Podemos definir una estructura que tenga entre sus miembros una
variable que sea también de tipo estructura (por ej., Cuadro de
Código 20.8).
SECCIÓN 20.7
Gestión de Archivos.
En este capítulo...
21.1 Tipos de dato con persistencia . . . . . . . . . . . . . . . . 542
541
542 Capítulo 21. Gestión de Archivos
SECCIÓN 21.1
Es posible crear ese tipo de dato con persistencia porque esa in-
formación queda almacenada sobre una memoria externa. Los ar-
chivos se crean sobre dispositivos de memoria masiva. El límite de
tamaño de un archivo viene condicionado únicamente por el límite
de los dispositivos físicos que lo albergan.
Sección 21.1. Tipos de dato con persistencia 543
SECCIÓN 21.2
SECCIÓN 21.3
SECCIÓN 21.4
SECCIÓN 21.5
FILE *puntero_a_archivo;
Apertura de archivo.
Su prototipo es:
FILE *fopen
(const char*archivo, const char *modo_apertura);
FILE *fichero;
fichero = fopen("datos.dat","w");
552 Capítulo 21. Gestión de Archivos
char nombre_archivo[80];
printf("Indique nombre archivo ... ");
Sección 21.5. Archivos secuenciales con buffer 553
gets(nombre_archivo);
fopen(nombre_archivo, "w");
FILE *archivo;
if(archivo = fopen("datos.dat", "w") == NULL)
printf("No se puede abrir archivo \n");
y
Sección 21.5. Archivos secuenciales con buffer 555
fputs(nombre,archivo);
int fprintf
(FILE *archivo, const char *formato [,arg, ...]);
int fscanf
(FILE *archivo, const char *formato [, dir, ...]);
size_t fread
(void *buffer, size_t n_bytes,
size_t contador, FILE *archivo);
size_t fwrite
(const void *buffer, size_t n_bytes,
size_t contador, FILE *archivo);
Su prototipo es:
Su prototipo es:
remove("numeros.dat");
SECCIÓN 21.6