Professional Documents
Culture Documents
Eric Jeltsch
F.
PROGRAMACIÓN EN C
(Tutorial para la asignatura Programación
Estructurada de la carrera Ingeniería en
computación)
Prologo:
______________________________________________________________________________________ 1
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
El lenguaje de programación C es básico para entender el Sistema Operativo (SO) UNIX
y sus aplicaciones. Por otra parte C es la fuente del lenguaje de programación C++, el cual es
utilizado en el nuevo paradigma de la Programación Orientada a Objetos, y de Visual C++,
lenguaje utilizado para el desarrollo de aplicaciones Cliente/Servidor en Windows. De manera que
el aprendizaje de C tiene variadas y justificadas razones para ser uno de los lenguajes que un
Ingeniero en Computación debiera conocer y dominar al final de su carrera.
Al mismo tiempo, con este material se persigue apoyar los contenidos del curso de
Programación Estructurada en un lenguaje dinámico y versátil. Por diferentes razones se ha
escogido el lenguaje C. La forma en que se abordan los contenidos de este material es porque
nuestros alumnos ya tienen un curso de programación básica, en donde usan el lenguaje Pascal
como referencia. De manera que muchos conceptos propios de los fundamentos de la
programación se han dejado de lado, como por ejemplo los diagramas de flujos o algunas otras
herramientas didácticas. Lo que se pretende es que rapidamente el alumno pueda familiarizarse con
la sintaxis del lenguaje C y así crear su propio estilo. Para mayor información en este sentido, vea el
documento DevDotStar_Read_Principios.pfd.
Se pretende que este tutorial a través de ejemplos escogidos brinde una visión general de
las distintas propiedades y funciones que el lenguaje C posee para la construcción de programas
eficientes, robustos, según algunos criterios básicos de análisis de algoritmos.
Contenidos:
1 INTRODUCCION
2 ESTRUCTURAS DE CONTROL ( Entrada y Salida de Datos )
2 FUNCIONES ( Diseño Top-Down ó Modular )
3 RECURSIVIDAD
______________________________________________________________________________________ 2
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
4 ITERACION
5 COMPLEJIDAD DE ALGORITMOS
6 PREPROCESADORES en C
7 PROCESANDO TIPOS DE DATOS CHAR
8 PUNTEROS
9 ARRAY
10 ESTRUCTURAS
APLICACIONES
11 ANEXOS
Literatura:
(1) Lenguaje C, Introducción a la Programación , Kelley-Pohl, Addison-Wesley Iberoamericana,
1987.
(2) El Lenguaje de Programación C, Brian W. Kernighan-Dennis Ritchie, Prentice-Hall
Hispanoamericana, 1991.
(3) Lenguaje C y Estructura de Datos, Juan García de Sola-Vicente Garcerán, McGraw-Hill
Interamericana, 1992.
(4) Turbo C/C++ 3.1, Manual de Referencia, Herbert Schild, McGraw Hill de Informática, 1994.
(5) Programación Estructurada en C, James L. Antonakos, Kenneth C. Mansfield Jr. Prentice-Hall,
1997.(Libro Guia, es decir nos orienta respecto de los conceptos que al final del curso deberíamos
dominar.)
(6) Toda la red Internet a disposición. Si Ud.le da a Google la palabra “programación en C” le
saldrán al menos 13.400.000 enlaces. Ahora si le da “Programming with C”, le saldrán al menos
19.400.000 enlaces. Sin embargo, es suficiente conocer y manejar los conceptos que se le brindan
en sesiones de clases y laboratorios. En resumen, no necesita una conexión a Internet para aprobar
la asignatura de “Programación Estructurada”, sólo basta que Ud. se comprometa a realizar todas y
cada una de las tareas que se le encomienden.
1. INTRODUCCION
La Ingeniería de Software (IS) afecta a la economía y a las sociedades de muchas
maneras.En los EEUU, el software contribuyó a 1/4 de todo el incremento del PIB durante los 90's
(alrededor de 90,000 millones de dólares por año), y 1/6 de todo el crecimiento de productividad
durante los últimos años de la década (alrededor de 33,000 millones de dólares por año). La
ingeniería de software contribuyó a $1 billón de crecimiento económico y productividad en esa
década. Alrededor del globo, el software contribuye al crecimiento económico en formas similares,
¿Cual es la realidad chilena?.
______________________________________________________________________________________ 3
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
La ingeniería de software cambia la cultura del mundo debido al extendido uso de la
computadora. El correo electrónico (E-mail), la WWW y la mensajería instantánea permiten a la
gente interactuar en nuevas formas. El software baja el costo y mejora la calidad de los servicios de
salud, las dependencias gubernamentales y otros servicios sociales. Los proyectos exitosos donde
se han usado métodos de ingeniería de software incluyen a Linux, el software del transbordador
espacial, los cajeros automáticos y muchos otros.
La ingeniería de software se puede considerar como la ingeniería aplicada al software,
esto es en base a herramientas preestablecidas, la aplicación de las mismas de la forma más eficiente
y óptima; objetivos que siempre busca la ingeniería. No es sólo de la resolución de problemas, sino
más bien teniendo en cuenta las diferentes soluciones, elegir la más apropiada.
Un objetivo de décadas ha sido el encontrar procesos o metodologías predecibles y
repetibles que mejoren la productividad y la calidad del software. La ingeniería de software
requiere llevar a cabo numerosas tareas, dentro de ellas están las siguientes:
- Análisis de requisitos
Es la tarea de extraer los requisitos de un producto de software, siendo ésta la
primera etapa para crearlo. Mientras que los clientes piensan que ellos saben lo que el software
tiene que hacer, se requiere de habilidad y experiencia en la ingeniería de software para reconocer
requisitos incompletos, ambiguos o contradictorios. El resultado del análisis de requisitos con el
cliente se plasma en el documento ERS, Especificación de Requerimientos del Sistema, cuya
estructura puede venir definida por varios estándares, tales como CMM-I u otros. Asimismo, se
define un diagrama de Entidad/Relación, en el que se plasman las principales entidades que
participarán en el desarrollo del software. La captura, análisis y especificación de requisitos (incluso
pruebas de ellos), es una parte crucial; de esta etapa depende en gran medida el logro de los
objetivos finales. La IEEE Std. 830-1998 normaliza la creación de las Especificaciones de
Requisitos Software (Software Requirements Specification).
- Especificación
Es la tarea de describir detalladamente el software a ser escrito, en una forma
matemáticamente rigurosa.
- Diseño y arquitectura
Se refiere a determinar como funcionará de forma general la propuesta, sin entrar en
detalles. Consiste en incorporar consideraciones de la implementación tecnológica, como el
hardware, la red, etc. Se definen los Casos de Uso para cubrir las funciones que realizará el
sistema, y se transforman las entidades definidas en el análisis de requisitos en clases de diseño,
obteniendo un modelo cercano a la programación orientada a objetos.
- Programación
Reducir un diseño a código puede ser la parte más obvia del trabajo de ingeniería de
software, pero no es necesariamente la porción más larga. La complejidad y la duración de esta
etapa está intimamente ligada al o a los lenguajes de programación utilizados.
______________________________________________________________________________________ 4
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
- Prueba
Consiste en comprobar que el software realice correctamente las tareas indicadas en la
especificación. Una técnica de prueba es probar por separado cada módulo del software, y luego
probarlo de forma integral, para asi llegar al objetivo. Se considera una buena practica el que las
pruebas sean efectuadas por alguien distinto al desarrollador que la programó, idealmente un area
de pruebas; sin perjuicio de lo anterior el programador debe hacer sus propias pruebas. En general
hay dos grandes formas de organizar un area de pruebas, la primera es que esté compuesta por
personal inexperto y que desconozca el tema de pruebas, de esta forma se evalúa que la
documentación entregada sea de calidad, que los procesos descritos son tan claros que cualquiera
puede entenderlos y el software hace las cosas tal y como estan descritas. El segundo enfoque es
tener un area de pruebas conformada por programadores con experiencia, personas que saben sin
mayores indicaciones en que condiciones puede fallar una aplicación y que pueden poner atención
en detalles que personal inexperto no consideraría.
- Documentación
Todo lo concerniente a la documentación del propio desarrollo del software y de la
gestión del proyecto, pasando por modelaciones (UML), diagramas, pruebas, manuales de usuario,
manuales técnicos, etc; todo con el propósito de eventuales correcciones, usabilidad,
mantenimiento futuro y ampliaciones al sistema.
- Mantenimiento
Mantener y mejorar el software para enfrentar errores descubiertos y nuevos
requisitos. Esto puede llevar más tiempo incluso que el desarrollo inicial del software. Alrededor de
2/3 de toda la ingeniería de software tiene que ver con dar mantenimiento. Una pequeña parte de
este trabajo consiste en arreglar errores, o bugs. La mayor parte consiste en extender el sistema
para hacer nuevas cosas.
Con el fin de llevar a cabo la implementación de las propuestas con relativo éxito se deben
considerar una serie de pasos, que en el futuro deberían ser realizadas en forma natural si Ud.
pretende ser Ingeniero en Computación de la ULS.
b) Este tipo de enunciados nos obligan a interactuar con la persona que propuso el problema, para
producir un conjunto de especificaciones claras, no ambiguas que llevan a aclarar lo que deseamos
hacer. Estas especificaciones se conocen como especificaciones de entrada y salida, y
procesamiento especial, y se obtienen a traves de preguntas que se hacen a la persona que planteó
el problema.
c) Si vemos el plantemiento anterior para la entrada, algunas preguntas pertinentes serian: ¿los
valores de entrada son caracteres?, en ese caso, ¿qué caracteres podemos encontrar?, ¿cómo saber
cuando se acabó el texto?, ¿qué pasa con la puntuación?, etc. Lo mismo ocurre respecto de su
salida, la que debe o debería respetar un cierto formato.
______________________________________________________________________________________ 6
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Otra forma, es que sin necesidad de un compilador el código sea comprensible por el ser humano,
esto se logra o es convertido en tiempo de ejecución (equivalente a una traducción simultánea) a
código comprensible por la máquina. Se diferencia del código compilado en que:
a. Es más rápido.
b. Es más fácil de mantener (modificar, corregir errores), ya que siempre es comprensible por el ser
humano.
c. Es más flexible ya que los lenguajes interpretados permiten mayores abstracciones que los
lenguajes compilados.
d. Es portable a cualquier plataforma que posea un intérprete. El programa compilado solo
funciona en la plataforma para la que fue compilado. Ejemplo de lenguaje habitualmente
interpretado: Perl, VBS, Basic, Javascript, PHP. Existen soluciones intermedias al código
compilado o interpretado. Ejemplo: Java, posee bytecodes que es código compilado intermedio que
requiere ser interpretado parcialmente.
______________________________________________________________________________________ 7
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Dicho lo anterior, digamos que un programa propone una solución a un problema, a través de un
algoritmo que emplea una estructura de datos apropiada. Los algoritmos son independientes del
lenguaje de programación y de la máquina en la que se ejecuta.
UN EJEMPLO
______________________________________________________________________________________ 8
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Titulo de la Actividad Ejemplo: En nuestro caso lo llamamos Recreemos los Triángulos.
Problema
Consideremos el plano bidimensional y en él se dan, por ahora, tres puntos P1, P2 y P3, que
representan los vértices de un triángulo. En este primer proyecto se desea computar alguna de las
características de ellos, como por ejemplo, el área, el perímetro, el baricentro y también si se da un
cuarto punto, se pide computar la distancia de este punto al triángulo.
Descripción
La entrada de los datos al programa por lo general es a través de datos que se ingresan por teclado
o por archivos. En esta oportunidad el ingreso de datos se considera solamente por teclado. En
todo caso el usuario deberá ser preguntado si desea ingresar los datos por archivo o por teclado.
Ud. deberá seleccionar por teclado, sin embargo si elige por archivo el programa no se debería
“caer”.
Una vez que el usuario ya ha sido preguntado, y Ud. elegido su opción por teclado, el programa le
invita a ingresar tres pares de puntos, es decir P1(x1, y1), P2(x2, y2) y P3(x3, y3), que
corresponden a los vértices del triángulo. Luego el programa le pide al usuario las coordenadas de
un cuarto punto P4(x4, y4), el que deberá ser usado para computar la distancia de P4 al triángulo.
El programa debería entregar como salida el resultado de estas operaciones. Por ejemplo:
Para el triángulo definido por (15,20.5) (10,10.5) (20,10.5) tiene:
Un área de 50
Un perimetro de 32.361
Un centroide de (15,13.8)
La distancia entre el punto (15,-5) y el triángulo es 15.5
- Análisis al problema.
Por ejemplo, los puntos P1, P2, P3 y P4 definidos por: P1=(x1,y1), P2=(x2,y2), P3=(x3,y3) y
P4=(x4,y4). ¿Cómo computo el área?. Hallamos la base b, luego encontramos la altura h y
entonces: area = (b*h)/2
______________________________________________________________________________________ 9
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
l12
P P2
(x,y) (x2,y2)
P1
(x1,y1)
P3
(x3,y3)
Para hallar la base necesitamos computar la distancia entre dos puntos del triángulo, digamos
(x1,y1) y (x2,y2) para definir la base para el triángulo, entonces
b = distancia(P1,P2),donde
distancia(P1,P2) = sqrt( (x1-x2)2 + (y1-y2)2 )….etc.
Otro camino es :
______________________________________________________________________________________ 10
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
P2
(x2,y2)
A2
P1
A1
(x1,y1)
A
b
A3
P3
(x3,y3)
a
El área del triángulo es:
A= a*b – A1 – A2 – A3, donde, las áreas A1, A2 y A3 del triángulo son fáciles de encontrar.
¿Cómo computo el perímetro?
P1
(x1,y1)
Pc
(xc,yc)
P23
(x23,y23)
P3
(x3,y3)
P1
(x1,y1)
P4
(x4,y4)
P3
(x3,y3)
Caso 2:
P2
(x2,y2)
P1
(x1,y1) P4
(x4,y4)
P3
(x3,y3)
Variables:
double b; /*base del triángulo*/
double h; /*altura del triángulo*/
- Diseño de la propuesta.
Algoritmo inicial, por ejemplo
Darle la opción para que el usuario diga si los datos los va a incorporar por archivos o por teclado.
Si es a través de un archivo, diga por esta vez NO!
Si la opción es por teclado, entonces invitar al usuario para que indique los cuatro puntos que se
requieren.
Computar el área, con ellos.
Computar el perímetro, con ellos.
Computar la distancia desde el cuarto punto al triángulo
Desplegar el área, perímetro y distancia.
Algoritmo Refinado, por ejemplo
Darle la opción (0 si es por teclado, 1 si es archivo).
Si la opcion = = 0
darle x1 y y1.
darle x2 y y2.
darle x3 y y3.
darle x4 y y4.
Si la opción = = 1
Decir que por ahora no hay archivo activo. Vuelva a preguntar.
Computar el área
Computar la base del triángulo:
b = distancia( x1, y1, x2, y2 ) = sqrt( (x1-y1)*( x1-y1) + (x2-y2)*( x2-y2) )
Computar la altura del triángulo
h = altura( x1, y1, x2, y2, x3, y3 )
(Todos estos cálculos se sustentan con el análisis.)
Computar el perimetro.
perimetro = distancia( x1, y1, x2, y2 ) + distancia( x1, y1, x3, y3 ) + distancia( x3, y3, x2, y2 )
Computar la distancia desde el cuarto punto al triángulo.
(Todos estos cálculos se sustentan con el análisis.)
Desplegar el área, perimetro y distancia.
- Implementación o código fuente.
______________________________________________________________________________________ 13
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
En este apartado recomiendo diferentes recursos LIBRES disponibles en la web. Por ejemplo, Dev-
C++, que es un entorno integrado de desarrollo (IDE) que emplea MinGW. Es una buena solución
si nos gustan los IDEs avanzados. Lo podemos descargar con MinGW incluido (e integrado).
/* Programa:
* Descripción:
* Autor:
* Curso:
* Profesor Laboratorio:
* Fecha:
*/
Con este ejemplo quiero mostrar lo que usualmente hacen los alumnos al saltarse el proceso de
análisis y diseño, pues de esta forma se llega a una solución funcional pero no robusta o capaz de
mantenerse en el tiempo, frente a otros requerimientos.
Implementación
#include<stdio.h>
int
main ()
{
int j, i, tmp ;
int v[10]={2,4,5,3,1,6,7,8,10,9};
for(i=0;i<10;i++)
printf("%i ",v[i]);
printf("\n");
for (i=0;i<10;i++) {
for (j=i+1;j<10;j++) {
if (v[i]>v[j]) {
tmp=v[i];
v[i]=v[j];
v[j]=tmp;
}
}
}
______________________________________________________________________________________ 14
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
for(i=0;i<10;i++)
printf("%i ",v[i]);
printf("\n");
getch();
return 0;
A continuación se muestran otras propuestas, que surgen a través de discutir o realizar el análisis y
el diseño de la propuesta. Por ejemplo, que algoritmo de ordenamiento utilizar y porque, se
consideran nº repetidos en la entrada, podrán ordenarse caracteres también. ….etc.
#include<stdio.h>
int
main ()
{
int j;int i;int tmp;int v[10]={2,4,5,3,1,6,7,8,10,9};
i=0;
while (i<10) {
printf("%i ",v[i]);
i++;
}
printf("\n");
i=0;
while (i<10) {
j=i+1;
while (j<10) {
if (v[i]>v[j]) {
tmp=v[i];
v[i]=v[j];
v[j]=tmp;
}
j++;
}
i++;
}
______________________________________________________________________________________ 15
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
i=0;
while (i<10) {
printf("%i ",v[i]);
i++;
}
printf("\n");
return 1;
}
#include<stdio.h>
int main ()
{
int v[100];
int dim,ok;
int i, j, tmp, k;
do {
printf("Introduce el tama¤o del vector seguido de intro (2-100): ");
scanf("%i",&dim);
if (dim>100 || dim<2) {
puts("Error: Fuera de rango");
ok=0;
} else {
ok=1;
}
} while (!ok);
do {
for (i=0;i<dim;i++) {
printf("elemento %i: ",i+1);
scanf("%i",&v[i]);
}
if(ok=buscaDuplicados(dim,v))
puts("Error: no repitas digitos, vuelve a introducir.");
} while(ok);
switch (ok) {
default:
puts("Error: opci¢n incorrecta.");
break;
case 1:
ordenaVector(dim,v);
for(i=0;i<dim;i++) {
for(j=i+1;j<dim;j++) {
if (v[i]>v[j]) {
tmp=v[i];
v[i]=v[j];
v[j]=tmp;
}
}
}
return;
}
______________________________________________________________________________________ 18
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
En general, un programa escrito en un lenguaje de alto nivel, tal como Pascal ó C, posee dos tipos
de items: DATOS y PROCEDIMIENTOS.
En C todos los procedimientos son llamados FUNCIONES, mientras que Pascal, posee
procedure y function.
/* file: ej0.c
Nombre del programa: factorial de 6
Fecha: 3.12.96.
Actualización: 11.07.2008
Propósito: Mostrar un primer programa en C
*/
#include<stdio.h>
#define VALOR 6
int i,j;
main( )
{ j=1;
______________________________________________________________________________________ 19
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
for (i=1; i<=VALOR; i++)
j=j*i;
printf( "el factorial de %d es %d\n", VALOR, j);
getch();
return(0);
}
Comentarios:
Ud. puede ver la correspondencia que existe entre Pascal y C, la diferencia es que C parte con el
código #include<stdio.h>, el cual incluye la librería estandar de Entrada/Salida para que Ud.
pueda leer y escribir valores, manejar archivos de texto, etc. C posee un gran número de librerías
las cuales son utilizadas dependiendo del problema, entre ellas se cuenta con stdio, string, time,
math y otras, las cuales a futuros veremos en que tipo de problemas se aplican.
Cuando Ud. ingresa este programa las líneas #include y #define parten al comienzo de la 1ª
columna, suponiendo la existencia de una barra virtual la cual clasifica el texto según casilleros ó
columnas. Para los usuarios de Borland C++ ó Turbo C/C++ el archivo debe tener la extensión
(.c) o bien (.cpp) y se compila, ejecuta, según los visores windows. La línea #define crea una
constante, este tipo de declaraciones son llamados preprocesadores. Dos variables globales son
declaradas usando la línea int i, j ; La línea main( ) declara la función principal. Todo programa en
C debe tener esta función principal. Cada programa en C es particionado en funciones que se
llaman entre sí. En C los paréntesis {, y } reemplazan el begin y end de Pascal. También, el
símbolo = remplaza la asignación := de Pascal. La estructura for de Pascal es semánticamente la
misma en C, salvo que C incorpora otros operadores para incrementar o decrementar las variables,
i++. La línea return(0); es utilizada para decirle al sistema operativo (SO) que el programa
termina y se sale ( status = 0 ), la declaración getch() se relaciona con el hecho de mantener en
pantalla la ejecución. En la declaración printf ( ) es extremadamente importante que el nombre del
operador esté en el formato correspondiente al tipo de la variable declarada.
Dadas las horas trabajadas y el pago por hora, escribir un programa que compute el sueldo de una
persona con un número específico ID. El programa deberá mprimir los datos y el sueldo.
Solución: Imprimir título del programa; (especificando file, nombre del programa, fecha y
propósitos del mismo;
set datos: set de números ID, horas trabajadas, pago por hora;
set sueldo: el producto de las horas trabajadas y el pago por hora;
print : datos y resultados;
/* file: pe971.c
Nombre del programa: sueldo
Fecha: 3.12.96
Actualización: 11.07.2008
______________________________________________________________________________________ 20
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Propósito: Este programa calcula el sueldo para una persona, dadas las horas
trabajadas y el costo por hora
*/
#include<stdio.h>
main()
{ /* declaración*/
int id_numero; /* tipo entero */
float horas_trabajadas, costo_por_hora, sueldo; /* tipo punto flotante */
/* Imprimir el título */
printf("***cálculo del sueldo***\n\n"); /* saltando una línea */
/* inicializando variables*/
id_numero=123;
horas_trabajadas=20.0;
costo_por_hora=7.5;
/* cálculo de sueldo */
sueldo=horas_trabajadas*costo_por_hora;
Comentarios:
En cualquier programa los simbolos /* y */ sirven para expresar los comentarios de un programa ó
dejar inactiva algunas líneas de la ejecución del mismo. Cada línea de sentencia termina con ;
Declaración de las librerías que utilizará, en este caso, <stdio.h>, la que se incluye con la línea
#include<stdio.h>
El cuerpo de la función main( ) está contenido entre { y }.
Tomar en cuenta que sobre un PC solamente 16 bits ( 2 bytes ) son usados, de manera que el rango
es de 32767 a -32768. (El rango representable por k-bits es desde -2k-1 a +2k-1 - 1.
¿ Qué resulta si declara int zip; zip= 92126; y lo ejecuta ?.
C utiliza punto decimal para distinguir entre número punto flotante y número entero.
printf( ) es la función utilizada para imprimir los resultados la cual está incluída en la librería
<stdio.h>. El simbolo \n , indica fin de línea.
printf ( ) imprime según los formatos respectivos, %d es la conversión a entero y %f es la
conversión a punto flotante.
La línea return(0); es utilizada para decirle al SO que el programa se sale ( Status=0 );
El programa como es sabido debe ser compilado, es decir trasladado a un lenguaje de máquina
(programa objeto) usando un compilador. Al final de este proceso, en donde C utiliza sus librerías
de funciones estandares, resulta un programa ejecutable. El efecto es:
______________________________________________________________________________________ 21
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
*** cálculo del sueldo ***
id_numero= 123
horas_trabajadas= 20.000000, costo_por_hora=7.500000
sueldo= 150.000000
Comentarios:
Respecto a la salida de los datos, podemos decir que, el primer printf( ) imprime el valor de
id_numero en la posición donde %d está localizada. La forma interna del valor de id_numero es
convertida a formato entero decimal e impreso, la salida es: id_numero= 123
El siguiente printf( ) escribe los valores de horas_trabajadas a la posición de la primera %f, y el
valor de costo_por_hora a la posición del segundo %f. Las formas internas son convertidas a
números reales decimales ( puntos flotantes ) e imprime. La salida es
horas_trabajadas= 20.000000, costo_por_hora=7.500000
Los valores punto flotante son impresos, por defecto, con seis dígitos después del punto decimal.
La impresión final es : sueldo= 150.000000
Utilizando el Ejemplo 2, construiremos un programa, pero que ahora los datos id_numero,
horas_trabajadas y costo_por_hora serán leídos desde el teclado.
Solución: Imprimir título del programa; (especificando file, nombre del programa, fecha y
propósitos del mismo;
leer los datos id_numero, horas_trabajadas y costo_por_hora ;
set sueldo: el producto de las horas trabajadas y el pago por hora;
print : datos y resultados;
/* file: pe972.cpp
Nombre del programa: sueldo
Fecha: 3.12.96
Propósito: Este programa calcula el sueldo para una persona, dadas las horas
trabajadas y el costo por hora, cuyos datos son ingresados por teclado
*/
#include<stdio.h>
main()
{ /* declaración*/
int id_numero; /* tipo entero */
float horas_trabajadas, costo_por_hora, sueldo; /* tipo punto flotante */
/* Imprimir el título */
printf("***cálculo del sueldo***\n\n"); /* saltando una línea */
/* leer datos en las variables */
printf(“tipo id_numero: “);
scanf(“%d”, &id_numero);
______________________________________________________________________________________ 22
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
printf(“horas_trabajadas : “);
scanf(“%f”, & horas_trabajadas);
printf(“costo_por_hora : “);
scanf(“%f”, & costo_por_hora);
/* cálculo de sueldo */
sueldo=horas_trabajadas*costo_por_hora;
Comentario:
Para que este programa lea el valor en vez de utilizar una constante como Ejemplo 1, se utilizó
El signo & delante de valor, representa la dirección del operador en C, lo que veremos en el tema
de punteros.
printf( ) es la función que facilita escribir por consola, similarmente existe la función scanf( ) para
leer datos desde el teclado y almacenarlos en algún objeto, esto último se realiza en C a través del
operador de dirección &.
Las distintas líneas pueden resumirse en
scanf(“%d %f %f, &id_numero, &horas_trabajadas, &costo_por_hora );
La salida es la misma a la que se obtuvo en el Ejemplo 2.
Utilizando el Ejemplo 3, se le pide construir un programa que sea capaz de calcular el sueldo,
excepto que las horas de sobretiempo se pagan a 1.5 veces el valor normal, de otra manera se
calcula el sueldo en forma normal.
La propuesta esta orientada a utilizar las diversas estructuras de control que posee C. Es así como
el programa( en esta nueva versión) deba durante su ejecución realizar decisiones, de manera que
debe incorporarse una etapa de if--then.
Trasladando a C queda:
Trasladando a C queda:
Observación:
Es útil recordar los operadores lógicos, precedencia y asociaciones, además ver la definición de
constantes para definir LIMITE y FACTOR ( preprocesadores #define...).
Ejemplo 6: ( Un simple...while )
Consideremos el Ejemplo 3 salvo que el programa ahora, lee los datos, computa el sueldo e
imprime los datos y el sueldo para un número desconocido de personas. Por tal motivo surge la
necesidad de usar otras estructuras de control, en esta oportunidad es el ciclo.
/* file: pe97c2.cpp
Nombre del programa: sueldo
Fecha: 3.12.96
Propósito: Este programa calcula el sueldo para un número arbitrario de
persona,
dada las horas trabajadas y el costo por hora
______________________________________________________________________________________ 24
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
*/
#include<stdio.h>
#define LIMITE 40.0 /* constantes */
#define FACTOR 1.5
main()
{ /* declaración*/
int id_numero, contador;
float horas_trabajadas, costo_por_hora, pago_regular, sobre_tiempo, sueldo;
/* Imprimir el título */
printf("***cálculo del sueldo***\n\n");
/* cálculo de resultados */
if (horas_trabajadas > LIMITE ) {
pago_regular= LIMITE * costo_por_hora;
sobre_tiempo= FACTOR * costo_por_hora * ( horas_trabajadas - LIMITE );
}
else {
pago_regular= horas_trabajadas * costo_por_hora;
sobre_tiempo= 0.0;
}
sueldo= pago_regular + sobre_tiempo;
/* contador */
contador= contador - 1;
}
return(0);
}
______________________________________________________________________________________ 25
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Tipo id_numero: 123
Horas trabajadas: 20
Costo por hora: 7.5
id_numero=123
horas_trabajadas=20.000000 , costo_por_hora= 7.500000
Pago_regular= 150.000000, Sobre_tiempo= 0.000000
Sueldo= 150.000000
id_numero=456
horas_trabajadas=50.000000 , costo_por_hora= 10.000000
Pago_regular= 400.000000, Sobre_tiempo= 150.000000
Sueldo= 550.000000
/* file: pe97c4.cpp
Nombre del programa: sueldo
Fecha: 10.12.96
Propósito: Este programa lee las horas trabajadas, costo por hora y calcula el
sueldo para un número arbitrario de persona. El programa también computa el
sueldo más alto, número de personas y el sueldo promedio.
*/
#include<stdio.h>
#define LIMITE 40.0
#define FACTOR 1.5
main()
{ /* declaración*/
int id_numero, contador;
float horas_trabajadas, costo_por_hora,
pago_regular, sobre_tiempo, sueldo, sueldo_alto, promedio;
/* Imprimir el título */
printf("***cálculo del sueldo***\n\n");
/* inicializa acumuladores */
contador=0;
sueldo_alto=0;
/* acumuladores activados */
contador= contador + 1;
sueldo_alto= sueldo_alto + sueldo;
______________________________________________________________________________________ 27
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
#include <stdio.h>
int main()
{
printf( "Hola mundo" );
getch();
return 0;
}
Observar que existen una serie de funciones en la biblioteca estándar de C, las funciones son
subprogramas que ya están compilados, es decir, junto a cualquier compilador de C se le deben
acompañar los códigos objeto de todas las funciones de su biblioteca estándar, pero no
necesariamente sus códigos fuente. Por tanto, aunque no sea posible modificar sus códigos fuente,
(en Java sí se puede) pero se pueden usar dichas funciones en cualquier programa. Por ejemplo, se
puede llamar a la función printf() para que muestre por pantalla el saludo "Hola mundo".
printf( "Hola mundo" );
______________________________________________________________________________________ 28
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Para utilizar una función (sea de la biblioteca estándar de C o no) en un programa, la función debe
ser declarada previamente, al igual que se tienen que declarar las variables y las constantes que usa
un programa. En este caso no fue necesario pues ella es encuentra en la librería stdio.h. (stdio,
Standard Input/Output). De allí la necesidad de informarle al compilador de la declaración de la
función printf, a través de la declaración en el encabezado #include <stdio.h> . Las funciones de la
biblioteca estándar de C están clasificadas en base a su funcionalidad, y sus declaraciones se
agrupan en archivos con extensión (.h), los cuales son llamados archivos de cabecera. Además
de stdio.h, algunos de los archivos de cabecera más utilizados en C son: math.h, string.h y stdlib.h.
En ellos están escritas, respectivamente, las declaraciones de las funciones matemáticas, funciones
de cadena y funciones de utilidad de la biblioteca estándar de C.
return 0;
Esto quiere decir que la función main devuelve el valor 0. Precediendo a main se ha escrito la
palabra reservada int, indicando así, que la función retornará un valor de tipo int entero).
int main()
En general, la instrucción return suele ser la última del bloque de instrucciónes de la función main.
Al retornar el valor 0, indica (informa al sistema operativo) que el programa finalizó correctamente,
es decir, sin producirse ningún error en su ejecución. Cuando la función main devuelva un valor
distinto de cero, esto siginificará que se ha producido algún error en la ejecución del programa, o
que ha ocurrido algo fuera de lo normal. Notar que se ha incluido en este programa la función
getch(), con el fin de mostrar la pantalla de MS-DOS y visualizar el resultado de su ejecución. La
instrucción return es una de las instrucciones de control que existen en C. Por tanto, es una
palabra reservada. Después del valor de retorno (que es una expresión) se debe escribir un punto y
coma (;).
#include <stdio.h>
int main()
{
int a, b;
______________________________________________________________________________________ 29
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
el programa se detiene a la espera de que el usuario teclee el dato de entrada requerido, el cual es
almacenado, temporalmente, en el buffer (memoria intermedia) de la entrada estándar. Y cuando se
pulsa la tecla INTRO, es, en ese momento, cuando a la variable a se le asigna el valor introducido.
Pero, además, se produce un salto de línea automático, de forma que, después de introducir el
número 12, la siguiente instrucción se muestra una línea más abajo. De igual forma, después de la
instrucción
scanf( "%d", &b );
también se produce un salto de línea automático. En este ejemplo todo ha ido muy bien, sin
embargo, se tiene que tener especial cuidado si utilizados scanf ( ) para leer caracteres. Notar ahora
lo siguiente,
#include <stdio.h>
int main()
{
char a, b, c;
return 0;
}
______________________________________________________________________________________ 30
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
después de asignar el carácter 'f' a la variable a, se produce un salto de línea automático, pero, en el
buffer del teclado también se ha quedado almacenada la secuencia de escape (\n), que es,
precisamente, un carácter. En consecuencia, cuando se ejecuta la instrucción
En pantalla veremos:
¿Y que fue lo que paso ahora….?. Como se puede comprobar en las tablas del ASCII, los números
102, 10 y 104 corresponden a los caracteres 'f', LF (Salto de Línea) y 'h', respectivamente. Veamos
a continuación este pequeño “detallito”.
El Código Estándar Americano para el Intercambio de Información (American Standard Code for
Information Interchange, ASCII) es, hoy en día, el código más utilizado en los equipos
computacionales. ASCII emplea grupos de 7 bits para codificar caracteres en binario, permitiendo
representar a 27 = 128 caracteres. Su tabla de correspondencias es la siguiente:
______________________________________________________________________________________ 31
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Los dígitos que rodean la tabla sirven para identificar al número decimal que corresponde a cada
carácter. De modo que, para un determinado carácter, el número decimal que le corresponde se
obtiene de agrupar los dígitos de su fila y de su columna.
Por ejemplo, al carácter H del ASCII le corresponde la agrupación de los dígitos (7) de su fila y (2)
de su columna, es decir, el carácter H se codifica con el código 7210 = 10010002.
Los primeros 32 caracteres del ASCII son de control. En la siguiente tabla se muestran sus
significados:
______________________________________________________________________________________ 32
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
______________________________________________________________________________________ 33
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
El carácter 32 (SP) representa al Espacio en Blanco y el carácter 127 (DEL) a Borrar. El resto de
caracteres corresponden a las letras del alfabeto inglés (a, b, c, d, e,...), los dígitos del sistema
decimal (0, 1, 2, 3,...) y caracteres especiales (@, #, %,...). Por ejemplo,
______________________________________________________________________________________ 34
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
También existe un ASCII extendido de 8 bits con el que se puede representar a 28 = 256 caracteres.
En dicho código, los 128 primeros caracteres coinciden con el ASCII de 7 bits y, el resto,
corresponden a algunos caracteres alfabéticos no ingleses (ñ, Ñ, á, é,...), algunas letras griegas,
símbolos matemáticos y caracteres gráficos. Véase la siguiente figura:
main()
{
char car1 = 'A', car2 = 65, car3 = 0;
car3 = car1 + 'a' - 'A';
printf("%d %c\n", car3, car3);
car3 = car2 + 32;
printf("%d %c\n", car3, car3);
getch();
}
Comentario:
char car1 = 'A', car2 = 65, car3 = 0; // el valor ASCII de 'A' es 65
car3 = car1 + 'a' - 'A'; // car3 = 'A' + 'a' - 'A' = 'a'
printf("%d %c\n", car3, car3); // 'A' dista de 'a' 32 caracteres, luego:
______________________________________________________________________________________ 35
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
car3 = car2 + 32; // car3 = 'A' + 32 = 'a'
Este es el código ASCII extendido más utilizado por las computadoras digitales. Sin embargo, los
caracteres (128-255) pueden variar de unos sistemas operativos a otros, dependiendo de su
configuración. Así, en función de los idiomas que se hablan en distintas zonas geográficas del
mundo, la Organización Internacional de Estándares (International Standards Organization, ISO) ha
definido distintos estándares ASCII, tales como: ISO 8859-1 (usado para el castellano), ISO 8859-
2 Latín (utilizado en Europa central), ISO 8859-5 Cirílico (para lenguajes eslavos), ISO 8859-6
Árabe (para lenguajes arábigos), etc.
En un procesador de texto, los caracteres del ASCII más frecuentemente utilizados, tales como:
letras (a, b, c,...), dígitos (0, 1, 2,...) y signos de puntuación (?, ;, :,...) son fáciles de imprimir por
pantalla, pulsando directamente su tecla correspondiente. Sin embargo, para mostrar otros
caracteres, es necesario utilizar una combinación de teclas, por ejemplo, el símbolo almohadilla (#)
se imprime pulsando las teclas (Alt Gr + 3). No obstante, cualquier carácter del ASCII se puede
mostrar por pantalla tecleando su código decimal, al mismo tiempo que se presiona la tecla Alt. Por
ejemplo, en un procesador de texto, el carácter H del ASCII se puede imprimir por pantalla
pulsando las teclas (7) y (2) del Bloque Numérico del teclado, al mismo tiempo que se mantiene
presionada la tecla (Alt).
Por otra parte, la combinación de la tecla (Alt) con los 32 primeros números decimales (0-31),
también imprime por pantalla algunos caracteres gráficos.
Para resolver este problema, antes de leer un carácter con scanf(), hay que vaciar (limpiar) el buffer
del teclado. Para ello, se utiliza la función fflush().
#include <stdio.h>
int main()
{
char a, b, c;
La primera vez que se ejecuta scanf(), el buffer del teclado está vacío, por tanto, no es preciso
utilizar fflush(), pero sí, en los dos casos posteriores. Obsérvese que, a fflush() hay que indicarle el
buffer a limpiar, Standar Input (stdin) en este caso. Como pueden ver esto nos introduce al hecho
que no todo puede funcionar como uno quisiera. Es así como en C existen diversos tipos de errores
(como en todo lenguaje de programación!!). Ellos son:
Error de sintaxis:
En programación, un error de sintaxis se produce al escribir, incorrectamente, alguna parte del
código fuente de un programa. De forma que, dicho error impedirá, tanto al compilador como al
intérprete, traducir dicha instrucción, ya que, ninguno de los dos entenderá qué le está diciendo el
programador. Por ejemplo, si en lenguaje C, en vez de la instrucción
un programador escribe
cuando el compilador o el intérprete lean esta línea de código, ninguno de los dos entenderá qué es
prrintf y, por tanto, no sabrán traducir esta instrucción a código máquina, por lo que, ambos
pararán la traducción y avisarán al programador con un mensaje de error.
Error de ejecución:
En programación, un error de ejecución se produce cuando la máquina no puede ejecutar alguna
instrucción de forma correcta. Por ejemplo, en lenguaje C, la instrucción
c = 5 / 0;
es correcta sintácticamente y será traducida a código binario. Sin embargo, cuando la computadora
intente realizar la división
5/0
se producirá un error de ejecución, ya que, matemáticamente, no se puede dividir por cero. Por
ejemplo,
#include <stdio.h>
int main()
{
int a;
float b;
______________________________________________________________________________________ 37
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
a = 0;
b = 6.4 / a;
printf( "%f", b );
getch();
return 0;
}
Error de lógica:
En programación, los errores de lógica son los más difíciles de detectar. Cuando un programa no
tiene errores de sintaxis ni de ejecución, pero, aún así, no funciona bien, esto es debido a la
existencia de algún error lógico. De manera que, un error de lógica se produce cuando los
resultados obtenidos no son los esperados. Por ejemplo, en lenguaje C, si en vez de la instrucción
c = a + b;
c = a * b;
hasta que no se mostrase por pantalla el resultado de la operación, el programador no podría darse
cuenta del error, siempre que ya supiese de antemano el resultado de la suma. En este caso, el
programador podría percatarse del error fácilmente, pero, cuando las operaciones son más
complejas, los errores de lógica pueden ser muy difíciles de detectar. Por ejemplo
#include <stdio.h>
int main()
{
float base, altura;
base = 6.3;
altura = 4.;
______________________________________________________________________________________ 38
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Formatos diversos.
Ejecuta el siguiente programa para aclarar las ideas sobre cómo funciona el operador división (/)
con distintos tipos de variables. En él se puede comprobar la diferencia entre la división entera y de
punto flotante. Guarde el programa como division.c.
Comentario:
Es importante recordar que el tipo de formato debe estar de acuerdo con el tipo del argumento en
la función printf(). Para el formato de salida (%6.3f) se tendrán un total de 6 espacios de
salida, de los cuales 3 serán decimales. En el siguiente programa te presentamos un avance de las
"complicadas" operaciones que puede realizar C. Escribe el programa y almacénalo como carrera.c.
Compila el programa y ejecútalo; apuntando el resultado. Después modifica el programa
sustituyendo 1760.0 por 1760 en la línea que calcula el número de kilómetros. Vuelve a compilar y
a ejecutar. ¿Sale lo mismo que antes? ¿Qué ha podido pasar?
______________________________________________________________________________________ 39
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
yardas = 385;
kilometros = 1.609 * (millas + yardas / 1760.0);
printf("\nUn marathon tiene %f kilometros.\n\n", kilometros);
getch();
}
Comentario:
En C las constantes que incluyen un punto decimal son de tipo double. La variable yardas es de tipo
int. Si en el denominador se pone sólo 1760, el resultado de yardas/1760 es entero y por tanto
incorrecto. Basta poner 1760.0 para que yardas sea promovido a double y todas las operaciones
aritméticas de esa sentencia se realicen con precision double.
En este ejemplo se muestra la construcción de un programa, de manera que una vez ejecutado nos
pregunta el número de calzado, peso y color favorito. Así, el formato %6.2f: deberá mostrar peso
en 6 espacios, de los cuales 2 serán para los decimales y 1 para el punto decimal.
#include <stdio.h>
void main(void)
{
int calzado;
float peso;
char color[20];
printf("Confiesa tu calzado, peso y color favorito:\n");
printf("\n Calzado: ");
scanf("%d", &calzado);
printf("\n Peso: ");
scanf("%f", &peso);
printf("\nColor favorito: ");
scanf("%s", color);
printf("¡El %s!\n", color);
printf("¿Cómo puede gustarte el %s\n", color);
printf("Calzando un %d y pesando %6.2f Kg.?\n", calzado, peso);
getch();
}
Comentario:
En la función printf() hay que utilizar diferentes formatos de salida para las variables que
deseamos imprimir en pantalla. Así, el formato %6.2f: mostrará peso en 6 espacios, de los cuales
dos serán para los decimales y uno para el punto decimal. Observa cómo se pide el peso, calzado y
color favorito de forma que los dos puntos (:) queden alineados en la pantalla.
#include <stdio.h>
main ()
{
/* Definición de variables*/
int a, b;
int suma, resta, producto, division, modulo;
int postincremento, preincremento;
int postdecremento, predecremento;
printf("introduzca dos números a y b: ");
______________________________________________________________________________________ 40
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
scanf("%d %d", &a, &b);
suma=a+b;
resta=a-b;
producto=a*b;
division=a/b;
modulo=a%b;
postincremento=a++;
preincremento=++a;
postdecremento=b--;
predecremento=--b;
printf("Suma= %d\n", suma);
printf("Resta= %d\n", resta);
printf("Producto= %d\n", producto);
printf("Division= %d\n", division);
printf("Modulo= %d\n", modulo);
printf("Postincremento de %d= %d\n", a, postincremento);
printf("Preincremento de %d= %d\n", a, preincremento);
printf("Postincremento de %d= %d\n", b, postdecremento);
printf("Predecremento de %d= %d\n", b, predecremento);
getch();
______________________________________________________________________________________ 41
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Es fácil de pensar que las tareas de diseño de los algoritmos pueden subdividirse en
sub-tareas, las que pueden ser resueltas independientemente. En esta parte discutiremos el método
de diseño modular de algoritmos y los programas que él permite implementar.
Veremos como las funciones pueden ser usadas en un programa C, y como nuevas funciones
pueden ser definidas en el programa. Veremos las facilidades que ofrecen las “macros”, y como
ellas pueden ser implementadas para hacer los programas más fáciles de leer y actualizar.
La mayoría de los lenguajes de programación crean sus propios procedimientos o
funciones, y C no podía ser la excepción. De manera que esta sección mostrará como dividir sus
códigos en funciones, el objetivo radica en que es más fácil cambiar segmentos de programas por
otros, en vez de cambiar el programa completo, más aún, si C facilita la compilación separada, es
decir, permite partir un programa en archivos en donde cada uno sea compilado por separado. La
ventaja es muy natural, pues no requiere de una compilación del programa completo ( para los
impacientes!!).
Las funciones son un grupo de códigos usados en forma de unidades compactas que
pueden ser utilizadas repetidas veces. La función main() es un ejemplo de ellas, la cual es llamada
al comienzo del programa, todas las otras funciones son llamadas directa o indirectamente desde
main().
Las siguientes consideraciones deben ser respetadas para PROTOTIPO DE
FUNCIONES.
/* Nombre: triangulo
Fecha: 12.12.96
Descripción: computa el Area de un Triángulo
Parámetros: base, altura
Returns: area
*/
float triangulo ( float base, float altura ) /* función prototipo */
{
float area; /* area del triángulo */
area = base * altura / 2.0 ; /* cálculo */
return(area);
}
______________________________________________________________________________________ 42
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Consideremos el Ejemplo 7, pero ahora el cómputo del sueldo se hace a través de una función.
/* file: pe97c5.cpp
Nombre del programa: sueldo mediante una función
Fecha: 10.12.96
Propósito: Este programa calcula e imprime el sueldo para un número arbitrario
de persona. Una función separada es usada para calcular el sueldo total.
*/
#include<stdio.h>
#define LIMITE 40.0
#define FACTOR 1.5
main()
{ /* declaración*/
int id_numero;
float horas_trabajadas, costo_por_hora, sueldo_total;
float calculo_sueldo(float horas, float costo); /* prototipo función */
/* Imprimir el título */
printf("***cálculo del sueldo***\n\n");
/* cálculo de sueldos */
sueldo_total=calculo_sueldo(horas_trabajadas, costo_por_hora);
id_numero=123
horas_trabajadas=20.000000 , costo_por_hora= $7.50
sueldo= $150.00
Comentarios:
Las sentencias debug muestran claramente los parámetros de entrada a calculo_sueldo() y el
retorno de sueldo. La utilidad de debug es detectar en la función cualquier anomalía
Cuando se invoca a una función, y se tenga solamente acceso a los valores de sus argumentos, y
NO a los argumentos mismos, se dirá que es una llamada por valor. En C todas las llamadas son
______________________________________________________________________________________ 44
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
por valor, es decir, es imposible que una función llamada tenga acceso directo a un objeto definido
en la función.
/* archivo pe97c6.cpp
12.12.96
programa demostrativo de una llamada por valor TRAZA
*/
#include<stdio.h>
main() x
{ int x; ?
int crece(int n);
printf("***llamada por valor***\n");
x=7; 7
printf("el valor original de x es %d\n", x); 7
printf("el valor de crece(x) es %d\n", crece(x)); 8
printf("el valor de x es ahora, ó siempre ha sido!! %d\n", x); 7
return 0;
}
/* función crece */ n
int crece(int n) 7
{
n= n+1; 8
return n; 8
}
La traza muestra que la variable x en main() tiene asignada a priori el valor 7 a la llamada crece(), la
cual incrementa su parámetro a 8 y retorna este valor. Después de la llamada a función, el valor de
x en main() es 7, el cual NO ha cambiado pues, SOLAMENTE EL VALOR de x es pasado a
crece(). Por lo tanto, hemos visto que una llamada a función NO puede directamente cambiar los
valores de un objeto definido en la función llamada.
Todas las variables y funciones de C poseen dos importantes atributos, ellos son: Amplitud y
Clase de Almacenamiento.
Amplitud de una variable es el área del programa en donde la variable es válida. Ellas pueden ser
variables globales, las cuales son válidas en todas partes ( de allí su nombre ), de manera que su
alcance es el programa mismo y variables locales las que se limitan al bloque donde ella está
declarada y no puede ser accesada fuera de este bloque, en donde bloque es una sección de
códigos encerrados en paréntesis { }.
______________________________________________________________________________________ 45
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Ejemplo 11: ( Diferencia entre variable local y global. )
EJEMPLO 12: ( Variables locales con el mismo nombre que las variables globales )
main( )
{
total = 0;
contador = 0; /* conjunto global contador */
Comentario:
Como se vé el campo de la variable contador (primera vez declarada) es válido en todo el
programa. La declaración de la segunda variable local contador toma precedencia sobre la
declaración global al interior del bloque más pequeño , que es donde fué declarada la variable
contador. En este bloque la variable global contador está escondida. Las estructuras de control aquí
utilizadas serán en los próximas páginas aclarados.
Almacenamiento
AUTO: Las variables declaradas dentro del cuerpo de funciones son automáticas por omisión. De
la misma manera las variables definidas dentro de bloques son también automáticas, esto se declara
mediante la palabra reservada AUTO la que por lo general, se omite.
Ejemplo 13:
{ es equivalente a {
char c; auto char c;
int i, j, k; auto int i,j,k;
} }
Dentro de este bloque se consideran las variables locales a él, lo que significa que saliendo del
bloque el sistema deja de reservar memoria para las variables AUTO, por lo que se pierden sus
valores. Si se ingresa nuevamente al bloque se activa otra vez el proceso pero SIN los valores
anteriores. La amplitud de las variables AUTO son LOCALES al bloque, en el cual han sido
definidas.
EXTERN: estás variables constituyen un método para transmitir información entre bloques.
Cuando una variable es declarada fuera de una función se le asigna almacenamiento permanente , y
su clase es EXTERN. Este tipo de variables se consideran globales para todas las funciones
declaradas después de ella. Notar que al salir del bloque ó de la función , la variable externa
permanece.
main( )
{
double f( );
z= f( );
printf(“%.lf %.lf %lf\n”, x, y, z); /* 3.0 2.0 9.0 */
}
double f ( ) /* la función posee la clase externa de almacenamiento */
{
double y, z;/* y, z son locales, y, z “globales” están escondidas */
x = y = z = 3.0;
return ( x + y + z );
}
Las variables externas permanecen existiendo durante la ejecución del programa, la utilidad es para
transmitir valores entre funciones, ó para informar al cuerpo de la función que se espera una
variable de otro lugar ( incluso puede NO ser visible dentro de este archivo, sino provenir de un
archivo externo).
REGISTER: Esta clase de almacenamiento indica que las variables deberán almacenarse en
registros de memoria de alta velocidad, objetivo principal de esta declaración es intentar mejorar la
velocidad de ejecución. Se recomienda declarar REGISTER las variables que tengan acceso más
frecuente a un ciclo ó funciones.
Ejemplo 15:
______________________________________________________________________________________ 47
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
{
register int i; /* notar que se declaro lo más cerca de su lugar de uso */
for (i = 0; i < LIMITE; ++i )
{
................
}
} /* la salida del bloque dejará libre al registro */
STATIC: Tiene dos usos importantes, uno de ellos es permitir que una variable local retenga su
valor previo antes de entrar de nuevo en el bloque donde reside, esto es lo contrario a las variables
AUTO que perdían su valor al salir del bloque donde residen, requiriendo nueva asignación de
valores iniciales. Sencillamente una variable local STATIC es una variable local que retiene su valor
entre llamadas de funciones.
Ejemplo 16: A veces es útil saber cuantas veces ha sido invocada una función. Para tal efecto y a
manera de ver como trabaja la variable STATIC se define la función cuentas( ).
#include <stdio.h>
include<conio.h>
int cuenta(int i);
main(void )
{
do
{
cuenta(0);
}
while (!kbhit()); /*espera a que se pulse una tecla , la función kbhit()
devuelve verdad si se ha pulsado una tecla del teclado, en cualquier otro caso
devuelve 0*/
printf(“ se ha invocado a cuenta %d veces”, cuenta(1));
return 0;
}
cuenta(int i);
{
static int c=0;
if (i ) return c;
else c++;
return 0;
}
Comentario:
En este ejemplo si se llama a cuenta() con un valor 0 se incrementa la variable c. Si se llama a
cuenta() con cualquier otro valor devuelve el número de veces que ha sido invocada la función. La
utilidad de este programa, aparte de ejemplificar la declaración STATIC, es mostrar el número de
veces que una función ha sido llamada, que puede ser mucha utilidad para el estudio del Análisis y
Complejidad de Algoritmos.
Otro buen ejemplo es para generar series numéricas que produzcan un nuevo número basado en el
último generado, de allí la conveniencia de utilizar STATIC. Un segmento de lo dicho se expresa en
el siguiente segmento de programa
______________________________________________________________________________________ 48
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
series ( void)
{
static int num;
Comentario:
La variable num sigue existiendo entre las sucesivas llamadas a la función, en lugar de ir y venir
como lo haría una variable local normal, de manera que cada llamada a series() produce un nuevo
miembro de la serie basado en el número precedente. Notar que carece de inicialización, pues la
primera vez que se llama a la función, num tendrá el valor implícito de cero. Por otra parte las
clases de almacenamiento pueden ser ya sea permanentes o temporales.Las variables globales
son siempre permanentes, ellas son creadas e inicializadas antes de que el programa comience y
se quedan hasta que el programa termina.
Las variables temporales están localizadas en una sección de memoria llamada STACK al
comienzo del bloque, por tal motivo si Ud. trata de almacenar muchas variables temporales, le
saldrá un mensaje “Stack overflow”. Cada vez que el bloque es ingresado las variables temporales
son inicializadas.
El tamaño de este Stack depende del Sistema Operativo y del Compilador que se este usando.
En UNIX el programa está localizado automáticamente en el Stack más grande posible.
En Turbo C el espacio STACK es al menos 64,000 bytes.
______________________________________________________________________________________ 49
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
3 RECURSIVIDAD
Una función recursiva debe tener dos reglas básicas: Debe tener un punto FINAL y
debe SIMPLIFICAR el código del programa.
Comentarios:
Se tiene en cuenta que una función es recursiva cuando se llama a sí misma, ya sea directa o
indirectamente.
Llamada de la función valor devuelto
factorial(1) 1
factorial(2) 2 * factorial(1)
factorial(3) 3 * factorial(2)
factorial(4) 4 * factorial(3)
En factorial(), la variable n se disminuyó en 1 cada vez, hasta llegar al caso
base con n igual a 1, esto significa que en el cálculo se realizan n-llamadas a la función.
/* file: ej41.cpp*/
#include<stdio.h>
#define N 5
int suma(int n);
void main(void)
{ /* prueba de la función*/
int n;
for(n=1; n<=N;++n)
printf("\n%2d", suma(n));
printf("\n\n");
}
int suma(int n)
{
if (n<=1)
return(n);
else
return(n+ suma(n-1));
}
Comentarios:
La función suma( ) se desglosa según lo siguiente:
Llamada de la función valor devuelto
suma(1) 1
suma(2) 2 + suma(1)
suma(3) 3 + suma(2)
suma(4) 4 + suma(3)
suma(5) 5 + suma(4)
En suma( ), la variable n se disminuyó en 1 cada vez, hasta llegar al caso base con n igual a 1.
______________________________________________________________________________________ 51
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
#include<stdio.h>
unsigned long fibo(unsigned long i)
{
if(i<=1L)
return 1L;
else
return(fibo(i-1L)+ fibo(i-2L));
}/* fibonacci como una función RECURSIVA*/
La función main( ) utiliza la función scanf( ) para leer un entero dentro del valor i de T.
Después invoca busqueda_binaria(1, N), la cual devuelve SI ó NO.
/* file ej50.cpp */
#include<stdio.h>
int si=1, no=0;
#define N 7
int X[]={0, 11, 22, 33, 44, 55, 66, 77};
int T;
int busqueda_binaria(int min, int max)
{
int k;
if ( min > max ) return no;
k=(min + max)/2;
if (T==X[k]) return si;
else
if(T<X[k]) return busqueda_binaria(min, k-1);
else
if(T>X[k]) return busqueda_binaria(k+1, max);
}
int main (void)
______________________________________________________________________________________ 52
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
{
scanf("%d", &T);
if (busqueda_binaria(1, N))
printf("encontrado\n");
else
printf("NO encontrado\n");
return 0;
}
4 ITERACION
int main(void)
{
long ulvalor;
for(ulvalor=0L; ulvalor<=65000L;ulvalor++)
factorial(12L);
printf("%ld\n", factorial(12L));
return(0);
}/* fin de la función main()*/
Comentarios:
Los números de Fibonacci tienen muchos usos y propiedades importantes, una de ellas es el
cuociente de Fibonacci, formado por el cuociente F(n) / F(n-1), el cual es posible de demostrar que
converge al número real 1/2(1+sqrt(5)).
5 COMPLEJIDAD DE ALGORITMOS
Sin embargo, después de todas estas observaciones sobre recursividad v/s no-recursivo, no
podría abandonar está parte sin entregarles al menos una “carta” respecto de la Complejidad de
Algoritmos, que es en definitiva quién nos dirá, según algunos mecanismos, que implementación
escoger.
En el caso que se utilice una ó pocas veces conviene escoger según el objetivo (1), sin embargo
frente a un algoritmo que requiere un uso constante, entonces es más ventajoso utilizar el objetivo
(2), de lo que se infiere, que un buen programador no sólo debe preocuparse que el programa se
ejecute con “rapidez”, sino que también debe saber cuándo aplicar algunas técnicas de optimización
ó ignorarlas.
* Unidades de medida:
En general no vamos a utilizar unidades de tiempo dependientes de una máquina específica, sino de
parámetros tales como Nº de comparaciones, Nº de intercambios, Nº de llamadas a un
procedimiento, etc.
BEGIN
y := 1; p:= 1; {* la inicialización tiene un costo constante de dos
asignaciones *}
WHILE (y < n) DO {* el ciclo es ejecutado n-veces, y cada vez se
ejecutan 3 sentencias. La comparación y las dos asignaciones en el cuerpo del
WHILE-DO *}
BEGIN
p:= p * i
y:= y + 1
END
END
{* el tiempo de complejidad f(n) de este algoritmo sobre una entrada n es f(n)=3n + 2. *}
Ejemplo.
el bucle exterior se realiza N veces, mientras que el interior se realiza 1, 2, 3, ... N veces
respectivamente. En total 1 + 2 + 3 + ... + N = N*(1+N)/2 , es decir O(n 2). A veces aparecen bucles
multiplicativos, donde la evolución de la variable de control no es lineal (como en los casos
anteriores)
c= 1;
while (c < N) {
algo_simple
c= 2*c;
______________________________________________________________________________________ 56
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
}
El valor incial de "c" es 1, siendo "2 k" al cabo de "k" iteraciones. El número de iteraciones es tal
que 2k ≥ N => k= eis (log2 (N)) [el entero inmediato superior] y, por tanto, la complejidad del bucle
es O(log n).
c= N;
while (c > 1) {
algo_de_O(1)
c= c / 2;
}
Un razonamiento análogo nos lleva a log2(N) iteraciones y, por tanto, a un orden O(log n) de
complejidad.
tenemos un bucle interno de orden O(log n) que se ejecuta N veces, luego el conjunto es de orden
O(n log n).
Los métodos y elementos para resolver recurrencias, analizar y optimizar algoritmos se verán en el
curso regular de DISEÑO Y ANALISIS DE ALGORITMOS.
A pesar que se tiene el conocimiento de una potente herramienta teórica para estimar el tiempo de
complejidad, no es demasiado temprano para preguntarnos si existe un método más práctico para
medir exactamente el costo de nuestro algoritmo en nuestro computador. La respuesta es SI
existen, y los elementos para llevarlos a cabo están en la librería TIME.H
______________________________________________________________________________________ 57
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
/* begin fibonacci recursivo */
/*file: fibo.cpp*/
#include<stdio.h>
#include<time.h>
unsigned long fibo(unsigned long i)
{
if(i<=1L)
return 1L;
else
return(fibo(i-1L)+ fibo(i-2L));
}
int main (void)
{
clock_t end;
unsigned long i;
printf("\n\n\n este programa mide el tiempo..\n\n");
for(i=0L; i<1000L;i++)
fibo(20L);
printf("%ld\n", fibo(20L));
end=clock();
printf("%lf segundos\n", end / CLK_TCK);
return(0);
}
/*fin fibonacci recursivo */
Comentario: Ejecute ambos programas por separado (por supuesto) y compare los resultado que
obtiene, los cuales dependerán evidentemente del computador que está utilizando.
start = clock();
for ( t=0; t< 500000L; t++);
stop= clock();
printf(" el ciclo for requiere %f segundos\n", (stop - start) / CLK_TCK);
return 0;
}
Comentario:
La función clock() devuelve un valor aproximado del tiempo que se ha estado ejecutando el
programa de llamada a clock(). Devuelve el valor -1 si el tiempo no está disponible. Para
transformar este valor a segundos, basta dividirlo por la constante CLK_TCK*/
6 PREPROCESADORES en C
Como Ud. puede ver el preprocesador reemplaza el nombre de la macro por el string especificado.
La amplitud de la definición de la macro es el código fuente después de la línea en donde se declaro
la #define. La definición puede ser removida utilizando #undef.
Es posible utilizar macros con argumentos para reemplazar la llamada a las funciones, por ejemplo
en vez de escribir la función cuadrado de un número bastará con definir la macro:
Sin embargo, deben recordar que las llamadas a macros son SUSTITUCIONES y los parámetros
de las macros NO son nunca evaluados o chequeados por algún tipo de dato consistente.
#include<stdio.h>
#define SQR(x) (x * x )/* después de ejecutarlo, diga que es lo que obtiene*/
main ( )
{
int contador; /* contador para el loop */
for ( contador = 0; contador < 5; contador ++ )
{
(void) printf (“x %d, x cuadrado %d\n”, contador + 1, SQR(contador + 1 ) );
}
return(0);
} /* Este programa trae un error, cómo lo mejora??*/
Comentario:
El problema surge porque SQR( contador + 1) es ( contador + 1 * contador + 1 ), luego la
solución al problema radica en cambiar la definición de #define SQR....por
#define SQR(x) ( (x) * (x) ).
______________________________________________________________________________________ 60
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Son frecuentemente utilizadas las macros para sustituir a llamadas de funciones por codificación
en línea, lo cual es más eficiente, por ejemplo
#define MAX(x,y) ( ( (x) > (y) ) ? (x) : (y) ) que utiliza el operador ?
/***********************************************
* Utiliza macros para el cálculo de algunas funciones
* Propósito: mostrar macros, y la recursividad de las macros*/
#include<stdio.h>
#include<stdio.h>
#define CUADRADO(x) x*x
#define CUBO(x) CUADRADO(x)*x
#define ABS(x) ((x >=0) ? x : 0 - x )
#define PRODUCTO(x,y) x*y
#define IMPRIME(x) printf("\n"#x)
void main(void)
{
float z= -7., v=6.;
Comentario:
Se definen 5 MACROS que son llamadas y ejecutadas desde main( ), la primera de ellas es el
cuadrado de un número, cuyo tipo NO se define en la macro, sino dentro del programa, la segunda
es una extensión de CUADRADO, la tercera utiliza la sentencia reducida de
IF-ELSE, y la última que imprime una cadena sin entrecomillarla.
/* pe97c7.cpp
nombre: dias calurosos
fecha : 12.12.96
propósito: contar el número de días calurosos de un conjunto de temperaturas
*/
#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define FRIO 80
#define CALOR 90
#define DCALOR(t) ((t) > CALOR )
#define DFRIO(t) ((t) < FRIO )
#define XDIAS(n,b) (((n)+(b))> 0)
int dias_bueno(int temp);
void impri_resul(int bueno, int nublados, int temp_sum);
main()
{ /* declaracion */
int temperatura, /* temperatura diaria */
total=0, /* inicializador del acumulador */
num_dias_bueno=0,
num_dias_nublados=0;
return TRUE;
}
if XDIAS(dias_bueno, dias_nublados) {
temp_promed= (float) total/ (float)(dias_bueno + dias_nublados);
printf("El promedio de temperaturas para %d dias fué de %f\n",
dias_bueno + dias_nublados, temp_promed);
}
}
Comentario:
Ejecute el programa para una cantidad de datos.
Una macro interesante que se encuentra en stdio.h es llamada EOF (End Of File)
De manera que es posible ahora escribir un programa que contenga un loop que TERMINE
cuando el FIN del archivo de entrada haya sido alcanzado.
#include<stdio.h>
......
semaforo=scanf( );
while ( semaforo != EOF ) {
........
______________________________________________________________________________________ 63
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
semaforo = scanf( );
}
Comentario:
El valor devuelto por scanf( ) es almacenado en la variable semaforo. El loop se repite hasta que
semaforo recibe (la luz verde ) EOF. El código anterior es portable a cualquiera implementación
ya que el valor está definido en stdio.h en todo implementación. Podemos entonces ahora escribir
un programa que use FIN de archivo para terminar la lectura de datos.
/* pe97c9.cpp
nombre: archivo EOF
fecha : 12.12.96
propósito: leer datos hasta fin de archivo
*/
#include <stdio.h>
int abs(int n);
main()
{ /* declaracion */
int largo=0, n, semaforo;
/* imprime titulo y prompt */
printf("***entero absoluto más grande***\n\n");
printf(" ingrese el entero, EOF para salir: "
"^Z para DOS, ^D para UNIX\n");
semaforo=scanf("%d", &n);
while ( semaforo!=EOF) {
if (abs(n)> largo)
largo= abs(n);
semaforo=scanf("%d", &n);
}
printf("El valor absoluto más grande es =%d\n",largo);
return 0;
}
/* función que retorna el valor absoluto de n */
int abs(int n)
{
if (n < 0 )
return -n;
else
return n;
}
Comentario:
La salida se ve, así
Hasta el momento hemos considerado solamente tipos de dato numéricos, sin embargo en
programación no todos los datos tienen esta cualidad, pues la programación de una password
encriptada podría ser una buena aplicación de los tipo de elementos char ó determinar el número de
comas ó dígitos ó símbolos extraños que un texto posee, lo que en Teoría de Autómatas y
Lenguajes Formales se conoce como un “reconocedor de palabras” , tema que se abordará en esa
asignatura. Por tal motivo veremos una serie de ejemplos que nos darán los rudimentos para
abordar este tipo de problemas.
______________________________________________________________________________________ 65
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
/* pe97c11.cpp
nombre: char: ch
fecha : 12.12.96
propósito: leer un stream de caracteres, un caracter a la vez, y enviarla a la
salida hasta EOF
*/
#include <stdio.h>
main()
{ char ch; /* declaración para un objeto ch */
int bandera; /* bandera almacena el número de items leídos por
scanf()*/
/* imprime titulo */
printf("***Copia del Programa***\n\n");
printf("tipo de texto, termina con EOF\n");
Comentario:
La conversión específicada para formatear datos de tipo character es %c.
Los datos de tipo caracter están representados en el computador usando un código numérico
estandarizado, llamado código ASCII, el cual posee 128 caracteres con valores del 0 al 127.
Entonces 7 bits son suficientes para representar los caracteres en ASCII, aunque algunos
computadores reservan 1byte (8bits) para los caracteres ASCII.
A propósito de la tabla de códigos ASCII, debemos hacer notar que ‘A’ tiene el código 65, el ‘B’
tiene el valor 66 y así sucesivamente. Es importante mencionar el hecho que los valores ASCII de
las letras ‘A’ hasta la ‘Z’ son contiguos en forma creciente desde el 65 hasta el 90, las minúsculas
en cambio comienzan del valor 97, con la misma particularidad que las mayúsculas. Similarmente
los dígitos del ‘0’ al ‘9’ , los cuales parten del valor 48. Cabe distinguir que los símbolos dígitos
son de tipo character, es decir NO confundir ‘0’ que tiene el valor 48 con el 0 como valor.
/* pe97c12.cpp
nombre: ascii
fecha : 12.12.96
propósito: leer una lista de caracteres hasta el fin del archivo, imprimiendo
los atributos reconocedores del código ASCII, entre otros.
*/
______________________________________________________________________________________ 66
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
#include <stdio.h>
void imp_reps(char ch);
main()
{ char ch; /* declaración para un objeto ch */
int bandera; /* bandera almacena el número de items leídos por
scanf()*/
/* imprime titulo */
printf("***Atributos***\n\n");
printf("tipo texto, termina con EOF\n");
bandera=scanf("%c", &ch);/* lee el primer caracter */
getchar( ) y putchar( ) son rutinas de la librería stdio.h, las cuales son más generales que las
librerías estandares de entrada y salida. La función getchar( ) lee un caracter simple desde la
______________________________________________________________________________________ 67
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
entrada estandar y retorna el valor del caracter como el valor de la función, el tipo del valor
retornado es int, aunque para evitar confusiones se considera signed char para almacenar los
valores. La rutina similar para salida de caracteres es putchar( ), la cual devuelve sus argumentos
como caracteres a la salida estandar. Es decir, devuelve los caracteres ASCII cuyos valores están
en c a la salida estandar, El argumento para putchar se espera que sea int, sin embargo la variable c
puede ser char (que corresponde a los valores enteros de ASCII). A continuación se escribe un
programa que usa esta nueva manera de entrada/salida en vez de las estandares scanf( ) y
printf( ).
Otra diferencia es que scanf( ) almacena los datos en un objeto cuya dirección está dada por sus
argumentos, mientras getchar( ) retorna el valor del caracter leído como su valor.
/* pe97c13.cpp
nombre: getchar() y putchar()
fecha : 12.12.96
propósito: copiar entrada estandar en salida estandar
*/
#include <stdio.h>
main()
{ signed char c; /* declaración para un objeto ch */
/* imprime titulo */
printf("***copia archivo***\n\n");
printf("tipo texto, se sale con EOF\n");
c=getchar();
while (c !=EOF) {
putchar(c);
c=getchar();
}
return 0;
}
Observación: En C no existe tipo dato primitivo para string; sin embargo constantes string
(también llamadas string literales) pueden ser escritas directamente en un programa usando
comillas. Por ejemplo string nulo es “ “, otra constante es “Juan Perez”. Entonces NOTAR la
diferencia entre ‘c’ que es una constante char y “c” que es una constante string de un caracter y el
caracter NULL, es decir, “c” se representa por ‘c’ \0’, “string” se representa por ‘s’ ‘t’ ‘r’ ‘i’ ‘n’ ‘g’
\0’, mientras que ‘c’ se representa por ‘c’
Lo que resulta bastante usual en programación es confeccionar macros que realicen tareas como
pasar un texto de mayúscula a minúscula, reconocer palabras ó dígitos, etc. dada una cadena de
caracteres. Aquí se presentarán dos programas, que deberían darle la inspiración necesaria para
implementar otras tareas en este tema.
/* pe97c14.cpp
nombre: mayuscula()
fecha : 12.12.96
propósito: copiar archivo de entrada a la salida estandar, después de convertir
minúsculas a mayúsculas
*/
#include <stdio.h>
______________________________________________________________________________________ 68
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
#define es_min(c) ((c) > = 'a' && (c) < = 'z')
#define va_may(c) ((c) - 'a' + 'A')
char mayuscula(char ch);
main()
{ signed char ch; /* declaración para un objeto ch */
/* imprime titulo */
printf("***copia programa- caso mayúscula***\n\n");
printf("tipo texto, se sale con EOF\n");
Comentario:
En la expresión while ((ch = getchar())!= EOF) se ha combinado la operación de leer un caracter
y preguntar por EOF. En los paréntesis internos son evaluados primero, getchar() leyendo un
caracter y asignando el valor retornado a ch. El valor asignado a ch está entonces comparándolo
con EOF. Si no es EOF el loop se ejecuta, de otra manera el loop termina. La precedencia es
importante, de allí los paréntesis.
/* pe97c15.cpp
nombre: getint()
fecha : 12.12.96
propósito: convertir una sucesión de caracteres dígitos a enteros
*/
#include <stdio.h>
#define DEBUG
#define es_min(c) ((c) >= 'a' && (c) <= 'z')
#define es_dig(c) ((c) >= '0' && (c) <= '9')
#define ERROR -1
main()
{
printf("***secuencia de dígitos a enteros***\n\n");
printf("Tipee una secuencia de dígitos\n");
printf("Entero=%d\n", getint());
return 0;
}
int getint()
{ int n=0;
______________________________________________________________________________________ 69
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
signed char ch;
ch=getchar();
while (es_dig(ch)){
n= n*10 + dig_ent(ch); /* approach modular */
______________________________________________________________________________________ 70
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
8 PUNTEROS
La mayoría de los programas que debemos implementar se sustentan en estructuras de
datos de longitud desconocida. Un ejemplo simple podría ser el de un programa que lee las líneas
de un archivo y las ordena. Por tanto, deberemos leer un número indeterminado de líneas, y tras
leer la última, ordenarlas. Una manera de manejar ese ``número indeterminado'', sería declarar una
constante, por ejemplo, MAX_LINEAS, darle un valor “grande” y, declarar un array de tamaño
MAX_LINEAS. Como se puede ver nuestro programa no sólo quedaría limitado por ese valor
máximo, sino que además gastaría esa enorme cantidad de memoria.
La propuesta para salvar esta situación es el de utilizar memoria dinámica. La memoria
dinámica es un espacio de almacenamiento que se solicita en tiempo de ejecución. De esa manera, a
medida que el proceso va necesitando espacio para más líneas, va solicitando más memoria al
sistema operativo para guardarlas. El medio para manejar la memoria que otorga el sistema
operativo, es el puntero, puesto que no podemos saber en tiempo de compilación dónde nos dará
espacios el sistema operativo. Hay un aspecto de las funciones en C que tienen singular importancia
para introducir el concepto de puntero. Por ejemplo,
#include<stdio.h>
#define PI 3.141596
float area(float);
main( )
{
float radio, superficie;
printf(“introduzca el radio\n”);
scanf(“%f”, radio);
superficie= area(radio);
printf(“\nRadio %f Superficie %f”, radio, superficie );
return0;
}
float area ( float rad)
{
float super;
super= PI * rad *rad;
return(super);
}
Comentario:
En este programa y en otros, los datos que pasamos a la función son copias de los datos, NO los
datos mismos, en tal caso, estamos frente a una llamada por valor.
En el ejemplo anterior, se copian 4 bytes de datos almacenados en la memoria reservada para el
nombre radio, a la zona de memoria llamada rad, que también posee 4 bytes. Las operaciones en
la función area( ) se realizan sobre esta última zona de memoria, no sobre radio, y el valor
resultante se almacena en super temporalmente, antes de copiarse en superficie. Las variables de
area( ) son locales de tipo automatic y quedan liberadas (su espacio es devuelto a la memoria
interna de la computadora) una vez que se ejecuta la función.
Para nuestros efectos, la variable radio de la función main( ) sigue invariable en tanto no tome un
nuevo valor en una nueva llamada a area( ), y el espacio de memoria y valores asociados a las
variables pertenecientes a area( ) desaparecen.
______________________________________________________________________________________ 71
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Otra transmisión de datos se refiere a llamada por referencia, en la cual NO se envía una copia de
los datos sino la dirección que estos ocupan en la memoria, de allí la posibilidad de utilizar
punteros.
Un puntero es la dirección de memoria de una variable. Las utilidades principales son:
* Poder proporcionar una rápida forma de referenciar los elementos de un array.
* Permitir a las funciones de C modificar los parámetros de llamada.
Operadores &y*
El operador & es un operador “monario” que entrega la dirección de memoria de un objeto. Por
ejemplo, m=&contador; /* asigna la dirección de contador a la variable m*/
& se aplica solamente a objetos que están en memoria
El operador *, el cual es también “monario”, devuelve el valor de la variable ubicada en la dirección
que se especifíca, por ejemplo q=*m; se refiere a “q recibe el valor de la dirección m”.
/* Deposita el valor 10 en la variable recibe */
main (void)
{
int recibe, fuente;
int *m;
fuente = 10;
m = &fuente; /* & es usada para obtener la dirección del objeto fuente */
recibe = *m; /* desreferencia a m, ó contenido del operador * */
return 0;
}
#include<stdio.h>
main( )
{
int x;
int *iptr;
Comentario:
Este programa produce la salida
Sin embargo, observar que NO se está interesado en el valor de la variable puntero en sí, puede
incluso ser diferente cada vez que el programa se corra, lo realmente importante es saber el
contenido de la celda a la cual el puntero apunta. (Vea GRAF1)
______________________________________________________________________________________ 72
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Cuando estas declaraciones son encontradas, las celdas de memoria para estas variables se ven así.
(Vea GRAF2)
Como se ha discutido en C los argumentos son pasados a la función por valor. Sin embargo, para
implementar la llamada por referencia que Pascal posee, se utilizan los punteros ( en realidad, NO
solamente para esto). A propósito las funciones en C pueden retornar valores simples como valor
de la función, sin embargo a través del acceso indirecto la llamada a una función puede retornar
varios valores. Solamente un valor es actualmente retornado como el valor de la función, todos los
otros valores pueden ser indirectamente almacenados en objetos en la función llamada. Este uso de
las variables punteros es el más común en C.
/* pe97c16.cpp
nombre: incremento
fecha : 19.12.96
propósito: ilustrar el acceso indirecto de x por una función indire_incre(),
función incrementa x en 1
______________________________________________________________________________________ 73
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
*/
#include <stdio.h>
void indire_incre(int *p);
main()
{
int x;
printf("***acceso indirecto***\n\n");
x=7;
printf("el valor original de x es %d\n", x);
indire_incre(&x);
printf("el valor de x es ahora %d\n", x);
return 0;
}
void indire_incre(int *p)
{
*p=*p + 1;
} /*Vea GRAF 9*/
/* pe97c17.cpp
nombre: retornar por acceso indirecto
fecha : 19.12.96
propósito: usar una función que retorne el cuadrado de un argumento
e indirectamente almacena el cubo
*/
#include <stdio.h>
double scubo(double x, double *pcubo);
main()
{
double x, square, cubo;
printf("***directa e indirectamente retorna valores***\n\n");
x=3;
square=scubo(x, &cubo);
printf("x=%f, square=%f, cubo=%f\n", x, square, cubo);
return 0;
}
double scubo(double x, double *pcubo)
{
*pcubo=x * x * x;
return(x * x);
} /*Vea GRAF 10*/
/* pe97c18.cpp
nombre: intercambio
fecha : 19.12.96
propósito: usar una función que intercambia valores a través de punteros
*/
#include <stdio.h>
void swap(int *p1, int *p2);
main()
{ int dat1=100,dat2=200;
printf("antes de la llamada a swap dat1=%d, dat2= %d\n", dat1,dat2);
swap(&dat1, &dat2);
printf("después de la llamada a swap dat1=%d,dat2=%d\n", dat1, dat2);
______________________________________________________________________________________ 74
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
return 0;
}
void swap(int *ptr1,int *ptr2)
{ int temp
temp=*ptr1;
*ptr1=*ptr2;
*ptr2=temp;
} /* Vea GRAF 11*/
______________________________________________________________________________________ 75
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
9 ARRAY
Un array al igual que en Pascal es un conjunto de localización de memoria consecutiva usada para
almacenar datos, cada item en array es llamado elemento y el número de elementos en un array es
llamado dimensión del array.
Arreglo Unidimensional:
Todos los array tienen el 0 como índice de su primer elemento, luego por ejemplo, int p[10] ;
declara un arreglo de enteros que tiene diez elementos, desde p[0] hasta p[9].
/*Cuenta el número de elementos no-cero, parando cuando encuentra el cero*/
#include<stdio.h>
int array[10]={4,5,8,9,8,1,0,1,9,3};
int indice;
main(void)
{
indice=0;
while (array[indice]!=0)
indice++;
(void)printf("El número de elementos antes de leer el cero fueron %d\n",
indice);
return(0);
}
/*Cuenta el número de elementos no-cero, parando cuando encuentra el cero, pero versión
punteros*/
#include<stdio.h>
int array[10]={4,5,8,9,8,1,0,1,9,3};
int *arreglo_ptr;
main(void)
{
arreglo_ptr=array;
while ((*arreglo_ptr)!=0)
arreglo_ptr++;
(void)printf("El número de elementos antes de leer el cero fueron %d\n",
arreglo_ptr - array);
return(0);
}
Arreglo de Caracteres:
Strings son array de caracteres. El caracter especial ´\0´ (cero ) es usado para indicar el fin del
string. Por ejemplo, este segmento crea un array de longitud cuatro
______________________________________________________________________________________ 76
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
char nombre[4] ;
main()
{
name[0] = ´S ;
name[1] = ´O´;
name[2] = ´S;
name[3] = ´\0´;
return(0);
}
En todo programa la línea #include<string.h> es necesaria para informar a C que esta usando la
función libreria string. La función (void) indica que no está usando el valor de retorno de
strcpy( ). Otras funciones relacionadas con el manejo de cadenas son: strcat( ), strlen( ),
strcmp( ).
/* Ilustrar el uso de las funciones strcpy(), strcat(), strlen() y strcmp()*/
#include<stdio.h>
#include<string.h>
main(void)
{
char cadena1[80], cadena2[80];
Arreglo Bidimensional:
Los array bidimensionales de Pascal se declaraban [0..5, 0..7]. Mientras que en C por cada nueva
dimensión debe agregarse un paréntesis. Por ejemplo
/*matriz tipica*/
int matriz[tamaño1] [tamaño2];
Para accesar el 10 en el lugar (1,2) de la matriz usamos matriz[1] [2] = 10.
______________________________________________________________________________________ 77
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
fopen retorna un apundador al archivo si la llamada fue exitosa, y sino, retorna NULL. El apuntador
al archivo se utiliza para indentificar la fuente del mismo, se pasa como parámetro a las rutinas de
escritura, lectura y manejo del archivo. El filename y modo son cadenas de caracteres.
La funcion fflush se usa para físicamente escribir (bajar) en el archivo cualquier data almacenada en
el "buffer" intermedio. Para hacer los programas mas eficientes y reducir las llamadas al sistema, los
archivos mantienen un buffer (memoria) intermedia, una vez que el buffer esta lleno, los datos se
______________________________________________________________________________________ 78
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
escriben en el archivo. La rutina fflush fuerza a que el buffer sea escrito en el archivo asociado. Su
prototipo es:
Para escribir datos en un archivo se utiliza la fprintf. Esta función es muy similar a printf, que ya
sabemos manejar bien. La única diferencia es que fprintf tiene un argumento adicional, el
apundador a archivo que especifica la fuente donde queremos escribir. Su prototipo es:
int fprintf(FILE *fp, const char* format, ....);
fprintf retorna el número de caracteres que fueron escritos exitosamente o un número negativo en
caso de falla.
Para leer datos de un archivo se utiliza la función fscanf. Esta función es muy similar a scanf, que
ya sabemos manejar bien. La única diferencia es que fscanf tiene un argumento adicional, el
apundador a archivo que especifica la fuente de donde queremos leer. Recuerden que los
argumentos para guardar datos deben ser apuntadores (i.e, llevan & en caso de ser variables
simples, y solo el nombre en caso de ser arreglos de caracteres). Su prototipo es:
int fscanf(FILE *stream, const char* format, ....);
Ejemplo
El siguiente programa abre un archivo que contiene un nombre y cedula de indentidad. Luego abre
un archivo de salida y escribe estos datos (pero en orden invertido). El archivo de entrada fue
creado con un editor de texto.
#include <stdio.h>
int main()
{
char ifilename[] = "entrada.txt";
char ofilename[] = "salida.txt";
char name[30];
int idNum;
Ejercicio de Practica
Extender el ejercicio anterior para que sea capaz de leer y escribir múltiples pares de nombres y
cédulas. Sugerencia: Crear un ciclo y chequear cuando la rutina scanf retorna EOF.
Solucion:
#include <stdio.h>
int main(){
char ifilename[] = "c:/entrada.txt";
char ofilename[] = "c:/salida.txt";
char name[30];
int idNum;
FILE *ofp, *ifp;
ifp = fopen(ifilename,"r"); /* Abrir archivo entrada */
ofp = fopen(ofilename,"w"); /* Abrir archivo salida */
while (fscanf(ifp,"%s %d",name,&idNum) != EOF) {/*Leer datos */
fprintf(ofp,"%d %s\n",idNum, name); /* Escribir datos */
}
fclose(ifp); fclose(ofp); /* Cerrar archivos */
return 0;
int *fgets(char *s, int n, FILE *fp); Retorna un apuntador a la cadena de caracteres
leida si resulta exitoso, o NULL si se llega al final del archivo o si ocurre un error. La cadena es
también almacenada en el arreglo de caracteres especificado como argumento. Un máximo de n-1
caracteres seran leídos. Lo cual da espacio para guardar el carácater de fin de cadena '\0'.
int fputs(const char s*, FILE *fp); Escribe una cadena de caracteres en el archivo, retorna
EOF si hubo alguna falla.
int fputc(int c, FILE *fp); Escribe un caracter solo en el archivo, si hubo algun problema
devuelve EOF.
int sprintf(char *buffer, const char *format, ...); Esta función es similar a fprintf,
excepto que los datos son escritos en un arrreglo (o buffer) de caracteres en lugar de en un archivo
de salida.
int sscanf(char *buffer, const char *format, ...); Esta función es similar a fscanf,
excepto que los datos son leidos de un arrreglo (o buffer) de caracteres en lugar de un archivo de
entrada.
______________________________________________________________________________________ 80
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Argumentos de Línea de Comando
C provee un mecanismo para pasar argumentos desde la línea de comandos al programa que se va a
ejecutar. Cuando el programa comieza su ejecución, la rutina main es llamada con dos argumentos:
un contador y un apuntador a un arreglo de cadenas de caracteres. El contador es llamdo por
convención argc y el apuntador argv. El uso de de argv es un poco truculento. Dado que argv es
un apundador a un arreglo de cadenas de caracteres, la primera cadena de caracteres es
referenciada por argv[0] (o *argv). La segunda cadena is referenciada por argv[1] (o *(argv + 1)),
la tercera por argv[2], y así sucesivamente. La primera cadena de caracteres, argv[0], contiene el
nombre del programa. Los argumentos comienzan realmente con argv[1].
Un ejemplo de llamada de un programa llamado copia, que copie un archivo en otro archivo seria:
copia fuente.txt destino.txt. Esto es, el nombre del programa mas dos argumentos que
corresponderian a los nombres de los archivos fuente y destino. Veamos un ejemplo que
simplemente muestra los argumentos de un programa.
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
fprintf("The number of command line arguments is %d\n", argc);
fprintf("The program name is %s\n",argv[0]);
for (i = 1; i < argc; i++) {
fprintf("%s",argv[i]);
}
fprintf("\n");
return 0;
}
Referencias
Tutorial de Programación en C , conciso y bien escrito, con enlaces a muchos otros recursos para la
programación en C y C ++.
#include <stdio.h>
int main()
{
char ifilename[] = "entrada.txt";
char ofilename[] = "salida.txt";
char name[30];
int idNum;
10 APLICACIONES
En esta sección crearemos un pequeño programa que genera 10 números al azar y luego los
ordena. En cursos de estadística se estudiará con mayor detalle lo que son los números aleatorios,
los cuales están relacionados con la forma de predecir un resultado antes de que este suceda, por
ejemplo en el lanzamiento de los dados. Las secuencias de números aleatorios son muy importantes
en las Ingenierías, debido a que muchos sistemas tienen aspectos que varían al azar. Este problema
en sí , nos lleva a analizar la generación al azar y el ordenamiento.
/* ej20.cpp
nombre: azar
fecha : 10.12.96
propósito: usar una función rand() que genera nº aleatorios y los ordena
*/
#include<stdio.h>
#include<stdlib.h>
#define MAX 20
int a[MAX];
void main()
{ int i, t, x, y;
for (i=0; i < MAX; i++)
{
a[i]=rand();
printf("%d\n", a[i]);
}
for (x=0; x< MAX-1; x++)
for (y=0; y< MAX-x-1; y++)
if (a[y] > a[y+1])
{
t=a[y];
a[y]=a[y+1];
a[y+1]=t;
}
printf("---\n");
for (i=0; i < MAX; i++)
printf("%d\n", a[i]);
}
Comentarios:
Este programa genera 20 nº al azar y los ordena según el método de la búrbuja. Este esquema es
posible realizarlo para escribir sus propias librerías. Practique este hecho separando el programa en
librerías
/* ej21.cpp
nombre: ordenar
fecha : 12.12.96
______________________________________________________________________________________ 82
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
propósito: ordenar una lista de notas
*/
#include<stdio.h>
#define MAX 20
void main()
{ int i, j, notas[MAX], suma=0, aux;
/* pe97c20.cpp
nombre: string como arreglos
fecha : 19.12.96
propósito: leer un caracter hasta una nueva línea, almacenándolos
en un array y terminando el string con un caracter NULL. Luego lo imprime
*/
#include <stdio.h>
#define MAX 20 /* dimensiona el tamaño del array */
#define TAM 100
main()
{ char mens[TAM], ch;
int i=0;
______________________________________________________________________________________ 83
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
printf("***strings de caracteres***\n\n");
printf("tipo de caracteres terminados por RETURN ó ENTER\n");
while (mens[i]!='\0')
putchar(mens[i++]);
printf("\n");
return 0;
}
/* pe97c21.cpp
nombre: arreglos a funciones
fecha : 19.12.96
propósito: usar funciones para leer valores de un array e imprimir los valores
*/
#include <stdio.h>
#define MAX 20 /* dimensiona el tamaño del array */
main()
{ int n,valor_examen[MAX];
printf("***Lista de Examenes***\n\n");
n=leer_array(valor_examen, MAX);
impri_array(valor_examen, n);
return 0;
}
/* función lectura de datos de un array */
int leer_array(int valor[], int lim)
{ int n, contador=0;
printf("Tipee el valor, EOF para salir\n");
while ((contador<lim)&&(scanf("%d", &n) != EOF)){
valor[contador]=n;
contador++;
}
return contador;
}
/* función que imprime lim elementos en el array */
void impri_array(int valor[], int lim)
{ int i;
printf("\n***Valor de los exámenes***\n\n");
for (i=0;i < lim; i++)
printf("%d\n", valor[i]);
}
/* pe97c22.cpp
nombre: leer y escribir
fecha : 19.12.96
propósito: leer y escribir hasta que un vacío sea encontrado.
______________________________________________________________________________________ 84
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Usa funciones leer e imprimir para los archivos estandar.
*/
#include <stdio.h>
#define TAM 100 /* dimensiona el tamaño del array */
void print_string(char s[]);
void lee_string(char s[]);
main()
{ char string[TAM];
do {
lee_string(string);
print_string(string);
} while (string[0]);
return 0;
}
/* función lectura de datos desde una entrada estandar hasta que una nueva
línea es leída */
/* función que imprime un string a salida estandar y termina con una nueva
línea */
/* pe97c23.cpp
nombre: inicializar
fecha : 19.12.96
propósito: inicializar arreglos
*/
#include <stdio.h>
#define MAX 10 /* dimensiona el tamaño del array */
main()
{ int i, ex[MAX]= {12, 23,9, 17, 16, 49};
char saludo[MAX]={'H', 'o', 'l', 'a', '\0'};
char mensaje[]="El saludo del día es: ";
printf("***inicializaciónn de arreglos***\n\n");
printf("%s%s\n", mensaje, saludo);
printf("arreglo inicializado: \n");
for (i=0;i < MAX; i++)
______________________________________________________________________________________ 85
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
printf("%d\n", ex[i]);
return 0;
}
/* pe97c24.cpp
nombre: encontrar
fecha : 20.12.96
propósito: búsqueda lineal o secuencial en un array[] de tamaño lim de un item
key
*/
#include <stdio.h>
int busq_sec(int x[], int lim, int key);
void print_array_linea(int x[], int lim);
main()
{ int id[]= {45, 67, 12, 34, 25, 39};
int n, i;
printf("***búsqueda secuencial***\n\n");
printf("el arreglo es: \n");
print_array_linea(id, 6);/* función imprimir array horizontalmente*/
printf("ingrese un entero, EOF para salir: \n");
while(scanf("%d", &n) != EOF) {
i=busq_sec(id, 6, n);
if (i>=0)
printf("Item %d es encontrado en el indice %d\n", n, i);
else
printf("Item %d NO está en el array\n", n);
printf("ingrese un entero, EOF para salir: \n");
}
return 0;
}/* driver para testear la función busq_sec */
/* pe97c25.cpp
nombre: ordenar por selección
fecha : 20.12.96
propósito: ordenar un arreglo por el método de Selección
______________________________________________________________________________________ 86
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
*/
#include <stdio.h>
#define MAX 10
void orden_selec(int x[], int lim);
int max_pos(int x[], int lim);
void print_array_linea(int x[], int lim);
int obt_maxpos(int x[], int tam);
main()
{ int datos[MAX]= {63, 75, 90, 12, 27};
printf("***arreglo original:\n\n");
print_array_linea(datos, 5);
orden_selec(datos, 5);
printf("\n***arreglo ordenado:\n\n");
print_array_linea(datos, 5);
return 0;
} /* función selección */
void orden_selec(int x[], int lim)
{ int tam, maxpos, tmp;
for (tam=lim ; tam > 1; tam--) {
maxpos=obt_maxpos(x, tam);
tmp= x[maxpos];
x[maxpos]=x[tam -1];
x[tam -1]=tmp;
}
}
/* función que retorna el indice del elemento más grande en el array x[]*/
int obt_maxpos(int x[], int tam)
{ int i, maxpos=0;
for (i=0; i < tam; i++)
maxpos=x[i] > x[maxpos] ? i:maxpos;
return maxpos;
}
/* función imprime un array entero de tamaño lim */
void print_array_linea(int x[], int lim)
{ int i;
for (i=0; i < lim; i++)
printf("%d ", x[i]);
}
/* pe97c26.cpp
nombre: base de datos
Fecha : 20.12.96
propósito: calcular y almacenar datos para un número id´s.
Obteniéndo los datos, cálculo del pago e imprimir los datos para todos los id´s
*/
#include <stdio.h>
#define MAX 10
#define REG_LIMITE 40
______________________________________________________________________________________ 87
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
#define FACTOR 1.5
main()
{ int n, id[MAX];
float hrs[MAX], razon[MAX], normal_pago[MAX], sobre_pago[MAX];
printf("***programa sueldos***\n\n");
n=obt_datos(id,hrs,razon,MAX);
calc_pago(hrs,razon,normal_pago,sobre_pago, n);
print_datos(id,hrs,razon,normal_pago,sobre_pago, n);
return 0;
}
/* obtener datos para todos los id´s válidos y retornar el número de id´s*/
int obt_datos(int id[], float hrs[], float razon[], int lim)
{ int n=0;
while (n < lim) {
printf("ID <cero para salir>: ");
scanf("%d", id + n); /* id + n es lo mismo que &id[n] */
if (id[n] <=0) return n;
printf("Horas Trabajadas: ");
scanf("%f", hrs + n);
printf("Razón de pago: ");
scanf("%f", razon + n);
n++;
}
printf("no más espacio para datos-procesar datos\n");
return n;
}
/* pe97c27.cpp
nombre: ordenar base de datos
Fecha : 20.12.96
propósito: calcular y almacenar datos para un número id´s.
Obteniene los datos, ordena y calcula el pago e imprime los datos para todos
los id´s
*/
#include <stdio.h>
#define MAX 10
#define TRUE 1
#define FALSE 0
#define REG_LIMITE 40
#define FACTOR 1.5
main()
{ int n=0,id[MAX];
float hrs[MAX], razon[MAX], normal_pago[MAX], sobre_pago[MAX];
ftmp= hrs[k];
hrs[k]=hrs[k+1];
hrs[k+1]=ftmp;
ftmp= razon[k];
razon[k]=razon[k+1];
razon[k+1]=ftmp;
swap=TRUE;
}
}
}
/* pe97c28.cpp
nombre: base de datos
______________________________________________________________________________________ 90
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Fecha : 20.12.96
propósito: búsqueda de algún item en una base de datos ordenada
*/
#include <stdio.h>
#define MAX 10
#define TRUE 1
#define FALSE 0
#define REG_LIMITE 40
#define FACTOR 1.5
main()
{ int i, n=0, key, id[MAX];
float hrs[MAX], razon[MAX], normal_pago[MAX], sobre_pago[MAX];
if (i>=0)
print_reg(id, hrs, razon, normal_pago, sobre_pago, i);
else printf("ERROR - no existe id\n");
ftmp= hrs[k];
hrs[k]=hrs[k+1];
hrs[k+1]=ftmp;
ftmp= razon[k];
razon[k]=razon[k+1];
razon[k+1]=ftmp;
swap=TRUE;
}
}
}
/* calcular el pago regular y sobretiempo para cada id*/
void calc_pago(float hrs[], float razon[], float normal[], float sobre[],int n)
______________________________________________________________________________________ 92
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
{ int i;
for (i=0; i < n; i++) {
if (hrs[i]<= REG_LIMITE) {
normal[i]=hrs[i]*razon[i];
sobre[i]=0;
}
else {
normal[i]=REG_LIMITE*razon[i];
sobre[i]=( hrs[i] - REG_LIMITE )* FACTOR * razon[i];
}
}
}
/* Imprimir la tabla de datos para todos los id´s */
void print_datos(int id[], float hrs[], float razon[], float normal[], float
sobre[], int n)
{ int i;
printf("***REPORTE FINAL - Sueldos Ordenados***\n\n");
printf("%4s\t%5s\t%5s\t%6s\t%6s\t%6s\n", "ID", "HRS", "RAZON",
"NORMAL", "SOBRE", "TOTAL");
for (i=0; i<n; i++)
printf("%4d\t%5.2f\t%5.2f\t%6.2f\t%6.2f\t%6.2f\n",
id[i], hrs[i], razon[i], normal[i], sobre[i], normal[i] +
sobre[i]);
}
ESTRUCTURAS
______________________________________________________________________________________ 93
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Una estructura es un conjunto de variables que se referencian con un único nombre. Esto es muy
útil cuando queramos mantener junta información relacionada. Para definir una estructura,
utilizamos la palabra clave struct. Esta palabra le indica al compilador que lo que viene a
continuación es una estructura. La forma general para definir una estructura es la siguiente:
struct nombre_estructura
{
tipo variable1;
tipo variable2;
...
...
tipo variablei [=expresión]
...
...
tipo variableN;
} lista_variables_estructura;
Con esta definición realmente haremos 2 cosas: por una parte, estamos definiendo una plantilla de
estructuras, la cual tomará el nombre que indique el parámetro nombre_estructura, y por otra parte,
estamos definiendo una serie de variables con la forma de la plantilla definida. Estas variables son
las que vendrían dadas por el parámetro lista_variables_estructura. Cada campo de una estructura
puede ser inicializado en la declaración mediante una expresión de la misma forma a como se hacía
al declarar una variable de un tipo básico. Un ejemplo más concreto podría ser la siguiente
estructura:
struct Datos_Persona
{
char nombre[20];
char apellido1[20];
char apellido2[20];
char calle[50];
char ciudad[20] = "Sevilla";
unsigned long DNI;
} pers1, pers2, pers3, pers4;
Hay que tener cuidado al elegir el lugar donde definimos la plantilla de estructura. Lo más normal
es declararla globalmente para que pueda ser utilizada en cualquier lugar del programa. A la hora de
definir la plantilla de estructura podemos omitir, o bien, el parámetro nombre_estructura, o bien, el
parámetro lista_variables_estructura. En el caso de que se omita el parámetro nombre_estructura,
sólo podremos usar la plantilla para definir las variables que aparezcan en el parámetro
lista_variables_estructura. Si posteriormente queremos declarar alguna otra variable utilizando esta
plantilla, tendremos que volver a definirla. Si el parámetro que omitimos es
lista_variables_estructura, lo que habremos hecho es crear una plantilla de estructura sin variables
asociadas, las cuales podremos crear en cualquier momento, usando el modo de declaración de
estructura visto anteriormente, es decir:
______________________________________________________________________________________ 94
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
struct nombre_estructura nombre_variable_nueva;
struct coordenada
{
int x;
int y;
int z;
} a, b, c;
a.x = 5;
a.y = 23;
a.z = 10;
eje_x = a.x;
eje_y = a.y;
eje_z = a.z;
Otra operación que podremos realizar son asignaciones entre variables estructuras con la misma
plantilla:
c = a;
b = c;
Los tipos de los elementos individuales de una estructura pueden ser simples (int, float, char, …) o
complejos (array, otra estructura, …). Veamos un ejemplo de una plantilla de estructura que
combina elementos individuales simples y complejos.
struct fecha
{
int dia;
int mes;
int anyo;
};
struct hora
{
int horas;
int minutos;
};
struct ficha
{
______________________________________________________________________________________ 95
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
char nombre[20];
char apellidos[40];
struct fecha dia_nacimiento;
struct hora hora_nacimiento;
};
Si queremos definir una variable tipo ficha, y queremos poner la fecha de nacimiento haremos:
persona.fecha.dia = 20;
persona.fecha.mes = 2;
persona.fecha.anyo = 2001;
En este caso una posible inicialización de la anterior matriz en el que todos sus componentes toman
como valor el origen de coordenadas quedaría de la siguiente manera:
Ejemplos más complejos se podrían crear a partir de la estructura ficha de forma que se pudieran
gestionar los datos de toda una población de individuos. En este caso tendríamos por ejemplo:
// Vector que sirve para gestionar los datos personales de 100 individuos.
Al igual que con el resto de tipos de variables, C permite crear variables punteros a estructuras. La
forma de declarar estas variables es:
Para poder acceder a los elementos individuales de una variable puntero a estructura se utiliza el
operador -> (el operador, denominado comunmente flecha, está formado por un signo menos
seguido de un signo de mayor, sin ningún espacio en blanco entre ellos). Siguiendo con el ejemplo
anterior de las coordenadas, vamos a definir un puntero a una variable de estructura de la siguiente
forma:
______________________________________________________________________________________ 96
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
a.x = 5;
a.y = 23;
a.z = 10;
b = a;
p = &b; /* &b nos devuelve la dirección de la estructura b */
p->x = 2;
p->y = a.y;
p->z = a.z;
Al igual que ocurría en el apartado anterior también existe la posibilidad de declarar tablas de
estructuras. El formato sería el siguiente:
Por supuesto también se pueden declarar tablas de punteros a estructuras de más de dos
dimensiones pero al igual que ocurría con la declaración de tablas de tipos de datos básicos, no
suelen ser muy usadas.
Un ejemplo de declaración de un vector de punteros a estructuras y un acceso al campo de una
estructura sería la siguiente:
vector_punteros_coordenadas[4] = &coor1;
vector_punteros_coordenadas[4]->y = 2;
Al igual que ocurría con los punteros a tipos básicos de datos también se pueden pasar punteros a
estructuras en las llamadas a funciones. Así por ejemplo tendríamos:
aux = (*c).x;
______________________________________________________________________________________ 97
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
(*c).x = (*c).y;
(*c).y = aux;
}
union nombre_union
{
tipo variable1;
tipo variable2;
...
...
tipo variableN;
} lista_variables_union;
Como se ve, la forma de declaración de declaración es similar a la de una estructura, de forma que
podremos declarar una variable, o bien colocando su nombre al final de la declaración inicial, o
posteriormente, utilizando una declaración aparte como muestra el siguiente código:
La forma de funcionamiento de las uniones es muy simple. Cuando definimos una unión y
declaramos variables asociadas, el compilador reservará para cada variable, un espacio de memoria
cuyo tamaño coincidirá con el tamaño del elemento más grande que se defina dentro de la unión.
Supongamos que tenemos la siguiente declaración:
union prueba_union
{
char letra;
char cadena[8];
int numero;
} u1;
El compilador reservará, para la variable u1, 8 bytes de memoria (que corresponde con el tamaño
del elemento cadena), de forma que en caso de acceder al elemento letra, estaremos accediendo al
primer byte de la variable, mientras que si accedemos al elemento numero, estaremos accediendo a
los dos primeros bytes de la variable. Por último, si accedemos al elemento cadena estaremos
accediendo a todos los bytes de la variable.
Una enumeración es un conjunto de constantes enteras con nombre, que especifica todos los
valores válidos que una variable de este tipo puede tener. La forma de definir una enumeración es:
Veamos un ejemplo:
enum color{blanco, amarillo, rojo, verde, azul, marron, negro} color_mesa;
Como con las estructuras, C permite definir posteriormente más variables enumeradas del tipo
color, la forma de hacerlo sería la siguiente:
Una vez definidas las variables enumeradas, las siguientes operaciones serían válidas:
color_mesa = verde;
color_coche = color_mesa;
if(color_mesa == azul)
printf("La mesa es de color azul\n");
switch(color_coche)
{
case blanco:
printf("El coche es de color blanco\n");
break;
case amarillo:
printf("El coche es de color amarillo\n");
break;
case rojo:
printf("El coche es de color rojo\n");
break;
case verde:
printf("El coche es de color verde\n");
break;
case azul:
printf("El coche es de color azul\n");
break;
case marron:
printf("El coche es de color marron\n");
break;
case negro:
printf("El coche es de color negro\n");
break;
}
Para poder definir nuevos nombres de tipos de datos, usamos la palabra clave typedef. Con esto,
realmente no estamos creando un nuevo tipo de datos, sino que se define un nuevo nombre a un
tipo ya existente. También podemos usar typedef para asignar un nombre de tipo a una estructura o
a una enumeración, de forma que para declarar las variables de estos tipos no necesitaremos
precederlos de las palabras clave struct o enum, respectivamente. La forma general de la sentencia
typedef es:
______________________________________________________________________________________ 99
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
typedef struct fecha FECHA;
typedef struct
{
float x,y,z;
} coordenada;
Si queremos definir una variable de este tipo de estructura basta con poner:
coordenada a;
______________________________________________________________________________________ 100
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
11 ANEXOS
Recordemos que en un computador la memoria está organizada como una secuencia de bytes, en
donde cada byte posee una dirección. Por ejemplo si 1 byte es usado para almacenar variables
enteras con signo, el rango de valores ( en decimal ) es -128 a 127; para enteros sin signo tienen el
rango 0 a 255.
Si ahora 2 bytes son usados para representar enteros con signo, el rango es -32768 a +32767; y de
0 a 65535 para enteros sin signo. Si se utilizan 4 bytes para representar enteros el rango será
relativamente más grande. Similarmente para números de punto flotante; si se utilizan 4 bytes para
representar números de punto flotante la precisión será equivalente a considerar 7 dígitos decimales
significativos y una magnitud de 10E38 a 10E-38. Si más bytes fuesen utilizados para números de
punto flotante la precisión y el rango de variación será mucho mayor.
C proporciona una serie de tipos de datos adicionales que proporcionan una presición mayor, sin
embargo contrario a Pascal, C no posee tipo de dato boolean, de manera que para representar las
condiciones en los ciclos, se considera que todo valor distinto a cero es TRUE, y si es cero se
considera FALSE.
Tipo char, signed char: Este tipo de dato cubre 8 bits, es decir un Byte. Con ello se dejan
representar 2^8 cifras distintas. dado que este tipo de dato trabaja orientado a los simbolos puede
aceptar valores de -128 a +127.
Tipo unsigned char: Dado que en C no existe el tipo de dato “string”, son almacenadas cadenas
de caracteres en variables de este tipo.
Tipo enum: Este tipo de dato ocupa 2 Byte, pudiendo aceptar valores numéricos de -32768 a
+32767.
Tipo int: Para Turbo C++ es int de tamaño 2 Byte. Con el tipo de dato int puede el procesador
realizar cálculos rápidos.
Tipo unsigned int: Este tipo de dato es como unsigned char. Los valores que acepta en Turbo C+
+ se extienden de 0 hasta +65535.
Las constantes de este tipo son escritas usando el prefijo u ó U. Por ejemplo, 0xFFFU, 123U,
0777u, etc.
Tipo short, short int: Son tipos de datos idénticos a int. La ventaja de short int radica en que en
casi todo computador tiene tamaño de 16 bit, de manera que la portabilidad se optimiza .
Tipo long: Este tipo de dato cubre 32 bit o 4 Byte. Un campo de 2147483648 hasta +2147483647
esta a disposición, con esto pueden ser trabajados una gran cantidad de números. En caso que Ud.
trabaje con números más grandes o más pequeños que el campo antes descrito se recomienda
utilizar “float”.
Para enteros, una constante que represente un long int puede ser explicitada usando el prefijo l ó
L. Por ejemplo, 123L, 45678l, etc.
______________________________________________________________________________________ 101
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Tipo float: En muchos programas no es posible realizar algunos cálculos, pues no existe
computador o programa que pueda satisfacer la exactitud en los cálculos numéricos, tales números
se describen como números puntos flotante. Este tipo de dato requiere 32 bits, trabajando con una
exactitud de siete lugares y con valores que varían de 3.4*10^-38 hasta 3.4*10^+38 siendo el más
apropiado para cálculos científicos.
Las constantes de punto flotante son consideradas como doble precisión, cuyas constantes se
especifican con una f ó F. Por ejemplo, 34.567f, 3.141516F, extra precisión puede ser escrita con
el sufijo l ó L. Por ejemplo, 234567.171819L
Tipo double: Este tipo requiere 64 bits y trabaja con una precisión de 15 lugares abarcando una
variación de 1.7*10^-308 hasta 1.7*10^+308 y es utilizado para cálculos numéricos de alta
precisión.
Las declaraciones signed, unsigned, long, short son llamados MODIFICADORES, cuyo
objetivo es precisar con relativa exactitud cada necesidad.
inum = 3;
iresul = 1/ inum;
printf ("el tipo de dato int\t\t1 /%d = %d\n", inum, iresul );
fresul = 1.0 / inum;
printf ("el tipo de dato float\t\t1 /%d = %.19f\n", inum, fresul);
dresul = 1.0 / inum;
printf ("el tipo de dato double\t\t1 /%d = %.19lf\n", inum, dresul );
ldresul = 1.0 / inum;
printf ("el tipo de dato long double\t1 /%d = %.19Lf\n", inum, ldresul );
return 0;
}/* fin de la función main() */
Comentarios:
En C no existe como en Pascal división entera, es importante que en fresul se escriba 1.0 en vez de
1, pues de otra manera fresul sería 0.000...otra alternativa mejor es fresul = (float) 1.0 / (float)
inum; pues obliga al compilador C transformar ambos valores al tipo dato float,
______________________________________________________________________________________ 102
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Existen otros tipos de datos, llamados enumerado, ellos son: void , enum, typedef.
void se refiere a un objeto que no tiene valor de ningún tipo, comportamiento similar a funciones
que no retornan ningún valor, es decir funciones, como las que muestra el siguiente ejemplo la cual
solamente imprime un mensaje y no tiene ningún valor para retornar.
Ejemplo:
/* file.cpp
este programa introduce datos de tipo void
*/
void print_mensaje(void);
main( )
{
/* imprime mensaje */
print_mensaje( );
}
/* función imprime un mensaje */
void print_mensaje( void )
{
printf(“***Hola alumnos***\n”);
}
typedef facilita definir sinónimos para tipos de datos, haciendo programas más legibles. Por
ejemplo, variables usadas para representar valores de años de personas u objetos pueden ser
definidos por un nuevo tipo, anno, es decir
typedef int anno;
anno age; /* la variable age puede tener tipos de valores anno. La diferencia es que podemos
tener más nombres para tipo de dato que el nombre genérico de int*/
(III) OPERADORES
______________________________________________________________________________________ 103
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Los tipos de datos y el valor de las expresiones depende del tipo de datos de los operandos y el
orden de evaluación de los operadores , los cuales están determinados por la precedencia y la
asociatividad de ellos. Cuando los operadores tienen el mismo nivel de precedencia en una
expresión, el orden de la evaluación está determinada por la asociatividad. Criterio que por lo
demás posee Pascal. Sin embargo, la tabla siguiente hace un resúmen de las distintas precedencias
y asociaciones de los operadores.
C proporciona un operador resumido para casos tales como incrementar, decrementar, multiplicar,
dividir o mod valores dados. Por ejemplo,
Una función que retorne el valor más grande entre dos argumentos double, puede escribirse,
Las macros pueden también utilizar este operador de manera bastante práctica.
Operador Coma
______________________________________________________________________________________ 104
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
Veremos la utilidad de este operador a través de una estructura for, pues permite una asignación
múltiple de valores iniciales y el procesamiento múltiple de índices.
Por ejemplo,
for (suma=0, y=1; y < = n; ++y)
suma += y;
printf( “\n%d”, suma ); /* imprimirá la suma de los enteros de 1 a n */
Operador sizeof
sizeof simplemente permite evaluar el número de bytes usados para el tipo del resultado. Por
ejemplo, la expresión sizeof x evalúa el tamaño de x en bytes.
/* pe97c10.cpp
nombre: sizeof
fecha : 12.12.96
propósito: evalúa el número de bytes utilizados
*/
#include <stdio.h>
main()
{ /* declaracion */
int x;
double y;
/* imprime titulo */
printf("***operador sizeof***\n\n");
printf("tamaño de x es %d bytes \n", sizeof (x));
printf("tamaño de x+y es %d bytes\n\n",sizeof (x+y));
printf("tamaño de tipo de dato en bytes:\n");
printf("tamaño de tipo int es %d\n",sizeof (int));
printf("tamaño de tipo long int es %d\n", sizeof(long int));
printf("tamaño de tipo short int es %d\n",sizeof (short int));
printf("tamaño de tipo unsigned int es %d\n", sizeof(unsigned int));
printf("tamaño de tipo float es %d\n",sizeof (float));
printf("tamaño de tipo double es %d\n",sizeof (double));
return 0;
}
/* la utilidad es hacer que el programa sea portable de un sistema a otro*/
Comentario :
la salida es
***operador sizeof***
tamaño de x es 2 bytes
tamaño de x+y es 8 bytes
______________________________________________________________________________________ 105
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
tamaño de tipo double es 8
Las estructuras condicionales if y los ciclos while en C están realizados sobre la idea de
Expresión Boolena, al igual que en Pascal. Sin embargo dado que en C , NO existe tipo booleano.
Ud. puede usar como ya hemos mencionado el valor entero 0 como FALSE, mientras que
cualquier otro valor entero es TRUE.
void main()
{
int a;
printf (“entre un número:”);
scanf (“%d”, a );
if (a)
{
hola, como estas
}
/* Si a es cualquier elemento que no sea 0, el codigo ( hola, como estas ) se
ejecutará. */
La lógica del for en C es la misma que en Pascal, es decir, se inicializa antes de ingresar al loop, se
condiciona el loop, y finalmente una forma de alcanzar la condición. El ejemplo 35 muestra que
while
de Pascal es equivalente al while de C, sin embargo este último puede ser interpretado como un for
en C, llamada forma simplificada.
x=1;
______________________________________________________________________________________ 106
Escuela Ingeniería en Computación, Universidad de La Serena
Programación en C Tutorial Dr. Eric Jeltsch
F.
while ( x < 10 ) for ( x = 1; x < 10; x++)
{ {
hola hola hola hola
x ++; /*x++ es lo mismo que x:=x+1 de Pascal */ }
}
Otro uso interesante del ciclo for es para crear un bucle infinito, por ejemplo
for( ; ; ) printf(“este ciclo siempre se estará ejecutando.\n”);
Las cadenas de condiciones if- then-else surgen comúnmente en programación, ahora C a través
de la declaración switch proporciona una alternativa que hace más fácil manipular este tipo de
estructuras.
Las utilidades más prácticas de break es por ejemplo la interrupción de ciertos ciclos, pasando el
control a la proposición inmediatamente posterior al ciclo. continue también altera el flujo normal
de control en un loop. Cuando una declaración continue es ejecutada en un loop la iteración
ocurrente del cuerpo del loop es abortada;
Ejemplo: Supongamos que deseamos escribir a través de un loop una rutina que imprima los
enteros de 0 a 9, excepto para el 5. Utilizando continue queda.
n=0;
while ( n < 10 ) {
if ( n == 5 ) {
n= n + 1;
continue;
}
printf (“ el siguiente número es %d\n”, n );
n= n + 1;
}
El loop se ejecuta normalmente excepto para n=5 . En este caso, la condición if es TRUE; n es
incrementado y la declaración continue es ejecutada donde el control pasa a testear la condición del
loop ( n < 10 ). La ejecución del loop continue en forma normal desde este punto. Excepto para
n=5, todo valor desde 0 a 9 será impreso.
______________________________________________________________________________________ 107
Escuela Ingeniería en Computación, Universidad de La Serena