Professional Documents
Culture Documents
PROGRAMACIN EN C 3 EDICIN
AUTORES:
Francisco J. Garca Pealvo
Juan Andrs Hernndez Simn
Roberto Thern Snchez
Vivian Flix Lpez Batista
Ivn lvarez Navia
F.J.G.P.
J.A.H.S.
V.F.L.B.
I..N.
TABLA DE CONTENIDOS
Prlogo _______________________________________________ 1
Prlogo a la Segunda Edicin _____________________________ 3
Prlogo a la Primera Edicin _____________________________ 5
1. Introduccin _________________________________________ 7
1.1. Conceptos bsicos ______________________________________ 7
1.1.1. Definiciones _____________________________________________ 7
1.1.2. Informacin _____________________________________________ 10
1.1.2.1. La informacin en los ordenadores _______________________ 11
1.1.2.2. Codificacin de los datos _______________________________ 12
1.1.3. Informacin _____________________________________________ 13
1.1.3.1. Unidad de entrada_____________________________________ 14
1.1.3.2. Unidad de salida ______________________________________ 14
1.1.3.3. Memoria ____________________________________________ 14
1.1.3.4. Unidad central de proceso ______________________________ 15
1.1.3.5. Buses ______________________________________________ 15
1.1.4. Clasificacin de los ordenadores _____________________________ 16
vi
TABLA DE CONTENIDOS
2.2.4.2. Transformacin de base decimal a base octal _______________ 33
2.2.4.3. Transformacin de base octal a base binaria ________________ 34
2.2.4.4. Transformacin de base binaria a base octal ________________ 34
2.2.5. El sistema hexadecimal ____________________________________ 34
2.2.5.1. Transformacin de base hexadecimal a base decimal _________ 34
2.2.5.2. Transformacin de base decimal a base hexadecimal _________ 34
2.2.5.3 Transformacin de base hexadecimal a base binaria ___________ 35
2.2.5.4 Transformacin de base binaria a base hexadecimal ___________ 35
2.2.6. Cambio de base K a base P _________________________________ 35
TABLA DE CONTENIDOS
vii
viii
TABLA DE CONTENIDOS
TABLA DE CONTENIDOS
ix
TABLA DE CONTENIDOS
9.1.2. Dnde almacenar la direccin de una variable? _______________ 263
TABLA DE CONTENIDOS
xi
xii
TABLA DE CONTENIDOS
TABLA DE CONTENIDOS
xiii
xiv
TABLA DE CONTENIDOS
14.4.1.1. El operador - > de seleccin de miembro _________________ 434
14.4.2. Construccin de una lista ________________________________ 435
14.4.3. Insercin de un elemento en una lista _______________________ 438
14.4.3.1. Insercin de un nuevo nodo en la cabeza de la lista _________ 438
14.4.3.2. Insercin de un nuevo nodo que no est en la cabeza de la lista 444
14.4.3.3. Insercin por la cola _________________________________ 445
14.4.3.4. Insercin en una posicin dada_________________________ 452
14.4.3.5. Insercin ordenada __________________________________ 453
14.4.4. Supresin de un nodo en la lista ___________________________ 453
14.4.4.1. Borrado de la cabeza ________________________________ 456
14.4.4.2. Borrado de la cola __________________________________ 457
14.4.5. Bsqueda de un elemento en la lista ________________________ 459
Prlogo
Con sta llegamos a la tercera edicin de este libro, que entre otras cosas ratifica el
alto grado de aceptacin que est obteniendo en las diferentes asignaturas que se toma
como texto de referencia o de apoyo, lo que viene demostrando la vigencia del
lenguaje C como lenguaje de programacin para el aprendizaje, pero tambin para el
desarrollo de sistemas reales.
Esta tercera edicin se caracteriza por estar dedicada a la limpieza del texto, es
decir, no hay cambios en la estructura del libro con respecto a la segunda edicin,
pero si se ha hecho un esfuerzo por eliminar erratas, actualizar algunas referencias y
URLs y reescribir diversos fragmentos buscando una mejor legibilidad y
comprensin. Desde aqu agradecer a todos los profesores y alumnos que nos han
hecho las oportunas indicaciones para mejorar este texto, y de nuevo invitar a que
cualquier problema o sugerencia de mejora se nos sea comunicada para hacer de este
libro algo vivo y que se adapta a las necesidades de su pblico.
-1-
-3-
-5-
1. Introduccin
La informtica, y los conceptos que de ella se derivan, se han introducido en la vida
cotidiana de millones de personas. El computador ha dejado de ser un elemento de
uso exclusivo para el personal de laboratorios, grandes empresas o fanticos de la
informtica, para sigilosamente penetrar en los hogares y en los pequeos y medianos
negocios. Actualmente, quien ms quien menos tiene algn contacto con el mundo de
la informtica, ya sea de forma directa manejando un computador, ya sea de forma
indirecta a travs del bombardeo de los medios de comunicacin o manejando alguno
de los mltiples electrodomsticos digitales que hoy en da existen en cualquier hogar
medio.
Todo esto influye en que cualquier persona se convierta en un usuario potencial de
computadores, sin que por ello tenga que convertirse en un experto en informtica,
aunque si debe contar con una cultura informtica bsica. Esta idea ha calado
profundamente en la Universidad espaola, donde ya son muchas las titulaciones que
en sus planes de estudios cuentan con al menos una asignatura troncal u obligatoria de
introduccin a la informtica.
En este primer captulo se va a proceder a introducir los conceptos bsicos que se
manejarn a lo largo de la asignatura, para lo cual el captulo se ha organizado en tres
apartados principales. El primero de ellos aborda las definiciones de la terminologa
bsica de la informtica, haciendo un especial hincapi en el concepto de informacin
y de su procesamiento automtico. El apartado dos se dedica a presentar las diferentes
generaciones de ordenadores. Por ltimo, el tercer apartado cierra el captulo con unas
conclusiones a modo de resumen del mismo.
1.1.1. Definiciones
El trmino informtica es un vocablo que se deriva de la palabra francesa
informatique, formada por la contraccin de otras dos palabras informacin y
automtica.
Se puede definir informtica como el conjunto de conocimientos cientficos y
tcnicas que hacen posible el tratamiento automtico de la informacin por medio de
ordenadores [RAE, 2001].
-7-
Programacin en C
Al igual que los trminos ordenadora (de raro uso en la literatura en castellano) y
computadora (de uso tan generalizado como su homnimo masculino).
2 Como curiosidad decir que el trmino ordenador fue acuado en Francia en 1956 por el
profesor Jacques Perret, haciendo referencia de forma genrica a un sistema para procesar
datos.
Introduccin
Entradas
Datos
+
Instrucciones
Ordenador
Salidas
Datos
Figura 1.1. Ordenador como caja negra que recibe, procesa y ofrece datos
Por ltimo, de la definicin (3), aunque escueta, conviene hacer un repaso por el
significado de cada uno de los trminos que la componen. As, la palabra digital hace
referencia a que los ordenadores trabajan con datos en formato digital; es decir, en
cdigos que representan las letras o los dgitos de los nmeros. Cualquier otro tipo de
datos, como puedan ser grficos o sonido, se almacena tambin en formato digital. El
formato digital significa que se emplea el sistema binario, esto es, los datos se
almacenan en el ordenador por secuencias de 0s y 1s. Esto es as porque el ordenador
es un conjunto de sistemas fsicos que slo pueden entender dos estados. La palabra
electrnica implica que un ordenador se construye usando componentes electrnicos
de estado slido, conocidos por circuitos integrados, o ms comnmente por chips. El
trmino tratamiento de la informacin es un concepto general que da cabida a un
enorme rango de actividades y trabajos que un ordenador puede llegar a realizar. Por
ltimo, la palabra mquina hace referencia a que los ordenadores estn en la misma
lnea de sucesin que otras mquinas menos sofisticadas y, como una mquina que es,
puede funcionar bien o mal, pero no es infalible3.
Cualquier ordenador se apoya en dos pilares bsicos que lo definen en s mismo y
le dan sentido a su existencia. Estos dos pilares son el soporte fsico y el soporte
lgico.
El soporte fsico, ms conocido por hardware4, es la mquina en s, la parte fsica y
tangible de un ordenador. As pues, puede definirse el hardware como el conjunto de
dispositivos fsicos (cables, armarios...) y circuitos electrnicos (tarjetas de red,
controladoras, circuitos integrados...) que constituyen un ordenador.
3
En este sentido se poda entrar en polmicas sobre la inteligencia, sentimientos, etc. que un
ordenador puede tener o experimentar, pero esto se aleja de los objetivos de este libro, y se
dejar para los defensores y detractores de la Inteligencia Artificial fuerte. En este sentido, se
recomienda a los lectores interesados por el tema la lectura del libro La nueva mente del
emperador [Penrose, 1991].
4 Este anglicismo significa literalmente herrajes o partes duras.
10
Programacin en C
1.1.2. Informacin
La informacin es un trmino de acepcin general que abarca hechos y
representaciones que pueden no estar relacionados. La informacin puede ser trivial o
trascendente, verdadera o falsa.
La informacin es la materia prima que las tcnicas y mtodos informticos permiten elaborar,
tratar, manipular o procesar.
I (E)
log
1
P( E )
Este anglicismo que se deriva del vocablo ingls soft (blando) tiene una difcil traduccin al
espaol. En algunos libros aparece referenciado con la palabra logical, aunque este trmino no
tiene demasiada aceptacin.
Introduccin 11
log a x
1
log b x
log b a
I (E)
ln
1
nats
P( E )
I (E)
lg 2
1
bits
P( E )
Es importante recalcar el hecho de que si P(E) = 1/2 entonces I(E) = 1 bit. Esto
permite definir al bit como la cantidad de informacin obtenida al especificar una
de dos posibles alternativas igualmente probables.
Aunque en la literatura especializada en informtica se suelen utilizar
indistintamente los conceptos de dato e informacin, stos no son sinnimos.
Un dato se define como una representacin de la informacin. La informacin
codificada mediante un conjunto de smbolos en la forma adecuada para ser objeto
de tratamiento. Los datos son conjuntos de smbolos utilizados para expresar o
representar un valor numrico, un hecho, un objeto o una idea; en la forma adecuada
para ser objeto de tratamiento [Prieto et al., 2002].
Es importante recalcar el hecho de que los datos por s solos no tienen significado,
adquirindolo nicamente cuando se hace una interpretacin de los mismos.
Datos + Interpretacin = Informacin til
1.1.2.1. La informacin en los ordenadores
El concepto de informacin en los ordenadores viene dado en funcin de un proceso o
tratamiento de datos. Dicho proceso es en una elaboracin consistente en la seleccin,
tratamiento y combinacin de los datos, con objeto de obtener un mensaje
significativo para alguien.
Los datos van a ser por tanto la representacin de la informacin que se tiene
acerca de un hecho. En relacin con el tratamiento se puede clasificar los datos en:
Datos elementales o datos base: Se trata de la constatacin de una
situacin o de un hecho, no habiendo habido tratamiento alguno.
Datos elaborados o resultantes: Son aqullos que proceden de la
combinacin de datos base previamente relacionados para su posterior
12
Programacin en C
Introduccin 13
Entre todos los tamaos privilegiados cabe destacar la unidad denominada byte u
octeto que expresa la cantidad de informacin empleada en un ordenador para
representar un carcter alfanumrico8. En su aceptacin ms generalizada consiste en
una cadena de ocho bits, aunque algunos ordenadores antiguos emplearon un nmero
diferente de bits.
Tomando el byte como unidad base aparecen otras unidades para medir los datos.
La primera unidad es el nibble o semibyte que es una cadena de cuatro bits.
Dado que el byte sigue siendo una unidad relativamente pequea, es ms usual
utilizar mltiplos suyos:
1 Kiliobyte (KB) = 210 bytes = 1.024 bytes
1 Megabyte (MB) = 220 bytes = 1.048.576 bytes
1 Gigabyte (GB) = 230 bytes = 1.073.741.824 bytes
1 Terabyte (TB) = 240 bytes = 1.099.511.627.776 bytes
1 Petabyte (PB) = 250 bytes
1.1.3. Informacin
El esquema funcional de un ordenador de hoy en da contina fiel a la arquitectura
propuesta por John von Neumann en 1945. Segn esta arquitectura un ordenador
est formado por un conjunto de unidades funcionales especializadas que se
encuentran interconectadas entre s.
14
Programacin en C
Introduccin 15
16
Programacin en C
Introduccin 17
18
Programacin en C
Samsung Yopi
Palm VIIx
Cassiopeia EM-500
Figura 1.4. Diferentes PDAs
Introduccin 19
20
Programacin en C
Introduccin 21
22
Programacin en C
Figura 1.9. Circuitos integrados realizados sobre soporte flexible (Archivos de Bull)
1.3. Resumen
En el presente captulo se ha pretendido hacer una introduccin a la informtica, en la
que se ha hecho hincapi a los conceptos ms bsicos que se van a ir repitiendo a lo
largo de esta asignatura ya sea de forma explcita o de forma implcita.
Parece necesario recalcar el sentido del trmino informtica en cuanto a su
acepcin de tratamiento automtico de los datos, de forma que el usuario pueda
obtener un provecho de este tratamiento para interpretarlo y obtener verdadera
informacin til.
Para la realizacin de este proceso automtico la informtica se apoya en los
ordenadores o computadores, los cuales actualmente son dispositivos electrnicos que
bajo el control de un software adecuado y con la interaccin humana pertinente a cada
caso son capaces de realizar diferentes procesos.
Otro aspecto importante que se ha abordado es la forma en que se almacenan los
datos dentro de un ordenador, utilizando cdigos derivados del sistema de numeracin
Introduccin 23
binario. Esto lleva a manejar magnitudes derivadas del bit que es la unidad ms
elemental de informacin dentro de un ordenador, y que en definitiva se reduce a un
simple valor binario (un cero o un uno).
Como complemento a la introduccin al concepto de ordenador se ha presentado
muy someramente las unidades funcionales de un ordenador, y que prcticamente
coincide con lo que se ha dado en denominar la arquitectura von Neumann, en la que
aparecen tres grandes unidades funcionales: la unidad de entrada/salida, la unidad
central de proceso y la memoria central.
En la ltima parte del captulo se han repasado los hitos hardware y software que
sirven para dividir la historia moderna de los computadores en cuatro generaciones, la
primera de ellas basada en las vlvulas de vaco, la segunda en los transistores, la
tercera en los circuitos integrados, y la cuarta en los circuitos integrados de muy alta
escala de integracin y, especialmente, en la introduccin del microprocesador.
Hay autores que hablan de una quinta, e incluso una sexta, generacin de
ordenadores, tomando como referencia ciertos proyectos japoneses de desarrollar
ordenadores basados en la inteligencia artificial, pero la realidad es que los
ordenadores actuales, cada vez ms potentes, continan siguiendo el modelo de von
Neumann y su unidad central de proceso sigue basada en microprocesador realizados
con semiconductores.
(http://www.foldoc.org),
al
Webopedia
(http://www.pcwebopedia.com) o al Computer User High-Tech Dictionary
(http://www.computeruser.com/resources/dictionary). Es destacable la enciclopedia
libre Wikipedia, em la que se pueden encontrar definiciones y referencias a diferntes
tpicos relacionados con el mundo de los ordenadores; a su versin en espaol se
puede acceder a travs de http://es.wikipedia.org/wiki/Portada.
24
Programacin en C
1.6. Referencias
[Allen et al., 1996] Allen, R. C., Bottcher, C., Bording, P., Burns, P., Conery, J., Davies, T.
R., Demmel, J., Johnson, C., Kantha, L., Martin, W., Parks, G., Piacsek, S.,
Pryor, D., Schlick, T., Strayer, M. R., Umar, V. M., Voigt, R., Wagener, J.,
Zachmann, D. y Ziebarth, J. Computational Science Education Project.
http://csep1.phy.ornl.gov/. [ltima vez visitado, 27-7-2005]. 1996.
[RAE, 2001] Real Academia Espaola Diccionario de la Lengua Espaola. Vigsimo
segunda edicin. http://www.rae.es. [ltima vez visitado, 27-7-2005]. 2001
[Goi, 1986] Goi, M. J. (Ed.). Diccionario Informtico. Gran Enciclopedia Informtica.
Ediciones Nueva Lente. Vol. 18. 1986.
[Miguel, 1994] Miguel Anasagasti, P. de. Fundamentos de los Computadores. 4 Edicin.
Paraninfo, 1994.
[Penrose, 1991] Penrose, R. La Nueva Mente del Emperador. Mondadori, 1991.
[Prieto et al., 2002] Prieto, A., Lloris, A. y Torres, J. C. Introduccin a la Informtica. 3
Edicin. McGraw-Hill, 2002.
[Tucker et al., 1994] Tucker, A. B., Bradley, W. J., Cupper, R. D. y Garnick, D. K.
Fundamentos de la Informtica. McGraw-Hill, 1994.
[Vaquero, 1999] Vaquero Snchez, A. La Lengua Espaola en el Contexto Informtico.
Revista de Enseanza y Tecnologa ADIE. (13):5-12. Enero-Abril, 1999.
2.1. Introduccin
Un ordenador es una mquina que procesa datos mediante la ejecucin de programas.
La ejecucin de un programa conlleva el procesamiento de una combinacin de datos,
segn especifica el conjunto ordenado de instrucciones que componen dicho
programa. Para que la ejecucin del mismo se lleve a cabo, el ordenador debe recibir
dos flujos de informacin, tal y como se muestra en la Figura 2.1; el primero de ellos
se corresponde con el flujo de datos de entrada que va a ser manipulado para
producir los resultados o datos de salida. El otro flujo es el de instrucciones de
mquina, o flujo de control, cuyo objetivo no es otro que el de expresar el proceso de
tratamiento de los datos de entrada.
26
Programacin en C
3.
4.
El caso ms habitual es aqul en que los datos de entrada se suministran con ayuda
de un alfabeto o conjunto de smbolos que se denominan caracteres. Estos caracteres
suelen agruparse en cinco categoras [Prieto et al., 2002]:
1. Caracteres alfabticos: Son las letras, tanto maysculas como
minsculas del abecedario ingls.
A, B, C, ..., X, Y, Z, a, b, c, ..., x, y, z
2. Caracteres numricos: Son las diez cifras del sistema numrico
decimal.
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
3. Caracteres especiales: Son los smbolos no incluidos en los dos
grupos anteriores, y engloba: smbolos de puntuacin, caracteres
propios de otros alfabetos (como la o las vocales acentuadas),
operadores aritmticos y de relacin, smbolos de moneda, el
espacio en blanco1, etc. Como muestra, y entre otros muchos, se
pueden presentar los siguientes:
(, *, /, ;, , , , , , !, :, $, , +, >
4. Caracteres de control: Representan rdenes de control, como
puede ser el carcter indicador de fin de lnea, el carcter de final de
fichero, etc.
5. Caracteres geomtricos y grficos: Son smbolos con los que se
pueden crear figuras o iconos elementales.
, , , ,
27
A las tres primeras categoras se las suele denominar como caracteres de texto,
mientras que el conjunto unin de las dos primeras categoras recibe el nombre de
caracteres alfanumricos.
Dado que un ordenador slo es capaz de trabajar con elementos binarios, se tiene
que traducir toda la informacin suministrada a secuencias binarias, por lo que se
establece una correspondencia entre el conjunto de todos los caracteres y el conjunto
binario.
Esto es, se disea una codificacin de los elementos del conjunto mediante los
elementos del conjunto , de forma que a cada elemento de
le corresponda un
patrn nico de n bits perteneciente al conjunto .
Los cdigos de transformacin reciben el nombre de cdigos de entrada/salida
(E/S) o cdigos externos, pudindose definir de forma arbitraria, aunque existen
cdigos de E/S normalizados que son utilizados de forma estndar en varias
arquitecturas de computadores.
Sin embargo, para la realizacin de operaciones aritmticas con datos numricos se
utiliza una representacin ms adecuada que la correspondiente a los cdigos
externos. Para ello, internamente se realiza una conversin entre cdigos binarios para
conseguir una representacin basada en el sistema de numeracin en base 2,
pasndose a utilizar una representacin posicional, que se adecua ms a la realizacin
de operaciones aritmticas.
El pueblo esquimal contaba en hombres y en dedos, de forma que por ejemplo, un hombre y
siete dedos representaban el nmero 27.
3 Una reminiscencia de este hecho es la forma de escribir ciertos nmeros franceses, por
ejemplo 80 es quatre-vingt (cuatro-veintes).
28
Programacin en C
29
n4 n3 n2 n1n0 , n 1n 2 n 3 n
p4 p3 p2 p1 p0 p 1 p 2 p 3 p
. Para calcular el
valor, V(N), del nmero N, se selecciona el peso adecuado del vector P para aplicar
el factor de escala oportuno a cada una de las cifras del nmero N de la siguiente
forma:
V N
p3 n3
p2 n2
p1 n1
p0 n0
p1 n1
n3
pi ni
i
k 4 k 3 k 2 k 1k 0 k 1k 2 k 3 k
V N
i
n4 n3 n2 n1n0 , n 1n 2 n 3 n
V N
d i 10i
10
i
30
Programacin en C
2.
b2 b1b0 , b 1b
a2 a1a0 , a 1a
donde:
ai
3.
bni
n 1
bni 1bni
0,2 10
0,001100110011 2
En la Tabla 2.1 se muestran los valores que se pueden formar con 4 bits, que se
corresponden con los nmeros decimales del 0 al 15.
31
peso:
2
37
17
1
2
18
0
2
9
1
2
4
0
2
2
0
2
1
32
Programacin en C
0,3750
x2
0,7500
0,7500
x2
1,5000
0,5000
x2
1,0000
a
0
0
1
1
b
0
1
0
1
ab
0
0
0
1
a
0
0
1
1
b
0
1
0
1
a/b
Indeterminacin
0
EJEMPLO
1011101 = 93
1110101 = 117
+ 1000100 = 68
11101011 = 235
10100001 = 161
1101010 = 106
1011101 = 93
87
1000100 = 68
0010011 = 19
0011001 = 25
1010111 =
1101010 = 106
11 =
3
1101010
1101010
100111110 = 318
1101010 = 106
10 =
0000000
1101010
11010100 = 212
33
8
92
12
4
0,33
x 8
2,64
0,64
x 8
5,12
0,12
x 8
0,96
8
11
0,96
x 8
7,68
1
0,68
x 8
5,44
...
34
Programacin en C
011
3
000,
0,
110)2
6
000,
0,
000
0
101)2
5
101
5
010
2
010,
2,
010
2
010)2 = 1522,22)8
2
35
EJEMPLO
7011,35)10 = 1B63,5999)16
7011
64
61
48
131
128
16
438 16
32
27 16
118 16 1
112 11
3
0,35
x16
5,6
0,60
x16
9,6
0,60
x16
9,6
0,60
x16
9,6
20B,02)16 = 0010
1010
A
0000
0
1111
F
0010,
2,
0000
0
1011,
B,
0000
0
0010)2
2
0110)2
6
0011
3
0101
5
0010,
2,
0100
4
1000)2 = 352,48)16
8
36
Programacin en C
EJEMPLO
Sea k = 16 y p = 8
F1)16 = 15 161 + 1 160 = 15 16 + 1 = 240 + 1 = 241)10
241 8
1 30 8
3
6
241)10= 361)8
F1)16
241)10
361)8
Recurdese que la palabra del procesador es el nmero de bits que ste puede manipular al
mismo tiempo.
37
Como resulta obvio, con este mtodo se pueden representar b cantidades distintas,
es decir, desde 0 hasta b1. Basta con elegir una base lo suficientemente grande para
38
Programacin en C
V N
n 1
2
d i 2i
i 0
39
V N
n 2
2
d i 2i
i 0
V N
n 2
2
i 0
n 1
di bi
i 0
Ecuacin 2.8. Valor de un nmero para un sistema de representacin con cualquier base
bn
40
Programacin en C
( N) = 2n (2n P) = P
Cambio de signo
n
( N) + ( M) = (2n P) + (2n Q) =
2 + (2n P Q )
eliminando el
bit n + 1
(2n P Q )
( 7) + (9) con n = 8
1111 1001
1111 0111
1 1111 0000
-16
0000 0110
1111 1001
1111 1111
Suma de un nmero positivo y otro
negativo
-1
N + ( M) = N + (2 P), con N > P
n
0000 1000
1111 1001
+
1 0000 0001
Se elimina el bit sobrante
Se utiliza la representacin en binario puro para los nmeros positivos, y para los
nmeros negativos se realiza el complemento a dos, es decir, se resta el nmero
negativo, sin signo, de 2n, de forma que el resultado tendr el bit de signo a 1. Por
ejemplo:
41
signo
magnitud
valor
0
1
0
0
0
0
0
1
+ 65)10
1
0
1
1
1
1
1
1
- 65)10
1 bit
n 1 bits
Ya que 2n P = 28 0100 0001 =1 0000 0000 0100 0001 = 1011
1111.
Para el caso del Complemento a Dos, se tiene el rango de representacin
correspondiente a [-2n-1, 2n-1 -1] y una resolucin de 1.
Este sistema fue ideado con la intencin de simplificar las operaciones de suma y
resta cuando se haca entre nmeros positivos y negativos. Se tiene el inconveniente,
sin embargo, de que se complican multiplicacin y divisin.
En la Tabla 2.7 se exponen diferentes posibilidades ilustrativas de la simplificacin
en el clculo de sumas y restas.
Se pueden destacar las siguientes caractersticas en el Complemento a Dos:
El signo no se utiliza para realizar sumas y resta.
La extensin de signo se hace colocando ceros a la izquierda en caso de
nmeros positivos, y unos en caso de nmeros negativos.
42
Programacin en C
Basta hacer el
complemento lgico
Cambio de signo
( N) + ( M) = (2n 1 P) +
(2 1 Q) = 2 1 + (2 1 P
Q)
reciclando el bit n + 1
n
(2 1 P Q )
( 7) + (9) con n = 8
1111 1000
+
1111 0110
1 1110 1110
Se recicla el bit sobrante
1110 1111
-16
n-1
N + ( M) = N + (2 1 P),
con N < P,
resultado negativo generado
directamente
Ej: 6 + (7) con n = 8
0000 0110
+
1111 1000
1111 1110
-1
n
N + ( M) = N + (2 1 P),
con N > P,
Reciclando el bit n + 1 se obtiene
el resultado positivo esperado
Ej: 8 + (7) con n = 8
0000 1000
+
1111 1000
1 0000 0000
1
0000 0001
1
43
BCD
0101 0100
Exceso a tres
1000 0111
2-4-2-1
2 entre 5
01010 01001
Estos cdigos presentan una dificultad adicional a la hora de generar los acarreos
cuando se realizan operaciones aritmticas.
Se pueden dar dos tipos de codificacin segn utilicen 4 u 8 bits de cada byte para
almacenar informacin, denominndose desempaquetado y empaquetado,
respectivamente.
44
Programacin en C
conocida con cuatro nombres: Punto Flotante, Coma Flotante, Notacin Cientfica o
Notacin Exponencial.
A continuacin (Ecuacin 2.9), se muestra la expresin general de un nmero
representado con punto flotante.
V N
M BE
45
2 ne 1 1; e
2 ne 1
1.m
con
1 M
46
Programacin en C
M 2 2 ( nm 1)
E 2S 2 ne 2
Exponente
M 2E
( nm 1)
(2 2
)2 2
ne
M 1
M des 2
Exponente
E
M 2E
a' M des 2 E
(2
nm
(2 ne 1
ne 1
nm
2)
2)
( 2 ne
2)
N b, N
b . Los nmeros correspondientes a
esta zona provocan lo que se conoce como
desbordamiento (overflow).
N<0
-b
-a
N>0
0
+a
underflow
overflow
Simple precisin.
+b
overflow
47
Sesgo: S 2
Si e 255 y m
Si e 255 y m
1 127
NaN
0
0
Si 0
e 255
Si e
0 ym 0
Si e
0 ym
( 1) s
( 1) s 2 e
127
1.m
(normalizado)
( 1) s 2
126
0.m
(desnormalizado)
( 1) s 0
Doble precisin.
210 1 1023
Si e
Si e
2047 y m 0
2047 y m 0
NaN
( 1) s
Si 0
e 2047
( 1) s 2 e
1023
1.m
(normalizado)
Si e
0 ym 0
( 1) s 2
1022
0.m
(desnormalizado)
Si e
0 ym
( 1) s 0
2.4. Cdigos
2.4.1. Cdigos de E/S
Como ya se dijo en la introduccin de este captulo, en la ejecucin de un programa
estn involucrados dos flujos de informacin: datos de entrada y datos de salida. Esta
informacin, compuesta por caracteres de tipo numrico, alfabtico o especial, ha de
ser traducida a unas determinadas combinaciones de bits. Mediante los cdigos de E/S
se consigue esta transformacin. Por tanto, un cdigo de E/S es una correspondencia
entre los conjuntos
0,1
48
Programacin en C
00
01
10
11
000
001
010
011
100
101
110
111
Con:
n = 3 (bits para la codificacin)
se tiene:
m = 8 (Hasta 8 smbolos codificados)
log 2 (m)
3.32 log( m)
En realidad, n debe ser el menor nmero entero que satisfaga la relacin anterior,
ya que slo se puede trabajar con un nmero entero de bits. Adems, se pueden
crearse cdigos que utilicen ms bits de los estrictamente necesarios.
Desafortunadamente, con el paso del tiempo, se han diseado muchos de esos
cdigos y se han utilizado con diferentes equipos, producindose una proliferacin de
los problemas de comunicacin [Glenn, 1995].
Debido a lo expuesto, es lgico pensar en la necesaria existencia de cdigos
normalizados que puedan utilizarse por todos los fabricantes de ordenadores, en lugar
de tener que enfrentar a un maremagno de cdigos arbitrarios. A continuacin se
realiza un rpido repaso a algunos de los ms difundidos.
Se ver que histricamente la evolucin de los distintos cdigos adoptados ha sido
influida por la creciente cantidad de caracteres que se han impuesto como una
necesidad y, por lo tanto, varan en funcin del nmero bits utilizados para realizar la
codificacin.
49
NUL
LF
DC4
RS
(
2
<
F
P
Z
d
n
x
SOH
STX
ETX
VT
FF
CR
NAK
SYN
ETB
US Espacio
!
)
*
+
3
4
5
=
>
?
G
H
I
Q
R
S
[
\
]
e
f
g
o
p
q
y
z
{
EOT
SO
CAN
,
6
@
J
T
^
h
r
|
ENQ
SI
EM
#
7
A
K
U
_
i
s
}
ACK
DLE
SUB
$
.
8
B
L
V
`
J
T
~
BEL
DC1
ESC
%
/
9
C
M
W
a
k
u
DEL
BS
DC2
FS
&
0
:
D
N
X
b
l
v
TAB
DC3
GS
1
;
E
O
Y
c
m
w
50
Programacin en C
51
0
0
1
0
1
0
1
0
1
0
0
1
1
0
0
1
1
0
Sin embargo, slo permite detectar error en un bit, ya que si se produjera error en
dos bits (o en un nmero par de bits), la paridad resultara correcta.
2.4.2.2. Cdigos correctores de Hamming
Los cdigos correctores mejoran el caso anterior, ya que permiten detectar errores en
ms de un bit adems de corregirlo, mediante una inversin de los bits errneos.
Para conseguir llevar a cabo tales propsitos se utilizan un nmero N de bits de
paridad que afectan individualmente a diferentes partes del cdigo, de forma que se
pueda decidir cules son las posiciones afectadas por el error mediante un mecanismo
de exclusin. Un mtodo bien conocido consiste en utilizar bits de paridad en
horizontal y vertical, es decir, para cada matriz de 8x8 bits se tiene un bit de paridad
por fila y otro por columna. As, un error en una posicin determinada de la matriz
ser detectado por los bits de paridad que indican sus coordenadas. Por ejemplo:
0
1
1
1
1
1
1
1
1
0
0
1
E
1
0
1
0
0
0
0
1
1
0
0
1
1
0
1
0
0
1
0
1
0
1
0
0
0
0
0
0
1
1
1
1
1
1
1
1
1
0
0
0
1
1
0
1
0
1
0
1
0
0
0
1
0
1
0
1
0
1
0
1
1
1
0
0
0
1
1
1
En caso de aparecer errores en ms de un bit, se podrn detectar, pero no corregir.
Los cdigos de Hamming tratan de optimizar este problema. Para ello, utilizando p
bits de paridad podrn corregir errores sencillos en datos de longitud n, siempre que
se cumpla que 2 p n p 1 .
Para un ejemplo como el anterior, en que se tienen 64 bits, n = 64, y dado que
128 > 64 + 7 +1, p ser 7, lo que mejorara sustancialmente el nmero de bits
de paridad necesarios (17 en el ejemplo anterior).
Un ejemplo es el cdigo de Hamming 11 (datos) + 4 (paridad), que tiene la
estructura que se muestra en la Figura 2.5.
2.4.2.3. Cdigos polinomiales
Los cdigos polinomiales o cclicos permiten detectar errores mltiples cuando estos
se producen en bits consecutivos. Se basan en aadir al dato el resultado de realizar la
operacin mdulo del mismo respecto a una determinada base, por tanto el dato pasa
a ser [dato, dato mod base].
Son tpicamente aplicados en las operaciones de transmisin en serie de
informacin donde un fallo en el medio de transmisin produce un error en un cierto
nmero de bits consecutivos.
52
Programacin en C
d10
d9
d8
d7
d6
d5
p8
d4
d3
d2
p4
d1
p2
p1
b15
b14
b13
b12
b11
b10
b9
b8
b7
b6
b5
b4
b3
b2
b1
15
p1 1
p2 1
p3 1
p4 1
14
13
p1 1
0
p3 1
p4 1
12
11
p1 1
p2 1
0
p4 1
10
9
p1 1
0
0
p4 1
7
p1 1
p2 1
p3 1
0
5
p1 1
0
p3 1
0
3
p1 1
p2 1
0
0
1
p1 1
0
0
0
0
p2 1
p3 1
p4 1
0
0
p3 1
p4 1
0
p2 1
0
p4 1
8
0
0
0
p4 1
0
p2 1
p3 1
0
4
0
0
p3 1
0
0
p2 1
0
0
Cada bit est protegido por los bits de paridad que indica su orden expresado en binario
p1 = b3 + b5 + b7 + b9 + b11 + b13 + b15 =
= d1 + d2 + d4 + d5 + d7 + d9 + d11
Cada bit de
paridad se
calcula como
la suma de
todos los bits
de datos a los
que protege
2.5. Resumen
Se ha realizado en el presente captulo una revisin de los sistemas numricos y de
representacin de la informacin ms destacable, partiendo de los ms sencillos hasta
los ms elaborados, para facilitar la comprensin al lector.
Se ha recorrido el camino que ha seguido la humanidad en su evolucin hasta los
sistemas de representacin de la informacin utilizados por los ordenadores. Se han
53
visto cules son las restricciones que aparecen al disponer siempre de un espacio
limitado para codificar los datos.
Partiendo del sistema decimal, que se utiliza en la vida cotidiana, se ha
generalizado a un sistema posicional de cualquier base. Se ha hecho un especial
hincapi en el sistema binario, el sistema de numeracin de la informtica por
excelencia, y se han repasado las principales operaciones aritmticas, analizando sus
ventajas y problemas. Se ha resaltado convenientemente los cambios entre las
distintas bases que utilizan los computadores.
Dada la relevancia de las operaciones aritmticas en cualquier sistema informtico,
se han introducido los fundamentos matemticos necesarios para comprender cmo se
puede manejar internamente los nmeros, tanto de tipo entero, ms sencillos, como
los de tipo real, con la complejidad que estos llevan asociada. A partir de este
momento ya se est en disposicin de poder destacar las propiedades de cada uno de
los sistemas de representacin interna de la informacin.
Finalmente, dado el carcter introductorio de este captulo, se han comentado
brevemente los principales cdigos de Entrada/Salida, as como algunos de los
mecanismos de proteccin de la informacin y de correccin de errores.
54
Programacin en C
3.
4.
5.
6.
7.
8.
9.
Escribe, si es posible, los siguientes nmeros en binario puro con una longitud de
palabra m = 5:
10, 20, 30, 40
Calcula el rango de representacin para una palabra de m = 16 en los siguientes
sistemas:
Punto fijo sin signo.
Punto fijo con complemento a uno.
Punto fijo con complemento a dos.
Cmo se representa el nmero 7 en ASCII? Y en binario puro? Por qu se
utilizan ambas representaciones?
Cules son los cdigos intermedios y por qu reciben este nombre?
Escribe todos los nmeros entre 1 y 50 en binario puro, en hexadecimal y en
octal.
A qu operaciones corresponden los desplazamientos de las cifras a izquierda y
derecha en un sistema posicional? Encuentra la correspondencia en decimal de la
siguientes series de desplazamientos:
00101110; 01011100; 10111000
10101000; 01010100; 00101010
00000001; 00000100; 00010000
Realiza las siguientes operaciones en binario puro, complemento a uno y
complemento a dos:
234 + 512
67 78
42 61
Codifica los siguientes nmeros en BCD:
1234, 999901, 312
Se tienen los siguientes datos de una representacin interna de nmeros reales,
n=16, ne=6 y B=2. Determinar qu nmeros representan cada una de las
siguientes codificaciones:
0111 0000 1110 1111
1111 1111 0000 1111
1010 1010 1010 1010
0111 1111 1111 1111
55
10. Representa los siguientes nmeros siguiendo el estndar 754 en sus dos formatos
bsicos: simple precisin y doble precisin.
23674.758423
1.5784343345
4.5
-89999.000056732
11. Encuentra y corrige el bit errneo en la siguiente informacin transmitida:
1
1
1
1
1
1
1
1
0
1
0
1
1
1
1
1
0
0
1
1
0
1
0
0
1
1
1
0
0
0
0
0
1
0
1
1
0
0
0
1
0
1
0
0
0
1
0
0
1
1
0
0
0
1
1
0
0
1
1
0
0
0
1
1
1
0
1
0
1
1
1
0
0
0
0
1
0
1
0
0
0
12. Utilizando el Cdigo de Hamming 11 + 4, calcula los bits de paridad para
proteger los siguientes datos:
111 0010 0010
111 1111 1111
000 0000 0000
010 1010 1010
2.8. Referencias
[Glenn, 1995] Glenn Brookshear, J.. Introduccin a las Ciencias de la Computacin. 4
Edicin. Addison-Wesley Iberoamericana, 1995.
[Miguel, 1994] Miguel Anasagasti, P. de. Fundamentos de los Computadores. 4 Edicin.
Paraninfo, 1994.
[Prieto et al., 2002] Prieto, A., Lloris, A. y Torres, J. C. Introduccin a la Informtica. 3
Edicin. McGraw-Hill, 2002.
58
Programacin en C
Es digno de mencin que la palabra lgebra procede del rabe al jabr que aparece en el ttulo
del libro.
59
cabo. Por su parte, una instruccin es un conjunto de smbolos que representa una
orden de operacin o tratamiento para el ordenador.
Existen diversos estilos de programacin (estructurada, orientada a objetos, basada
en reglas, lgica, funcional...), sin embargo esta introduccin se centra
exclusivamente en la programacin estructurada.
Utilizar programacin estructurada implica escribir un programa de acuerdo a las
siguientes reglas:
Diseo modular atendiendo a diferentes niveles de abstraccin.
Utilizacin de diseo descendente (top-down) en la definicin de los
mdulos.
Cada mdulo se construye utilizando las tres estructuras de control bsicas:
secuencia, seleccin y repeticin.
Cuando se dice que un programa tiene un diseo modular se est haciendo
referencia a la denominada programacin modular, que es la tcnica por la cual el
programa se divide en mdulos (partes independientes) cada uno de los cuales lleva a
cabo una nica actividad, codificndose y depurndose de forma independiente de
los otros mdulos.
Segn Dijkstra, descomponer un programa en trminos de recursos abstractos
consiste en descomponer una determinada accin compleja en trminos de un nmero
de acciones ms simples capaces de ejecutarlas o que constituyan instrucciones de
ordenador disponibles.
El diseo descendente es el proceso por el
que un problema se descompone en una serie
de niveles o pasos sucesivos de refinamiento.
Recibe el nombre de descendente o top-down
porque va desde lo general a lo particular, de
niveles de abstraccin ms altos a niveles ms
concretos, aplicando sucesivos refinamientos
que aaden informacin, esto es, el diseo se
refina como una jerarqua de niveles de
Nivel n
qu hace?
detalles creciente [Wirth, 1971]. Se tiene una
Nivel n+1 cmo lo hace?
descomposicin del problema en etapas.
Figura 3.1. Diseo descendente
Las estructuras de control son los
mtodos para especificar el orden en el que
las instrucciones de un algoritmo van a ser ejecutadas. El orden de ejecucin de las
instrucciones determina el flujo de control. Existen tres tipos de estructuras de
control: secuencia, seleccin y repeticin (ver Figura 3.2).
La secuencia establece un conjunto de instrucciones que se ejecutarn de
forma secuencial.
Las estructuras de seleccin, tambin denominadas estructuras alternativas
son aqullas que controlan la ejecucin de una o ms instrucciones en
funcin de que se cumpla o no una condicin previamente establecida.
Las estructuras repetitivas son aqullas que permiten variar la secuencia
normal de ejecucin de un programa haciendo posible que un grupo de
instrucciones se ejecute ms de una vez de forma consecutiva. A estas
estructuras se las denomina tambin bucles o lazos.
60
Programacin en C
M d u lo 1 .1
M d u lo 1.2
Nivel 1
Nivel 2
M d ulo 2
M d u lo 3
M d u lo 2 . 1
M d u lo 3 .1
M du lo 2 .1 .1
M d ulo 2 .1 .2
M d u lo 4
Nivel 3
Nivel 4
61
Por ejemplo, la codificacin es una etapa que precede a la fase de pruebas. Sin embargo,
partes de la fase de codificacin y partes de la fase de pruebas pueden realizarse de forma
simultnea.
3 El ciclo de vida debe preverse para proyectos de cualquier dimensin y complejidad, si bien
en el caso de proyectos pequeos, varias etapas pueden ser agrupadas y algunas no existir.
62
Programacin en C
Definicin
Desarrollo
Fallos de
definicin
Mantenimiento
Modificaciones y
adaptaciones
Errores
63
todos los caminos, con todos los casos posibles. En general, no se puede
asegurar totalmente la ausencia de errores.
64
Programacin en C
65
Descripcin
entrada
Anlisis
Descripcin salida
Definicin del
problema
66
Programacin en C
67
68
Programacin en C
PSEUDOCDIGO
+
*
/
=, <, >, <>
div
mod
** ^
and y
or o
entero
inicio
si
desde
(* *)
//
real
final
entonces
mientras
(suma)
(resta)
(multiplicacin)
(divisin real)
(igual, menor, mayor, distinto)
(divisin entera)
(resto entero)
(potenciacin)
(operador lgico and)
(operador lgico or)
(asignacin)
}
(comentario)
carcter
cadena
leer
escribir
si no
segn
repetir
hasta que
Diagramas de flujo
Los diagramas de flujo (flowcharts en la bibliografa en ingls o en algunos textos
donde no se ha traducido el trmino) son herramientas grficas para la representacin
visual de algoritmos. Estn compuestos por una serie de smbolos icnicos unidos por
flechas. Los smbolos representan acciones y las flechas el orden de realizacin de las
mismas, marcando el sentido o flujo lgico del algoritmo. Por tanto, cada smbolo
tendr al menos una flecha que conduzca a l y una flecha que parte de l, a
excepcin de los terminadores y conectores. Al igual que un libro, un diagrama de
flujo se lee de arriba a abajo y de izquierda a derecha.
Los smbolos estn normalizados para facilitar el intercambio de documentacin
entre el personal. Para ello existen normas en las que basarse, dictadas por las
organizaciones de estandarizacin internacionales ANSI (American National
Standard Institute) e ISO (International Standard Organization). Los principales
smbolos normalizados por ANSI/ISO se recogen en la Figura 3.8 y en la Figura 3.9.
Tradicionalmente los diagramas de flujo se pueden clasificar en dos grandes
grupos: organigramas y ordinogramas. La principal diferencia es que los
organigramas eran diagramas que se realizaban en la fase anlisis y los ordinogramas
en la fase de diseo, pero con la evolucin de las metodologas estructuradas, los
organigramas han sido sustituidos por otras herramientas grficas ms expresivas,
quedando relegados exclusivamente para la descripcin de algoritmos en el apartado
del diseo de procedimientos, emplendose la palabra organigrama para
referenciarlos en detrimento del trmino ordinograma.
La principal ventaja de los diagramas de flujo viene de la mano de sus
caractersticas grficas y visuales que los convierten en elementos muy sencillos de
entender. Otra caracterstica importante es su estandarizacin lo que permite la
comunicacin entre miembros del mismo o de diferentes equipos de desarrollo.
Su mayor desventaja es la dificultad de mantenimiento y actualizacin,
dependiendo de editores grficos.
INICIO o FIN
ENTRADA/
SALIDA
PROCESO
DECISION
NO
SI
DECISION
MULTIPLE
SUBPROCESO
CONECTOR
FLECHAS Y
LINEAS
69
70
Programacin en C
PANTALLA
IMPRESORA
TECLADO
BANDA
DISCO
COMENTARIO
Figura 3.9. Smbolos estndar para diagramas de flujo (ANSI/ISO) Smbolos secundarios
Diagramas de Nassi-Schneiderman
Los diagramas de Nassi-Schneiderman se conocen tambin como diagramas de
Chapin o simplemente como diagramas N-S. Estos diagramas aparecen contenidos en
un rectngulo, donde un conjunto de smbolos adyacentes representan las estructuras
de control bsicas de la programacin estructurada.
Condicin
V
Tareas
Tareas
Condicin
Tareas Tareas
Caso de condicin
Valor 1 Valor 2
...
Tareas Tareas
...
Condicin
repeticin
seleccin
seleccin mltiple
Tarea 1
Tarea 2
Tarea 3
71
72
Programacin en C
Diagrama de Nassi-Schneiderman
Inicio
Leer temp_c
temp_f
Mostrar temp_f
Fin
Diagrama de flujo
Primera versin
Segunda versin
73
74
Programacin en C
Diagrama de Nassi-Schneiderman
El diagrama de Nassi-Schneiderman slo se va a hacer de la segunda versin porque
la primera no cumple las reglas de la programacin estructurada al incluir estructuras
de control con saltos incondicionales.
Inicio
Leer num
x 2
num mod x
resto
num mod x
x = num
Mostrar Es Primo
No
Mostrar No Es Primo
Fin
3.3.3. Codificacin
Esta fase consiste en la traduccin de la solucin obtenida en el diseo de los
algoritmos al lenguaje de programacin escogido.
Las caractersticas generales de esta fase son:
Se sustituyen las palabras del pseudocdigo, por sus homnimos o
conjunto de sentencias equivalentes en el lenguaje de programacin
escogido.
Se requiere conocer el juego de instrucciones del lenguaje de ordenador
escogido.
Utilizando un editor de textos se genera en un fichero plano en disco
el programa fuente.
Esta actividad se constituye la programacin propiamente dicha.
3.3.3.1. Lenguajes de programacin
Los programas indican al ordenador qu tiene que hacer, y ste nicamente realiza las
operaciones que el programa incluye. Un programa y las sentencias que lo constituyen
se construyen con unos smbolos, y de acuerdo con unas reglas, que constituyen la
gramtica del lenguaje de programacin.
Se puede definir un lenguaje de programacin como el conjunto de smbolos y de
reglas para combinarlos, que se usan para expresar algoritmos.
Los lenguajes de programacin se pueden denominar con otros nombres, tales
como lenguajes formales o lenguajes artificiales, con el fin de distinguirlos de los
lenguajes naturales (espaol, ingls...).
Los lenguajes de programacin, a semejanza de los lenguajes que usan los
humanos para comunicarse, poseen un lxico (vocabulario o conjunto de smbolos
permitidos), una sintaxis que indica cmo realizar construcciones del lenguaje y una
semntica que determina el significado de cada construccin correcta.
75
A9
8D
A9
8D
AD
09
8D
60
A9
8D
A9
8D
A9
8D
60
16
00
08
18
11
20
11
15
18
1B
11
17
00
DD
D0
D0
D0
D0
D0
D0
76
Programacin en C
Lenguaje ensamblador
Surge como sustituto del lenguaje mquina para evitar la dificultad de ste. Est
basado en el uso de nemotcnicos (palabras abreviadas procedentes del ingls) para
representar los cdigos de operacin y los operandos.
La programacin en lenguaje ensamblador precisa de un amplio conocimiento
sobre la constitucin, estructura y funcionamiento interno del computador, as como
habilidad en el manejo de cdigos y sistemas de numeracin, en especial binario y
hexadecimal.
Con el lenguaje ensamblador se sigue teniendo una dependencia de la mquina,
ms concretamente del microprocesador.
A diferencia del lenguaje mquina s se programa en ensamblador en la
programacin de dispositivos electrnicos de control de procesos en tiempo real, o en
situaciones donde la rapidez de ejecucin es crtica, porque los programas realizados
en lenguaje ensamblador son ms rpidos que los realizados en lenguajes de alto
nivel.
Por el contrario, los programas realizados en lenguaje ensamblador son ms
difciles de escribir y depurar, complicando todas las actividades de codificacin,
prueba y mantenimiento.
Un programa escrito en lenguaje ensamblador no puede ser ejecutado directamente
por la computadora, sino que requiere una traduccin al lenguaje mquina.
Todas las computadoras tienen un ensamblador (traductor) propio del
microprocesador que posean, como se puede apreciar en la Figura 3.11
77
.long
0xcccccccd,0x3ffccccc
.align 8
.LC4:
.long
0x0,0x40400000
.text
.align 4
.globl main
.type
main,@function
main:
pushl
%ebp
movl
%esp, %ebp
subl
$24, %esp
subl
$12, %esp
pushl
$.LC0
call
printf
addl
$16, %esp
subl
$12, %esp
pushl
$.LC1
call
printf
addl
$16, %esp
subl
$8, %esp
leal
-4(%ebp), %eax
pushl
%eax
pushl
$.LC2
call
scanf
addl
$16, %esp
flds
-4(%ebp)
fldl
.LC3
fmulp
%st, %st(1)
fldl
.LC4
faddp
%st, %st(1)
fstps
-8(%ebp)
subl
$4, %esp
flds
-8(%ebp)
leal
-8(%esp), %esp
fstpl
(%esp)
pushl
$.LC5
call
printf
addl
$16, %esp
leave
ret
.Lfe1:
.size
main,.Lfe1-main
.ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-85)"
78
Programacin en C
MQUINA
ENSAMBLADOR
ALTO NIVEL
Muy alta
Alta
Baja
SI
SI
NO
Prcticamente
NO
Control de procesos
donde el tiempo de
ejecucin es crtico
Sistemas Operativos
Todo tipo de
aplicaciones:
gestin,
cientficas...
El programa es
directamente ejecutable
SI
NO
por el ordenador
Tabla 3.2. Comparativa entre los tres tipos de lenguajes
NO
79
80
Programacin en C
temp_c, temp_f
: real;
begin
write ('Introduzca el valor de la temperatura ');
write ('en grados centgrados: ');
readln (temp_c);
temp_f := (9.0/5.0) * temp_c + 32;
write ('Temperatura en grados fahrenheit: ', temp_f);
end.
81
82
Programacin en C
Programa Fuente
Proceso de Traduccin
Anlisis lexicogrfico
Anlisis sintctico
Anlisis semntico
Generacin de cdigo
Optimizacin
001010101110
110101010100
001010101010
Programa objeto
83
Programa
Fuente
Compilador
Compilador
Sistema Operativo
Hardware
Ejecutable
Usuario
Sistema Operativo
Hardware
84
Programacin en C
Programa fuente
Anlisis
Anlisis lexicogrfico
Anlisis sintctico
Sntesis
Anlisis semntico
Tablas de
smbolos
Generacin de cdigo
Optimizacin
Programa objeto
Muchas veces al corregir ciertos errores de compilacin, el nmero de ellos que se genera en
una segunda compilacin aumenta en lugar de disminuir. Esto es debido a que ciertos errores
primeramente detectados enmascaraban otros que salen en posteriores compilaciones.
85
86
Programacin en C
3.3.4.2. Intrpretes
Un intrprete hace que un programa fuente escrito en un lenguaje de alto nivel vaya
traducindose y ejecutndose sentencia a sentencia. Toma una sentencia del programa
fuente cada vez (ver Figura 3.17), la analiza e interpreta, ejecutndola
inmediatamente. Por lo tanto, no se crea un fichero objeto que se pueda almacenar en
disco para posteriores ejecuciones. Esto conduce a que la ejecucin del programa est
supervisada siempre por el intrprete, como se puede apreciar en la Figura 3.18.
Programa
Fuente
Intrprete
Sistema Operativo
Hardware
87
prueba, compuesto por valores de entrada normales, extremos, incorrectos, con salida
y resultado conocido..., que comprueban el funcionamiento de los aspectos esenciales
del programa.
88
Programacin en C
3.3.6. Documentacin
El objetivo de esta fase es la creacin de los documentos necesarios para facilitar la
comprensin, mantenimiento, evolucin y uso del programa.
Existen dos tipos principales de documentacin: la documentacin tcnica para el
mantenimiento del programa y la documentacin para el usuario final del programa.
3.3.6.1. Documentacin tcnica: Interna y externa
La documentacin externa se realiza en ficheros distintos al programa fuente, y debe
incluir:
El anlisis y diseo de los algoritmos.
Diagramas de flujo y pseudocdigo.
Especificacin de los formatos de los datos de entrada y salida del
programa.
Explicacin de cualquier frmula o clculo y expresin compleja del
programa.
Todas las consideraciones que se consideren oportunas que deba saber
cualquier programador que necesite modificar posteriormente el
programa.
La documentacin interna se incluye en el cdigo del programa fuente, usando
tanto comentarios (ver Tabla 3.3) como identificadores significativos.
Respecto a los comentarios en un programa se puede afirmar que:
Su objetivo es ayudar a la comprensin del cdigo.
7
La traduccin estricta del ingls de trmino debug es desinfectar o matar chinches. En los
primeros tiempos de la informtica, una polilla colocada sobre un contacto electromecnico del
ordenador Mark II ocasion un error en el programa que ejecutaba esta mquina. A partir de
entonces, se asocia el trmino debug al hecho de corregir errores en un programa.
89
Es habitual incluir en cada fichero fuente una cabecera entre comentarios que
especifican bsicamente los siguientes datos:
Nombre y finalidad del programa.
Fecha de creacin.
Nombre del analista y del programador.
Descripcin bsica.
Limitaciones y dependencias para su ejecucin.
A continuacin se presenta un ejemplo de cabecera.
/*
* Nombre
* Conversor de Celsius a Fahrenheit
* Sinopsis
*
Programa que genera una tabla de equivalencias entre
*
grados Celsius y Fahrenheit.
* Descripcin de la ejecucin del programa
*
Desde la lnea de rdenes C2F.
*
No admite ningn parmetro de entrada.
* Directivas de compilacin
*
Ninguna.
* Lista de cdigos de salida
*
Ninguno.
* Dependencias funcionales
*
El programa completo se encuentra en el fichero C2F.C.
* Lista de situaciones crticas
*
No se ha detectado ninguna
* Organizacin
*
Universidad de Salamanca
* Analista
*
Francisco Jos Garca
* Programador
*
Ivn lvarez
* Fecha
*
26 - 10 - 2000
* Versin
*
1.5
* Lista de versiones
*
* Referencia a las fuentes consultadas
*/
90
Programacin en C
91
92
Programacin en C
Documentos pblicos
Septiembre de 2001
Junio de 1999
Modificaciones editoriales
Julio de 1998
UML 1.0
UML 0.9 & 0.91
Estandarizacin
UML 1.1
Unificacin
Colaboradores y
expertos
OMT-2
Fragmentacin
Otros mtodos Booch91
OMT-1
OOSE
93
94
Programacin en C
3.5. Resumen
En este captulo se ha realizado una presentacin de los conceptos bsicos que se
necesitan manejar en el desarrollo de programas de ordenador, haciendo especial
hincapi en las denominadas tcnicas estructuradas de programacin.
95
96
Programacin en C
Los libros presentados en este prrafo estn disponibles traducidos al espaol: Meyer, B.
Construccin de Software Orientado a Objetos. 2 Edicin. Prentice Hall, 1999; Booch, G.
Anlisis y Diseo Orientado a Objetos con Aplicaciones. 2 Edicin. Addison-Wesley/Diaz
de Santos, 1996; Rumbaugh, J., Blaha, M., Premerlani, W., Eddy, F., y Lorensen, W.
Modelado y Diseo Orientados a Objetos. Metodologa OMT. Prentice Hall, 2 reimpresin,
1998; Budd, T. Programacin Orientada a Objetos. Addison-Wesley Iberoamericana, 1994.
9 Los libros presentados en este prrafo estn disponibles traducidos al espaol: Booch, G.,
Rumbaugh, J. y Jacobson, I. El Lenguaje Unificado de Modelado. Addison Wesley, 1999;
Rumbaugh, J., Jacobson, I. y Booch, G. El Lenguaje Unificado de Modelado. Manual de
Referencia. Addison-Wesley. 2000.
97
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
98
Programacin en C
3.8. Referencias
[AECC, 1986] Asociacin Espaola para la Calidad. Glosario de Trminos de Calidad e
Ingeniera del Software. AECC, 1986.
[Champeaux et al., 1993] Champeaux, D., Lea, D. y Faure, P. Object-Oriented System
Development. Addison Wesley. 1993.
[Dahl et al., 1970] Dahl, O., Myrhaug, B. y Nygaard, K. (Simula 67) Common Base
Language. Norsk Regnesentral (Norwegian Computing Center), Publication N. S22, Oslo. October 1970.
[Garca y Pardo, 1998] Garca Pealvo, F. J. y Pardo Aguilar, C. UML 1.1. Un Lenguaje
de Modelado Estndar para los Mtodos de ADOO. Revista Profesional para
Programadores (RPP), Editorial Amrica-Ibrica, V(1):57-61. Enero, 1998.
[Goodman y Hedetniemi, 1977] Goodman, S. E. y Hedetniemi, S. T. Introduction to the
Design and Analysis of Algorithms. McGraw-Hill. 1977.
[Hamilton, 1997] Hamilton, G. (Ed.). JavaBeans Specification 1.01. Sun Microsystems.
http://java.sun.com/products/javabeans/docs/spec.html. [ltima vez visitado,
27/7/2005]. 1997.
[Holland et al., 1997] Holland, S., Griffiths, R. y Woodman, M. Avoiding Object
Misconceptions. In Proceedings of the twenty-eighth SIGCSE technical symposium
on Computer Science Education (SIGCSE97). (Feb. 27-Mar. 1, 1997, San Jose, CA
USA). Pages 131-134. 1997.
[Kozaczynski y Booch, 1998] Kozaczynski, W. y Booch, G. Component-Based Software
Engineering. IEEE Software, 15(5):34-36. 1998.
[Microsoft, 1995] Microsoft. The Component Object Model Specification. Version 0.9.
October 1995.
[OMG, 2003] OMG. OMG Unified Modeling Language Specification Version 1.5. Object
Management Group Inc. Document formal/03-03-01. http://www.omg.org/cgibin/doc?formal/03-03-01. [ltima vez visitado, 27/7/2005]. March 2003.
[Rational et al., 1997] Rational Software Corporation, Microsoft, Hewlett-Packard,
Oracle, Sterling Software, MCI Systemhouse, Unisys, ICON Computing
IntelliCorp, i-Logix, IBM, ObjecTime. Platinum Technology, Ptech, Taskon,
Reich Technologies y Softeam. UML Proposal to the Object Management. In
Response to the OA&D Task Forces RFP-1. UML 1.1 Referece Set 1.1. 1
September 1997.
[Rumbaugh et al., 1991] Rumbaugh, J., Blaha, M., Premerlani, W., Eddy, F. y Lorensen,
W. Object-Oriented Modeling and Design. Prentice-Hall, 1991.
[Scacchi, 1987] Scacchi, W. Models of Software Evolution: Life Cycle and Process. SEI
Curriculum Module SEI-CM-10-1.0, Pittsburgh (EEUU), Software Engineering
Institute (Carnegie Mellon University). October 1987.
99
[Sevilla,
?
>
;
*
^
(
.
/
"
)
,
=
'
[
_
%
&
#
~
\
|
]
{
}
espacio blanco
Tabla 4.1. Caracteres especiales que permiten casi todos los lenguajes de alto nivel
102
Programacin en C
Ejemplo en C
Apunte de C
break
do
for
return
switch
while
case
double
goto
short
typedef
char
else
if
signed
union
const
enum
int
sizeof
unsigned
continue
extern
long
static
void
4.1.2. Identificador
Nombre que el programador puede elegir libremente para referenciar a distintos
elementos dentro del programa como datos, funciones...
Existen unas normas generales para su empleo comunes a la mayora de todos los
lenguajes de programacin:
Puede estar formado por letras, dgitos y el carcter guin2.
Debe comenzar siempre por una letra o el carcter subrayado.
1
Algunos compiladores de C pueden reconocer otras palabras reservadas. Para obtener una
lista completa de las mismas para un compilador determinado se debe consultar su manual de
referencia.
2Unos lenguajes de programacin slo admiten el guin bajo ( _) y otros slo el guin medio (-).
103
Identificadores vlidos:
x
y12
Nombre area
suma_1
_temperatura
indicador_de_error
TABLA
Identificadores no vlidos:
4num
%iva
indicador de error
EJEMPLO
Buen Identificador
puntos_acum
tot_ventas_mes
saldo_final
nom_empl
Mal Identificador
pac
total_vendido_a_final_de_mes
saldo
var1
3 ANSI
104
Programacin en C
Apunte de C
En C puede pueden utilizarse tanto las maysculas como las minsculas para
escribir un identificador.
Pero C es un lenguaje sensible a las maysculas y minsculas: para C no son
lo mismo las letras maysculas que las minsculas.
Es decir, los siguientes son cuatro identificadores vlidos pero distintos:
saldo
Saldo
SALDO
SalDo
Los datos se clasifican de manera que los programas sean capaces de realizar los
tratamientos necesarios de forma determinada. La forma de clasificar los datos
constituye la estructura de datos dentro de un lenguaje de programacin.
Un dato dentro de un programa se caracteriza por llevar asociado: un
identificador, un tipo y un valor.
Identificador. Nombre para referenciar al dato dentro del programa.
Tipo. Los tipos de datos que admite un lenguaje de programacin estn
clasificados. El tipo de un dato determina el rango de valores que puede
105
Identificador
puntos_acum
talla
nombre_empleado
Tipo
Valor
entero (numrico sin decimales) 123
1,75
real (numrico con decimales)
JUAN PREZ SERRANO
cadena de caracteres
106
Programacin en C
byte (8 bits)
bytes (16 bits)
bytes (32 bits)
bits
28 = 256
216 = 65536
232 = 4294967296
2n
0
0
0
0
255
65535
4294967295
2n -1
Tabla 4.5. Relacin entre bytes utilizados e intervalos de representacin en enteros sin signo
107
+45
00000000 00101101
-789
11111100 11101011
Nmeros enteros representados en C-2 en 16 bits.
Exceso a 2n-1: No se emplea ningn bit para el signo y el valor se
corresponde con la representacin en binario puro del nmero ms el
exceso.
32768 + +45 = 32813
10000000 00101101
32768 + -789 = 31979
01111100 11101011
Nmeros enteros representados en exceso 2n-1. El exceso para 16
bits es 216-1 = 32768.
Decimal desempaquetado: Cada dgito ocupa un octeto, teniendo un
cuarteto de zona (el cuarteto de la izquierda, que para todos los
dgitos menos para el ltimo contiene 1111) y un cuarteto de
contenido (el de la derecha) donde se halla el dgito decimal
representado en binario puro. El ltimo dgito del nmero contiene en
el cuarteto de zona el signo (1100 para + y 1101 para -).
+2015
-2015
byte (8 bits)
bytes (16 bits)
bytes (32 bits)
bits
28 = 256
216 = 65536
232 = 4294967296
2n
-128
-32768
-2147483648
-2n-1
+127
+32767
+2147483647
-2n-1 - 1
108
Programacin en C
=
=
=
0,344346 x 104
-0,75 x 10-1
0,25 x 108
=
=
=
0,344346E4
-0,75E-1
0,25E8
Hasta la dcada de los 80 cada fabricante de ordenadores utilizaba un sistema propio para la
representacin de los nmeros reales. El IEEE 754 es un estndar de aritmtica en coma
109
Apunte de C
Figura 4.3. Tabla de cdigos ASCII utilizada para el sistema operativo MS DOS
110
Programacin en C
En este grupo se encuentran por ejemplo las vocales acentuadas, la letra para el castellano, o
la para el francs.
111
Truco
En un editor o procesador de texto se puede obtener un carcter de la tabla ASCI,
utilizando el teclado numrico del ordenador, tecleando Alt+<cdigo ASCII>.
As, por ejemplo Alt 65 producir una A en pantalla.
Apunte de C
Apunte de
En algunos lenguajes como COBOL o Pascal se incluye como tipo de dato bsico el tipo
alfanumrico, que no es ms que una cadena de caracteres. En otros como C se considera este
tipo de dato como estructurado, al ser tratado como una tabla unidimensional de caracteres.
112
Programacin en C
alfanumrica que no puede cambiar ms que con una nueva compilacin del
programa.
Existen tres tipos de constantes: numricas, que sern valores numricos, enteros
o de coma flotante (reales), constantes carcter, que ser cualquier carcter
individual encerrado entre comillas7, y constantes cadenas de caracteres, que ser
cualquier conjunto de caracteres alfanumricos encerrados entre comillas 8.
Las constantes pueden usarse de dos formas:
Constantes literales. Escribiendo explcitamente el valor embebido
dentro de las propias sentencias del programa.
Ejemplo en pseudocdigo:
ptos_totales partidos_ganados * 3 + partidos_empatados * 1
reparto ganacias_totales / 6
precio_final precio + (precio * 6.0) / 100
ASIGNACION_PERSONAL 500000;
ASIGNACION_HIJO
100000;
113
. . .
ingreso_imponible sueldo_bruto
- ASIGNACION_PERSONAL
- (numero_hijos * ASIGNACION_HIJO);
Esta segunda forma incluye las constantes como literales numricos dentro
del propio cdigo del programa.
ingreso_imponible sueldo_bruto - 500000 (numero_hijos * 100000);
Se advierte claramente que una de las ventajas de las constantes con nombre frente
a las constantes literales es en el caso de las primeras, las sentencias de cdigo quedan
autodocumentadas.
4.4.2. Variables
Representacin en un programa de un dato cuyo valor puede variar durante la
ejecucin del mismo, bien porque es un dato de entrada, un dato intermedio calculado
o un dato de salida.
Las variables deben definirse al comienzo del programa, indicando el nombre
que el programador le asigna (identificador) y su tipo. As, un ejemplo en
pseudocdigo puede ser:
real precio, precio_final
entero puntos_totales
Antes de utilizar una variable para realizar algn clculo (por ejemplo precio en
la anterior expresin), deber habrsele asignado un valor vlido.
Una variable slo podr tomar un valor dentro del rango de la definicin de su tipo.
Si se intenta asignar un valor de otro tipo pueden producirse truncamientos o
desbordamientos en el caso de variables numricas, o incluso un error de compilacin
o ejecucin, en el caso de variables de otros tipos9.
Esto depender del compilador. Incluso puede que el compilador no avise y simplemente el
programa produzca resultados incorrectos.
114
Programacin en C
Las variables que alberguen los resultados para la salida del programa, debern
mostrarse en pantalla, grabar su valor en disco, llevarlas a una impresora...
Apunte de
escribir (precio_final)
Estticos
Estructurados
Internos
Dinmicos
Estructurados
Externos
Definidos por el usuario
Vaco
Puntero
Heterogneos Registro
Enumeracin
Homogneos Tabla
Cadena caracteres
Lista
Lineales
Pila
Cola
No lineales
rbol
Grafo
Fichero
void
struct, union
enum
FILE
typedef
Identificador
de tipo
void
Significado
Tamao
(bytes)
Rango de valores
(cdigo de 16 bits)
char
nulo o ninguno
carcter
0
1
-128 a 127
int
entero
-32.768 a 32.767
float
real
(simple precisin)
real doble
(doble precisin)
1.0e+38 a 1.0e-38
precisin ~ 7 dgitos
1.0e+308 a 1.0e-308
precisin ~15 dgitos
double
115
Constantes
relacionadas
CHAR_MIN
CHAR_MAX
INT_MIN
INT_MAX
FLT_MIN
FLT_MAX
DBL_MIN
DBL_MAX
Algunos tipos admiten los modificadores de tipo, lo que hace variar tanto su
tamao del almacenamiento en memoria como el rango de valores representables.
Los modificadores soportados en el lenguaje C son:
short
unsigned
long
signed
carcter
0 a 255
UCHAR_MAX
entero corto
-32.768 a 32.767
long int
entero largo
unsigned int
2
2
-2.147.483.648
a 2.147.483.647
0 a 65.535
0 a 65.535
SHRT_MIN
SHRT_MAX
LONG_MIN
LONG_MAX
0 a 4.294.967.295
10
unsigned
short int
unsigned
long int
long double
UINT_MAX
USHRT_MAX
ULONG_MAX
La Tabla 4.10 muestra la relacin entre los tipos short, int y long en el
lenguaje C. De todas formas, estas especificaciones pueden variar de un compilador
de C a otro, pero lo que garantiza el ANSI C es que el rango de int no es nunca
menor que el de short, ni mayor que el de long.
116
Programacin en C
Ordenadores con
longitud de palabra
2 bytes (16 bits)
Ocupacin y rango
tipo short
2 bytes
-32.768 a 32.767
Las constantes literales de tipo int pueden escribirse en tres sistemas numricos:
Decimal (base 10), utilizando los dgitos 0 1 2 3 4 5 6 7 8 9.
Octal (base 8), utilizando los dgitos 0 1 2 3 4 5 6 7.
Hexadecimal (base 16), utilizando los dgitos 0 1 2 3 4 5 6 7 8 9 y las
letras A B C D E F.
Las constantes literales de tipo int expresadas en notacin decimal tienen que
cumplir las siguientes restricciones:
Puede estar formada por una combinacin de dgitos del 0 al 9.
Si tiene dos o ms dgitos, el primero nunca puede ser cero.
Si es negativo debe incluir el signo menos (-) por delante.
El rango de valores admitidos para representaciones de16 bits es
desde -32768 a 32767.
EJEMPLOS
117
EJEMPLOS
01
1
010
8
0743
483
07777
4095
Valor en decimal
Ejemplos de constantes literales tipo int incorrectas expresadas en octal:
743
no comienza por 0.
05684
dgito ilegal (8).
0777.77
carcter ilegal (.).
0277777
98303, fuera de rango en 16 bits (vlida para 32 bits).
Las constantes literales de tipo int expresadas en notacin hexadecimal tienen
que cumplir las siguientes restricciones:
Pueden estar formada por una combinacin de dgitos del 0 al 9 y letras
de la A a la F, tanto maysculas como minsculas.
Deben comenzar por 0X 0x.
El rango de valores admitidos para 16 bits es de 0 a 0X7FFF (0 a
32767) y de 0X8000 a 0XFFFF (-32768 a -1).
EJEMPLOS
0x1
0x7fff
0X3A98
Valor en decimal
0
1
32767
5000
Ejemplos de constantes literales tipo int incorrectas expresadas en hexadecimal:
0x12.34
carcter ilegal (.).
0BE3
no comienza por 0X.
0x12AG
carcter ilegal (G).
0XFFFFF
1048575, fuera de rango en 16 bits (vlida para 32 bits).
118
Programacin en C
Las constantes literales de tipo long se expresan aadiendo una letra L mayscula
o minscula al final de la misma. Los rangos de valores admitidos para
representaciones de 16 bits son:
Constantes enteras largas decimales: 2147483648L a 1L y 0 a
2147483647L.
Constantes enteras largas octales: 0 a 017777777777L y
080000000000L a 037777777777L.
Constantes enteras largas hexadecimales: 0 a 0X7FFFFFFFL y
0X80000000L a 0XFFFFFFFFL.
Las constantes literales de tipo unsigned int tienen que cumplir las siguientes
restricciones:
Se identifican aadiendo una letra U mayscula o minscula al final de
la misma.
Sus valores no pueden ser negativos.
Su valor mximo es aproximadamente el doble que una constante entera
con signo.
Los rangos de valores admitidos para representaciones de 16 bits son:
o Constantes enteras sin signo decimales: 0 a 65535U.
o Constantes enteras sin signo octales: 0 a 0177777U.
o Constantes enteras sin signo hexadecimales: 0 a 0XFFFFU.
119
EJEMPLOS
unsigned short num1, num2;
const unsigned short KB = 128U;
Las constantes literales de tipo unsigned long tienen que cumplir las
siguientes restricciones:
Se identifican aadiendo las letras UL maysculas o minsculas al final
de la misma.
Sus valores no pueden ser negativos.
Su valor mximo es aproximadamente el doble que una constante entera
larga con signo.
Los rangos de valores admitidos para representaciones de 16 bits son:
o Constantes enteras largas sin signo decimales: 0 a
4294967295UL.
o Constantes enteras largas sin signo octales: 0 a
037777777777UL.
o Constantes enteras largas sin signo hexadecimales: 0 a
0XFFFFFFFFUL.
EJEMPLO
120
Programacin en C
0.2
1.66657E+3
2E-2
0.006e-4
0.00074 .1253
3E+5
3e+5
3.0e5
30.0E+4
300E+3 0.003E+8
Las constantes literales reales tienen que cumplir las siguientes restricciones:
En cdigo de 16 bits, las constantes reales (en coma flotante) se
representan en C como cantidades de doble precisin (tipo
double, 8 bytes).
Para representar una constante en coma flotante en simple precisin
(tipo float, 4 bytes), se aade una letra F mayscula o minscula
al final de la constante.
Para representar una constante en coma flotante larga (tipo long
double, 10 bytes), se aade una letra L mayscula o minscula al
final de la constante.
EJEMPLO
121
3E+5F
3E+5L
Para el uso de las constantes literales de tipo carcter es conveniente conocer los
siguientes hechos:
Una constante tipo char o unsigned char se representar como un
solo carcter encerrado entre comillas simples.
'A'
'3'
'c'
'?'
00000000
0
. . .
. . .
01000001
65
01000010
66
. . .
. . .
01111111
127
10000000
128
10000001
129
. . .
. . .
11111110
254
11111111
255
Tabla 4.11. Tipos carcter con y sin signo
0
65
66
127
-128
-127
-2
-1
Truco
Con las constantes carcter se puede realizar operaciones aritmticas, pues C
internamente operar con el cdigo numrico correspondiente a dicho carcter
(ver tabla ASCII - Figura 4.3).
122
Programacin en C
EJEMPLOS
'w'
'G'
Secuencia
de escape
\0
\a
\b
\t
\v
\n
\f
\r
\"
\'
\?
\\
\xdd
\ooo
Valor
ASCII
0
7
8
9
11
10
12
13
34
39
63
92
EJEMPLOS
123
124
Programacin en C
'M'
'I'
' '
'C'
'A'
'S'
'A'
'\0'
77
73
32
67
65
83
65
0
Para definir variables de tipo cadena, stas se definen como vectores de caracteres,
esto es, anteponiendo la palabra reservada char al identificador de la variable, y
despus entre corchetes la longitud mxima de la cadena. En el caso de las constantes
se antepone la palabra reservada const a todo ello.
La definicin de variables de tipo cadena tiene algunas excepciones a la regla
general que se muestran y se explican en los siguientes ejemplos.
EJEMPLOS
char mensaje[30];
En este otro caso se est definiendo una cadena para albergar hasta 79
caracteres ms el carcter nulo final. Adems de definirla se inicia a un valor.
Con la iniciacin slo se emplearn 23 de los 80 caracteres de la cadena
saludo.
const char CAD[20]= "Fin de proceso OK";
En este ejemplo se est definiendo una constante cadena para albergar hasta
20 caracteres ms el carcter nulo final. Slo se emplean 18 de los 20
caracteres de la cadena CAD.
const char LETRAS[] = "CALIFORNIA";
En este caso puede observarse que en la definicin de esta constante cadena
no se ha incluido entre los corchetes el nmero de elementos (caracteres) de
dicha cadena. No es necesario porque al existir a la derecha la asignacin del
valor inicial para la cadena, el compilador calcula y reserva automticamente
125
el espacio necesario para guardar en dicha cadena el valor con que se inicia,
en este caso 11 bytes (10 caracteres ms el carcter nulo al final).
ndice
Elemento
de la cadena
1
2
3
4
5
6
7
8
9
10
11
0
1
2
3
4
5
6
7
8
9
10
LETRAS[0]
LETRAS[1]
LETRAS[2]
LETRAS[3]
LETRAS[4]
LETRAS[5]
LETRAS[6]
LETRAS[7]
LETRAS[8]
LETRAS[9]
LETRAS[10]
'C'
'A'
'L'
'I'
'F'
'O'
'R'
'N'
'I'
'A'
'\0'
Valor ASCII
11010100
'M'
77
carcter 'M'
11010100
00000000
'M'
'\0'
77
0
cadena "M"
126
Programacin en C
/*
/*
/*
/*
/*
/*
*/
*/
*/
*/
*/
*/
127
mucho ms fcil cambiar el valor de una constante simblica y volver a compilar que
repasarse un programa entero buscando donde aparece una secuencia de caracteres
concreta que hay que modificar.
Una diferencia entre las constantes simblicas y las constantes declaradas es que en
las primeras no existe reserva de posiciones de memoria.
EJEMPLO
INTERES 0.23
PI 3.141593
FALSE
1
NOMBRE "Juan Antonio"
{
FACTOR_IVA = 12;
ASIGNACION_PERSONAL = 500000;
ASIGNACION_HIJO
= 100000;
128
Programacin en C
. . .
ingreso_imponible = sueldo_bruto
- ASIGNACION_PERSONAL
- (numero_hijos * ASIGNACION_HIJO);
iva = ( precio / 100 ) * FACTOR_IVA;
. . .
}
CONSTANTES LITERALES
#include <stdio.h>
void main(void) {
. . .
ingreso_imponible = sueldo_bruto
- 500000
- (numero_hijos * 100000);
iva = ( precio / 100 ) * 12;
. . .
}
500000
100000
void main(void) {
. . .
ingreso_imponible = sueldo_bruto
- ASIGNACION_PERSONAL
- (numero_hijos * ASIGNACION_HIJO);
iva = ( precio / 100 ) * FACTOR_IVA;
. . .
}
EJEMPLO
valor_1 = valor_2;
129
int main ( )
{
...
}
Cabecera de la funcin
Nombre de la funcin
Sentencias
La funcin main() representa el punto de entrada al programa, siendo su
estructura es:
int main() {
/* Sentencias */
}
El conjunto de sentencias incluidas entre llaves se denomina bloque. Un programa
slo puede tener una nica funcin main().
A continuacin, se presenta el que suele ser el primer programa que se hace en
cualquier lenguaje de programacin: el hola mundo.
/* Programa HolaMundo.c */
#include <stdio.h> /* Archivo cabecera para funciones de E/S bsica*/
int main () {
/* Funcin main */
printf(HOLA MUNDO); /* Saca por pantalla el mensaje */
return 1;
}
130
2.
3.
4.
Programacin en C
6.
program
valor?
variable
IMPUESTOS
impuestos
7.
main
$volcado
j77
5.
si
Nombre_fichero
InDiCe
_impuesto
0758
5000L
42345
777777L
75678u
2.E-01L
4.5e4F
3E5
0777777L
0x3A
12458698UL
0B12
010
077.77
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
- scanf("%s", nombre);
- printf("%c", nombre[0]);
20.
131
-18
0.0001
{
"Adrin"
'\n'
5. Expresiones y operadores
El proceso bsico de transformacin de los datos de entrada en datos de salida que
hace cualquier programa lleva asociado un conjunto de operaciones de diversa
complejidad. En este captulo se va a abordar cmo los lenguajes de programacin en
general, y en concreto C, hacen uso de los operadores para construir las expresiones
que dan soporte a dichos procesos de transformacin, conjugando para ello conceptos
como los de prioridad y asociatividad.
As, este captulo se ha organizado en siete secciones. En las dos primeras se
introducen los conceptos de operador y expresin respectivamente. La seccin tres se
dedica a repasar las caractersticas de los operadores ms frecuentemente utilizados en
el lenguaje C. La cuarta seccin estudia las reglas de prioridad de los operadores. La
quinta seccin aborda el tema de las funciones intrnsecas, mientras que la sexta
seccin concreta este tema para el lenguaje C. Finalmente, la sptima seccin presenta
una lista de cuestiones y ejercicios de repaso.
5.1. Operadores
Son tems (smbolos formados por uno o ms caracteres) que actan sobre una, dos o
ms variables para realizar una determinada operacin (un clculo predeterminado),
produciendo siempre un determinado resultado.
Algunos requieren dos operandos (binarios), mientras que otros actan slo sobre
un operando (unarios o monarios), incluso los hay que actan sobre tres operandos
(ternarios).
Normalmente, los operadores permiten expresiones1 como operandos, aunque
existen tambin los que slo permiten variables como operandos.
Hay operadores que slo pueden actuar con operandos de un tipo de dato
determinado, produciendo un resultado siempre de un tipo de dato establecido. Sin
embargo, hay otros operadores que pueden actuar sobre operandos de diversos tipos
de datos. En estos casos, es comn que el operador pueda originar un resultado donde
su tipo de dato depende del tipo de dato de los operandos. Esto se denomina
sobrecarga de operadores.
Cada lenguaje posee un conjunto determinado de operadores, algunos de stos son
comunes a casi todos los lenguajes, e incluso se representan por el mismo smbolo,
como se puede ver en la Tabla 5.1.
5.2. Expresiones
Las expresiones son combinaciones de constantes y variables relacionadas a travs de
operadores y/o nombres de funciones, donde adems tambin pueden incluirse
parntesis.
1
134
Programacin en C
Smbolo
Cobol
C
Clasificacin
Operador
Asignacin
Aritmticos
:=
=
=
=
asignacin
suma
+
+
+
+
resta
multiplicacin
*
*
*
*
/
/
/
/
divisin
div
\
/
/
divisin entera
mod
mod
mdulo o resto divisin
%
potenciacin
^
igual que
=
=
=
==
!=
distinto
<>
<>
not =
mayor
>
>
>
>
menor
<
<
<
<
mayor o igual
>=
>=
>=
not <
menor o igual
<=
<=
<=
not >
not
not
not
!
negacin
and
and
and
conjuncin (Y)
&&
or
or
or
disyuncin (O)
||
Tabla 5.1. Ejemplos de operadores en diferentes lenguajes
Relacionales
Lgicos
Pascal
Basic
Pseudocdigo
+
*
/
div
mod
elevado a
=
<>
>
<
>=
<=
not no
and y
or o
b* a 5
a
b 3
*c
f
3.1
Una expresin siempre toma un valor, que se determina tomando los valores de las
variables y constantes implicadas y ejecutando las operaciones indicadas. El tipo de
dato del resultado depende tanto del operador o funcin utilizada como del tipo de los
operandos implicados.
En ocasiones, la introduccin de parntesis y espacios en blanco mejora la
legibilidad de la expresin a la hora de expresarla en un lenguaje de programacin,
aunque, en el caso de los parntesis, pueda llegar a ser innecesario en algunos casos.
EJEMPLO
Expresiones y operadores
135
a + b
Variable
operador de asignacin
expresin
El operando de la derecha del operador asignacin puede ser una variable simple o
una expresin, pero el operando de la izquierda debe ser siempre una variable.
5.3. Operadores en C
En esta seccin se va a hacer un repaso por los operadores que ofrece el lenguaje C,
explicando sus caractersticas y sintaxis.
Operacin
Tipo del resultado
Asigna el valor del operando de su derecha Se acomoda a la variable
(expresin) al operando (variable) de su que recibe el valor
izquierda, sustituyendo al valor que tuviera sta
Tabla 5.3. Operador de asignacin en C
Resultado
3
2
-7
136
Programacin en C
Resultado
i y j con valor 3
i, j, k con valor -5
si k vale -5, m y n con valor -10
EJEMPLO
Cdigo ASCII
120
48
Expresin
i = '0';
i = '0' 'x';
Resultado
i vale 48
i vale -72
EJEMPLO
Expresiones y operadores
137
viene determinado por las reglas del lgebra, mientras que para el operador mdulo
(%), el signo del resultado es el del primer operando, esto es, el signo del dividendo.
Operador
+
*
/
%
Tipo del
resultado
suma
Numricos
numrico
resta
Numricos
numrico
producto
Numricos
numrico
divisin
Los dos enteros y el segundo no cero
entero (*1*)
alguno de ellos real y el segundo no cero
real
mdulo o resto Los dos enteros y el segundo no cero (*2*) entero
Tabla 5.4. Operadores binarios aritmticos en C
Operacin
EJEMPLO
Resultado
13
7
-7
30
3
0
1
3
EJEMPLO
Resultado
14.5
25.0
(No permitido)
Expresin
v1 - v2
v1 / v2
Resultado
10.5
6.25
EJEMPLO
EJEMPLO
138
Programacin en C
cdigo que se est utilizando (por ejemplo la tabla ASCII). Supngase las
siguientes variables tipo carcter:
Identificador de variable
c1
c2
c3
c4
Expresin
Resultado
c4
102
c3 15
50
c1 + c2 + 5
169
c1 + c2 + '5' 217
Valor
'P'
'T'
'A'
'5'
'f'
Cdigo ASCII
80
84
65
53
102
Expresin
Resultado
c1 + c2
164
2 * c3
130
c3 / 2
32
EJEMPLO
Ejemplo
-x
++x
++
x++
--x
--
x--
Significado
Operador signo menos.
Cambia el signo del operando.
Operador incremento. El operando debe ser una variable.
Pre-incremento: Incrementa x, es decir, hace x=x+1
antes de cualquier operacin con la variable x.
Post-incremento: Incrementa x, es decir, hace x=x+1
despus de cualquier operacin con la variable x.
Operador decremento. El operando debe ser una variable.
Pre-decremento: Decrementa x, es decir, hace x=x-1
antes de cualquier operacin con la variable x.
Post-decremento: Decrementa x, es decir, hace x=x-1
despus de cualquier operacin con la variable x.
Tabla 5.5. Operadores unarios en C
EJEMPLO
Expresiones y operadores
139
=
=
=
=
1;
i;
++i;
2*(++i);
valor
valor
valor
valor
valor
de i
de a
de b
de c
final de i
1
1
2
6
3
=
=
=
=
1;
i;
i++;
2*(i++);
valor
valor
valor
valor
valor
de i
de a
de b
de c
final de i
1
1
1
4
3
140
Programacin en C
5.
int
int
long
int
long
double
Resultado 4027.2 de tipo double
double
Expresiones y operadores
141
Otra clase de conversin implcita tiene lugar cuando el resultado de una expresin
es asignado a una variable, pues dicho resultado se convierte al tipo de la variable.
En este caso, sta puede ser de menor rango que la expresin, por lo que en esta
conversin puede perderse informacin y ser peligrosa.
EJEMPLO
3/5
0.75/2;
0 (int)
0.375 (double)
float b =
50/2
25 (int)
7%3;
1 (int)
int c =
1.75F;
(float)
int c =
1.75e9F;
(1750000000 float)
160/2 + 5;
80 (int) + 5 (int)
Cuando a una variable entera se le asigna en tiempo de ejecucin un valor que queda fuera del
rango permitido (situacin de overflow o valor excesivo), de ordinario el programa no se
interrumpe, por lo que puede producirse un error lgico en el programa de consecuencias
imprevisibles. La variable quedar cargada con un valor impredecible.
142
Programacin en C
Ejemplo
Significado equivalente
de uso
x += y
x = x + y
x += 1
x = x + 1
x -= y
x = x - y
x -= 1
x = x - 1
x *= y
x = x * y
x *= 3
x = x * 3
x /= y
x = x / y
x /= 10
x = x / 10
x %= y
x = x % y
x %= 5
x = x % 5
Tabla 5.6. Operadores de asignacin compuestos en C
Comparacin que
Tipo de datos que puede
realiza
comparar
igual
numricos, carcter, punteros
distinto
numricos, carcter, punteros
menor que
numricos, carcter, punteros
mayor que
numricos, carcter, punteros
menor o igual que
numricos, carcter, punteros
mayor o igual que
numricos, carcter, punteros
Tabla 5.7. Operadores relacionales en C
Tipo del
resultado
int
int
int
int
int
int
EJEMPLO
Expresiones y operadores
Expresin
i < j
(i + j) >= k
(j + k) > (i + 5)
k != 3
j == 2
f > 5
(i + f) > 10
c != 'p'
k >= 10 * (i + f)
Interpretacin
cierto
cierto
falso
falso
cierto
cierto
falso
cierto
falso
143
Resultado
1
1
0
0
1
1
0
1
0
&&
||
En la Tabla 5.8 se pueden observar los operadores lgicos que ofrece el lenguaje C,
mientras que a continuacin se muestran las tablas de verdad de dichos operadores.
EJEMPLO
3
144
Programacin en C
Interpretacin
cierto
falso
falso
cierto
falso
falso
cierto
falso
Resultado
1
0
0
1
0
0
1
0
k == j || (k - i*j)
Expresiones y operadores
145
EJEMPLO
Operador
Tipo del
resultado
entero
entero
entero
entero
entero
entero
~
&
|
^
<<
>>
&
&
&
&
&
B
0
1
0
1
=
=
=
=
=
=
=
=
=
=
C
0
0
0
1
A
0
0
1
1
|
|
|
|
|
B
0
1
0
1
=
=
=
=
=
=
=
=
=
=
C
0
1
1
1
A
0
0
1
1
^
^
^
^
^
B
0
1
0
1
=
=
=
=
=
=
=
=
=
=
C
0
1
1
0
A
1
0
~A
0
1
Todos los operadores de la Tabla 5.9, salvo el operador de complemento a uno (~)
son binarios, y por lo tanto necesitan dos operandos.
146
Programacin en C
Expresin
~i
Resultado
-13
Comprobacin
12 en binario en 2 bytes
complemento a 1
00000000
11111111
00001100
11110011
j & k
136
00000000
00110001
00000000
10001100
10011010
10001000
j | k
12702
00000000
00110001
00110001
10001100
10011010
10011110
j ^ k
12566
j << 2
560
k << 3
-29488
k >> 1
6349
Tipo del
operando
Tipo del
resultado
cualquiera
operando
Tabla 5.10. Operador tamao (sizeof) en C
entero
Hay que recordar que el tamao de una variable depende del compilador y del tipo de
ordenador utilizado.
Expresiones y operadores
147
Resultado
4
4
1
2
148
Programacin en C
Este operador es un operador unitario, donde el tipo de dato del operando no vara
en su definicin, nicamente se convierte temporalmente para evaluar la expresin en
la que se utiliza el operador de molde.
EJEMPLO
Hay que ser cuidadoso, pues el operador cast acta sobre la variable ms prxima.
As, si se tiene la declaracin:
int x = 11;
Y se tiene la expresin:
(float) x/2
sta convierte x a float, por lo que 2 es considerado como float y, por tanto,
la divisin se realiza entre reales, dando un resultado de tipo float que ser 5.5.
Si por el contrario se tiene la expresin:
(float) (x/2)
Primero se realiza la divisin entera obtenindose un resultado entero sin
decimales (truncado), y posteriormente este resultado es convertido a float, pero se
han perdido los decimales. El resultado ser 5, es decir, no se ha hecho nada!
EJEMPLO
Expresiones y operadores
149
producto = a * (long) b;
Pero ser incorrecto producto = (long) (a * b); por los motivos
expuestos anteriormente.
La expresin:
a = (b = 5, c = 3, b+c);
Se puede escribir como:
b = 5;
c = 3;
a = b+c;
Por lo que en la variable a se almacenar el valor 8.
Para realizar varias operaciones dentro de la condicin de un bucle for.
EJEMPLO
for (i= 0, k = 15; i < k; k--, i++) {
Equivale a escribir:
i= 0;
for (k = 15; i < k; k--) {
...
i++;
}
...
150
Programacin en C
Tipo de los
operandos
cualquiera
x = (a > b) ? a : b;
Asigna a x el mayor entre a y b
y = (f < g) ? f : g;
Asigna a y el menor entre f y g
indicador = (i < 0) ? 0 : 100;
Si i es negativo, se le asignar a indicador el valor 0. Si
fuese cero o positivo, se le asignar el valor 100.
Expresiones y operadores
151
3.
152
Programacin en C
Sentido de
crecimiento de la
prioridad
Ms baja
OPERADORES
()
parntesis y llamada a funcin
[]
subndice de una tabla
.
miembro de una estructura
->
puntero a miembro de una estructura
!
no lgico
~
complemento a uno a nivel de bit
signo menos
++
incremento
-decremento
&
direccin de una variable
*
valor almacenado para punteros
(tipo)
molde o <<cast>>
sizeof
tamao
* /
%
multiplicacin, divisin, mdulo o resto
+ suma, resta
<<
desplazamiento a la derecha
>>
desplazamiento a la izquierda
< <= > >=
menor que, menor o igual que, mayor que,
mayor o igual que
==
igualdad
!=
desigualdad
&
and a nivel de bit
^
or exclusivo a nivel de bit
|
or a nivel de bit
&&
and lgico
||
or lgico
? :
condicional
= += -= *= /= %= &= ^= |= <<= >>=
asignacin
,
coma
ASOCIATIVIDAD
Izq.
Der.
Izq.
Der.
Izq.
Der.
Izq.
Der.
Izq.
Der.
Izq.
Der.
Izq.
Der.
Izq.
Izq.
Izq.
Izq.
Izq.
Der.
Der.
Der.
Der.
Der.
Izq.
Der.
Izq.
Der.
Izq.
Der.
Expresiones y operadores
153
Donde:
f es el nombre de la funcin, la cual slo tiene un argumento, de
tipo real. El resultado que proporcionar tambin ser real.
x es el parmetro formal que representa el argumento en la
definicin de la funcin f.
154
Programacin en C
f (3, 4) = - 0.04
Para poder utilizar una funcin intrnseca en un lenguaje de programacin se debe
conocer la interfaz (o prototipo) de la funcin, es decir:
El nombre de la funcin.
El nmero y tipo de sus argumentos.
El tipo del resultado que proporciona.
Dependiendo del lenguaje, la sintaxis que se utilizar para indicar la interfaz de una
funcin intrnseca ser parecida a una de estas dos:
nombre_funcin (parmetro1 tipo1, parmetro2 tipo2, ...): tipo_resultado
EJEMPLO
Expresiones y operadores
155
Prototipo
fabs(x)
ceil(x)
floor(x)
fmod(x,y)
double fmod(double x,
double y);
exp(x)
log(x)
pow10(x)
log10(x)
pow(x,y)
double
double
double
double
double
double
double
double
sqrt(x)
hypot(x,y)
log(double x);
pow10(int x);
log10(double x);
pow(double x,
y);
sqrt(double x);
hypot(double x,
y);
sin(x)
cos(x)
tan(x)
asin(x)
acos(x)
atan(x)
atan2(x,y)
double atan2(double x,
double y);
double sinh(double x);
double cosh(double x);
double tanh(double x);
int atoi(const char
*s);
sinh(x)
cosh(x)
tanh(x)
atoi(s)
atol(s)
atof(s)
Descripcin
Archivo
cabecera
Valor absoluto de x.
Valor absoluto de x.
math.h
math.h
Valor absoluto de x.
Redondea x al entero superior ms
prximo.
Redondea x al entero inferior ms
prximo (trunca x).
Resto de la divisin x / y, con el
mismo signo que x.
Exponencial de x: e elevado a x,
donde e=2.7182818...
Logaritmo neperiano de x
Potencia x de 10: 10 elevado a x.
Logaritmo decimal de x.
Potencia: x elevado a y.
math.h
math.h
Raz cuadrada de x.
Calcula la hipotenusa de un
tringulo rectngulo, dados sus
catetos x, y.
Seno del ngulo x expresado en
radianes.
Coseno del ngulo x expresado en
radianes.
Tangente del ngulo x expresado
en radianes.
Proporciona el ngulo en radianes
cuyo seno es x.
Proporciona el ngulo en radianes
cuyo coseno es x.
Proporciona el ngulo en radianes
cuya tangente es x.
Proporciona el ngulo en radianes
cuya tangente es x/y.
Seno hiperblico de x.
Coseno hiperblico de x.
Tangente hiperblica de x.
Convierte una cadena s en un
entero. Devuelve 0 si la conversin
no es posible.
Convierte una cadena s en un
entero largo. Devuelve 0 si la
conversin no es posible.
Convierte una cadena s en un real.
Devuelve 0 si la conversin no es
posible.
math.h
math.h
math.h
math.h
math.h
math.h
math.h
math.h
math.h
math.h
math.h
math.h
math.h
math.h
math.h
math.h
math.h
math.h
math.h
stdlib.h
stdlib.h
stdlib.h
156
Programacin en C
Funcin
Prototipo
toascii(c)
tolower(c)
toupper(c)
frexp(x,n)
ldexp(m,n)
modf(x,d)
Descripcin
Archivo
cabecera
ctype.h
ctype.h
ctype.h
math.h
math.h
math.h
ln b
b2
4ac
e 2a
Expresiones y operadores
157
mdulo
x2
y2
z2
#include <stdio.h>6
#include <math.h>
double x, y, z, modulo;
/* Aqu se codificarn las sentencias
para leer de teclado los valores de las
coordenadas del vector x, y y z */
modulo = sqrt(x * x + y * y + z * z);
/* Aqu se codificarn las sentencias
para escribir en pantalla el valor de la
variable modulo calculada */
EJEMPLO
Llamada a la funcin
Resultado
Archivo cabecera
mayus=toupper(letra);
minus=tolower('B');
mum2=abs(num1);
realalto=ceil(numreal);
realbajo=floor(5.7);
resto=fmod(7,2);
resto=fmod(25.63,3);
raiz=sqrt(abs(num1));
mayus='A'
minus='b'
num1=57
realalto=6.0
realbajo=5.0
resto=1
resto=1.63
raiz=7.5498
#include
#include
#include
#include
#include
#include
#include
#include
<ctype.h>
<ctype.h>
<math.h>
<math.h>
<math.h>
<math.h>
<math.h>
<math.h>
158
Programacin en C
2.
a - b = c;
3.
4.
5.
ma
cos eno 2T
x1 y 2
9
C 32
5
W
T
6.
3 - c = d + 4;
ax 2
tan
Z
B
x1 x 2
x1 x 2
bx c
Z
x2
y2
7.
x > y >= z
x, y y z son mayores que cero
x es diferente a y y a z
x igual a y y tambin igual a z
x es menor o igual que 500 y mltiplo de 5, pero
distinto de 100
(g) x igual a y pero distinto de z, y adems z mayor que
15 o distinto de 7.
8.
9.
5 + 3) / 2 *
35 > 47 && 9
9 == 15 || 8
8 * 2 < 5 ||
3) / 2 - (int) 28.75 / 4 + 29 % 3 * 4
== 9 || 35 != 3 + 2 && 3 >= 3
!= 5 && 7 > 4
7 + 2 > 9) && 8 - 5 < 18
Expresiones y operadores
10.
159
11.
12.
13.
14.
15.
16.
b) 5
c) 7
d) 4
17.
18.
! a && (b > c) || d
a = b
a = 7
19.
21.
a = 'b'
a = '7'
20.
y
y
/ 0
/ 4
/ -4
/ 4
/ -4
13
13
13
-13
-13
% 0
% 4
% -4
% 4
% -4
(x
(x
(x
(x
(x
(1)
(2)
(3)
(4)
(5)
! (x != y) && (y == z)
! ((x <= y) || (y < z))
((y < z) || (y == z))) || (x == y)
!(x >= y) && !(y >= z)
! ((x == y) && (y != z))
160
22.
Programacin en C
23.
Podras modificar ahora los parntesis para que el resultado fuera falso?
Cada una de las siguientes expresiones utiliza una funcin de biblioteca.
Identificar el propsito de cada una de ellas e indicar cul es su archivo de
cabecera.
abs(i - 2 * j)
toupper(d)
floor(x + y)
log(x)
fmod(x,y)
pow(x - y, 3.0)
fabs(x + y)
ceil(x)
exp(x)
sqrt(pow(x,2) + pow (y,2))
tolower(65)
sin(x - y)
La sentencia:
leer (cantidad_inicial, porcentaje, duracion)
Representa en pseudocdigo la lectura de teclado de tres valores de entrada
que se asignarn a las variables cantidad_inicial, porcentaje y
duracion.
El siguiente fragmento de cdigo:
suma_total 25.67
escribir ("El resultado es ", suma_total)
- 161 -
162
Programacin en C
Los mensajes deben de ser cadenas de caracteres sin datos variables, aunque
pueden incluir espacios en blanco.
Esta funcin tiene un nico parmetro (literal o variable cadena de caracteres), que
es el mensaje a imprimir en pantalla. Al mostrar el mensaje por pantalla genera
automticamente un salto de lnea al final del texto impreso en pantalla.
EJEMPLO
163
164
Programacin en C
Introduzca su nombre:
Juan Prez <intro>
(entrada del usuario)
Hola
Juan Prez
Su ordenador personal le saluda.
Salida en pantalla
a
cd
Salida en pantalla
AAAA
Salida en pantalla
A
CD
Salida en pantalla
pepe's
165
Ambas funciones se usan para leer un carcter de teclado sin necesidad de pulsar
<intro> despus de pulsar el carcter. En el momento en que se pulse un carcter
en el teclado, ste es devuelto por las funciones y se contina con la siguiente
instruccin.
No tienen argumentos, pero requieren siempre un par de parntesis vacos detrs
del nombre de la funcin.
La forma de recoger el valor ledo de teclado ser realizar una asignacin a una
variable de tipo carcter:
variable_caracter = getch();
variable_caracter = getche();
166
Programacin en C
6.6 se resumen los datos fundamentales necesarios para el uso de esta funcin.
Prototipo:
Archivo cabecera:
Argumentos:
Valor devuelto:
Finalidad:
Si el usuario teclea:
LAS TARJETAS DOMINARAN EL COMERCIO ELECTRONICO<intro>
Prototipo:
Archivo cabecera:
Argumentos:
Valor devuelto:
Finalidad:
167
168
Programacin en C
Tipo del
argumento
Especificadores de formato
%d
%i
%o
int
%x
%X
%h
short
%hd
%hx
%hX
%ho
long
%ld
unsigned int
unsigned
short
unsigned
long
%lo
%lx
%lu
float
%G
long double
carcter
cadena
puntero
%lf
%u
%hu
%f
%e
%E
%g
double
Comentario
%le
%lE
%lG
%Lf %Le %LE %Lg
%LG
%c
%s
%p
Se aade prefijo L
169
EJEMPLO
170
Programacin en C
char nombre[80];
printf("Introduzca su nombre: ");
gets(nombre);
printf("\nHola %s, tu ordenador personal te saluda.",nombre);
El resultado sern dos lneas con las dos primeras estrofas de la famosa
poesa de Jos de Espronceda.
Con diez caones por banda,
viento en popa a toda vela
printf("%s\n%s\n%s\n%s\n",
"Con diez caones por banda,",
"viento en popa a toda vela,",
"no cruza el mar sino vuela,",
"un velero bergantn.");
EJEMPLO
4\n");
printf("1234567890123456789012345678901234567890\n");
printf("Compra\tVenta\tTotal\n");
printf("1.100\t345\t755\n");
printf("1.520\t786\t734\n");
printf("ABCDEFG\b12345 \n");
printf("RSTUVWXYZ\r12345\n");
171
*/
*/
*/
printf("\51 \n");
*/
y escribo.
1
2
3
4
1234567890123456789012345678901234567890
Compra Venta
Total
1.100
345
755
1.520
786
734
ABCDEF12345
12345WZYZ
"El Quijote de la 'Mancha' de Cervantes"
\Madrid\
El signo de porcentaje es %.
A
K
K
)
e
(En este momento sonar el pitido 2 veces)
172
Programacin en C
printf("%12g\n", f);
Salida en pantalla:
1.45
1.45
1.45
1.45
Especificacin de la precisin
Para las cantidades numricas reales la precisin significa el nmero de decimales a
mostrar. Para ello se antepone al carcter de conversin del especificador de formato
un punto y un nmero entero que representar el nmero de decimales a mostrar. El
nmero real se redondear si se le debe recortar, o se le aadirn ceros si se le debe
aumentar el nmero de decimales reales que tiene la cantidad para ajustarla a la
precisin indicada. Normalmente, si se especifica precisin se suele especificar
tambin el ancho de campo mnimo.
Para cantidades numricas enteras la precisin indica el mnimo nmero de cifras a
mostrar. Para ello se completar, si es necesario, con ceros por la izquierda el nmero
a mostrar.
Para cadenas de caracteres la precisin especifica el mximo nmero de caracteres
a mostrar.
173
EJEMPLO
Salida en pantalla:
123.567000
123.56700
123.57
123.5670
124
EJEMPLO
Salida en pantalla:
Precisin con cadenas
Precisin
Preci
EJEMPLO
Salida en pantalla:
00000012
000167
31243
174
Programacin en C
EJEMPLO
Longitud mnima?: 15
Nmero de decimales?: 2
1:
123.46
2:123.5
3:
123.456000
4:
123.46
5: 145
Salida en pantalla:
123.4560
0000123.4560
78
00000078
175
f1);
f2);
f3);
f4);
printf("**%-12.4f",
printf("**%-12.4f",
printf("**%-12.4f",
printf("**%-12.4f",
printf("**\n");
f1);
f2);
f3);
f4);
printf("**%12.4s", mensaje);
printf("**%-12.4s", mensaje);
printf("**%.4s", mensaje);
printf("**\n");
Salida en pantalla:
**
123.4560**
23.4000**
1333.4561**
345.6788**
**123.4560
**23.4000
**1333.4561
**345.6788
**
**
Depe**Depe
**Depe**
Indicador de formato.
Signo - (indica ajuste a la izquierda).
Dgito 0 (si justificacin derecha, rellena con 0 los
caracteres en blanco de la izquierda).
Anchura mnima total del campo.
Un punto decimal.
Precisin.
Si enteros, l para long y h para short.
Carcter de conversin del especificador de formato.
EJEMPLO
176
Programacin en C
int dd = 7, mm = 9, aa = 1997;
int hh = 6, mi = 9, ss = 56;
Salida en pantalla
printf("%02d/%02d/%4d\n", dd, mm, aa);
07/09/1997
printf("%d-%d-%d\n", dd, mm, aa);
7-9-1997
printf("%4d%02d%02d\n", aa, mm, dd);
19970907
printf("%d del %d de %d\n", dd, mm, aa);
7 del 9 de 1997
printf("%d del %d de %d.%d\n", dd, mm, aa/1000, aa%1000); 7 del 9 de 1.997
printf("%02d:%02d:%02d\n", hh, mi, ss);
06:09:56
printf(">>%10o<<\n", 12);
>>
14<<
printf(">>%120X<<\n", 12);
>>
C<<
printf(">>%70x<<\n", 12);
>>
c<<
En la funcin scanf() los argumentos que siguen a la cadena de control deben ser pasados
por referencia, ya que la funcin los lee y tiene que trasmitirlos al mdulo que la ha llamado.
Para ello, dichos parmetros deben estar constituidos por las direcciones de las variables en las
que hay que depositar los datos (operador indireccin & precediendo al nombre de la variable),
177
int
%o
%x
short
long
unsigned int
unsigned short
unsigned long
float
double
long double
carcter
cadena
Especificadores de
formato
%d
%i
%h
%hd
%ho
%hx
%ld
%lo
%lx
%u
%hu
%lu
%f %e %g
%lf
%le
%lg
%Lf %Le %Lg
%c
%s
%[...]
Comentario
Entero con signo en decimal
Entero en decimal, octal (si comienza por 0)
hexadecimal (si comienza por 0x 0X)
Entero en octal, sin el cero inicial
Entero en hexadecimal, sin el prefijo 0x
0X
Se aade prefijo h para octal y hexadecimal
Se aade prefijo l
178
Programacin en C
carcter tabulador o carcter de fin de lnea. Estos tres caracteres reciben el nombre
genrico de caracteres separadores.
EJEMPLO
Sentencia scanf():
1235
0.050000
Caracteres de tabulacin.
cremallera
1235
0.050000
1235
En aquellos casos en los que la cadena de control de scanf() est constituida por
caracteres que no sean caracteres de separacin, ni tampoco un especificador de
formato, dichos caracteres sern detectados en la lnea de entrada y descartados. Es
una forma de leer datos con un determinado formato.
EJEMPLO
179
Har que la variable concepto se cargue slo con el valor ACD, ya que la E
no se encuentra entre los corchetes.
Al leer con scanf() una cadena de caracteres, como el carcter espacio es un
carcter separador, las cadenas que se tecleen no podrn incluir espacios en blanco.
Existen dos posibles alternativas para solucionar este problema.
1. Emplear la funcin gets(), que es la solucin ms frecuentemente
utilizada.
2. Utilizar scanf() con el especificador de formato [..]. Dentro de los
corchetes se debe incluir el carcter acento circunflejo (^), que provoca
que los caracteres que se especifiquen posteriormente sean considerados
de forma opuesta, es decir, se leern caracteres del dispositivo de entrada
mientras no se encuentren dentro de los corchetes.
EJEMPLO
Sea el siguiente fragmente de un programa escrito en lenguaje C:
char concepto[80];
scanf("%[^\n]", concepto);
DE
MLAGA<intro>
Har que toda la cadena tecleada, incluidos los espacios en blanco, ser
cargada en la variable concepto, ya que la entrada estndar terminar slo
cuando encuentre un carcter fin de lnea (<intro>).
180
Programacin en C
181
Valor de a
1
123
789
123
Valor de b
2
456
456
4
Valor de c
3
789
256
3 caracteres para cada dato
567
8 y 9 son ignorados
EJEMPLO
Valor de i
10
Valor de x
256.8
Valor de c
7
5 y T son ignorados
182
Programacin en C
EJEMPLO
123
25
183
%c", &c1);
%c", &c2);
%c", &c3);
%c", &c4);
184
Programacin en C
2.
2.
3.
4.
5.
6.
short
unsigned int
float
long double
int en octal
unsigned short
long
una cadena de caracteres
int en hexadecimal
long vix;
unsigned vu;
long int vlix;
char vc;
Escribir una funcin scanf() para cada uno de los siguientes grupos de
variables. Supngase que los enteros se leern como cantidades decimales.
7.
185
8.
9.
10.
11.
12.
13.
14.
Escribir para cada una de las siguientes cuestiones una sentencia printf()
que la resuelva:
Cul es el cdigo ASCII de la letra A?
Cul es el cdigo ASCII de la letra Z?
Cul es la letra que corresponde al cdigo ASCII 70?
Cul es la letra que corresponde al cdigo ASCII 36?
Cmo se llama el archivo cabecera de las funciones de entrada/salida
estndar en la mayora de las versiones de C? Cmo se incluye este archivo
en un programa?
Qu se entiende por especificar la longitud de campo mnima en salida con
printf()? Y por especificar la longitud de campo mxima en entrada con
scanf()?
Cmo se puede suprimir la asignacin de un dato de entrada mediante
scanf() a un argumento?
Realizar la declaracin de una variable cadena de 80 caracteres a la que se va
a denominar mensaje, y una variable entera a la que se va a denominar
numero.
Cmo se leera de teclado con scanf() dicha cadena?
Cmo se leera de teclado con scanf() dicho entero?
Qu diferencia se puede observar entre las dos anteriores lecturas?
Cmo se leera de teclado con gets() dicha cadena?
Cmo se leera de teclado con gets() dicho entero?
Cmo se escribira en pantalla con printf() dicha cadena?
Cmo se escribira en pantalla con printf() dicho entero?
Cmo se escribira en pantalla con puts() dicha cadena?
Cmo se escribira en pantalla con puts() dicho entero?
Qu ocurre si el dato de salida tiene ms caracteres que la especificada por
la longitud de campo mnima en printf()? Y si la entrada tiene ms
caracteres que la especificada por la longitud de campo mxima en
scanf()?
Cmo se especificara en una cadena de control de scanf() que se desean
leer argumentos:
enteros cortos
enteros largos sin signo
15.
Escribir de forma adecuada una funcin scanf() que permita introducir los
valores numricos de i, j, k asumiendo que:
186
16.
17.
18.
Programacin en C
stas representan el da (dd), mes (mm) y ao (aa) de una fecha. Escribir las
sentencias printf() necesarias para mostrar dicha fecha en los siguientes
formatos:
12-06-1999
//12//06//99/
19990612
12 del 6 de 1999
19.
12/06/99
990612
12 del 6 de 1.999
20.
187
7. Sentencias de control
En los ejemplos de los programas que se han visto hasta ahora, las sentencias se
ejecutan una nica vez y en el mismo orden en que aparecen en el programa, es decir,
cada una a continuacin de la anterior escrita en el programa fuente, empezando por
la primera y terminando por la ltima.
Los programas que se suelen realizar en la prctica no son tan sencillos, ya que los
que se han visto no incluyen ningn tipo de elemento de control lgico. En
particular, en estos programas no aparecen comprobaciones de condiciones que sean
ciertas o falsas ni aparece la ejecucin repetida de grupos individuales de sentencias
de forma selectiva.
Muchos programas requieren que se efecte una comprobacin lgica en algn
punto concreto de los mismos y a continuacin realizar alguna accin que depender
del resultado de la prueba lgica realizada. Esto se conoce como ejecucin
condicional. Existe tambin una clase especial de ejecucin condicional, llamada
seleccin, en la que se selecciona un grupo de sentencias entre varios grupos
disponibles.
Adems, los programas pueden requerir que un grupo de sentencias se ejecute
repetidamente, hasta que se satisfaga alguna condicin lgica. Esto se conoce con el
nombre de bucle.
Las sentencias de control son aqullas que permiten variar o alterar la secuencia
normal de ejecucin de un programa. Prcticamente la totalidad de lenguajes de
programacin de alto nivel soportan tres tipos de sentencias de control:
Instrucciones condicionales o alternativas. Controlan la ejecucin de
un grupo u otro de sentencias de un programa en funcin de que se
cumpla o no una condicin lgica previamente establecida. Tambin
conocidas como bifurcaciones.
Instrucciones de salto. Alteran o rompen la secuencia normal de
ejecucin de un programa, perdindose toda posibilidad controlada de
retornar la ejecucin del programa al punto de llamada, a no ser que se
vuelva a utilizar otra sentencia de salto.
Instrucciones repetitivas. Hacen posible que un grupo de sentencias se
ejecute ms de una vez, de forma consecutiva, hasta que se verifique
cierta condicin lgica. Tambin conocidas como bucles.
As, este captulo se ha organizado en siete secciones. Las tres primeras secciones
introducen las sentencias condicionales, de salto y repetitivas, respectivamente. Las
siguientes tres secciones hacen lo propio pero desde el punto de vista del lenguaje de
programacin C. Finalmente, la sptima y ltima seccin presenta una lista de
cuestiones y ejercicios de repaso.
190
Programacin en C
Sentencias de control
191
algoritmo sistema_dos_ecuaciones_lineales
variables
real a, b, c, d, e, f /* Coeficientes */
real x, y
/* Solucin
*/
real denominador
inicio
leer (a, b, c, d, e, f)
denominador a*e b*d
Si denominador = 0
escribir("El sistema no tiene solucin)
Si no
x (c*e b*f) / denominador
y (a*f c*d) / denominador
escribir(x, y)
FinSi
fin
192
Programacin en C
R r para resta.
P p para producto.
D d para divisin.
En funcin del tipo de operacin que se teclee se deber realizar la operacin
correspondiente. Si se recibiera un tipo de operacin distinto a los anteriores,
deber darse un mensaje de error.
algoritmo aritmtica_bsica
variables
real num1, num2, solucion
caracter operacion
inicio
leer (num1)
leer (num2)
leer (operacion)
Segn_valor operacion hacer
'S', 's':
solucion num1 + num2
escribir (solucion)
'R', 'r':
solucion num1 - num2
escribir (solucion)
'P', 'p':
solucion num1 * num2
escribir (solucion)
'D', 'd':
solucion num1 / num2
escribir (solucion)
Sino:
escribir (Tipo de operacin incorrecto)
FinSegn_valor
fin
Sentencias de control
193
algoritmo sea claro es preciso utilizar sangra en las instrucciones, de modo que se
haga coincidir en la misma columna las palabras reservadas Si, Si no y FinSi
correspondientes.
EJEMPLO
falso
verdadero
verdadero
verdadero
falso
n1 > n2
falso
Los nmeros NO
son distintos
verdadero
n1 > n3
mayor
n1
falso
n2 > n3
mayor
n3
mayor
n2
mayor
n3
El nmero
mayor es mayor
194
Programacin en C
seguir la ejecucin del mismo, pero perdiendo toda posibilidad de retornar, de forma
controlada, la ejecucin del programa al punto de llamada.
No se aconseja su uso, pues crea un cdigo difcil de leer y mantener. Su uso est
muy restringido, por no decir prohibido, en la programacin estructurada.
Su forma general es:
ir_a <etiqueta>
Donde <etiqueta> es un identificador que se utiliza para rotular la sentencia
dentro del programa a la que se transfiere el control.
La sentencia de destino debe estar precedida por este identificador:
<etiqueta:> sentencia
Las sentencias de salto pueden clasificarse de la siguiente manera:
Salto condicional. Alteran la secuencia de ejecucin de un programa
slo y exclusivamente en el caso de que una condicin especfica sea
cierta.
Salto incondicional. Alteran la secuencia de ejecucin de un programa
siempre, pues no van acompaadas de una condicin que limite en
determinadas ocasiones la realizacin del salto a otra parte del programa.
Sentencias de control
195
El cuerpo del bucle son las sentencias que se repiten. Cada repeticin del cuerpo
del bucle se denomina iteracin.
En cada iteracin se evala la expresin de control del bucle (condicin), que
determina si se contina realizando otra iteracin o bien se sale definitivamente del
bucle.
En la Figura 7.5 se presenta el esquema general de un bucle.
Se pueden distinguir tres tipos de bucles, dependiendo de que la condicin de
control del bucle se evale antes o despus de cada iteracin, y de que se pueda fijar
de antemano o no el nmero de iteraciones a realizar.
196
Programacin en C
inicio
suma 0
leer (numero)
Mientras (numero >= 0)
suma suma + numero
leer (numero)
FinMientras
escribir(suma)
fin
Sentencias de control
Ao
1
2
3
4
Pobl.inicial
100
120
144
172
Crecimiento
20
24
28
34
197
Pobl.final
120
144
172
206
198
Programacin en C
variables
entero v
v vi
Mientras v <= vf
sentencia 1
sentencia 1
...
sentencia m
v v + n
FinMientras
EJEMPLO
Sentencias de control
199
1 x 23 = 23
2 x 23 = 46
3 x 23 = 69
...
19 x 23 = 437
20 x 23 = 460
algoritmo suma_numeros2
constantes
entero N 10
variables
entero num, cuantos
entero suma 0
inicio
cuantos 0
Mientras (cuantos < N)
leer(num)
suma suma + num
cuantos cuantos + 1
FinMientras
escribir(suma)
fin
200
Programacin en C
Sentencias de control
201
EJEMPLO
Se va a escribir un algoritmo en pseudocdigo que permita calcular el valor
medio de una coleccin de nmeros enteros positivos que se introducirn por
teclado.
La introduccin de nmeros terminar cuando se teclee un nmero negativo.
Se va a utilizar un bucle mientras controlado por centinela, donde el valor
centinela ser cualquier nmero negativo.
algoritmo media_lista_enteros_positivos
variables
entero numero, cuantos 0, suma 0
real
media
inicio
leer(numero)
Mientras (numero >= 0)
cuantos cuantos + 1
suma suma + numero
leer(numero)
FinMientras
Si cuantos > 0
media suma / cuantos
Si no
media 0
FinSi
escribir (media)
fin
202
Programacin en C
Sentencias de control
203
204
Programacin en C
EJEMPLO
Realizar un algoritmo que dado un intervalo de nmeros enteros positivos determine
cuantos nmeros primos hay dentro del mismo, y cul es la suma de dichos nmeros
primos.
Anlisis: Un nmero n es primo si slo tiene como divisores a l mismo y la unidad.
Por ejemplo 1, 2, 3, 5, 7 y 11 son primos, mientras que 4, 6, 8, 9 y 10
no lo son.
Mediante un bucle externo se recorre el intervalo, determinando en cada iteracin el
nmero a investigar.
Mediante el bucle interno se va dividiendo dicho nmero por 2, 3, 4...,
terminando bien cuando alguna de estas divisiones d resto cero, en cuyo caso se
habr encontrado un divisor de dicho nmero, por lo que NO es primo, o bien cuando
se llegue a dividir el nmero n a investigar por l mismo, en cuyo caso por no haber
encontrado ningn divisor, el nmero SI es primo.
Se puede mejorar el rendimiento del algoritmo buscando divisores del nmero n slo
en el intervalo [2, n ] , pues puede demostrarse que si en ese intervalo no existen
divisores del nmero n, tampoco existirn en el intervalo [
n , n 1] .
algoritmo primos
constantes
entero LIMINF 150
entero LIMSUP 2500
variables
entero numero, divisor, cuantos 0, suma 0
real limite
lgica primo /* flag: cierto falso */
inicio
Desde numero LIMINF hasta LIMSUP con incremento 1
primo cierto
divisor 2
limite raizcuadrada(numero)
Mientras (primo and divisor <= limite)
Si (numero mod divisor) = 0
primo falso
FinSi
divisor divisor + 1
FinMientras
Si (primo)
cuantos cuantos + 1
suma suma + numero
FinSi
FinDesde
escribir (cuantos)
escribir (suma)
fin
Sentencias de control
205
206
Programacin en C
Sentencias de control
207
#include <stdio.h>
void main (void) {
float a, b, c, d, e, f; /* Coeficientes */
float x, y;
/* Solucin
*/
float denominador;
/* Presentacin
*/
printf("Resolucin del sistema de ecuaciones lineales\n");
printf("
aX + bY = c
\n");
printf("
dX + eY = f
\n");
/* Peticin de datos */
printf("\nIntroduzca los coeficientes\n");
printf("Coeficiente a?: "); scanf("%f", &a);
printf("Coeficiente b?: "); scanf("%f", &b);
printf("Coeficiente c?: "); scanf("%f", &c);
printf("Coeficiente d?: "); scanf("%f", &d);
printf("Coeficiente e?: "); scanf("%f", &e);
printf("Coeficiente f?: "); scanf("%f", &f);
/* Clculos y presentacin de resultados */
printf("\n\nEl sistema\n);
printf("
%gX + %gY = %g
\n", a, b, c);
printf("
%gX + %gY = %g
\n", d, e, f);
denominador = a*e b*d;
if (denominador == 0)
printf("\nNo tiene solucin.);
else {
x = (c*e b*f) / denominador;
y = (a*f c*d) / denominador;
printf("\nTiene por soluciones:\n);
printf("X = %g\n, x);
printf("Y = %g\n, y);
}
}
208
Programacin en C
EJEMPLO
Sentencias de control
209
210
Programacin en C
if (indicador == 0)
y = sqrt(x);
else if (indicador == 1)
y = x;
else
if ((indicador==2)||
(indicador==3))
y = 2*(x-1);
else
y = 0;
EJEMPLO
Construccin switch:
switch (opcion) {
case 'A':
case 'a':
area = b * a;
perimetro = 2*(b+a);
break;
case 'B':
case 'b':
area = 3.14159*r*r;
perimetro= 2*3.1416*r;
break;
default:
printf("No valido");
area = 0;
perimetro = 0;
}
if ((opcion == 'A') ||
(opcion == 'a'))
{ area = b * a;
perimetro = 2*(b+a);
}
else if ((opcion == 'B') ||
(opcion == 'b')) {
area = 3.14159*r*r;
perimetro= 2*3.1416*r;
}
else
{ printf("No valido");
area = 0;
perimetro = 0;
}
La expresin:
x = ( (a > b) ? a : b );
La expresin:
indicador = (i < 0) ? 0 : 100;
- 211 -
212
Programacin en C
EJEMPLO
Sea la sentencia:
eleccion ? printf("No cero.\n") : printf("Cero.\n");
Sentencias de control
213
214
Programacin en C
EJEMPLO
tiempo = 0;
while (tiempo++ < 3)
printf("Valor de tiempo = %d \n", tiempo);
EJEMPLO
El siguiente programa permite obtener la suma, la media y el nmero de
elementos que componen una coleccin de nmeros enteros positivos que se
introducirn por teclado. La introduccin de nmeros terminar cuando se
teclee un valor negativo (bucle controlado por centinela).
#include <stdio.h>
void main (void) {
int numero; /* Cada uno de los nmeros de la coleccin */
long
suma;
float
media;
unsigned int cuantos;
/* Presentacin
*/
printf("Suma de una lista de nmeros enteros positivos \n");
printf("==============================================
\n\n");
printf("Introduzca una lista de nmeros enteros positivos y
\n");
printf("el programa calcular su suma. \n");
printf("Para finalizar la introduccin de nmeros teclee
\n");
printf("cualquier valor negativo. \n\n");
/* Peticin de datos y clculos */
suma = 0;
cuantos = 0;
printf("Introduzca nmero?: ");
scanf("%d", &numero);
while (numero >= 0) {
suma += numero;
cuantos++;
printf("Introduzca nmero?: ");
scanf("%d", &numero);
}
/* Presentacin de resultados */
if (cuantos > 0) {
media = (float) suma / cuantos;
printf("\n");
Sentencias de control
215
EJEMPLO
cont++;
EJEMPLO
216
Programacin en C
#define NULO '\0'
int cont;
cont = 0;
while (mensaje[cont] != NULO) {
if (mensaje[cont] == c_ini)
mensaje[cont] = c_ult;
cont++;
}
EJEMPLO
Hay ocasiones en las que al usuario se le pide que teclee una cadena de caracteres,
y sta puede ser leda carcter a carcter, ya que en algunos casos, segn el algoritmo
a desarrollar, es ms conveniente recibir la cadena de esta forma. Para ello se utiliza
un bucle while y la funcin getchar().
EJEMPLO
Sentencias de control
217
ape1[cont] = getchar();
}
ape1[cont] = NULO;
cont = 0;
ape2[cont] = getchar();
while (ape2[cont] != FINLINEA) {
cont++;
ape2[cont] = getchar();
}
ape2[cont] = NULO;
218
Programacin en C
EJEMPLO
Sentencias de control
219
EJEMPLO
Mltiplo 100
(n%100==0)
No
Si
Si
Mltiplo 400
(n%400==0)
Si
No
Bisiesto
No
Si
Si
No
#include <stdio.h>
#include <ctype.h>
void main (void) {
int anio;
int bisiesto;
char terminar;
/* Presentacin */
printf("Aos bisiestos\n");
printf("==============\n");
printf("\nDetermina si el ao que se indica es bisiesto o no.\n\n");
do {
/* Peticin de datos.
Se repite hasta que se introduzca un ao correcto */
do {
printf("\nAo?: ");
scanf("%d", &anio);
} while (anio <= 0);
/* Clculos */
if (anio % 4)
bisiesto = 0;
else if (anio % 100)
bisiesto = 1;
else if (anio % 400)
bisiesto = 0;
else bisiesto = 1;
/* Resultados */
if (bisiesto)
printf("%d es bisiesto.", anio);
else printf("%d NO es bisiesto.", anio);
printf("\n\nTerminar (S/N)?: "); scanf("%*c%c", &terminar);
} while (toupper(terminar) != 'S');
}
EJEMPLO
220
Programacin en C
En el lenguaje C, el bucle for ofrece una gran potencia y una enorme flexibilidad,
pues su formato no es tan rgido como el que, de forma genrica, se ha descrito
anteriormente para el bucle desde, comn a la mayora de los lenguajes de
programacin de alto nivel.
Sentencias de control
221
222
Programacin en C
2.
3.
tiempo <=3
tiempo++
El siguiente bucle admite una cadena por teclado y muestra por pantalla los
caracteres que la constituyen junto con su correspondiente cdigo ASCII.
for (; (valor = getchar() ) != '\n';) printf("%c - %d\n", valor, valor);
La salida sera:
A - 65
B - 66
C - 67
EJEMPLO
2
5
8
11
14
Sentencias de control
223
Salida en pantalla:
00:00
00:01
00:02
...
00:58
00:59
01:00
01:01
...
01:58
01:59
02:00
02:01
...
23:57
23:58
23:59
Se imprimen 24 x 60 = 1440.
EJEMPLO
224
Programacin en C
#include <stdio.h>
void main(void) {
char linterior, lexterior;
for (lexterior= 'Z'; lexterior >='A'; lexterior--) {
for (linterior=lexterior; linterior >='A'; linterior--)
printf("%c", linterior);
printf("\n");
}
}
EJEMPLO
Sentencias de control
225
int i, j, k, b;
for (i=0; i <= 9; i++) {
for (b=1; b <= 9-i; b++)
printf("%c", BLANCO);
for (k=i; k >= 1; k--)
printf("%d", k);
for (j=0; j <= i; j++)
printf("%d", j);
printf ("\n");
}
for (i=8; i >= 0; i--) {
for (b=1; b <= 9-i; b++)
printf("%c", BLANCO);
for (k=i; k >= 1; k--)
printf("%d", k);
for (j=0; j <= i; j++)
printf("%d", j);
printf ("\n");
}
}
/*bucle 1*/
/*bucle 2*/
/*bucle 3*/
/*bucle 4*/
/*bucle 5*/
/*bucle 6*/
EJEMPLO
226
Programacin en C
externo,
Salida en pantalla:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
0,
0,
0,
1,
1,
1,
2,
2,
2,
3,
3,
3,
4,
4,
4,
5,
5,
5,
6,
6,
6,
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
3
4
5
3
4
5
3
4
5
3
4
5
3
4
5
3
4
5
3
4
5
Sentencias de control
227
EJEMPLO
Salida en pantalla:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
externo:
1,
1,
1,
3,
3,
3,
5,
5,
5,
7,
7,
7,
9,
9,
9,
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
interno:
3
4
5
3
4
5
3
4
5
3
4
5
3
4
5
3.
228
4.
5.
6.
Programacin en C
c) x diferente a z.
d) x menor o igual a 0.
e) y igual a 0.
f) x deber ser mayor que z o menor que 0 y, adems, distinto de y.
g) a distinto de b y distinto de c, y b tambin distinto de c.
h) a distinto de 10 o distinto de 24.
i) z debe estar comprendido entre -5 y 15.
j) y no puede estar comprendido entre 5 y 25.
k) a, b y c deben tener el mismo valor.
Construir en C una sentencia if que imprima en pantalla el mensaje ES
UNA MAYUSCULA, si el valor del carcter letra es una letra mayscula;
imprima el mensaje ES UNA MINUSCULA si el valor del carcter letra
es una letra minscula, y el mensaje NO ES UNA LETRA si el valor del
carcter letra no es una letra. (Atencin con la letra , la letra , y las
vocales acentuadas. Comprobar en la tabla ASCII en qu posicin est).
La Sentencia switch:
Cul es su propsito?
Entre cuntas bifurcaciones de cdigo permite escoger como mximo?
El siguiente fragmento de cdigo escrito en C visualiza por pantalla todos los
mltiplos de 13 comprendidos entre 13 y 10000 (ambos lmites incluidos).
Se ha utilizado una estructura while para realizar el bucle. Realizar el
mismo algoritmo utilizando una estructura do-while y una estructura for.
multiplo = 13;
while (multiplo <= 10000) {
printf("%d", multiplo);
multiplo = multiplo + 13;
}
7.
8.
9.
Sentencias de control
for
for
for
for
for
for
for
10.
Indicar cuntas veces se ejecutarn los siguientes bucles. Dibujar cul ser el
resultado de su ejecucin en pantalla.
a) i = 1;
while (i < 10) {
i++;
printf("%d", i);
printf("*");
}
c) i = 1;
do {
printf("%d", i);
i = i * 2;
printf("*\n");
} while (i > 0);
11.
229
b) i = 10;
do {
printf("%d\n", i);
i += 3;
printf("*");
} while (i != 20);
d) for(i = -1; i >= -20; i--) {
x = 0;
while (x < 10) {
printf("%d", x);
x = x + 2;
}
}
e) i= 0;
j= 2;
printf("j
i\n");
for(i = 1; i <= 3; i++) {
printf("-\n");
for(j = 12; j >= 10, j--)
printf("%d %d\n", j, i);
}
230
12.
Programacin en C
13.
14.
15.
16.
17.
18.
Sentencias de control
19.
231
20.
21.
22.
23.
24.
232
25.
26.
27.
28.
29.
Programacin en C
30.
31.
(num) {
2:
3:
5:
7: printf("Nmero primo entre 1 y 10.");
break;
case 11:
case 13:
case 17:
case 19: printf("Nmero primo entre 11 y 20.");
break;
case 23:
case 29: printf("Nmero primo entre 21 y 30.");
break;
default: printf("El nmero no est entre los primeros primos.");
}
32.
33.
234
Programacin en C
Se llama ndices de la matriz a cada uno de los valores numricos enteros a travs
de los cuales se puede acceder directa e individualmente a los elementos de una
matriz. Cada uno de estos ndices marca la situacin relativa de cada elemento dentro
de la matriz. Debe ser expresado mediante una constante, una variable o una
expresin de tipo entero.
La dimensin de la matriz viene determinada por el nmero de ndices que son
necesarios para acceder a cualquiera de sus elementos, tal y como se muestra en la
Tabla 8.1.
Nmero
de ndices
1
2
3
4 o ms
Denominacin
Llamada tambin
Matriz unidimensional
Vector o lista esttica
Matriz bidimensional
Tabla
Matriz tridimensional
Cubo
Matriz multidimensional
Tabla 8.1. Dimensiones de una matriz
7
x(2)
11
x(3)
23
x(n-1)
31
x(n)
Apunte de C
7
x[1]
11
x[2]
23
x[n-2]
31
x[n-1]
235
Filas
1
2
3
m-1
y(i,j)
n-1
n
Apunte de C
Filas
0
1
2
m-2
m-1
y[i][j]
n-2
n-1
236
Programacin en C
EJEMPLOS
x(2)
x(3)
x(4)
x(5)
x(6)
x(7)
x(8)
x(9)
x(10)
1
2
3
4
5
6
8.2.1. Definicin
Se debe indicar el tipo base de los elementos de la matriz y su tamao.
Suponiendo que se necesita un byte para almacenar una variable de tipo carcter, dos bytes
para un entero, cuatro bytes para variables de tipo real y ocho bytes para el real doble.
237
EJEMPLOS
num(1)
num(5)
num(6)
1
2
3
tbl(2,3)
1
1.1
21
31.2
2
1.2
22
32
3
1.3
23
33
238
Programacin en C
dispositivo de salida), normalmente no puede hacerse en una nica sentencia, sino que
deber realizarse individualmente sobre los elementos de la misma, recorriendo toda
la matriz.
Estas operaciones de recorrido de la matriz se realizan utilizando estructuras
repetitivas, cuyas variables de control (por ejemplo i, f, c), se utilizarn como
subndices de la matriz (por ejemplo num(i) o tbl(f,c) en los ejemplos
anteriores). El incremento de la variable de control del bucle producir el tratamiento
sucesivo de los elementos de la matriz.
Debern utilizarse tantas estructuras repetitivas anidadas como ndices tenga la
matriz (una para vectores y dos para tablas).
EJEMPLOS
Se utilizarn las definiciones del vector num y la tabla tbl de los ejemplos
anteriores.
Vectores
Recorrido ascendente de los elementos de un vector para lectura.
Se recorre el vector desde el elemento de ndice menor hasta el de ndice
mayor.
Bucle Desde
Bucle Mientras
i1
Mientras i<=6
leer(num(i))
ii+1
FinMientras
i1
Repetir
leer(num(i))
ii+1
Mientras i<=6
Bucle Mientras
i1
Mientras i<=6
num(i)(2*i)-1
ii+1
FinMientras
i1
Repetir
num(i)(2*i)-1
ii+1
Mientras i<=6
Bucle Mientras
i6
Mientras i>=1
escribir(num(i))
ii-1
FinMientras
i6
Repetir
escribir(num(i))
ii-1
Mientras i>=1
Tablas
Recorrido por filas de los elementos de una tabla para lectura.
239
Bucles Mientras
f1
f1
Mientras f<=3
Repetir
c1
c1
Mientras c<=4
Repetir
leer(tbl(f,c))
leer(tbl(f,c))
cc+1
cc+1
FinMientras
Mientras c<=4
ff+1
ff+1
FinMientras
Mientras f<=3
Bucles Mientras
Bucles Repetir
Mientras
c1
Mientras c<=4
f1
Mientras f<=3
escribir(tbl(f,c))
ff+1
FinMientras
escribir(lf)
cc+1
FinMientras
c1
Repetir
f1
Repetir
escribir(tbl(f,c))
ff+1
Mientras f<=3
escribir(lf)
cc+1
Mientras c<=4
240
Programacin en C
12
x0
15
23
x1
x2
-7
x3
9
x[4]
x4
x[3]
Primer elemento
del vector
ltimo elemento
del vector
x[2]
x[1]
x[0]
Direcciones
FFF5
FFF4
FFF3
FFF2
FFF1
FFF0
FFEF
FFEE
FFED
FFEC
9
-7
23
15
12
nombre_vector tamao ;
El valor del ndice para acceso a los elementos del vector x ir de 0 a 99, y
para acceso a los elementos del vector val_medios ir de 0 a 24:
x0
primer elemento
x1
segundo elemento
...
x 98 penltimo elemento
x 99 ltimo elemento
val_medios 0
val_medios 1
primer elemento
segundo elemento
...
val_medios 23
penltimo elemento
val_medios 24
ltimo elemento
241
EJEMPLOS
int vt 5 = {1, 3, 45, 34, 211, 79};
Incorrecto. Se especifican ms valores para iniciacin que el tamao del vector.
int vt 5 = {1, 3, 45};
Correcto. Los elementos vt 3 y vt 4 se inician a 0.
int vt 5 ;
Correcto, pero no se inician a ningn valor los elementos del vector.
char letras 5 = {'A', 'B', 'C'};
Correcto. Los elementos letras 3 y letras 4 se inician a valor ASCII 0 ('\0').
EJEMPLOS
letras 4
pal 5
pal2 5
pal3 5
=
=
=
=
242
Programacin en C
/*Asignacin directa*/
/*Lectura de teclado*/
EJEMPLO
#define DIM 7
...
int vector DIM ;
int i;
/*
/*
/*
/*
Nmeros a introducir
Media aritmtica a calcular
Nmero que se lee de teclado
Contador para for
*/
*/
*/
*/
243
EJEMPLO
desviacini
nmeroi
media
diml
DIM
[DIM-2]
[DIM-1]
en
244
Programacin en C
do {
printf("Nmeros a introducir (mx.%d)?: ", DIM);
scanf("%d", &diml);
} while ((diml <=0) || (diml > DIM));
/* Se carga el vector de nmeros y calculamos la media */
media = 0;
printf("\n");
for (j = 0; j < diml; j++) {
printf("Nmero %d?: ", j+1);
scanf("%f", &vx[j]);
media = media + vx[j];
}
media = media / diml;
printf("\n");
printf("Media: %g\n", media);
/* Se calcula y se muestra la desviacin de cada nmero respecto
de la media */
printf("Nmero
Valor Desviacin\n");
printf("------ -------- ----------\n");
for (j = 0; j < diml; j++)
printf("%5d %9.3f %9.3f\n", j+1, vx[j], vx[j]-media);
Ejemplo de ejecucin
Nmeros a introducir (mx.100)?: 6
Nmero
Nmero
Nmero
Nmero
Nmero
Nmero
1?:
2?:
3?:
4?:
5?:
6?:
34.56
-12.3
56
4
0.89
5.66
Media: 14.8017
Nmero
Valor Desviacin
------ -------- ---------1
34.560
19.758
2
-12.300
-27.102
3
56.000
41.198
4
4.000
-10.802
5
0.890
-13.912
6
5.660
-9.142
EJEMPLO
Ejemplo de ejecucin
Nmeros a
Nmero 1?:
Nmero 2?:
Nmero 3?:
Nmero 4?:
Nmero 5?:
Nmero 6?:
introducir (mx.100)?: 6
12.5
8.45
15.8
4
15.8
5.66
245
246
Programacin en C
Mximo
15.8 (veces repetido 2)
Mnimo
4 (veces repetido 1)
Nmero
Valor Dif.maximo Dif.mnimo
------ -------- ---------- ---------1
12.500
3.300
8.500
2
8.450
7.350
4.450
3
15.800
0.000
11.800
4
4.000
11.800
0.000
5
15.800
0.000
11.800
6
5.660
10.140
1.660
EJEMPLO
vx DIM ;
diml;
j, k;
repetido;
100
1
0
247
Columnas
tb[3][2]
Filas
[1]
[2]
10
11
12
20
21
22
30
31
32
tb[3][1]
tb[3][0]
tb[2][2]
tb[2][1]
Direcciones
FFF5
FFF4
FFF3
FFF2
FFF1
FFF0
FFEF
FFEE
FFED
FFEC
32
31
fila 3
30
22
21
...
...
10
tb[1][0]
FFE5
FFE4
tb[0][2]
FFE3
FFE2
FFE1
FFE0
tb[0][1]
tb[0][0]
FFDF
FFDE
fila 2
fila 1
Direcciones
de memoria
crecientes
fila 0
Donde:
248
Programacin en C
La carga de datos en una tabla puede hacerse por iniciacin o por asignacin
En la iniciacin se asignan los valores en la declaracin de la tabla, de acuerdo a la
siguiente sintaxis:
tipo_bsico
tb
0
1
2
0
63
10
454
1
t 56
b 7
231
2
21
3
4
3
3
9
8
4
5
1
6
tnum
0
1
2
3
0
3.2
1
5.9
9
1
0.5
3
7
8
249
EJEMPLOS
int tb1 2 3 = {1, 3, 45, 34, 2, -11, 79};
Incorrecto. Se especifican ms valores para iniciacin que el tamao de la tabla.
int tb2 2 4 = {1, 3, 45, 6, 12, -2};
Correcto. Los elementos tb 1 2 y tb 1 3 se inician a 0.
int tb3 3 6 ;
Correcto, pero no se inician a ningn valor los elementos de la tabla.
3
5
Para declarar e iniciar una tabla de cadenas de caracteres, se puede realizar como
se muestra en el siguiente ejemplo.
EJEMPLO
char nombres 4 7 = {"JUAN", "PEDRO", "PEPE", "DAVID"};
O bien:
0
1
2
3
char nombres
0
1
J
U
P
E
P
E
D
A
7 = {"JUAN",
2
A
D
P
V
"PEDRO",
3
N
R
E
I
"PEPE", "DAVID"};
4
5
6
\0
O
\0
\0
D
\0
Donde:
nombres 3 2
es el carcter 'V'
Pero la tabla puede ser tratada como un vector de cadenas de caracteres,
utilizando nicamente el primer ndice de la misma.
nombres 3
es la cadena "DAVID"
250
Programacin en C
Para cargar de valores una tabla mediante asignacin, se asigna un valor de manera
individual a cada elemento de la tabla.
Normalmente, para cargar una tabla en tiempo de ejecucin se recorre sta
secuencialmente, desde el primer elemento hasta el ltimo, asignando a cada elemento
un valor determinado.
EJEMPLO
#define FILAS
3
#define COLUMNAS 4
...
int matriz_a FILAS COLUMNAS ;
...
matriz_a 2 3 = -14;
Asignacin directa
scanf("%d", &matriz_a 2 2 ); Lectura de teclado
EJEMPLO
EJEMPLO
Matriz a introducir
1
69
93
115
304
615
1001
7
70
95
123
405
617
1205
9
73
99
156
408
709
1300
25
81
101
198
459
800
1525
Elemento
Elemento
Elemento
Elemento
Elemento
Elemento
Elemento
Elemento
...
Elemento
Elemento
Elemento
34
90
112
203
512
909
1709
Almacenamiento en memoria
c
1
69
93
115
304
615
1001
7
70
95
123
405
617
1205
9
73
99
156
408
709
1300
25
81
101
198
459
800
1525
34
90
112
203
512
909
1709
c
f
Almacenamiento en memoria
1
69
93
115
304
615
1001
7
70
95
123
405
617
1205
9
73
99
156
408
709
1300
25
81
101
198
459
800
1525
34
90
112
203
512
909
1709
1,1:
1,2:
1,3:
1,4:
1,5:
2,1:
2,2:
2,3:
1
7
9
25
34
69
70
73
7,3: 1300
7,4: 1525
7,5: 1709
251
252
Programacin en C
Presentacin en pantalla
1
7
9
25
34
69
70
73
81
90
93
95
99
101
112
115
123
156
198
203
304
405
408
459
512
615
617
709
800
909
1001
1205
1300
1525
1709
EJEMPLO
Realizar un programa que pida por pantalla una matriz de nmeros enteros
de 5 filas por 3 columnas. Debe presentarse posteriormente en la pantalla la
suma de cada fila, el mximo de cada columna y la matriz traspuesta a la
introducida.
Esquema del programa
#define FILAS
5
#define COLUMNAS 3
int mx FILAS COLUMNAS ; /* Matriz de nmeros enteros */
float lsum FILAS ;
/* Vector suma de cada fila */
int lmax COLUMNAS ;
/* Vector mximo de cada columna */
int f, c;
/* ndices para recorrido matriz */
lsum
FILAS
COLUMNAS
lmax
/* Se introduce desde teclado la matriz por filas */
for (f = 0; f < FILAS; f++)
for (c = 0; c < COLUMNAS; c++) {
printf("Elemento (%d,%d)?: ", f+1, c+1);
scanf("%d", &mx[f][c]);
}
/* Se calcula la suma de cada fila */
for (f = 0; f < FILAS; f++) {
lsum[f] = 0;
for (c = 0; c < COLUMNAS; c++)
lsum[f] = lsum[f] + mx[f][c];
}
/* Se calcula el mximo de cada columna */
for (c = 0; c < COLUMNAS; c++) {
lmax[c] = mx[0][c];
for (f = 1; f < FILAS; f++)
if (mx[f][c] > lmax[c])
lmax[c] = mx[f][c];
}
/* Se presenta la matriz introducida y la suma de cada fila */
printf("\nMatriz introducida: \n");
for (f = 0; f < FILAS; f++) {
for (c = 0; c < COLUMNAS; c++)
printf("%8d", mx[f][c]);
253
printf("
Suma fila %d: ", f+1);
printf("%8g\n", lsum[f]);
}
/* Se presenta el mximo de cada columna */
printf("\nMximo de cada columna: \n");
for (c = 0; c < COLUMNAS; c++)
printf("%8d", lmax[c]);
/* Se presenta la tabla traspuesta */
printf("\nMatriz traspuesta: \n");
for (c = 0; c < COLUMNAS; c++) {
for (f = 0; f < FILAS; f++)
printf("%8d", mx[f][c]);
printf("\n");
}
(1,1)?:
(1,2)?:
(1,3)?:
(2,1)?:
(2,2)?:
(2,3)?:
(3,1)?:
(3,2)?:
(3,3)?:
(4,1)?:
(4,2)?:
(4,3)?:
(5,1)?:
(5,2)?:
(5,3)?:
2
5
7
51
4
7
8
69
50
45
3
95
14
5
96
Matriz introducida:
2
5
51
4
8
69
45
3
14
5
7
7
50
95
96
Suma
Suma
Suma
Suma
Suma
fila
fila
fila
fila
fila
1:
2:
3:
4:
5:
14
62
127
143
115
8
69
50
45
3
95
14
5
96
EJEMPLO
Realizar un programa que permita introducir por pantalla una matriz cuadrada de
nmeros enteros. Posteriormente se presentar su traza y se indicar si la matriz
introducida es simtrica. El programa deber permitir trabajar con matrices de hasta
10 x 10 elementos.
Se recuerda que:
La traza de una matriz cuadrada es la suma de los elementos de su
diagonal principal.
La diagonal principal de una matriz cuadrada la forman todos los
elementos aij donde i=j
254
Programacin en C
=
=
tb
col
fil
FILAS
255
/* La matriz es cuadrada */
col = fil;
/* Se introduce desde teclado la matriz por filas */
for (f = 0; f < fil; f++)
for (c = 0; c < col; c++) {
printf("Elemento (%d,%d)?: ", f+1, c+1);
scanf("%d", &tb[f][c]);
}
/* Se calcula la traza de la matriz */
traza = 0;
for (f = 0; f < fil; f++)
traza = traza + tb[f][f];
/* Se comprueba si la matriz es simtrica...
*/
/* ----- con bucle for ------------------------- */
simetrica = CIERTO;
for (f = 0; f < fil; f++)
for (c = 0; c < col; c++)
if (tb[f][c] != tb[c][f])
simetrica = FALSO;
printf("\nLa traza vale %ld\n", traza);
if (simetrica)
printf("La matriz es simtrica\n");
else
printf("La matriz NO es simtrica\n");
Ejemplo de ejecucin
-18
2
3
4
2
1
5
7
3
5
24
3
4
7
3
-9
Tabla tb
256
Programacin en C
Nmero de filas
Elemento (1,1)?:
Elemento (1,2)?:
Elemento (1,3)?:
Elemento (1,4)?:
Elemento (2,1)?:
Elemento (2,2)?:
Elemento (2,3)?:
Elemento (2,4)?:
Elemento (3,1)?:
Elemento (3,2)?:
Elemento (3,3)?:
Elemento (3,4)?:
Elemento (4,1)?:
Elemento (4,2)?:
Elemento (4,3)?:
Elemento (4,4)?:
de la matriz (max.10)?: 4
-18
2
3
4
2
1
5
7
3
5
24
3
4
7
3
-9
La traza vale 2
La matriz es simtrica
EJEMPLO
Realizar un programa que multiplique dos matrices de nmeros reales.
Deber permitirse trabajar con matrices de hasta 25 x 25 elementos.
Se recuerda que:
Para que dos matrices puedan multiplicarse se exige que el nmero
de columnas de la primera coincida con el nmero de filas de la
segunda.
La matriz producto tendr tantas filas como la primera y tantas
columnas como la segunda.
a11 a12 a13
p11 p12 p13 p14 p15
b11 b12 b13 b14 b15
a21 a22 a23
p21 p22 p23 p24 p25
b21 b22 b23 b24 b25
a31 a32 a33
p31 p32 p33 p34 p35
b31 b32 b33 b34 b35
a41 a42 a43
p41 p42 p43 p44 p45
Matriz A (4f x 3c)
Donde:
a41b15
a42b25
a43b35
pij
ai1b1 j
ai 2b2 j
ai 3b3 j
Es decir:
ainbnj
257
258
Programacin en C
printf("%8.2f", tbp[f][c]);
printf("\n");
2.
Responde a las siguientes cuestiones, pero antes recuerda que en una matriz
sus elementos individuales se comportan como variables del tipo base de la
matriz.
En un vector de N elementos, cul es el ndice del primer elemento? Y
el del ltimo elemento?
Cmo se declarara un vector de enteros llamado vector1, para
almacenar 100 enteros?
Qu hace la siguiente sentencia: vector1[3] = 27;?
Cmo se almacenara en la primera posicin del vector el valor -15?
Cmo se almacenara en la ltima posicin del vector el valor 54?
Qu
hace
la
siguiente
sentencia:
scanf("%d",
&vector1[75]);?
Cmo se mostrara en pantalla el valor contenido en la quinta posicin
del vector?
Indicar qu hacen las siguientes sentencias:
- int edades[20];
- float notas[100];
- char nombre[26];
3.
4.
5.
6.
7.
scanf("%d", &edades[2]);
notas[99] = 7.5;
printf(nombre);
printf("%c", nombre[0]);
8.
9.
10.
11.
12.
13.
14.
15.
16.
259
float
char
int
long
double
valores[100 ;
lista[21 ;
vector[10 ;
v3[200 ;
lista77[200 ;
260
17.
Programacin en C
9. Punteros
Los punteros son variables que contienen una direccin de memoria que,
normalmente, representa la posicin de otra variable en memoria. La correcta
comprensin y uso de los punteros en C es fundamental para obtener los mximos
beneficios en este lenguaje, especialmente por el uso que se hace de ellos, por
ejemplo, para el paso de argumentos por referencia en una funcin, para la asignacin
dinmica de memoria o para el soporte de estructuras de datos avanzadas.
No obstante, y aunque los punteros son una de las herramientas de programacin
ms poderosas del lenguaje C, los punteros son una caracterstica peligrosa que
pueden provocar fallos diversos en el sistema, fallos que pueden ser muy difciles de
localizar.
En este captulo se van a estudiar los fundamentos de los punteros, para lo cual ste
se ha divido en cinco secciones. La primera explica cmo se almacenan las variables
en la memoria de un ordenador, introduciendo el concepto de direccin de memoria.
La segunda seccin introduce los punteros desde un punto de vista general, mientras
que la seccin tercera lo hace desde el punto particular del lenguaje C. La cuarta
seccin explica la estrecha relacin que existe entre los punteros y las matrices en el
lenguaje C. Finalmente, la quinta seccin presenta una lista de cuestiones y ejercicios
de repaso.
c
i
f
d
'q'
2581
123.456
1.56
- 261 -
262
Programacin en C
tamao
direccin
comienzo
1 byte
FFF4
2 bytes
FFF2
q
2581
Direcciones
de memoria
crecientes
123.456
f
4 bytes
FFEE
1.56
8 bytes
FFE6
Suponiendo que el compilador necesita un byte para almacenar una variable de tipo carcter,
dos bytes para un entero, cuatro bytes para variables de tipo real y ocho bytes para el real doble.
Esta suposicin se realizar para todos los ejemplos planteados en pseudocdigo en este
captulo.
Punteros
263
Nombre
variable
punt
Direccin
comienzo
FFE6
FFF4
Asignacin de valores
f 123.456
punt direccin(f)
Direcciones
de memoria
crecientes
123.4
f
FFE6
56
9.2. Punteros
Un puntero es un tipo de dato soportado por la mayora de los lenguajes de
programacin. Las variables declaradas de tipo puntero se utilizan para contener la
direccin de comienzo en memoria de otra variable.
Como los punteros son a su vez variables, estn almacenados en algn lugar de la memoria y
tienen su propia direccin.
264
Programacin en C
nombre_puntero
NULO
Suponiendo que el compilador necesita dos bytes para almacenar una variable de tipo entero,
una variable puntero ocupar dos bytes en memoria, independientemente del tipo de variable a
la que apunte.
4 Los literales y las expresiones no tienen direccin, por lo que no se les puede aplicar el
operador direccin. Tampoco puede modificarse la direccin de una variable.
Punteros
265
EJEMPLO
/* -- Declaracin de variables -- */
puntero a entero pntc
puntero a real pntr
...
real nreal
entero cant
...
cant 15 /* Se asigna a cant un valor */
pntc direccin(cant) /* El puntero pntc apunta a la variable cant */
...
nreal 166.176
/* Se asigna a nreal un valor */
pntr direccin(nreal) /* El puntero pntr apunta a la variable nreal */
nombre
variable
direccin
comienzo
pntc
FFF4
pntr
FFF2
FFAA
FFAC
Direcciones de
memoria
crecientes
166.176
nreal
FFAC
cant
FFAA
15
9.2.3.2. Indireccin
Se entiende por indireccin la forma de referenciar el valor de una variable a travs de
un puntero que apunta a dicha variable. Para realizar la indireccin se utiliza el
operador indireccin, que permite acceder a la variable cuya direccin est contenida
en dicho puntero.
El operador indireccin suele representarse en pseudocdigo como
nombre_puntero.
Con el nombre de la variable puntero (nombre_puntero), se accede a la
direccin de comienzo de la variable referenciada o apuntada. Mientras que con el
nombre del puntero, aplicando el operador indireccin (nombre_puntero), se
accede al valor de la variable referenciada o apuntada por el puntero.
EJEMPLO
/* -- Declaraciones -- */
entero a 40, b 0
puntero a entero pnum
...
266
Programacin en C
Nombre
variable
Direccin
comienzo
Direcciones de
memoria
crecientes
40
a
FFDA
FFD8
pnum
FFEC
FFDA
pnum direccin(a)
escribir("a = ", a, " b = ", b )
escribir("La variable apuntada por pnum contiene ", pnum)
Salida en pantalla:
a = 40 b = 0
La variable apuntada por pnum contiene 40
Nombre
variable
Direccin
comienzo
FFDA
FFD8
pnum
FFEC
Direcciones
de memoria
crecientes
pnum 145
145
0
FFDA
Punteros
Nombre
variable
Direccin
comienzo
FFDA
267
b pnum
FFD8
pnum
FFEC
145
Direcciones de
memoria
crecientes
145
FFDA
EJEMPLO
/* -- Declaraciones -- */
Nombre
entero a 5, b, c
variable
...
puntero a entero pt1 direccin(a)
/* pt1 apunta a la variable a */
puntero a entero pt2 NULO
a
/* pt2 no apunta a ninguna variable */
Direccin
comienzo
FFEA
FFE8
FFE6
pt1
FFBC
pt2
FFBA
FFEA
NULO
Direcciones de
memoria
crecientes
268
Programacin en C
pt2 pt1
/*pt2 se carga con la direccin de memoria contenida en pt1
pt2 y pt1 apuntan a la variable a */
b pt1
c pt2
Nombre
variable
Direccin
comienzo
FFEA
FFE8
FFE6
pt1
FFBC
pt2
FFBA
5
5
5
FFEA
FFEA
Direcciones de
memoria
crecientes
Nombre
variable
Direccin
comienzo
FFEA
FFE8
pt1
FFB4
pt2
FFB2
pt3
FFB0
5
7
FFE8
FFEA
FFEA
Direcciones de
memoria
crecientes
Punteros
269
9.3. Punteros en C
Los punteros tienen tres usos fundamentales en C: soporte para uno de los
mecanismos de comunicacin con las funciones; capacidad de sustitucin de las
matrices; y soporte para las rutinas de asignacin dinmica de memoria.
*apunt = NULL;
*pnum = NULL;
*cad = NULL;
270
Programacin en C
2.
Punteros
printf("Variable
printf("-------printf("nreal
printf("nume
printf("ptint
printf("pt
Direccin
-----------%p (%u)
%p (%u)
%p (%u)
%p (%u)
Salida en pantalla:
MAPA DE MEMORIA
Variable
-------nreal
nume
ptint
pt
Direccin
-----------FFF2 (65522)
FFF0 (65520)
FFEE (65518)
FFEC (65516)
Valor\n");
--------\n");
%g\n", &nreal, &nreal, nreal);
%d\n", &nume, &nume, nume);
%p\n", &ptint, &ptint, ptint);
%p\n", &pt, &pt, pt);
Nombre
variable
Valor
------166.386
2581
FFF0
FFF2
271
Direccin
comienzo
166.386
nreal
FFF2
nume
FFF0
ptint
FFEE
pt
FFEC
2581
FFF0
FFF2
Direcciones de
memoria
crecientes
9.3.3.2. Indireccin
Se entiende por indireccin la forma de referenciar el valor de una variable a travs de
un puntero que apunta a dicha variable. Para realizar la indireccin se utiliza el
operador monario asterisco (*) que cuando precede al nombre del puntero
correspondiente permite acceder a la variable cuya direccin est contenida en dicho
puntero.
EJEMPLO
/* -- Declaraciones -- */
int a = 40;
Nombre
variable
int b = 0;
...
int *pnum;
...
Direccin
comienzo
FFDA
40
FFD8
pnum
FFEC
Direcciones de
memoria
crecientes
FFDA
pnum = &a;
printf("a = %d ", a);
printf("b = %d\n", b);
printf("La variable apuntada por pnum contiene %d\n", *pnum);
Salida en pantalla:
a = 40
b = 0
La variable apuntada por pnum contiene 40
272
Programacin en C
*pnum = 145;
Nombre
variable
Direccin
comienzo
FFDA
145
FFD8
pnum
FFEC
Direcciones de
memoria
crecientes
FFDA
Nombre
variable
Direccin
comienzo
FFDA
145
FFD8
145
pnum
FFEC
Direcciones de
memoria
crecientes
FFDA
Se vuelve a recalcar el hecho de que los punteros nunca deben dejarse sin iniciar,
para lo cual se presentar el siguiente contraejemplo.
CONTRAEJEMPLO
int *ptr;
*ptr = 10;
Punteros
273
Direccin
comienzo
FFEA
FFE8
FFE6
pt1
FFBC
pt2
FFBA
*/
*/
FFEA
NULL
Direcciones de
memoria
crecientes
pt2 = pt1;
/*pt2 se carga con la direccin de memoria contenida en pt1 */
/*pt2 y pt1 apuntan a la variable a */
b = *pt1;
/*se carga en b el valor de la variable apuntada por pt1 (variable a) */
c = *pt2;
/*se carga en c el valor de la variable apuntada por pt2 (variable a) */
Nombre
variable
Direccin
comienzo
FFEA
FFE8
FFE6
pt1
FFBC
pt2
FFBA
5
5
5
FFEA
FFEA
Direcciones de
memoria
crecientes
274
Programacin en C
Nombre
variable
Direccin
comienzo
FFEA
FFE8
pt1
FFB4
pt2
FFB2
pt3
FFB0
FFE8
Direcciones de
memoria
crecientes
FFEA
FFEA
Tambin es posible utilizar los operadores relacionales >, >=, <, <= con dos
punteros para comparar las posiciones relativas en memoria que ocupan las variables
apuntadas por ellos.
EJEMPLO
Punteros
275
*pte);
*pte);
*pte);
Nombre
variable
Direccin
comienzo
a[3]
FFEA
a[2]
FFE8
a[1]
FFE6
a[0]
FFE4
1
10
100
1000
*pte);
pte
FFBA
FFE4
Direcciones de
memoria
crecientes
Salida en pantalla:
*pte:
*pte:
*pte:
*pte:
1000
100
1
1000
char cd[4]={'D','C','B','A'};
...
char *ptc = &cd[3];
int i;
for (i = 1; i <= 4; i++) {
printf("%c\n", *ptc);
ptc--;
}
/* O bien */
for (i = 1; i <= 4; i++)
printf("%c\n", *ptc--);
Nombre
variable
Direcciones de
memoria
crecientes
Direccin
comienzo
cd[3]
cd[2]
cd[1]
cd[0]
FFD5
FFD4
FFD3
FFD2
A
B
C
D
ptc
FFB2
FFD5
Salida en pantalla:
A
B
C
D
Debe prestarse especial atencin a la combinacin de los operadores *, ++ y -sobre el mismo puntero. Todos ellos tienen la misma prioridad y su asociatividad es
de derecha a izquierda, por tanto:
276
Programacin en C
*++apunt
++*apunt
*apunt++
*(apunt++)
(*apunt)++
EJEMPLO
int a[4]={1000,100,10,1};
...
int *pte = &a[0];
Nombre
variable
Direccin
comienzo
a[3]
FFEA
a[2]
FFE8
a[1]
FFE6
a[0]
FFE4
pte
FFBA
1
10
100
1000
Direcciones
de memoria
crecientes
FFE4
Salida en pantalla:
Valor: 100
Nombre
variable
Direccin
comienzo
a[3]
FFEA
Primero se incrementa la
direccin contenida en pte y
posteriormente se obtiene el
valor apuntado por la nueva
direccin de pte.
a[2]
FFE8
a[1]
FFE6
a[0]
FFE4
pte
FFBA
1
10
100
1000
Direcciones
de memoria
crecientes
FFE6
++*pte;
Se incrementa la variable
apuntada por pte.
Nombre
variable
Direccin
comienzo
a[3]
FFEA
a[2]
FFE8
a[1]
FFE6
a[0]
FFE4
pte
FFBA
1
10
101
1000
FFE6
Direcciones
de memoria
crecientes
Punteros
Salida en pantalla:
Nombre
variable
Direccin
comienzo
a[3]
FFEA
a[2]
FFE8
a[1]
FFE6
277
Valor: 101
(*pte)++;
Se incrementa el valor
apuntado por pte.
a[0]
FFE4
pte
FFBA
Nombre
variable
Direccin
comienzo
a[3]
FFEA
a[2]
FFE8
a[1]
FFE6
a[0]
FFE4
pte
FFBA
1
10
101
1000
Direcciones
de memoria
crecientes
FFE8
1
11
101
1000
Direcciones
de memoria
crecientes
FFE8
278
Programacin en C
Direccin
comienzo
lista
FFEE
Son equivalentes...
lista[3]
FFF4
lista[2]
FFF2
lista[1]
lista[0]
FFF0
FFEE
1
10
100
1000
Direcciones
de memoria
crecientes
lista[3]
*(lista+3)
lista[2]
*(lista+2)
lista[1]
*(lista+1)
lista[0]
*lista
Punteros
Son equivalentes...
lista[0] *lista
lista[1] *(lista+1)
lista[2] *(lista+2)
lista[3] *(lista+3)
Valor
1000
100
10
1
Son equivalentes...
&lista[0] lista
&lista[1] lista+1
&lista[2] lista+2
&lista[3] lista+3
279
Valor
FFEE
FFF0
FFF2
FFF4
Copia de vectores.
#define DIM 120
int vector1[DIM], i, vector2[DIM];
for (i=0; i<DIM; i++)
/* Se inicia el vector1 */
vector1[i]=i);
/* Se quiere copiar vector1 en vector2 */
/* vector2 = vector1 ---- ILEGAL !!!! */
for (i=0; i<DIM; i++)
vector2[i] = vector1[i];
EJEMPLO
Comparacin de vectores.
#define DIM 120
int vector1[DIM], i, vector2[DIM];
int iguales;
for (i=0; i < DIM; i++)
/* Lectura del vector1 de teclado*/
scanf("%d", &vector1 i );
for (i=0; i < DIM; i++)
/* Lectura del vector2 de teclado*/
scanf("%d", &vector2 i );
/* Se quiere comparar si son iguales vector1 y vector2 */
/* if (vector1 == vector2) ---- INCORRECTO !!!!
iguales = 1;
else iguales = 0;
*/
iguales = 1;
i = 0;
do
if (vector1[i] != vector2[i])
iguales = 0;
else i++;
while (i < DIM && iguales);
EJEMPLO
280
Programacin en C
Punteros
281
i=0;
while (pt != mensaje) {
*(aviso_inv+i) = *pt;
pt--;
i++;
}
/* Se carga el primer carcter de mensaje en aviso_inv y
el '\0' al final de la cadena aviso_inv */
*(aviso_inv+i) = *pt;
i++;
*(aviso_inv+i) = NULO;
El nombre de la tabla (sin ndices ni corchetes) ser por tanto una constante
puntero que contiene la direccin del primer elemento, es decir, la direccin de la
primera fila de la tabla.
En la Figura 9.2 se muestra una posible representacin en memoria de la tabla
mat. En este caso concreto, mat es un puntero que contiene la direccin de la
primera fila de la tabla.
Si se obtiene su contenido, *mat, se tendr el elemento al que apunta, es decir, la
primera fila de la tabla (mat[0]). Pero *mat (o mat[0]) es a su vez el nombre de
282
Programacin en C
mat[3][2]
mat[3][1]
mat[3][0]
mat[2][2]
mat[2][1]
mat[2][0]
mat[1][2]
mat[1][1]
mat[1][0]
mat[0][2]
mat
FFDE
mat[0][1]
mat[0][0]
Direcciones
FFF5
FFF4
FFF3
FFF2
FFF1
FFF0
FFEF
FFEE
FFED
FFEC
FFEB
FFEA
FFE9
FFE8
FFE7
FFE6
FFE5
FFE4
FFE3
FFE2
FFE1
FFE0
FFDF
FFDE
32
31
Fila 4
30
20
21
Direcciones
de memoria
Fila 3 crecientes
20
12
11
Fila 2
10
2
1
Fila 1
Punteros
283
Son equivalentes...
*mat
*(mat+1)
*(mat+2)
*(mat+3)
mat[0]
mat[1]
mat[2]
mat[3]
fila
fila
fila
fila
[0]
[1]
[2]
[3]
de
de
de
de
Son equivalentes...
**mat
*(*mat+1)
*(*mat+2)
**(mat+1)
*(*(mat+1)+1)
*(*(mat+1)+2)
mat[0][0]
mat[0][1]
mat[0][2]
mat[1][0]
mat[1][1]
mat[1][2]
mat
mat
mat
mat
puntero
puntero
puntero
puntero
Valor
0
1
2
10
11
12
al
al
al
al
primer
primer
primer
primer
elemento
elemento
elemento
elemento
de
de
de
de
fila
fila
fila
fila
[0]
[1]
[2]
[3]
Son equivalentes...
**(mat+2)
*(*(mat+2)+1)
*(*(mat+2)+2)
**(mat+3)
*(*(mat+3)+1)
*(*(mat+3)+2)
mat[2][0]
mat[2][1]
mat[2][2]
mat[3][0]
mat[3][1]
mat[3][2]
de
de
de
de
mat
mat
mat
mat
Valor
20
21
22
30
31
32
mat[2][0]
mat[1][2]
mat[1][1]
mat[1][0]
mat[0][2]
mat[0][1]
mat[0][0]
FFEB
FFEA
FFE9
FFE8
FFE7
FFE6
FFE5
FFE4
FFE3
FFE2
FFE1
FFE0
FFDF
FFDE
20
mat+2
Puntero al tercer elemento
(fila) de la tabla (a la fila [2])
12
11
10
mat+1
Puntero al segundo elemento
(fila) de la tabla (a la fila [1])
2
1
0
mat
Puntero al primer elemento
(fila) de la tabla (a la fila [0])
mat[2][0]
mat[1][2]
mat[1][1]
mat[1][0]
mat[0][2]
mat[0][1]
mat[0][0]
FFEB
FFEA
FFE9
FFE8
FFE7
FFE6
FFE5
FFE4
FFE3
FFE2
FFE1
FFE0
FFDF
FFDE
20
12
11
10
*(mat+2)
*(mat+1)+2
*(mat+1)+1
*(mat+1)
*mat+2
2
1
*mat+1
*mat
Figura 9.4. Direcciones de los elementos de cada fila dentro de una tabla
La Figura 9.5 muestra otro tipo de esquema para poder comprender la relacin
entre punteros y tablas descrita anteriormente. Como se puede apreciar en ella el
nombre de la tabla (mat) es un puntero al primer elemento de un vector de punteros,
284
Programacin en C
mat[], cuyos elementos contienen las direcciones del primer elemento de cada fila
de la tabla (el nombre mat por tanto es un puntero a puntero).
Segn describe por tanto la Figura 9.5:
*mat (o mat[0]), es un puntero a la primera fila de la tabla.
**mat (o mat[0][0]), es el primer elemento de la primera fila de la
tabla.
*(*mat+1) (o mat[0][1]), es el segundo elemento de la primera fila de
la tabla.
...
*(mat+1) (o mat[1]), es un puntero a la segunda fila de la tabla.
**(mat+1) (o mat[1][0]), es el primer elemento de la segunda fila de
la tabla.
*(*(mat+1)+1) (o mat[1][1]), es el segundo elemento de la segunda
fila de la tabla.
...
Al igual que suceda con los vectores, el nombre de una tabla es una constante
puntero a su primera fila, por tanto:
Dos tablas no pueden copiarse directamente una en otra, sino que hay
que copiarlas elemento a elemento.
Dos tablas no pueden compararse directamente para ver si son iguales
(contienen los mismos valores en los elementos de posiciones
equivalentes), sino que hay que compararlas elemento a elemento.
EJEMPLO
Copia de tablas.
#define FIL 12
#define COL 24
int tabla1[FIL][COL], tabla2[FIL][COL];
int f, c;
...
/* Se quiere copiar tabla1 en tabla2 */
/* tabla2 = tabla1 ---- ILEGAL !!!! */
for (f=0; f < FIL; f++)
Punteros
285
EJEMPLO
Comparacin de tablas.
#define FIL 12
#define COL 24
int tabla1[FIL][COL], tabla2[FIL][COL];
int f, c;
int iguales;
...
/* Se quiere comparar si son iguales tabla1 y tabla2 */
/* if (tabla1 == tabla2) ---- INCORRECTO !!!!
iguales = 1;
else iguales = 0;
*/
iguales = 1;
f = 0;
do {
c = 0;
do {
if (tabla1[f][c] != tabla2[f][c])
iguales = 0;
else c++;
} while (c < COL && iguales);
f++;
} while (i < DIM && iguales);
es equivalente a
es equivalente a
*(*(mat+f)+c)
*(*(pt+f)+c)
286
5.
6.
7.
8.
9.
10.
11.
Programacin en C
12.
= 'A';
*pv = &v;
1;
1;
13.
14.
15.
16.
17.
Punteros
287
direccin
FFEC
FFE8
FFE4
FFE0
FFDC
18.
a) p = &numreal;
b) p++;
c) p = &num1;
d) p = &num3;
e) p++;
f) p = &num2;
g) p--;
19.
288
Programacin en C
20.
21.
22.
23.
24.
25.
Cul es el significado de x?
Cul es el significado de (x+2)?
Cul es el valor de *x?
Cul es el valor de (*x + 2)?
Cul es el valor de *(x + 2)?
Cul es el significado de x+7?
Cul es el valor de *(x + 7)?
Cul es el valor de (*x + 7)?
Cul es el valor de *(x + 7) + 7?
26.
27.
10.1.1. Definicin
Para definir una cadena en C se utiliza la siguiente sintaxis:
char nombre_cadena tamao+1 ;
Donde tamao representa la longitud mxima de la cadena que es posible utilizar,
ya que como el lenguaje C inserta automticamente un carcter nulo ('\0') al final
de toda cadena de caracteres, en la definicin de una variable cadena, se debe prever
una posicin para este carcter.
EJEMPLO
290
Programacin en C
10.1.2. Iniciacin
Se asignan el valor de la cadena en la declaracin de la misma. Como cualquier
vector, una variable cadena de caracteres slo podr ser iniciada en el momento de la
declaracin, nunca dentro de las sentencias ejecutables del programa.
La iniciacin puede hacerse de formas diferentes:
char cadena[] = "HOLA";
Aunque no se indica entre corchetes la longitud de la cadena, el
compilador reserva automticamente el nmero correcto de posiciones
de memoria para almacenar cada elemento de la cadena, incluyendo el
carcter nulo final. En este caso se reservan cinco posiciones de
memoria, como se muestra en el siguiente esquema.
Direcciones
de memoria
Direcciones
de memoria
crecientes
FFA6
FFA5
FFA4
FFA3
FFA2
Cdigo
ASCII
'\0'
'A'
'L'
'O'
'H'
0
65
76
79
72
Obsrvese que:
o Los literales cadena de caracteres se encierran entre dobles
comillas.
"verde"
"La respuesta correcta es:"
"923-123456"
"Pablo Milans"
"" (cadena de caracteres vaca o nula)
"Lnea 1\nLnea 2\nLnea 3"
Cadenas de caracteres en C
291
Direcciones
de memoria
crecientes
FFA5
FFA4
FFA3
FFA2
Cdigo
ASCII
'A'
'L'
'O'
'H'
65
76
79
72
292
Programacin en C
terminada la entrada del dato, por lo que no se podr cargar desde teclado cadenas que
incluyan el carcter espacio.
Para dar entrada por scanf() a cadenas de caracteres que incluyan caracteres
espacio como parte de los datos, se debe utilizar como especificador de formato
%[^\n], que indica que slo los caracteres incluidos entre corchetes sean
considerados como terminacin de dato, en este caso slo el carcter fin de lnea
(intro o \n).
EJEMPLO
Cadenas de caracteres en C
293
printf("\nHola ");
puts(nombre);
}
Realizar un programa que lea en tres variables cadena, el nombre y los dos
apellidos de una persona y, posteriormente, concatene en una cuarta variable
cadena las tres anteriores, separando cada una de ellas por el carcter
asterisco (*).
#include <stdio.h>
#define N 30
#define SEPARADOR '*'
#define NULO '\0'
void main (void) {
int j, i;
char nomb[N];
char ape1[N];
char ape2[N];
char iden_persona[3*N];
printf("Introduzca el nombre: ");
gets(nomb);
printf("Introduzca el primer apellido: "); gets(ape1);
printf("Introduzca el segundo apellido: "); gets(ape2);
i = 0;
/* Se recorre carcter a carcter la cadena nomb, llevando de
uno en uno los caracteres a la cadena iden_persona.
Se termina cuando se localice el carcter nulo final de la
cadena nomb */
j = 0;
while (nomb[j] != NULO) {
iden_persona[i] = nomb[j];
j++;
i++;
}
294
Programacin en C
/* Se coloca el carcter separador a iden_persona */
iden_persona[i] = SEPARADOR;
i++;
/* Se recorre carcter a carcter la cadena ape1, llevando de
uno en uno los caracteres a la cadena iden_persona.
Se termina cuando se localice el carcter nulo final de la
cadena ape1 */
j = 0;
while (ape1[j] != NULO) {
iden_persona[i] = ape1[j];
j++;
i++;
}
iden_persona[i] = SEPARADOR;
i++;
/* Se recorre carcter a carcter la cadena ape2, llevando de
uno en uno los caracteres a la cadena iden_persona. Se
termina cuando se localiza el carcter nulo final de la
cadena ape2 */
j = 0;
while (ape2[j] != NULO) {
iden_persona[i] = ape2[j];
j++;
i++;
}
/* Se coloca el carcter nulo final a iden_persona */
iden_persona[i] = NULO;
printf("Identificacin persona: %s\n", iden_persona);
}
Cadenas de caracteres en C
295
EJEMPLO
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
string.h
stdlib.h
stdlib.h
stdlib.h
ctype.h
ctype.h
ctype.h
ctype.h
ctype.h
ctype.h
ctype.h
ctype.h
ctype.h
ctype.h
296
Programacin en C
}
Salida por pantalla:
=
=
=
=
"ESTA ES MI CADENA";
"abcdef";
"123456";
"VWXYZ";
Cadenas de caracteres en C
printf("Al principio.
printf("string: %s\n", string);
297
");
string:
string:
string:
string:
ESTA ES MI CADENA
abcdef
1234ef
VW
Este programa forma una frase concatenando tres cadenas. De la ltima slo
concatena tantos caracteres como posiciones queden disponibles en la cadena
destino.
298
Programacin en C
#include <stdio.h>
#include <string.h>
#define MAXLON 55
void main(void) {
char cad1[30];
char mensaje[MAXLON+1]="Hola ";
char cad2[] = ". Bienvenido al sistema.";
int lon;
printf("\nIntroduzca su nombre: "); gets(cad1);
strcat(mensaje, cad1);
lon = strlen(mensaje)+strlen(cad2);
if (lon < MAXLON)
strcat(mensaje, cad2);
else
strncat(mensaje, cad2, MAXLON-strlen(mensaje));
puts(mensaje);
Cadenas de caracteres en C
299
EJEMPLO
EJEMPLO
Este programa localiza la posicin inicial y final de un carcter dentro de una
cadena.
#include <stdio.h>
#include <string.h>
#define MAXLON 80
void main() {
char cad[MAXLON], c, *ptr;
int i;
printf("Introduce una cadena: ");
gets(cad);
300
Programacin en C
printf("Introduce un carcter: ");
scanf("%c", &c);
Este programa busca cuantas veces aparece una subcadena dentro de una
cadena.
#include <stdio.h>
#include <string.h>
#define MAXLON 80
void main() {
char cad[MAXLON], palabra[80] , *ptr;
int lon, contador=0;
printf("Introduce una cadena: ");
printf("Introduce una palabra: ");
lon=strlen(palabra);
ptr=cad;
do {
ptr=strstr(ptr, palabra);
if (ptr) {
contador++;
ptr += lon;
}
} while (ptr);
gets(cad);
gets(palabra);
Cadenas de caracteres en C
301
Este programa busca en la cadena que se introduzca por teclado los signos de
puntuacin y los sustituye por espacios.
#include <stdio.h>
#include <string.h>
#define MAXLON 80
#define ESPACIO ' '
void main() {
char cad[MAXLON], *ptr;
printf("Introduzca una cadena con signos de puntuacin:\n");
gets(cad);
ptr = cad;
while (ptr) {
ptr = strpbrk(ptr, ".,!;'\"?-");
if (ptr)
*ptr = ESPACIO;
}
puts(cad);
}
302
Programacin en C
"1234567890";
"123DC8";
"1234567";
"12345678";
Cadenas de caracteres en C
303
304
Programacin en C
Cadenas de caracteres en C
305
EJEMPLO
#include <string.h>
#include <stdio.h>
void main(void) {
char *forward = "string";
char *cadena1 = "Hola Mundo";
char *cadena2;
printf("Antes
de strrev(): %s\n", forward);
strrev(forward);
printf("Despus de strrev(): %s\n", forward);
printf("Antes
de strrev(): %s\n", cadena1);
cadena2 = strrev(cadena1);
printf("Despus de strrev(), cadena1: %s\n", cadena1);
printf("Despus de strrev(), cadena2: %s\n", cadena2);
de
de
de
de
de
strrev():
strrev():
strrev():
strrev(),
strrev(),
string
gnirts
Hola Mundo
cadena1: odnuM aloH
cadena2: odnuM aloH
Los prototipos de las funciones as categoras para cada funcin son las siguientes:
int isalnum (int c);
int isalpha (int c);
int isascii (int c);
int iscntrl (int c);
int isdigit (int c);
306
Programacin en C
2.
3.
Qu diferencia
existe
entre
scanf("%s",
cadena)
gets(cadena)? En qu casos ser mejor utilizar una u otra?
Qu diferencias y analogas hay entre las siguientes variables?
char **prt1;
char *prt2[55];
char *prt3[14][18];
4.
5.
6.
7.
Cadenas de caracteres en C
'2': retorno
'3': retorno
'4': retorno
'5': retorno
'6': retorno
'7': retorno
'8': retorno
'9': retorno
fin segn sea
fin numero
8.
307
2
3
4
5
6
7
8
9
9.
10.
308
Programacin en C
retorno (num)
Sino retorno (-1)
fin si
fin valor
11.
12.
13.
14.
15.
11. Funciones en C
Las aplicaciones informticas que habitualmente se utilizan, incluso en el mbito de la
informtica personal, suelen contener decenas y an cientos de miles de lneas de
cdigo fuente. A medida que los programas se van desarrollando y aumentan de
tamao, se convertiran rpidamente en sistemas poco manejables si no fuera por la
modularizacin, que es el proceso consistente en dividir un programa muy grande en
una serie de mdulos mucho ms pequeos y manejables.
A estos mdulos se les suele denominar de distintas formas (subprogramas,
subrutinas, procedimientos, funciones...) segn los distintos lenguajes. El lenguaje C
utiliza el concepto de funcin.
Sea cual sea la nomenclatura, la idea es siempre la misma: dividir un programa
grande en un conjunto de subprogramas o funciones ms pequeas que son llamadas
por el programa principal; stas a su vez llaman a otras funciones ms especficas y
as sucesivamente.
La divisin de un programa en unidades ms pequeas o funciones presenta, entre
otras, las ventajas siguientes:
Modularizacin. Cada funcin tiene un propsito nico e identificable, de
modo que no tiene un nmero de lneas excesivo y siempre se mantiene dentro
de un tamao manejable.
Claridad lgica de los programas. Como resultado de la divisin del
programa en varios mdulos (funciones) concisos ms pequeos, donde cada
mdulo representa alguna parte bien definida del problema global.
Independencia de datos y ocultamiento de informacin. Es muy frecuente
que al hacer una modificacin en un programa para aadir funcionalidad o
corregir un error, se introduzcan nuevos errores en partes del programa que
antes funcionaban correctamente. Una funcin es capaz de mantener una gran
independencia con el resto del programa, manteniendo sus propios datos y no
permitiendo ninguna posibilidad de acceso a su informacin por parte de otros
componentes del programa.
Cdigo no redundante. Evita la necesidad de repetir las mismas instrucciones
de forma redundante en distintas partes del programa. stas se incluirn en una
funcin y se llamar a la misma cuando sea necesario. Incluso podr ser
utilizada por otros programas.
Ahorro en tiempo de desarrollo. Cada funcin puede desarrollarse y
depurarse por separado, de forma independiente por programadores diferentes.
Creacin de bibliotecas personalizadas. Permite la creacin de bibliotecas
de funciones a medida del programador, pudiendo as reutilizar cdigo ya
probado y verificado en el desarrollo de nuevos programas.
En este captulo se van a estudiar los fundamentos de las funciones segn la
perspectiva del lenguaje de programacin C, para lo cual ste se ha divido en nueve
secciones. La primera explica cmo se utilizan las funciones, distinguiendo tres fases
en su empleo: declaracin, definicin y llamada. La segunda seccin explica cmo el
uso de funciones obliga a distinguir varios tipos de variables. La tercera seccin se
centra en explicar los argumentos de una funcin, diferencindose los argumentos que
- 309 -
310
Programacin en C
Funciones en C
311
tipo_r
nombre
{
declaracin de las variables locales;
Cuerpo de la funcin
Definicin
de la funcin
correcto
incorrecto
Si la funcin no requiere parmetros, se puede colocar entre los parntesis el
tipo de dato void.
Los nombres de los argumentos no pueden coincidir entre s, ni tampoco con
el nombre de las variables o constantes definidas dentro de la funcin.
El cuerpo de la funcin incluye la siguiente informacin:
Declaraciones locales: Es el conjunto de definiciones y declaraciones de datos
que la funcin necesita utilizar para la realizacin de la tarea especfica. Tanto
los parmetros o argumentos de la cabecera de la funcin, como para las
variables y constantes que se definen dentro de la funcin, son locales: no son
reconocidos fuera de la funcin (este concepto de localidad se explica en la
seccin 11.2). No podrn ser utilizados ms que por las sentencias o
instrucciones incluidas en el cuerpo de la funcin.
312
Programacin en C
Funciones en C
313
EJEMPLO
314
Programacin en C
O simplemente
char mayus (char);
EJEMPLO
Funciones en C
315
*/
*/
316
Programacin en C
Funciones en C
317
318
Programacin en C
Funciones en C
319
Externa.
Registro.
Esttica.
Automtica.
El especificador precede al resto de la declaracin de la variable, siendo su formato
general:
especificador tipo identificador;
11.2.1.1. Variables externas
El especificador extern permite que todos los archivos que forman un programa C
conozcan las variables globales requeridas por el programa. Esto es as porque las
variables globales slo se pueden declarar una vez; as si se declaran dos variables
globales con el mismo nombre en el mismo archivo, el compilador informar del
error. El mismo tipo de problema ocurrira si se declaran todas las variables globales
en cada archivo. En este caso el compilador no dara ningn mensaje de error en
tiempo de compilacin, pero el problema surgira en el momento del enlazado, y el
enlazador emitira un mensaje porque no sabra que variable usar. La solucin a este
problema es definir todas las variables globales en un archivo y usar declaraciones
extern en el resto de los archivos.
As el especificador extern permite que el compilador conozca los tipos y
nombres de las variables globales sin crear un nuevo almacenamiento para ellas, de
forma que cuando el linker enlaza los mdulos se resuelven todas las referencias a las
variables externas.
EJEMPLO
extern int i;
extern float x;
void f2() {
i = (int) x;
}
320
Programacin en C
EJEMPLO
EJEMPLO
Funciones en C
321
void f() {
static int j=10;
printf ("%d ", j);
j++;
}
Se presenta una funcin para calcular la suma de todos los nmeros enteros
impares comprendidos en un intervalo. La funcin recibe dos parmetros de
tipo int que marcan respectivamente el inicio y final del intervalo, y
devuelve un long con la suma calculada.
322
Programacin en C
Funciones en C
323
void main(void) {
float radio;
A float area_c;
float volumen_e;
presentacion();
Retorno al punto
de llamada
Retorno al
punto de llamada
Variables y
constantes locales
resultado = PI * rd * rd;
return (resultado);
}
Retorno al punto
de llamada
G
}
return ( (4.0/3.0) * PI
* rd * rd * rd );
printf("\n\n");
}
324
Programacin en C
Funciones en C
325
Las funciones creadas sin efectos laterales se comporta como cajas negras 3
totalmente exportables a otros programas, con slo conocer el rea de interfaz: los
parmetros con que hay que llamarlas y el tipo de dato del valor de retorno.
El mdulo que invoca slo espera de una funcin que le resuelva una tarea y, si es
el caso, que le proporcione un resultado que deber ser recogido por el propio mdulo
que origin la llamada.
Desde el punto de vista de la propia funcin, sta no es ms que un conjunto de
instrucciones que se ejecutarn cuando la funcin sea llamada, y reciba sobre sus
parmetros formales los valores que se le han pasado desde el mdulo que la
invoc. La funcin devolver el valor resultado de su clculo a travs del valor de
retorno, el cual deber ser recogido por el mdulo que hizo la llamada.
Todas las funciones que se codifiquen de acuerdo a las anteriores normas podrn
engrosar una biblioteca propia de funciones del programador, que completarn a las
intrnsecas del lenguaje, de forma que con el paso del tiempo programar ser mucho
ms fcil, rpido y seguro, pues se estar utilizando cdigo ya probado con un
comportamiento conocido.
Por tanto, la interfaz es la forma natural y directa de comunicacin entre una
funcin y el mdulo que la llama. Es la forma que tiene la funcin de recibir del
exterior informacin con la que realizar su tarea especfica, para la que ha sido
diseada, y de devolver el valor de retorno calculado.
EJEMPLO
Mdulos independientes de los que el programa principal no conoce su contenido, slo lo que
hacen. Estos mdulos independientes pueden ser probados y depurados por s solos, lo que hace
mucho ms fcil acotar e identificar posibles errores de funcionamiento de los programas.
326
Programacin en C
#include <stdio.h>
void calcular_factorial (void); /* Prototipos */
int numero;
long factorial;
int i;
void main(void) {
printf("\nIntroduzca un nmero entero para calcular su
factorial: ");
scanf ("%d", &numero);
calcular_factorial();
printf("\nEl factorial de %d es %ld\n, numero,
factorial);
}
void calcular_factorial (void) {
factorial = 1;
for (i=1; i<=numero; i++)
factorial *= i;
}
Funciones en C
327
Los parmetros formales de una funcin son variables locales a la misma, los
cuales, al ser llamada la funcin, se crean y reciben el valor de los parmetros reales
de la llamada, y se destruirn al salir de la misma.
El paso de estos parmetros a una funcin puede hacerse de dos formas: mediante
paso por valor o mediante paso por referencia.
Direccin
FFF4
FFF2
FFD8
125
FFD6
23
Direcciones de
memoria
crecientes
23
125
328
Programacin en C
EJEMPLO
Direccin
FFF4
FFF2
Direcciones
de memoria
crecientes
23
125
FFD8
FFFF2
FFD6
FFF4
Funciones en C
329
Se utiliza paso por referencia cuando la funcin usa los parmetros como
entrada/salida, es decir, accede desde los parmetros formales (que son punteros) a
los parmetros reales y, adems de utilizar el valor de stos, modifica finalmente el
valor de los mismos. Tambin se utiliza el paso por referencia cuando se quiere
construir una funcin que devuelva ms de un resultado.
EJEMPLO
Esta funcin utiliza los valores de los parmetros reales recibidos y los
devuelve modificados convenientemente.
Un ejemplo de llamada se presenta en el siguiente esqueleto de programa.
int horas = 5;
int minutos = 57;
int incremento = 148;
...
printf("Tiempo inicial: %2d:2d\n", horas, minutos);
330
Programacin en C
float radio;
float angulo;
float ordenada, abcisa;
...
scanf("%f", &radio);
scanf("%f", &angulo);
...
polares_a_cartesianas (radio, angulo, &abcisa, &ordenada);
Funciones en C
331
EJEMPLO
Una cadena de caracteres debe pasarse a una funcin siempre por referencia,
utilizando el nombre de la cadena, que es un puntero al primer carcter. Por tanto, el
parmetro formal de la funcin debe ser un puntero de tipo char, para poder recoger
su direccin.
No hace falta pasar a la funcin la dimensin de la cadena, pues la funcin la
puede obtener localizando el '\0' final de la cadena.
332
Programacin en C
EJEMPLO
Una tabla4 debe pasarse a una funcin siempre por referencia, utilizando el nombre
de la tabla, que es un puntero a la primera fila de la tabla. Por tanto, el parmetro
formal de la funcin debe ser un puntero a filas de la tabla, para poder recoger su
direccin.
Adems la funcin que manipule la tabla deber conocer el nmero de filas de la
tabla, por lo que se le pasar siempre en un segundo parmetro, en este caso
normalmente por valor.
El nmero de columnas de la tabla se est pasando a la funcin de forma implcita
en la definicin del parmetro formal puntero a filas.
EJEMPLO
El siguiente ejemplo implementa dos funciones que reciben un entero y una matriz de
enteros, la primera calcula la traza de la matriz, funcin traza(), y la segunda que
presenta en pantalla la matriz que recibe, funcin presenta_matriz().
Una tabla puede considerarse como un vector de filas, donde cada fila es a su vez un vector de
dimensin el nmero de columnas de la tabla.
Funciones en C
#include <stdio.h>
#define FIL 3
#define COL 3
333
/* Prototipos */
float traza (int, int (*)[COL]);
void presenta_matriz (int, int [][COL]);
void main(void) {
int mat[FIL][COL] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int i,j;
presenta_matriz(FIL, mat);
printf("Traza: %g\n", traza(FIL, mat));
}
float traza (int filas, int (*ma)[COL]) {
int f;
float tr = 0;
for (f=0; f<=filas-1; f++)
tr = tr + ma[f][f];
return (tr);
}
void presenta_matriz (int filas, int ma[][COL]) {
int f,c;
for (f = 0; f <= filas-1; f++) {
for (c = 0; c <= COL-1; c++)
printf("%5d", ma[f][c]);
printf("\n");
}
}
11.6. Recursividad
11.6.1. Conceptos bsicos
El concepto de recursividad est presente en la mayora de los lenguajes de
programacin. Consiste en el hecho de que una funcin haga referencia a s misma
dentro de su definicin.
Un programa que hace uso de la recursividad contiene una funcin que se llama a
s misma de forma repetida, hasta que se satisface alguna determinada condicin de
salida. Este mecanismo es muy til cuando se requieren clculos en los que cada
accin se determina segn el resultado anterior. sta es por tanto una valiosa forma de
abordar muchos problemas iterativos.
Para que una funcin recursiva sea vlida, la referencia a s misma debe ser de
alguna forma ms sencilla que el caso considerado. En trminos de ejecucin, la
recursividad supone que una invocacin al subprograma recursivo genere una o ms
invocaciones al propio subprograma. La cadena de invocaciones terminar cuando
alguna no genere nuevas invocaciones. Cuando estas llamadas terminales acaban su
ejecucin, devuelven el control a la llamada anterior, que a su vez, har lo mismo,
334
Programacin en C
hasta que todas las cadenas de invocacin, incluida la propia llamada inicial,
terminan.
Para que se pueda resolver un problema mediante recursividad, se deben satisfacer
dos condiciones: en primer lugar, el problema se debe escribir de forma recursiva y
segundo, la sentencia del problema debe incluir una condicin de fin.
11.6.1.1. Algoritmo Recursivo
Un algoritmo recursivo es aqul que, en parte, est formado por s mismo o se define
como funcin de si mismo. Tiene como principal ventaja la posibilidad de definir un
conjunto infinito de objetos mediante una proposicin finita, ya que un conjunto
infinito de clculos puede describirse mediante un programa recursivo finito, sin que
contenga repeticiones explcitas. Siendo una situacin idnea aqulla donde el
problema por resolver, la funcin por calcular o la estructura de datos por procesar ya
estuvieran definidos en trminos recursivos.
EJEMPLO
Funciones en C
335
Algunos autores slo distinguen entre recursividad directa, que englobara a todos los dems
tipos de recursividad enumerados, y la recursividad indirecta.
336
Programacin en C
else
return (impar(np - 1));
}
int impar(long int ni){
if (ni == 0)
return (0);
else
return (par(ni - 1));
}
Funciones en C
337
Diseo Recursivo:
Calcular la potencia n-sima de un nmero, es decir, se trata de
calcular an.
P = an
D = (a, n).
La aplicacin al problema de la exponenciacin es simple:
suponiendo que ya se sabe calcular an-1, resolver el problema
original an resulta inmediato.
Calcular an es P, mientras que an-1 es D. Resolver el problema
original es evidente:
an = a * a n-1
Ntese que el par (a, n-1) es del mismo tipo que (a, n), pero
ms sencillo.
Se trata de encontrar una relacin de recurrencia para solucionar el
problema sobre datos cada vez ms pequeos:
D>D>D>...>Dt (obtenindose una sucesin finita).
Diseo Iterativo:
Se llega a unos datos lo suficientemente sencillos, Dt para que P sea
resuelto directamente. Siendo Dt un caso trivial.
El problema p consiste en multiplicar dos nmeros x y a.
Repitindose el problema p exactamente n veces. En total hay
involucrados dos problemas distintos, P y p, y dos tipos de datos, D
y d en general distintos.
338
Programacin en C
a * a * ... * a (n veces)
Se tienen un conjunto de instrucciones que se repiten un nmero de
veces.
El fundamento de un programa recursivo es un reflejo de siguiente anlisis: habr
una o ms instrucciones condicionales dedicadas a separar los tratamientos
correspondientes al caso trivial o casos triviales de los correspondientes al caso o
casos no triviales. Los primeros tienen el aspecto de un programa convencional
mientras que, en los segundos, se pueden distinguir las siguientes partes:
Primero se calcular D, el sucesor de D. Se debe aadir que se produce una
descomposicin recursiva de los datos D para obtener los datos ms sencillos
D. A veces se dice que D es un subproblema de D.
A continuacin, se produce una llamada recursiva para obtener la solucin a
un subproblema D.
Finalmente, se opera sobre los resultados obtenidos para D a fin de calcular
la solucin para D.
En general, la versin iterativa ser siempre menos legible y modificable, la
ganancia en eficiencia debe estar suficientemente justificada.
Funciones en C
339
340
Programacin en C
Funciones en C
341
342
Programacin en C
1
2 * 1 = 2
3 * 2 * 1 = 6
4 * 3 * 2 * 1 =24
n * (n - 1)! = ...
Funciones en C
343
La sucesin de Fibonacci.
Como ya se vio ejemplificando la recursividad mltiple, la sucesin de
Fibonacci se corresponde con la siguiente definicin:
fib(1) = 1; fib(0) = 0
fib(n) = fib(n - 1) + fib(n - 2) si n >= 2
344
Programacin en C
for (i
c =
a =
b =
}
return
= 2; i <= n; i++){
a + b;
b;
c;
(c);
Funciones en C
345
346
Programacin en C
Funciones en C
347
El cdigo en C para la funcin recursiva que permitiera dar por escrito las
instrucciones a los monjes se muestra a continuacin. La llamada inicial sera
mueve(64, 1, 3, 2):
/* a: aguja origen
b: aguja destino
c: aguja temporal
*/
void mueve(int n, int a, int b, int c){
if (n > 0){
mueve (n - 1, a, c, b);
printf(Mueve un disco de %d a %d, a, b);
mueve(n - 1, c, b, a);
}
}
348
Programacin en C
definir punteros a funciones, lo que permitir establecer otra forma de llamar a una
funcin y de recoger sus resultados.
Es importante destacar que la definicin y declaracin de la funcin no se
modifican, se trata nicamente de un modo diferente de hacer uso de la misma. As,
un puntero a funcin almacena la direccin de memoria de una funcin.
La principal ventaja del uso de este tipo de variables es la simplificacin del
cdigo, sobre todo cuando se tienen que aplicar diferentes criterios sobre un conjunto
de elementos como son las estructuras.
La declaracin de un puntero a funcin tiene la siguiente forma:
tipo_r (*nombre)(tipo1 par1, ..., tipon parn);
Se debe resaltar que los parntesis que encierran al nombre de la variable son
indispensables, ya que tipo_r *nombre se corresponde con la definicin de una
funcin que devuelve como resultado un puntero al tipo de datos tipo_r.
EJEMPLOS
int (*accion)(int a, int b);
float (*beneficios)(int incial, int stock, float margen)
11.7.1. Uso
Al igual que con los punteros estudiados en el captulo 9, slo se le pueden asignar
direcciones de memoria de funciones que retornen el mismo tipo de dato, y que
tengan la misma lista de parmetros (lo que evita errores de indireccin). La
asignacin, lgicamente, consistir en igualar el nombre del puntero con el nombre de
la funcin a la que debe apuntar.
Al igual que los dems punteros, estos pueden cambiar de direccin cuantas veces
se necesite.
EJEMPLO
/* Definicin de funciones */
int sumar(int a, int b);
int restar(int a, int b);
int multiplicar(int a, int b);
int dividir(int a, int b);
/* Declaracin del puntero a funcin */
int (*accion)(int a, int b);
... /* resto de sentencias */
/* En este punto, el programa se requiere hacer una suma */
valor_a = 2;
valor_b = 3;
accion = sumar;
resultado = accion(valor_a, valor_b);
... /* resto de sentencias */
/* En este punto, el programa se requiere hacer un producto */
valor_a = 27;
valor_b = 10;
accion = multiplicar;
resultado = accion(valor_a, valor_b);
... /* resto de sentencias */
Funciones en C
349
350
Programacin en C
en la funcin principal*/
Funciones en C
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
351
352
Programacin en C
printf("\n");
for (i=1, i<=temp, i++)
printf("%c", c);
printf("\n");
temp = a; a = b; b = temp;
21.
}
void main(void) {
scanf("%d %d", &a, &b);
scanf("%d", &c);
printf("A=%d, B=%d, C=%c\n", a, b, c);
proceso1();
printf("A=%d, B=%d, C=%c\n", a, b, c);
}
#include <stdio.h>
/* Programa: MBITO DE VARIABLES.
Desarrollado por: Prcticas de programacin.
Descripcin: Muestra el comportamiento en cuanto al
mbito de existencia de las variables globales,
locales y parmetros de las funciones en C. */
int x, y;
void f1(void) {
int x1, y1;
x1 = 101;
y1 = 102;
printf("\nFuncin f1.
} /* fin funcin f1 */
Funciones en C
353
22.
23.
354
24.
25.
26.
27.
28.
29.
30.
31.
Programacin en C
32.
33.
34.
12.1. Estructuras
Una estructura es una agrupacin de datos, que pueden ser de distintos tipos, a los que
globalmente puede hacerse referencia bajo un mismo nombre.
Los datos individuales que forman la estructura se denominan elementos o
miembros de la estructura.
Los miembros de una estructura normalmente estn relacionados de una forma
lgica desde el punto de vista de la informacin que tratan.
Donde:
struct nombre_tipo_estructura {
tipo1 miembro1;
tipo2 miembro2;
tipon miembron;
};
- 355 -
356
Programacin en C
Supngase que se desea disear una estructura para relacionar los datos
correspondientes a un alumno de primer curso. Esta estructura, a la que se va
a llamar alumno, deber contener el nombre, la direccin, el nmero de
matrcula, el telfono y las notas de 10 asignaturas.
La declaracin del tipo de la estructura puede hacerse del siguiente modo:
struct alumno {
char nombre [51];
char direccion [81];
unsigned long num_matricula;
unsigned long telefono;
float notas[10];
};
(miembro)
(miembro)
(miembro)
(miembro)
(miembro)
Las declaraciones de estructuras en un programa suelen hacerse de forma global para permitir
la definicin de las variables del tipo estructura en los diversos mdulos o funciones, sin tener
que volver a declarar la plantilla de la estructura en cada funcin.
357
struct nombre_tipo_estructura {
tipo1 miembro1;
tipo2 miembro2;
...
tipon miembron;
} nombrevariable;
En este caso es posible omitir, si se desea, el nombre del tipo estructura, por
lo que tambin sera vlida una declaracin como la que sigue:
struct {
char nombre [51];
char direccion [81];
unsigned long num_matricula;
unsigned long telefono;
float notas[10];
} alumno1, alumno2;
358
Programacin en C
EJEMPLO
359
O tambin:
printf ("%s", nuevo_alumno.direccion);
360
Programacin en C
struct fecha {
int dia;
int mes;
int anio;
};
struct cuenta {
unsigned long numero;
char tipo;
char titular[51];
float saldo;
struct fecha fapertura;
};
struct cuenta nuevocliente = {30056231452, 'C',
"SANTIAGO DENIA", 365800, 12, 5, 1989};
361
EJEMPLO
/* Fecha de nacimiento */
362
Programacin en C
clase[0]
clase[1]
PEDRO PEREZ
12
6
1970
clase[0].nombre
5.5
clase[0].nota
clase[1].nombre
MARIA GARCIA
31
3
1972
3.4 4.1
clase[44]
clase[0].fnac
clase[1].fnac
6.2
SUSANA RODRIGUEZ
8
7
1971
8
6.5
clase[0].fnac.dia
clase[0].fnac.mes
clase[0].fnac.anio
clase[1].fnac.dia
clase[1].fnac.mes
clase[1].fnac.anio
clase[1].nota
clase[1].nota[4]
5.5 7.9
clase[44].nota[2]
363
Para apuntar con un puntero a una variable estructura, se utiliza el operador &
(operador direccin), igual que para cualquier otro tipo de dato de C.
struct nombre_tipo_estructura nombrevariable;
nombrepuntero = &nombrevariable;
En este momento el puntero nombrepuntero apunta a la variable estructura
nombrevariable, y esto permite una nueva forma de acceder a sus miembros,
utilizando el operador flecha (->), llamado operador puntero a miembro de una
estructura, y constituido con los smbolos (-) y (>).
Se utiliza de forma anloga a como se utiliza el operador punto (.), pero en lugar
de utilizar el nombre de la variable estructura se utiliza el nombre del puntero.
nombrepuntero->nombremiembro;
Tambin se puede utilizar el operador asterisco (*) pero es muy infrecuente:
(*nombrepuntero).nombremiembro;
En este segundo caso, obsrvese la necesidad de utiliza los parntesis, por la mayor
prioridad del operador (.) respecto al operador (*).
364
Programacin en C
struct alumno {
char nombre [81];
struct fecha fnac; /* Fecha de nacimiento */
float nota[NOTAS];
} anterioralumno, nuevoalumno;
Donde los miembros individuales (los campos de bits) tienen el mismo significado
que en una declaracin de estructura, pero ahora, cada declaracin de miembro debe
incluir una especificacin del tamao en bits del campo correspondiente. Para
hacerlo, el nombre del miembro debe ir seguido por dos puntos (:) y un entero sin
signo que indique el tamao del campo.
Un campo de bits debe ser declarado como int o unsigned int. Los campos
de bits de longitud 1 deben ser declarados como unsigned porque un nico bit no
puede tener signo.
Normalmente, los programas que incluyen campos de bits no son directamente
transportables entre mquinas. Esto es debido a que la asignacin de estos campos de
bits puede variar de un compilador a otro. Por ejemplo, algunos compiladores pueden
asignar los campos de bits de derecha a izquierda, mientras que otros los asignan de
izquierda a derecha (deber consultarse, por tanto, el manual del compilador
correspondiente). Se supone asignacin de derecha a izquierda en los ejemplos que se
muestren en este apartado.
365
{
1;
3;
2;
1;
struct muestra v;
sin uso
bit nmero
12.3. Uniones
Las uniones, son similares a las estructuras, ya que contienen miembros cuyos tipos
de datos pueden ser diferentes. La diferencia de las uniones con las estructuras es que
los miembros que componen una unin comparten la misma rea de almacenamiento
dentro de la memoria, mientras que cada miembro de una estructura tiene asignada su
propia rea de almacenamiento.
Las uniones se usan para ahorrar memoria. Son tiles para aplicaciones que
involucren mltiples miembros donde no se necesita asignar valores a todos los
miembros simultneamente. Y son muy utilizadas cuando se necesita manejar
diferentes clases de datos en una nica rea de memoria.
La forma de declarar una unin es anloga a la de las estructuras. Tambin la
forma de acceder a los elementos, bien por nombre, bien mediante puntero.
EJEMPLO
Se supone que se desea acceder a un byte de dos formas distintas: una como
entidad de informacin (un carcter), y la otra bit a bit. Para ello se declara
un campo de bits y una unin de la siguiente forma:
366
Programacin en C
struct byte {
unsigned a:1;
unsigned b:1;
unsigned c:1;
unsigned d:1;
unsigned e:1;
unsigned f:1;
unsigned g:1;
unsigned h:1;
};
union caracter {
char car;
struct byte bit;
};
union caracter car_1;
EJEMPLO
Escribir un programa que pida una lnea de texto por teclado y visualice en
binario, segn el cdigo ASCII, los caracteres de la misma. Se utilizar una
unin que contenga un carcter y una estructura de campos de bits para
contener el octeto correspondiente a cada carcter de la lnea de texto.
#include <stdio.h>
struct octeto {
unsigned a : 1;
unsigned b : 1;
unsigned c : 1;
unsigned d : 1;
unsigned e : 1;
unsigned f : 1;
unsigned g : 1;
unsigned h : 1;
};
union bits {
char car;
struct octeto bit;
};
void visualizabit (union bits);
void main (void) {
char frase[81];
int i;
union bits codigo;
printf("Introduzca una frase (mx. 80 caracteres): ");
gets(frase);
i = 0;
printf("Carcter ASCII binario\n");
printf("-------- ----- -------\n");
367
{
printf("0");
printf("0");
printf("0");
printf("0");
printf("0");
printf("0");
printf("0");
printf("0");
12.4. Enumeraciones
Una enumeracin es un tipo de dato que consta de una lista de constantes enteras con
signo. Los nombres de estas constantes representan los valores legales que puede
tomar una variable que se defina de ese tipo.
La declaracin de la plantilla o tipo de una enumeracin se realiza con la palabra
reservada enum y la lista de constantes encerrada entre parntesis. Tambin se les
suele llamar miembros de la enumeracin a cada una de las constantes de la lista.
enum nombre_tipo_enumeracion {
constante1,
constante2,
...
constanten,
};
Los nombres de las constantes deben ser todos diferentes entre s, adems de
distintos a los nombres de otros identificadores cuyo mbito sea el mismo que el
mbito de la enumeracin.
La definicin de variables tipo enum se realiza de forma anloga a como se define
una variable estructura:
enum nombre_tipo_enumeracion variable_enumeracion;
O bien:
enum nombre_tipo_enumeracion {
constante1,
constante2,
...
constanten,
} variable_enumeracion;
O bien:
368
Programacin en C
enum {
constante1,
constante2,
...
constanten,
} variable_enumeracion;
Internamente los elementos que forman parte de una enumeracin son constantes
enteras con signo, cuyos valores son asignados automticamente por el compilador,
comenzando por cero para la primera constante, uno para la segunda, y as
sucesivamente.
EJEMPLO
Puede pensarse en una variable llamada diasemana que slo puede tomar
los siete siguientes valores: lunes, martes, miercoles, jueves,
viernes, sabado y domingo.
Se comienza por declarar un nuevo tipo enumeracin al que se va denominar
dia.
enum dia {lunes, martes, miercoles, jueves, viernes,
sabado, domingo };
La declaracin anterior crea un nuevo tipo de dato (tipo enum dia) cuyas
variables que se definan de dicho tipo slo podrn tomar uno de los siete
valores especificados.
Posteriormente la definicin de la variable diasemana se realiza de la
siguiente forma:
enum dia diasemana;
0
1
3
4
5
6
En esta segunda declaracin los valores que tomarn las constantes son:
silla
mesa
puerta
escalera
armario
0
1
100
101
102
369
Los nicos operadores que pueden acompaar a los tipos enumerados son el
operador de asignacin y los de relacin.
EJEMPLO
370
Programacin en C
condiciones que puedan haber surgido como resultado de clculos internos anteriores.
Desde esta perspectiva se aconseja el uso de variables de enumeracin dentro de un
programa complejo. No obstante, debe quedar claro que se pueden usar variables
enteras en lugar de variables de enumeracin. Por lo tanto, las variables de
enumeracin, a parte de facilitar la codificacin y la legibilidad de los programas, no
proporcionan nuevas capacidades.
EJEMPLO
371
372
Programacin en C
Donde tipo es cualquier tipo de datos legal, y nombre el alias. El nuevo nombre
es una adicin a los tipos de existentes, no una sustitucin de stos.
Adems, es posible utilizar distintos nombres para un mismo tipo de dato,
pudindose usar la construccin typedef tambin para los tipos de datos complejos
y compuestos.
EJEMPLO
Con esta definicin no se ha creado un tipo nuevo sino que se emplea otro
nombre para un tipo de dato ya existente que sigue estando activo.
EJEMPLO
373
Puede utilizarse typedef para definir un tipo de dato importe para ser
utilizado con variables que representan importes, de la siguiente forma:
typedef float importe;
374
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
Programacin en C
32.
33.
Declarar una variable estructura llamada t de tipo equipo. Iniciar t con los
siguientes valores:
nombre: Osos de Chicago.
ganados: 4.
perdidos: 2.
porcentaje: 87.5.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
375
1
2
376
Programacin en C
mi
fa
sol
la
si
57.
58.
3
4
5
6
7
1
15
10
25
50
100
59.
60.
61.
378
Programacin en C
379
380
Programacin en C
Como claves tpicas ms utilizadas estn los cdigos de identificacin, tales como,
nmero de matrcula de un alumno, nmero de empleado, nmero de cliente...
13.1.1.2. Registro fsico o bloque
Un registro fsico o bloque es la cantidad ms pequea de datos que pueden
transferirse en una operacin de entrada/salida entre la memoria central del ordenador
y sus dispositivos perifricos o viceversa.
13.1.1.3. Factor de bloqueo
El factor de bloque es el nmero de registros lgicos que puede contener un registro
fsico o bloque. Se pueden dar las situaciones que se recogen en la Tabla 13.1.
Relacin entre registro lgico y
Factor de bloqueo
Denominacin
bloque
Registro lgico > Registro fsico Factor de bloqueo < 1
Registros expandidos
Un registro lgico ocupa varios
bloques
Registro lgico = Registro fsico Factor de bloqueo = 1
Registros no bloqueados
Registro lgico < Registro fsico Factor de bloqueo > 1
Registros bloqueados
Un bloque contiene varios
registros lgicos
Tabla 13.1. Posibilidades del factor de bloqueo
900.000x10ms = 9.000.000ms = 9.000s = 2,5 horas (ya que 1 hora son 3.600 segundos)
381
Figura 13.3), y, por tanto, el aumento del bloque implicara el aumento de la memoria
intermedia y, por consiguiente, se reducira el tamao de la memoria central.
En el caso de computadoras personales, el bloque suele tener el tamao de un
sector del disco (512 bytes).
EJEMPLO
Cadena (20)
Cadena (30)
Cadena (45)
Numrico entero
20 bytes
30 bytes
45 bytes
2 bytes
382
Programacin en C
Figura 13.4. Smbolos en los diagramas de flujo para los soportes direccionables y secuenciales
Registro 1
Registro 2
Registro n-1
Registro n
Fin de archivo
Registro final-1
Registro final
Figura 13.5. Organizacin secuencial
383
384
Programacin en C
385
3.
386
Programacin en C
El sistema de entrada y salida de alto nivel de este lenguaje ofrece una interfaz
independiente del dispositivo, apoyado en la existencia de streams (flujos).
Sea cual sea el dispositivo fsico donde se quiere escribir o leer, el sistema de
ficheros ANSI lo transforma en un dispositivo lgico, llamado stream. El dispositivo
fsico es el archivo y el dispositivo lgico es el stream.
El programador siempre escribe en el stream. El sistema de entrada y salida es el
que se encarga de escribir en el archivo.
Existen dos tipos de streams: binarios y de texto.
Los streams binarios son una secuencia de bytes que mantienen una
correspondencia biunvoca con lo que aparece en el dispositivo fsico. No existe
traduccin de uno a otro.
Los archivos creados con streams binarios (llamados ficheros binarios) tendrn las
siguientes caractersticas:
Los datos son almacenados en disco en el mismo formato en que se
almacenan en la memoria central del ordenador. No existe conversin
alguna.
Slo pueden ser creados, visualizados y modificados por un programa que
se codifique particularmente para ellos.
Los streams de texto son una secuencia de caracteres. No tiene que haber
correspondencia entre los caracteres del stream y los que aparecen en el dispositivo.
Puede ser necesaria una traduccin de ciertos caracteres, dependiendo del entorno.
Los archivos creados con streams de texto (llamados ficheros de texto), tendrn las
siguientes caractersticas:
Estn constituidos por una secuencia indefinida de caracteres ASCII.
Puede existir una conversin o transformacin de datos de cmo son
almacenados en memoria y cmo son grabados en el fichero.
Pueden ser creados, visualizados y modificados por un editor de texto.
EJEMPLO
387
388
Programacin en C
Prototipo:
Archivo cabecera:
Argumentos:
Valor devuelto:
Finalidad:
Se fp un puntero a FILE.
FILE *fp;
A la hora de crear un fichero se deben respetar las normas, con respecto a los
nombres de los archivos, impuestas por el sistema operativo que se est ejecutando en
el ordenador, as como tener en cuenta la correcta utilizacin del carcter \ cuando
fuera necesario utilizarlo.
3
389
Programa
Fichero
Finalidad:
390
Programacin en C
Archivo cabecera:
Argumentos:
Valor devuelto:
Finalidad:
391
stdio.h
El argumento c es el carcter a escribir.
Puntero de tipo FILE correspondiente al fichero que se est tratando.
Retorna el carcter escrito si tiene xito. En caso de fracaso retorna
EOF.
Escribe un carcter en un stream.
Tabla 13.7. Funcin fputc()
EJEMPLO
Ejemplo de ejecucin:
Introduzca una frase: Nosotros, los Programadores de C
EJEMPLO
392
Programacin en C
Valor devuelto:
Finalidad:
EJEMPLO
393
funcin.
Prototipo:
Archivo cabecera:
Argumentos:
Valor devuelto:
Finalidad:
394
Programacin en C
Ejemplo de ejecucin:
Nmero
Cadena
Nmero
Nmero
Cadena
Nmero
Nmero
Cadena
Nmero
entero: 125
de caracteres: JUAN
real: -0.537
entero: -768
de caracteres: ANTONIO
real: 1234.567
entero: 1355
de caracteres: FERNANDEZ
real: 0.0067
JUAN
-0.53
ANTONIO 1234.57
FERNANDEZ
0.01
395
Cada uno de los argumentos arg1, arg2, ..., argn, debe ser la direccin de
memoria de la variable donde se desea almacenar la informacin leda.
Se comporta de forma idntica que scanf(), pero con la diferencia de que
mientras que scanf() permite leer de teclado informacin formateada, fscanf()
est destinada a la lectura de ficheros de texto.
La cadena de control puede constar de:
Especificadores de formato, similares a los de la funcin scanf().
Caracteres separadores, son ignorados. Caracteres separadores son el
carcter espacio, tabulador, nueva lnea, retorno de carro, tabulador
vertical.
Caracteres ordinarios que no son espacios en blanco, dan lugar a que
se descarte un carcter igual del stream de entrada. Si no se encuentra, la
lectura concluir.
Al igual que en la funcin scanf(), los especificadores de formato pueden
incluir modificadores que especifiquen la longitud mxima del campo de entrada, o el
carcter asterisco (*) de supresin de asignacin en entrada.
EJEMPLO
396
Programacin en C
printf("Cadena: %s\n", cadena);
printf("Nmero real: %g\n", real);
}
fclose (fp);
Ejemplo de ejecucin:
Utilizando en entrada el archivo de texto C:\DATOS\LISTA.TXT
generado en el ejemplo anterior, la salida a pantalla del programa ser:
Nmero entero: 125
Cadena: JUAN
Nmero real: -0.53
Nmero entero: -768
Cadena: ANTONIO
Nmero real: 1234.57
Nmero entero: 1355
Cadena: FERNANDEZ
Nmero real: 0.01
"MADRID",
"AVILA",
"SORIA",
"CADIZ",
"BURGOS",
23,
22,
8,
25,
19,
1.7,
1.85,
1.04,
1.69,
1.8};
397
lista[i].st_nombre,
lista[i].st_provincia,
lista[i].st_edad,
lista[i].st_talla);
398
Programacin en C
lista[i].st_nombre,
lista[i].st_provincia,
lista[i].st_edad,
lista[i].st_talla);
399
*pnom,
*pprov,
*pedad,
*ptalla) {
if ( fscanf(f, "%[^*]%*c%[^*]%*c%[^*]%*c%[^\n]%*c",
pnom, pprov, x_edad, x_talla) == EOF )
return (EOF);
else { *pedad = atoi(x_edad);
*ptalla = atof(x_talla);
return 0;
}
}
400
Programacin en C
int
t_edad;
float t_talla;
char
char
int
float
*pnom,
*pprov,
*pedad,
*ptalla) {
401
if ( fscanf(f, "%[^\t]%*c%[^\t]%d%f%*c",
pnom, pprov, &t_edad, &t_talla) == EOF )
return (EOF);
else {
*pedad = t_edad;
*ptalla = t_talla;
return 0;
}
Columnas (longitud)
01 - 44 (44)
45 - 58 (14)
59 - 62 (04)
63 - 67 (05)
Tipo
Alfanumrico, justificado a la derecha
Alfanumrico, justificado a la derecha
Entero
Real
402
Programacin en C
int cuantos = 0;
int edad;
float talla;
float media_edad = 0, media_talla = 0;
char nombr[45];
char provin[15];
...
while (leer_encolumnado(fp, nombr, provin, &edad, &talla)!=EOF) {
media_edad += edad;
media_talla += talla;
cuantos++;
}
media_edad /= cuantos;
media_talla /= cuantos;
...
int leer_encolumnado(FILE *f,
char
char
int
float
*pnom,
*pprov,
*pedad,
*ptalla) {
int
t_edad;
float t_talla;
if ( fscanf(f, "%44[^\t]%14[^\t]%4d%5f%*c",
pnom, pprov, &t_edad, &t_talla) == EOF )
return (EOF);
else {
recortarizq (pnom);
recortarizq (pprov);
*pedad = t_edad;
*ptalla = t_talla;
return 0;
}
}
void recortarizq (char *cad) {
/* Elimina los espacios por la izquierda de la cadena del
argumento, generando, por tanto, una cadena de longitud menor a la
recibida, o como mucho igual, en caso de que la cadena recibida no
contenga espacios por la izquierda */
const char ESPACIO = '\x20';
long k;
while (cad[0] == ESPACIO) {
k = 0;
while (cad[k] != '\0') {
cad[k] = cad[k+1];
k++;
}
}
}
403
404
Programacin en C
Valor devuelto:
Finalidad:
Prototipo:
Archivo cabecera:
Argumentos:
Valor devuelto:
Finalidad:
405
La funcin fseek() fija la posicin de acceso del stream con el objeto de realizar
operaciones de entrada y salida directa. En la Tabla 13.15 se resumen los datos
fundamentales necesarios para el uso de esta funcin.
Prototipo:
Archivo cabecera:
Argumentos:
Valor devuelto:
Finalidad:
Valor devuelto:
Finalidad:
406
Programacin en C
Valor devuelto:
Finalidad:
void main() {
int m1[DIM][DIM], m2[DIM][DIM];
char nombre[50];
/* Se introduce la matriz por teclado */
IntroduceTeclado(m1, DIM);
/* Se guardan los elementos de la matriz en un fichero binario */
puts("\nIntroduce el nombre del fichero.\n");
gets(nombre);
GuardaFichero(m1, nombre, DIM);
/* Se leen los datos de la matriz del fichero */
LeeFichero(m2, nombre, DIM);
/* Se presentan los datos por pantalla */
MuestraMatriz(m2, DIM);
}
void IntroduceTeclado(int m[][DIM], int lim) {
int j, i=0;
for(;i<lim;i++)
for(j=0;j<lim;j++) {
printf("\nElemento (%d, %d): ", i+1, j+1);
scanf("%d", &m[i][j]);
}
fflush(stdin);
}
void GuardaFichero(int m[][DIM], char *nombre, int lim) {
FILE *fich;
int j, i=0;
/* Se crea el fichero binario */
407
if ( (fich=fopen(nombre, "w"))==NULL) {
printf("\nERROR AL CREAR EL FICHERO %s !!!!\n", nombre);
exit(-1);
}
/* Si no ha habido problemas se escriben los datos */
for(;i<lim;i++)
for(j=0;j<lim;j++)
fwrite(&m[i][j], sizeof(int), 1, fich);
/* Se cierra el fichero */
fclose(fich);
}
void LeeFichero(int m[][DIM], char*nombre, int lim) {
FILE *fich;
int j, i=0;
/* Se abre el fichero binario para lectura*/
if ((fich=fopen(nombre, "r"))==NULL) {
printf("\nERROR AL ABRIR EL FICHERO %s !!!!\n", nombre);
exit(-1);
}
/* Si no ha habido problemas se leen los datos */
for (;i<lim;i++)
for(j=0;j<lim;j++)
fread(&m[i][j], sizeof(int), 1, fich);
fclose(fich);
}
void MuestraMatriz(int m[][DIM], int lim) {
int j, i=0;
for (;i<lim;i++) {
for (j=0;j<lim;j++)
printf("%10d", m[i][j]);
printf("\n");
}
}
EJEMPLO
408
Programacin en C
printf("%4x ", car);
if (car > 31)
*(cadena+i)=car;
else
*(cadena+i)='';
/* Carcter no imprimible */
}
*(cadena+i) = '\0';
printf("
%s\n", cadena);
} while (eof == FALSO);
fclose(fich);
EJEMPLO
409
410
Programacin en C
OrdenaIndice(nproductos, idx);
fwrite(idx, sizeof(struct Indice), nproductos, fich_idx);
fclose(fich);
fclose(fich_idx);
411
strcpy(idx[j].cod, p.cod);
*np += 1;
idx[j].pos = *np;
fclose(fich);
412
2.
3.
4.
5.
6.
7.
8.
9.
Programacin en C
414
Programacin en C
415
En este ejemplo se van a declarar dos variables puntero, una a entero y otra a
real. Se reserva espacio para crear dos variables dinmicas, cada una de ellas
apuntada por un puntero (tamao representa el operador que devuelve el
nmero de bytes que ocupa un tipo de dato).
Estas variables dinmicas no tienen nombre, y la nica forma de acceder a
ellas es a travs de los respectivos punteros que las apuntan.
Se utilizan para almacenar dos datos que se leen de teclado y posteriormente
se presenta la suma de los datos introducidos.
Antes de finalizar se libera el espacio de memoria reservado anteriormente.
/* -- Declaraciones -- */
puntero a entero pt1
puntero a real pt2
...
Nombre
variable
Direccin
comienzo
Direcciones
de memoria
libres
Direcciones de
memoria
crecientes
pt1
FFB4
pt2
FFB2
416
Programacin en C
pt1 reservar(tamao(entero))
pt2 reservar(tamao(real))
leer (pt1)
Nombre
leer (pt2)
variable
escribir (pt1 + pt2)
liberar (pt1)
liberar (pt2)
Direccin
comienzo
5.14
FFEA
FFE8
pt1
FFB4
pt2
FFB2
FFE8
FFEA
Valor devuelto:
Finalidad:
Direcciones de
memoria
crecientes
417
EJEMPLO
EJEMPLO
418
Programacin en C
Prototipo:
Archivo cabecera:
Argumentos:
Valor devuelto:
Finalidad:
EJEMPLO
EJEMPLO
Valor devuelto:
Finalidad:
419
EJEMPLO
EJEMPLO
Valor devuelto:
Finalidad:
420
Programacin en C
EJEMPLO
421
Se ha definido el vector a (lnea 6): como int *a, es decir, como puntero a
entero.
No se trata de un puntero a un entero, sino de un puntero a una secuencia de
enteros. Ambos conceptos son equivalentes en C, pues ambos son meras
direcciones de memoria.
La variable a es un vector dinmico de enteros, pues su memoria se obtiene
dinmicamente, esto es, en tiempo de ejecucin y segn convenga a las
necesidades. No se conoce an cuntos enteros sern apuntados por a, ya que
el valor de talla no se conocer hasta que se ejecute el programa y se lea
por teclado.
La lnea 10 reserva memoria para talla enteros y guarda en a la direccin
de memoria en la que empiezan esos enteros.
Si el usuario decide que talla valga, por ejemplo, 5, se reservar un total
de 20 bytes y la memoria quedar as tras ejecutar la lnea 10:
422
Programacin en C
423
reservada. De ello se encarga la lnea 15. Dicha lnea est en un bucle, as que se
ejecuta para m[0], m[1], m[2], ... El efecto es proporcionar un bloque de
memoria para cada celda de m. He aqu el efecto final:
Cmo se usa m ahora? Pues cmo cualquier matriz! Pero, qu ocurre cuando se
accede a m[1][2]. Analcese m[1][2] de izquierda a derecha. Primero se tiene m,
que es un puntero (tipo double**), o sea, un vector dinmico a elementos del
tipo double*. El elemento m[1] es el segundo componente de m, y de qu tipo es?
De tipo double*, un nuevo puntero o vector dinmico, pero a valores de tipo
double. Si es un vector dinmico, se puede indexar, as que es vlido escribir
m[1][2], y de qu tipo es esta expresin? De tipo double, como se muestra a
continuacin.
m es de tipo double **.
m[1] es de tipo double *.
m[1][2] es de tipo double.
424
Programacin en C
Resta la liberacin de memoria. Obsrvese que hay una llamada a free() por cada
llamada a malloc() realizada con anterioridad (lneas 2023). Se ha de liberar cada
uno de los bloques reservados y se ha de empezar a hacerlo por los de segundo nivel,
es decir, por los de la forma m[i]. Si se comenzara liberando m, se cometera un
grave error: si se libera m antes que todos los m[i], se perdera el puntero que los
referencia y, en consecuencia, no podran ser liberarlos!
EJEMPLO
EJEMPLO
425
printf("\n");
}
EJEMPLO
426
Programacin en C
Debe recordarse que los parntesis deben estar presentes, sino sera sendas
matrices de punteros. ste es el caso de la declaracin int *pt1[N] que
representa una matriz de punteros, en estos casos debe ser de una dimensin
menor que la matriz multidimensional.
En trminos generales, una matriz bidimensional, que es este caso, se puede
definir como una matriz unidimensional de punteros escribiendo:
tipo-dato *puntero[TAM1];
Que corresponde con el espacio necesario para almacenar las N filas por M
columnas.
La matriz resultante de la multiplicacin se declara igual que en los dos
primeros ejemplos estudiados con matrices dinmicas, ella representa una
matriz dinmica de matrices dinmicas (int **pt3). Notar que la reserva
y comprobacin de memoria se hace de forma similar a los ejemplos
estudiados, pero en este caso utilizando calloc().
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N
100
#define M
100
void main(void) {
int *pt1[N],(*pt2)[M],**pt3,i,j,k;
427
clock();
for(i=0;i<N;i++)
if(NULL==(pt1[i]=(int *)calloc(M,sizeof(int)))){
for(j=i-1;j>=0;j--) free(pt1[j]);
printf("\nError al reservar memoria 1...");
exit(0);
}
if(NULL==(pt2=(int (*)[M])calloc(N,sizeof(int[M])))) {
for(j=N-1;j>=0;j--) free(pt1[j]);
printf("\nError al reservar memoria 2...");
exit(0);
}
if(NULL==(pt3=(int **)calloc(N,sizeof(int **)))) {
for(j=N-1;j>=0;j--) free(pt1[j]);
free(pt2);
printf("\nError al reservar memoria 3...");
exit(0);
}
for(i=0;i<N;i++)
if(NULL==(pt3[i]=(int *)calloc(M,sizeof(int)))) {
for(j=N-1;j>=0;j--) free(pt1[j]);
free(pt2);
for(j=i-1;j>=0;j--) free(pt3[j]);
free(pt3);
printf("\nError al reservar memoria 4...");
exit(0);
}
srand((int)clock());
for(i=0;i<N;i++)
for(j=0;j<M;j++) {
pt1[i][j]=rand();
pt2[i][j]=rand();
}
for (i=0;i<N;i++)
for(j=0;j<M;j++) {
pt3[i][j]=0;
for(k=0;k<M;k++)
pt3[i][j]+=pt1[i][k]*pt2[k][j];
}
for(i=0;i<N;i++) {
for(j=0;j<M;j++)
printf("%d ",pt3[i][j]);
printf("\n");
}
for(i=0;i<N;i++) {
free(pt1[i]);
free(pt3[i]);
}
free(pt2);
free(pt3);
}
428
Programacin en C
429
430
Programacin en C
NULL
Principio
Fin
La flecha representa
estar apuntando a
431
NULL
Principio
Fin
Figura 14.2. Lista enlazada representacin grfica tpica
Obsrvese que el campo de enlace del primer nodo apunta al segundo nodo, y el
campo de enlace del segundo apunta al tercero, y as sucesivamente. El campo de
enlace del quinto nodo contiene NULL. Esto indica que el quinto nodo constituye el
fin de la lista enlazada y no apunta a ningn otro. La Figura 14.3 muestra diferentes
representaciones grficas que se utilizan para dibujar el campo enlace del ltimo
nodo.
A
NULL
432
Programacin en C
los dems nodos (*, -, +) hecho ste, que en muchos casos facilita el trabajo con
listas enlazadas. Un ejemplo de lista con nodo de cabecera se muestra en la Figura
14.4.
*
Pepe
Susy
NULL
Lul
Principio
Figura 14.4. Ejemplo de lista con nodo de cabecera
Para el caso de las listas sin nodo de cabecera, se usar la expresin primero para
referenciar al primer nodo de la lista, y primero->elemento y primero->siguiente para
hacer referencia al dato almacenado y al enlace al siguiente nodo respectivamente. En
el caso de las listas con nodo de cabecera el primero de la lista ser el que aparezca a
continuacin del mismo.
En ocasiones, se mantiene tambin un puntero al ltimo nodo de la lista (cola de la
lista), recibiendo el nombre de puntero cola.
Si la lista est vaca se asigna el puntero NULL a la cabeza y la cola, en caso
contrario para hacer cualquier recorrido de la lista, la posicin actual se referencia por
un puntero.
Pablo
Pepe
Susy
NULL
Lul
Ptr_cabeza
Ptr_cola
Figura 14.5. Punteros de cabeza y de cola
47
69
80
95
NULL
433
47
69
80
95
47
69
80
95
Para cada uno de estos tipos de estructuras de lista, se puede elegir una
implementacin basada en matrices (asignacin esttica) o basada en punteros
(asignacin dinmica), que como ya se ha comentado difieren en el modo en que se
asigna la memoria para los datos de los elementos, cmo se enlazan juntos los
elementos y cmo se accede a dichos elementos.
434
Programacin en C
Entonces si se necesita cambiar el tipo de datos en los nodos, slo tendr que
cambiar la sentencia de declaracin de tipos que afecta a elemento. Siempre que
una funcin necesite referirse al tipo del dato del nodo, puede utilizar el nombre
elemento.
Cada puntero a Nodo debe ser declarado como una variable puntero. Por ejemplo,
si se mantiene una lista enlazada con un puntero de cabecera y otro de cola, se deben
declarar dos variables puntero:
struct Nodo *ptr_cabeza;
struct Nodo *ptr_cola;
435
Al igual que con cualquier objeto, se puede acceder a los dos miembros de
*ptr_cabeza. La sentencia siguiente puede utilizarse para escribir los datos del
nodo cabecera.
printf (%lf, (*ptr_cabeza).dato);
NULL
Principio
Fin
Figura 14.4. Lista de caracteres
436
Programacin en C
Se comienza por el caso ms sencillo, suponiendo que los nodos ya estn creados y
que slo sera necesario hacer el encadenamiento de datos.
Se inicializan los nodos a un valor nulo (ver Figura 14.5) lo que implica que la lista
est vaca (no tiene elementos).
x.siguiente = y.siguiente = z.siguiente = NULL;
x
A
y
NULL
z
NULL
NULL
En la estructura hay un campo para almacenar datos y otro para hacer conexiones.
La asignacin de valores se realiza con las siguientes instrucciones:
x.dato = 'A';
y.dato = 'B';
z.dato = 'C';
El campo de enlace permite acceder al siguiente elemento hasta llegar a una marca
de final convenida.
x.siguiente -> dato es 'B'
x.siguiente -> siguiente -> dato es 'C'
Como sera muy poco til usar variables diferentes para manejar estructuras
dinmicas, se va a utilizar otra variante del algoritmo, considerando que:
El final de la lista se marca asignando el valor nulo al campo puntero del
ltimo elemento.
Se manejan dos punteros auxiliares para poder acceder al primer
elemento y al ltimo.
Se usa una variable genrica para representar los elementos de la lista.
Se considera ahora que un elemento de la lista se puede definir con la ayuda de la
estructura siguiente, que a diferencia del campo datos de la estructura anterior, que
reservaba espacio para un carcter, es ms general:
# define NULL 0
typedef char TIPO_DATOS;
struct lista {
TIPO_DATOS dato;
struct lista *siguiente;
};
typedef struct lista ELEMENTO;
typedef ELEMENTO *ENLACE;
ENLACE nodo, principio, fin;
El puntero principio y fin se inicializan a un valor nulo lo que implica que la lista
est vaca (no tiene elementos).
Se crean los nodos de forma dinmica (cada vez que se necesiten), asignndoles en
tiempo de ejecucin posiciones de memoria no utilizadas, para ello hay que reservar
tanta memoria como tamao tiene cada nodo, y asignar la direccin de la memoria
reservada al puntero nodo:
nodo = (ELEMENTO *) malloc( sizeof (ELEMENTO) ); (1)
437
Figura 14.6.
(1)
(2)
(3)
NULL
(4)
NULL
A
Principio
Fin
Figura 14.6. Definicin del primer elemento de la lista
NULL
NULL
NULL
NULL
Principio
Fin
(6)
A
Principio
Fin
A
(7)
Principio
Figura 14.7. Aadir un nuevo nodo
Fin
438
Programacin en C
Para continuar estudiando el resto de las operaciones con listas enlazadas en primer
lugar se gestionar una lista directamente, desde un programa principal, centrando la
atencin en la realizacin de una serie de acciones que parten de un estado de la lista
y la dejan en otro estado diferente. Se ilustrar cada una de las acciones mostrando
con todo detalle qu ocurre paso a paso. Seguidamente se encapsular cada accin
elemental (aadir elemento, borrar elemento, etc.) en una funcin independiente.
Se va a crear una lista de enteros. Se comienza por definir el tipo de registro que
compone la lista:
struct Nodo {
int info;
struct Nodo * sig;
};
439
int main(void ) {
struct Nodo * lista = NULL;
if (lista != NULL)
lista = (Nodo *) malloc(sizeof (struct Nodo ));
...
Siendo el resultado:
lista
He aqu el resultado:
8
lista
440
Programacin en C
...
441
aux
8
lista
La lnea 10, (lista->info = 3), asigna al campo info del nuevo nodo
(apuntado por lista) el valor 3:
aux
3
lista
lista
442
Programacin en C
Ahora, se puede declarar una lista como struct Nodo* o como TipoLista,
indistintamente. Por comodidad, se hace referencia al tipo de una lista con
TipoLista y al de un puntero a un nodo cualquiera con struct Nodo*, ambos
tipos son equivalentes.
Creacin de lista vaca
La primera funcin crear una lista vaca. El prototipo de la funcin, que se declara en
el fichero cabecera lista.h, es ste:
TipoLista lista_vacia(void );
elegante proporcionar funciones para cada una de las operaciones bsicas que ofrece
una lista, y crear una lista vaca es una operacin bsica.
Lista vaca?
Vendra bien disponer de una funcin que devuelva cierto o falso en funcin de si la
lista est vaca o no. El prototipo de la funcin es:
int es_lista_vacia(TipoLista lista);
443
Impresin en pantalla
No resulta en absoluto difcil disear una funcin que muestre el contenido de una
lista en pantalla. El prototipo es ste:
void muestra_lista(TipoLista lista);
444
Programacin en C
int elemento;
LISTA *q,*p;
do {
printf("\n Introduzca elemento: ");
scanf (" %d,&elemento);
if(elemento != 0)
p=(LISTA *) malloc(sizeof(LISTA));
if (primero == NULL)
primero=p;
else
q->enlace=p;
p->dato=elemento;
p->enlace=NULL;
q=p;
} while(elemento != 0);
printf("\nLa nueva lista enlazada es: ");
mostrar_lista(primero);
}
void mostrar_lista(LISTA *ptr) {
while(ptr != NULL) {
printf("%d",ptr->dato);
ptr = ptr->enlace;
}
printf("\n");
}
Ejemplo de ejecucin:
Introduzca elemento: 1
Introduzca elemento: 3
Introduzca elemento: 5
Introduzca elemento: 7
Introduzca elemento: 9
Introduzca elemento: 0
La nueva lista enlazada es: 13579
Presione otra tecla para continuar
445
4.
En la variable puntero anterior tener la direccin del nodo que est antes
de la posicin deseada para el nuevo nodo. Hacer que anterior->siguiente
apunte al nuevo nodo que se acaba de crear.
Si se desea insertar en una posicin exacta p lo que implica insertar antes.
Si la lista tiene nodo ficticio se puede insertar al comienzo de la lista sin
necesidad de alterar la variable posicin que la mantiene.
Si no tiene nodo ficticio:
Es preciso pasar por referencia la direccin de comienzo de la
lista.
Se debe comprobar si la posicin p coincide con el comienzo
de la lista para cambiar la direccin de comienzo.
En cualquier de los dos casos, al menos en principio, es necesario buscar el nodo
anterior al referenciado para poder insertar antes.
14.4.3.3. Insercin por la cola
Se tiene un nuevo objetivo. Se va intentar aadir un nuevo nodo al final de la lista. Es
decir, partiendo de la ltima lista:
3
lista
446
Programacin en C
Se ver cmo queda la memoria paso a paso. Tras ejecutar la lnea 6 se tiene la
siguiente configuracin:
aux
3
lista
O sea, la lista que cuelga de lista sigue igual, pero ahora aux apunta a un nuevo
nodo. Si se pasa a estudiar la lnea 9 (lista->sig->sig = aux), si lista es un
puntero, y lista->sig es el campo sig del primer nodo, que es otro puntero,
entonces lista->sig->sig es el campo sig del segundo nodo, que es otro puntero.
Si a ese puntero se le asigna aux, el campo sig del segundo nodo apunta a donde
apunta aux.
aux
3
lista
aux
lista
lista
lista
2.
Pedir un nodo nuevo y mantenerlo apuntado con otro puntero auxiliar, dgase
nuevo.
aux
3
lista
nuevo
3.
Escribir en el nodo apuntado por nuevo el nuevo dato y hacer que su campo
sig apunte a NULL.
aux
lista
nuevo
3
2
4.
447
Hacer que el nodo apuntado por aux tenga como siguiente nodo al nodo
apuntado por nuevo.
aux
3
lista
nuevo
nuevo
Se va a disear ahora una funcin que inserte un nodo al final de una lista. Su
prototipo sera:
TipoLista inserta_por_cola(TipoLista lista, int valor);
Dicha funcin se dividir en dos etapas: una primera que localice al ltimo
elemento de la lista, y otra que crea el nuevo nodo y lo une a la lista.
La primera etapa sera:
TipoLista inserta_por_cola(TipoLista lista, int valor) {
struct Nodo * aux;
for (aux = lista; aux->sig != NULL; aux = aux->sig);
...
}
Se puede analizar paso a paso el bucle con un ejemplo. Imaginase que la lista que
contiene lista ya tiene tres nodos:
448
Programacin en C
lista
La primera iteracin del bucle hace que aux apunte al primer elemento de la lista:
aux
lista
10
aux
lista
449
Est claro que ha funcionado correctamente. Tal vez resulte de ayuda ver la misma
estructura reordenada as:
nuevo
aux
lista
10
EJEMPLO
450
Programacin en C
p1 = *ptr;
if(p1 == NULL) {
p1 = (LISTA *) malloc(sizeof(LISTA));
if (p1 != NULL) {
p1->dato = elemento;
p1->enlace = NULL;
*ptr = p1;
}
}
else {
while(p1->enlace != NULL)
p1 = p1->enlace;
p2 = (LISTA *) malloc(sizeof(LISTA));
if (p2 != NULL) {
p2->dato = elemento;
p2->enlace = NULL;
p1->enlace = p2;
}
}
}
Ejemplo de ejecucin:
Introduzca
Introduzca
Introduzca
Introduzca
elemento: c
elemento: p
elemento: u
elemento:'\r'
EJEMPLO
void main() {
LISTA *primero = NULL;
char elemento;
do {
printf("\nIntroduzca elemento: ");
elemento = getchar();
if(elemento != '\t')
insertar(&primero, elemento);
} while(elemento != '\t');
printf("\nLa nueva lista enlazada es: ");
mostrar_lista(primero);
insertar_al_principio(&primero,'s');
printf("La nueva lista enlazada es: \n");
mostrar_lista(primero);
insertar_al_final(primero,'m');
printf("La nueva lista enlazada es: ");
mostrar_lista(primero);
}
void mostrar_lista(LISTA *ptr) {
while(ptr != NULL) {
printf("%c",ptr->dato);
ptr = ptr->enlace;
}
printf("\n");
}
void insertar_al_principio(LISTA **ptr, char item) {
LISTA *nuevo;
nuevo = (LISTA *)malloc(sizeof(LISTA));
if(nuevo != NULL) {
nuevo->dato = item;
nuevo->enlace = *ptr;
*ptr = nuevo;
}
}
void insertar_al_final(LISTA *ptr, char item) {
LISTA *nuevo;
while(ptr->enlace != NULL)
ptr = ptr->enlace;
nuevo = (LISTA *)malloc(sizeof(LISTA));
if(nuevo != NULL) {
ptr->enlace = nuevo;
nuevo->dato = item;
nuevo->enlace = NULL;
}
}
void insertar(LISTA **ptr, char elemento) {
LISTA *p1, *p2;
p1 = *ptr;
if(p1 == NULL) {
p1 = (LISTA *)malloc(sizeof(LISTA));
if (p1 != NULL) {
p1->dato = elemento;
p1->enlace = NULL;
*ptr = p1;
}
}
else {
while(p1->enlace != NULL)
p1 = p1->enlace;
451
452
Programacin en C
p2 = (LISTA *)malloc(sizeof(LISTA));
if(p2 != NULL) {
p2->dato = elemento;
p2->enlace = NULL;
p1->enlace = p2;
}
}
}
Ejemplo de ejecucin:
Introduzca elemento: c
Introduzca elemento: a
Introduzca elemento: t
Introduzca elemento:'\r'
La nueva lista enlazada es: cat
La nueva lista enlazada es: scat
La nueva lista enlazada es: scatm
3
0
8
1
Y su implementacin:
453
454
Programacin en C
d'
d'
Lista nueva
lista
Vuelve al
almacenamiento libre
455
Se va a aprender ahora a borrar elementos de una lista. Se comienza por ver cmo
eliminar el primer elemento de una lista. El objetivo es, partir de esta lista:
lista
lista
puede ejecutarse! Tan pronto como se ha ejecutado la lnea 6, se tiene otra fuga de
memoria:
lista
456
Programacin en C
1 int main(void )
2 {
3 struct Nodo * lista = NULL, * aux, * nuevo;
4
5 ...
6 aux = lista->sig;
7 free(lista);
8 lista = aux;
9
10 return 0;
11 }
Se va a ver paso a paso qu hacen las ltimas tres lneas del programa.
La asignacin aux = lista->sig introduce una referencia al segundo nodo:
aux
lista
Y su implementacin:
TipoLista borra_cabeza(TipoLista lista) {
struct Nodo * aux;
if (lista != NULL) {
aux = lista->sig;
free(lista);
lista = aux;
}
return lista;
}
457
aux
3
lista
Y en la segunda iteracin:
aux
atrs
lista
Y en la tercera:
aux
atrs
3
lista
No importa cun larga sea la lista; el puntero atras siempre va un paso por detrs
del puntero aux. En el ejemplo presentado ya se ha llegado al final de la lista, as que
ahora se puede liberar el nodo apuntado por aux:
atrs
lista
aux
8
458
Programacin en C
aux
8
Esta funcin ser satisfactoria incluso si la lista est compuesta por un solo
elemento.
EJEMPLO
459
460
Programacin en C
mostrar_lista(primero);
printf("\nIntroduzca un carcter a buscar en la lista:\n");
fflush(stdin);
item = getchar();
encontrado = buscar_en_lista(primero,item);
printf("\nEl caracter %c ",item);
encontrado ? printf(" ha ") : printf(" no ha ");
printf("sido encontrado en la lista: ");
mostrar_lista(primero);
}
void mostrar_lista(LISTA *ptr) {
printf("\n");
while(ptr != NULL) {
printf("%c",ptr->dato);
ptr = ptr->enlace;
}
}
int buscar_en_lista(LISTA *ptr, char item) {
if(ptr == NULL)
return(0);
else {
do {
if(ptr->dato == item)
return(1);
ptr = ptr->enlace;
} while(ptr != NULL);
return(0);
}
}
void insertar(LISTA **ptr, char elemento) {
LISTA *p1, *p2;
p1 = *ptr;
if(p1 == NULL) {
p1 = (LISTA *)malloc(sizeof(LISTA));
if (p1 != NULL) {
p1->dato = elemento;
p1->enlace = NULL;
*ptr = p1;
}
}
else {
while(p1->enlace != NULL)
p1 = p1->enlace;
p2 = (LISTA *)malloc(sizeof(LISTA));
if(p2 != NULL) {
p2->dato = elemento;
p2->enlace = NULL;
p1->enlace = p2;
}
}
}
461
462
Programacin en C
EJEMPLO
463
464
Programacin en C
define un tipo para poner nfasis en que un puntero representa a la lista que cuelga de
l.
typedef struct DNodo * TipoDLista ;
Puede observarse que cada nodo tiene dos punteros, uno al nodo anterior y otro al
siguiente. Qu nodo sigue al ltimo nodo? Ninguno, o sea, NULL. Y cul antecede
al primero? Ninguno, es decir, NULL.
Se vern una operacin de insercin y otra de supresin para ilustrar los problemas
que se pueden plantear.
465
lista
lista
lista
466
Programacin en C
lista
3
0
2
2
lista
467
nuevo
nuevo
nuevo
5. Se hace que el nodo anterior a aux tenga como siguiente a nuevo, es decir,
aux->ant->sig = nuevo.
468
Programacin en C
aux
lista
nuevo
6. Slo resta que el nodo anterior a aux sea nuevo con la asignacin
aux->ant=nuevo.
aux
lista
nuevo
469
1.
2.
lista
aux
lista
4.
3.
aux
Y se pone el campo sig del que hasta ahora era el penltimo nodo (el
apuntado por atras) a NULL.
atrs
lista
aux
470
Programacin en C
El caso de la lista vaca tiene fcil solucin, no hay nada que borrar. Es ms
problemtica la lista con slo un nodo. El problema con ella estriba en que no hay
elemento penltimo (el anterior al ltimo es NULL). Se tiene, pues, que detectar esta
situacin y tratarla adecuadamente.
TipoDLista borra_por_cola(TipoDLista lista) {
struct struct DNodo * aux, * atras;
/* Lista vaca */
if (lista == NULL)
return lista;
/* Lista con un nodo */
if (lista->sig == NULL) {
free(lista);
lista = NULL;
return lista;
}
/* Caso general */
for (aux=lista; aux->sig!=NULL; aux=aux->sig);
atras = aux->ant;
free(aux);
atras->sig = NULL;
}
2. Se hace que el nodo que sigue al anterior de aux sea el siguiente de aux. O
sea, se hace aux->ant->sig=aux->sig.
aux
lista
471
3. Ahora se hace que el node que antecede al siguiente de aux sea el anterior a
aux. Es decir, aux->sig->ant=aux->ant.
aux
lista
Se ha de ser cautos. Hay un par de casos especiales que merecen ser tratados
aparte, el borrado del primer nodo y el borrado del ltimo nodo. Se va a estudiar
cmo proceder en el primer caso, se va a tratar de borrar el nodo de valor 3 en la lista
del ejemplo anterior.
1. Una vez apuntado el nodo por aux, se sabe que es el primero porque apunta
al mismo nodo que lista.
aux
lista
2.
Se hace que el segundo nodo deje de tener antecesor, es decir, que el puntero
aux->sig->ant valga NULL (que, por otra parte, es lo mismo que hacer
aux->sig->ant=aux->ant).
aux
lista
3.
4.
472
Programacin en C
1.
2.
Se hace que el siguiente nodo del que antecede a aux sea NULL, esto es
aux->ant->sig=NULL.
aux
lista
3.
473
14.6.2. Pila
Muchas operaciones computacionales se ven simplificadas por el uso de pilas y colas
controladas por software. Son estructuras de datos que almacenan y recuperan sus
elementos atendiendo a un estricto orden.
Una pila es una lista, con la restriccin de que las inserciones y las eliminaciones
slo se pueden realizar en una posicin: al final de la lista. Esta posicin final se
denominado tope o cima.
Una caracterstica de la pila es que el ltimo elemento que se introduce es siempre
el primer elemento que se saca. Por esta razn se conocen como estructuras de tipo
LIFO (Last In, First Out), esto es, existe algn elemento que est en la cima de la pila
y es el nico visible o accesible.
474
Programacin en C
tope
Elemento 7
Elemento 6
Elemento 5
Elemento 4
Elemento 3
Elemento 2
Elemento 1
Pila
475
476
Programacin en C
}
void mostrar_pila(PILA *ptr) {
while(ptr != NULL) {
printf("%c",ptr->dato);
ptr = ptr->enlace;
}
printf("\n");
}
int vacia(PILA *ptr) {
if(ptr == NULL)
return(1);
else
return(0);
}
void introducir(PILA **ptr, char item) {
PILA *p;
if(vacia(*ptr)) {
p = malloc(sizeof(PILA));
if(p != NULL) {
p->dato = item;
p->enlace = NULL;
*ptr = p;
}
}
else {
p = malloc(sizeof(PILA));
if(p != NULL) {
p->dato = item;
p->enlace = *ptr;
*ptr = p;
}
}
}
void extraer(PILA **ptr, char *item) {
PILA *p1;
p1 = *ptr;
if(vacia(p1)) {
printf("Error! La pila esta vacia.\n");
*item = '\0';
}
else {
*item = p1->dato;
*ptr = p1->enlace;
free(p1);
}
}
477
Ejemplo de ejecucin
La pila es como sigue: cba
El primer elemento obtenido es
b
a
14.6.3. Cola
Se trata de una lista en la que se establecen las siguientes restricciones en cuanto a las
operaciones de insercin y extraccin:
La insercin se realiza al final de la lista (fondo): encolar.
La eliminacin se realiza al comienzo de la lista (frente): desencolar.
As pues se trata de una lista de tipo FIFO (Firs In, First Out), primero en entrar,
primero en salir. En la Figura 14.13 se presenta grficamente una cola.
frente
fondo
Existen diferentes situaciones en las que son tiles las colas. En general, en toda
situacin en la que es necesario mantener una estructura FIFO. Ejemplos
significativos son las colas de impresin y de procesos de los sistemas operativos.
Las operaciones que generalmente incluye una cola son:
Crea_vaca(C)
o Inicia o crea la cola C como una cola vaca, sin ningn elemento.
Frente(C)
o Devuelve el valor del elemento del frente de la cola.
o No siempre se utiliza.
Desencola(C) o Saca(C)
o Suprime el elemento del frente o primer elemento de la cola,
pasando a ser el nuevo frente el siguiente elemento.
o Generalmente, adems de suprimir tambin se devuelve el valor
almacenado en esa posicin y no se utiliza la funcin antes vista.
Encola(x, C) o Pon_en_cola(x, C)
478
Programacin en C
cola
fondo
frente
10
Figura 14.14. Representacin grfica de una cola mediante una lista simplemente enlazada
EJEMPLO
479
encolar(&una_cola, 'b');
encolar(&una_cola, 'c');
printf("La cola es como sigue: ");
mostrar_cola(una_cola);
while (!vacia(una_cola)) {
item = desencolar(&una_cola);
printf("\nEl siguiente elemento obtenido de la cola es %c\n", item);
}
return (1);
}
void iniciar_cola(COLA *ptr)
{
ptr->frente = ptr->fondo = NULL;
}
void mostrar_cola(COLA cola)
{
NODO *ptr;
ptr=cola.frente;
while (ptr != NULL) {
printf("%c", ptr->dato);
ptr = ptr->enlace;
}
printf("\n");
}
int vacia(COLA cola)
{
if (cola.frente == NULL)
return (1);
else
return (0);
}
void encolar(COLA * ptr, char item)
{
NODO
*p;
p = (NODO *) malloc(sizeof(NODO));
if (p != NULL) {
p->dato = item;
p->enlace = NULL;
if (!vacia(*ptr)) {
ptr->fondo->enlace = p;
ptr->fondo = p;
} else
ptr->frente = ptr->fondo = p;
}
}
480
Programacin en C
Ejemplo de ejecucin
La cola es como sigue: cba
El primer elemento obtenido de la cola es a
El segundo elemento obtenido de la cola es b
El tercer elemento obtenido de la cola es c
14.7. Resumen
Se han presentado los conceptos bsicos relacionados con memoria dinmica
utilizando matrices y listas enlazadas.
Existen muchas estructuras dinmicas de datos que permiten acelerar sobremanera
los programas que gestionan grandes conjuntos de datos. Apenas se ha empezado a
conocer y aprender a manejar las herramientas ms elementales con las que se
construyen los programas que utilizan estas estructuras.
Se debe elegir entre representacin con matrices o representacin con punteros
(listas enlazadas, simples, dobles, circulares). La base en que se ha de sustentar la
eleccin debe tener en cuenta diversos factores, tales como:
Operaciones que se deben realizar.
Operaciones se van a utilizar ms frecuentemente.
Tamao que puede alcanzar la lista y el hecho de si se conoce el tamao
mximo de sta.
Adems, otros aspectos fundamentales como los siguientes:
La utilizacin de matrices obliga a la especificacin de un tamao
mximo en tiempo de compilacin. Si no es posible, se deben utilizar
listas enlazadas.
La utilizacin de matrices puede desaprovechar mucha memoria, sobre
todo si existe una gran diferencia entre el tamao mximo y el real
ocupado durante la ejecucin.
Elegir aquella representacin en la que las operaciones que ms se van a
utilizar sean ms rpidas.
481
2.
3.
4.
5.
6.
7.
8.
Escribe un programa que lea por teclado un vector de double cuyo tamao
se solicitar previamente al usuario. Una vez ledos los componentes del
vector, el programa copiar sus valores en otro vector distinto que ordenar
con el mtodo de la burbuja.
Escribe una funcin que lea por teclado un vector de double cuyo tamao
se solicitar previamente al usuario. Escribe, adems, una funcin que reciba
un vector como el ledo en la funcin anterior y devuelva una copia suya con
los mismos valores, pero ordenados de menor a mayor.
Disea un programa que haga uso de las dos funciones anteriores.
Reacurdese liberar toda memoria dinmica solicitada antes de finalizar ste.
Escribe una funcin que reciba un vector de enteros y devuelva otro con sus
n mayores valores, siendo n un nmero menor o igual que la talla del vector
original.
Crear una lista enlazada que funcione como agenda con los campos nombre
y telfono que permita, adems de aadir nuevos elementos, eliminar y
mostrar la agenda completa.
Escribir un programa que cree una lista enlazada de nmeros enteros
positivos al azar, la insercin debe realizarse por el ltimo nodo. Recorrer la
lista para mostrar los elementos por pantalla y eliminar todos los nodos que
superen un valor dado.
Escribir una funcin que devuelva verdadero si la lista est vaca.
Se tiene un archivo de texto de palabras separadas por un blanco o el carcter
de fin de lnea. Escribir un programa para formar una lista enlazada con las
palabras del archivo. Una vez formada la lista se pueden aadir nuevas
482
9.
Programacin en C
484
Programacin en C
Figura 15.2. El fichero 3 contiene funciones que han sido modificadas, es el nico que se
recompila
La mayora de los entornos actuales suelen, adems, presentar una interfaz grfica
de usuario, lo que facilita enormemente acceder a todas las herramientas. En estos
casos el entorno suele recibir el nombre de Entorno de Desarrollo Integrado (EDI)
(tambin conocidos por sus siglas en ingls, IDE, Integrated Development
Environment). En algunos casos estos EDI son entornos grficos que engloban y
recubren un conjunto de herramientas (rdenes en la lnea de rdenes) no grficas.
Por ejemplo, en MS Windows se dispone de MS Visual C++
(http://www.microsoft.com) o Borland C++ Builder (http://www.borland.com),
485
486
Programacin en C
487
488
Programacin en C
anterior. Adems, la lnea de rdenes que se debe escribir cada vez que se genera el
ejecutable resulta muy larga y, por tanto, ms propensa a que se cometan errores. Esta
situacin se agrava conforme crece el nmero de archivos fuente que forman el
proyecto.
As, se debe realizar la compilacin de cada fichero por separado, para pasar a
continuacin al enlazado de todos los ficheros objeto generados (ver Figura 15.4). La
secuencia de rdenes sera la siguiente:
gcc -c ordena.c
gcc -c mem.c
gcc -c aux.c
gcc -c principal.c
De esta manera se compilan por separado los cuatro ficheros, generando cuatro
ficheros objeto, cuyo nombre coincidir con el del correspondiente fichero fuente
salvo la extensin, que pasa de ser .c a .o. Esto se realiza al invocar gcc con la
opcin -c, que indica que se debe generar el correspondiente fichero con el cdigo
objeto, pero no realizar el enlazado. Para generar el ejecutable se enlazan los cuatro
ficheros objeto generados utilizando, para ello, el mismo comando gcc:
gcc ordena.o mem.o aux.o principal.o -o ordena
Figura 15.5. Proceso de generacin del ejecutable ordena, tras una modificacin en
ordena.c
489
ordena.c. As, una vez generado el nuevo fichero objeto correspondiente al fichero
fuente modificado, ordena.o, slo queda enlazarlo con el resto de ficheros objeto
existentes, mem.o, aux.o y principal.o, que no ha sido necesario regenerar
(ver Figura 15.5).
En este caso la secuencia de comandos a ejecutar sera:
gcc ordena.c
gcc ordena.o mem.o aux.o principal.o -o ordena
Como se puede apreciar, no se realiza el proceso de compilacin de los ficheros no
modificados, con el correspondiente ahorro de tiempo.
En cualquier caso, realizar todo el proceso mediante la invocacin directa de la
orden puede dar lugar a gran cantidad de confusiones, sobre todo, cuando el nmero
de ficheros involucrados crece. De hecho, un proyecto de tamao medio suele estar
constituido por un nmero de ficheros bastante elevado, no siendo nada extrao
encontrarse con proyectos con varias decenas o, incluso centenares, de ficheros. Esta
situacin puede resultar muy difcil de gestionar, pudindose dar el caso de no
incorporar cambios realizados, o aparecer errores cuya solucin puede resultar muy
ardua de encontrar.
Una situacin muy tpica es el cambio de alguna variable o prototipo de una
funcin modificada en un fichero fuente o fichero de cabecera (extensin .h). Puede
haber ficheros donde esta funcin o esta variable son utilizadas, luego podra precisar
cambios o, cuando menos, recompilacin de estos ficheros. Si no se realiza, se estara
enlazando cdigo objeto obsoleto, lo que podra implicar importantes errores.
490
Programacin en C
491
492
Programacin en C
493
494
Programacin en C
495
objeto que se van a enlazar para conseguir el objetivo por defecto. De esta manera se
evitan posibles errores al no tener que repetir dos veces esta cadena.
Tambin se dispone de un conjunto de macros internas, ya predefinidas (ver Tabla
15.1), y que se pueden utilizar en la lnea de rdenes. Adems, si la lnea de rdenes
que comienza con el carcter (@) sta no tendr eco en consola.
Macro interna
Significado
$@
Nombre del objetivo actual.
$?
La lista de dependencias que han cambiado ms recientemente
que el objetivo actual.
$<
Nombre de la dependencia actual que ha cambiado ms
recientemente que el objetivo actual.
$^
Lista de todas las dependencias.
Tabla 15.1. Macros internas predefinidas por make
Cuando la cadena de caracteres que se debe escribir es muy larga y se desea dividir
en varias lneas, para una mejor lectura, se debe utilizar el carcter (\). Siguiendo con
el ejemplo:
OBJS = principal.o aux.o
\
mem.o ordena.o
CC = gcc
OPS = -O -c
SOURCES = principal.c aux.c
\
mem.c ordena.c
HEADERS = mem.h aux.h ordena.h
ordena : $(OBJS)
$(CC) $^ -o $@
@ echo Construccin terminada
principal.o : principal.c aux.h mem.h ordena.h
aux.o : aux.h
mem.o : mem.h
ordena.o : ordena.h
proyecto.tar : $(SOURCES) $(HEADERS) makefile
tar -cvf proyecto.tar $^
clean:
rm *.o
Se puede apreciar que hay bastantes cambios. El primero aparece en la primera
regla y consiste en la utilizacin de la macro interna $^, que ser sustituida por la
cadena de dependencias en la regla actual, $(OBJS), que a su vez es otra macro, a
sustituir por su definicin. En cuanto a la otra macro interna, $@, ser sustituida por el
nombre del objetivo en la regla actual, ordena.
Las reglas para la generacin de los ficheros objeto carecen de lnea de rdenes.
Esto se debe a que make, adems de macros internas, tiene reglas y macros
predefinidas, que evitan redundancias. Una regla predefinida invoca la orden $(CC)
-c xxx.c -o xxx.o para todos los objetivos que tengan la extensin .o y no
exista una regla especificando como crearlo, como sucede en el ejemplo. Es ms, no
es necesario incluir el fichero fuente en las dependencias, ya que make supone que
496
Programacin en C
existe un fichero con el mismo nombre que el objetivo, pero con extensin .c, y ste
ser el que utilice. En cuanto a macros predefinidas, CC tiene como valor predefinido
el nombre del compilador por defecto, y CFLAGS las opciones del compilador por
defecto. Estas definiciones se pueden modificar, como ocurre en el ejemplo con CC.
Por ltimo, existe ms de un objetivo: proyecto.tar y clean. Estos objetivos
no se llevarn a cabo, ya que el objetivo que se crea por defecto no depende de ellos.
Para que se cumpla cualquiera de ellos se debe invocar make con la indicacin
expresa de que as se haga, como se muestra a continuacin:
make proyecto.tar
make clean
Entonces se salta la regla correspondiente al objetivo por defecto, ordena, y se
ejecuta la correspondiente a proyecto.tar o clean, respectivamente. El primero
de ambos construye un fichero, proyecto.tar, que empaqueta todos los archivos
fuente del proyecto, incluyendo el propio makefile, y utilizando para ello la orden
tar. El segundo borra todos los archivos objeto existentes en el directorio.
497
ejecuta la correspondiente regla predefinida. Busca la regla que se debe lanzar para
cumplir la dependencia y la lanza. De manera definitiva, el fichero Makefile del
ejemplo debera contener las lneas:
.PHONY: clean
clean
rm *.o
Otros objetivos predefinidos se recogen en la Tabla 15.2.
.PHONY
Los requisitos que aparecen en la correspondiente lista de este
objetivo se consideran objetivos ficticios. Cuando estas dependencias
se consideran como objetivos, las rdenes asociadas a las
correspondientes reglas se ejecutan de forma incondicional, exista o
no un fichero con el mismo nombre y, si existe, independientemente
de los atributos de fecha y hora de ltima modificacin.
.SUFFIXES La lista de dependencias es una lista de sufijos (extensiones) que se
utilizarn en el chequeo de reglas de sufijos.
.DEFAULT
498
Programacin en C
En GNU C y, en general, en los compiladores C sobre entornos UNIX la opcin suele ser g.
En los EDIs se debe buscar el correspondiente cuadro de dilogo de compilacin que permitir
marcar dicha opcin.
2 Entorno de escritorio en el sentido ms amplio del trmino. Incluye un amplio abanico de
aplicaciones que van desde una simple calculadora, a un gestor de archivos, navegador Web, o,
incluso, procesador de texto, hoja de clculo y herramienta de presentaciones.
499
500
Programacin en C
Una vez se ha terminado, la aplicacin muestra una ventana (Figura 15.9) con:
La correspondiente barra de mens, con todas las opciones que ofrece la
aplicacin. Las tpicas como File, Edit y las especficas como Project con
todas las opciones relacionadas con la gestin del proyecto (aadir
archivos nuevos o ya existentes, por ejemplo), o la opcin Build con todas
las opciones relacionadas con las tareas de compilacin, enlazado y
generacin de ejecutables.
501
En este momento se puede empezar a escribir el cdigo fuente del programa, sin
ms que empezar a aadir archivos, bien de nueva creacin, bien ya existentes, todo
desde la misma opcin de men: Project -> New o Project -> Files respectivamente.
En el entorno KDevelop la tarea de creacin de un proyecto es muy similar. De
hecho la apariencia que presentan ambos entornos es muy parecida, por no decir
idntica. Cuando se instala KDevelop ejecuta un pequeo programa de configuracin
(KDevelop Setup) que permite proporcionar al entorno datos como rutas donde
502
Programacin en C
503
Figura 15.11. Asistente de KDevelop solicitando informacin nombre y ubicacin del proyecto
Una vez finalizado el asistente, KDevelop se encarga de generar todos los ficheros
necesarios, incluyendo informacin sobre la aplicacin en desarrollo (sendos ficheros
de texto LEEME, README), y de gestin del proyecto basado en autogen y
autoconf (autotools), adems de ficheros fuente que constituyen un esqueleto
bsico de la aplicacin que se desea desarrollar. La apariencia de KDevelop una vez
finalizado este proceso se puede apreciar en la Figura 15.12. Como se puede ver se
trata, de nuevo, de una interfaz basada en documento mltiple con paneles anlogos a
los que presenta MS Visual C++, por lo que no se volver a repetir la descripcin.
Para aadir nuevos archivos de cdigo fuente, bien de nueva creacin, bien
archivos ya existentes, al proyecto recin creado se selecciona la opcin de men
Proyecto -> Aadir archivos, o si es distinto para los nuevos. Una vez aadido el
archivo se podr comenzar con la edicin.
504
Programacin en C
505
Figura 15.14. Acceso a travs del navegador de KDevelop a la funcin burbuja en el cdigo
fuente
506
Programacin en C
507
Es importante que el desarrollador preste atencin a todos los mensajes que recibe
por parte del entorno en los procesos de compilacin y enlazado. De hecho, ambos
entornos suelen indicar el punto donde se ha producido el error, en el propio cdigo
508
Programacin en C
Figura 15.18. Configurando el proyecto en KDevelop para que inserte informacin de depuracin
509
Figura 15.19. Depurador integrado en KDevelop, con las opciones de men y un punto de ruptura
marcado (breakpoint)
510
Programacin en C
15.3. Conclusiones
En este captulo se han presentado, por un lado, la necesidad de modularizar el
cdigo, algo en lo que ya se haba insistido en captulos anteriores. Por otro lado, se
han presentado herramientas que ayudan al desarrollador en sus tareas.
A la hora de dividir el cdigo en diferentes archivos de cdigo fuente es importante
tener presentes las reglas de mbito de C. Existen especificadotes de almacenamiento,
static, extern, que ayudan a resolver cualquier problema en este sentido, tanto al
manejar variables globales como funciones. Tambin es importante utilizar
adecuadamente los archivos de cabecera (.h), donde se deben realizar las
definiciones y declaraciones que se desea compartir entre diferentes archivos de
cdigo fuente.
En cuanto a las herramientas de apoyo, se presentan dos tipos: sin interfaz grfica
(lo que no implica necesariamente complejidad, ni que estn faltas de potencia, de
hecho algunas con interfaz grfica no son ms que recubrimientos de stas) como
make. Existen otras ms potentes (autotools) pero ms complejas de utilizar. El
otro tipo, con interfaz grfica, los entornos integrados de desarrollo, EDI. De stos
ltimos se han presentado algunas caractersticas relevantes de dos de los ms
conocidos, por un lado MS Visual C++, en el mbito comercial (propietario, de pago),
por otro lado KDevelop en el mbito del software libre (entornos GNU/Linux y otros
UNIX, y libre de pago de licencias).
Es importante recordar al lector que se han tomado como ejemplo ilustrativo estos
entornos, pero existen ms, tanto de pago como gratuitos y tambin software libre3, y
en cualquier plataforma, MS Windows, GNU/Linux y otros UNIX. Las plataformas
Apple (http://www.apple.com) cuentan en su nuevo sistema operativo, Mac OS X,
con un excelente de entorno de desarrollo, con un funcionamiento similar al estudiado
en este captulo, y que se proporciona gratuitamente junto con el propio sistema. An
as se debe tener presente que este sistema es un UNIX, y como tal tambin se puede
utilizar KDevelop.
Por lo tanto, debe ser el desarrollador quien elija el entorno que mejor se adapte a
sus necesidades, a las caractersticas del proyecto que se desea desarrollar... La
interfaz que presentarn estas herramientas ser siempre muy parecida a la estudiada,
con las mismas opciones, o similares. Sin embargo, siempre se puede recurrir a la ms
bsica y existente en todas las plataformas, propietarios y libres: GNU C, GNU Make
y el editor que ms le guste, vi, emacs
15.4. Bibliografa
A la hora de desarrollar el presente captulo se han consultado diferentes fuentes
bibliogrficas entre las que cabe destacar las siguientes:
KDevelop. Ayuda en lnea de KDevelop.
3
Software libre no significa software gratis. Significa que se debe distribuir, junto con los
binarios, el cdigo fuente. Generalmente el software libre suele estar tambin libre del pago
de licencias.
511