Documentos de Académico
Documentos de Profesional
Documentos de Cultura
PROLOGO
1.- FUNDAMENTOS DE PROGRAMACIÓN...............................................................................5
1.1.- Definiciones......................................................................................................................5
1.2.- Tipos de lenguajes...........................................................................................................5
1.3.- Requisitos para la compilación de programas..................................................................6
1.4.- Compilación de programas según la plataforma..............................................................6
1.4.1.- Linux.....................................................................................................................6
5.2.2.- Windows...............................................................................................................7
2.- HISTORIA DE C.....................................................................................................................9
2.1.- Un poco de historia..........................................................................................................9
2.2.- Características del lenguaje de programación.................................................................9
3 – INTRODUCCIÓN AL LENGUAJE C....................................................................................11
3.1.- El conjunto de caracteres...............................................................................................11
3.2.- Identificadores, palabras reservadas y caracteres especiales.......................................11
3.3.- Tipos de datos................................................................................................................12
3.4.- Constantes.....................................................................................................................15
3.5.- Variables........................................................................................................................17
3.6.- Declaraciones................................................................................................................18
3.7.- Expresiones...................................................................................................................18
3.8.- Sentencias o instrucciones............................................................................................18
3.9.- Operadores....................................................................................................................19
3.10.- Estructura de un programa en C..................................................................................21
Ejercicios resueltos.............................................................................................................22
4 – FUNCIONES BÁSICAS DE E/S..........................................................................................25
4.1.- getchar() y putchar().......................................................................................................25
4.2.- gets() y puts().................................................................................................................26
4.3.- printf() y scanf()..............................................................................................................27
Ejercicios resueltos.............................................................................................................29
5 – SENTENCIAS DE CONTROL E FLUJO.............................................................................30
5.1.- Sentencias de salto........................................................................................................30
5.1.1 Break....................................................................................................................30
5.1.2 Continue...............................................................................................................31
5.2.- Sentencias condicionales...............................................................................................28
5.2.1 if then else............................................................................................................31
5.2.2 switch....................................................................................................................32
5.3.- Sentencias de bucle.......................................................................................................32
5.3.1 for.........................................................................................................................32
5.3.2 while.....................................................................................................................34
5.3.3 do while.................................................................................................................34
Ejercicios resueltos..................................................................................................................36
6.- FUNCIONES.........................................................................................................................37
6.1.- ¿Qué es una función?....................................................................................................38
6.2.- Partes de una función....................................................................................................38
6.2.1 Declaración...........................................................................................................39
6.2.2 Definición..............................................................................................................40
Ejercicios resueltos..................................................................................................................43
7.- ARRAYS...............................................................................................................................46
7.1.- Definición de un array....................................................................................................46
7.2.- Arrays unidimensionales................................................................................................46
7.3.- Arrays bidimensionales..................................................................................................47
7.4.- Cadenas de caracteres..................................................................................................49
Ejercicios resueltos..................................................................................................................51
8.- PUNTEROS..........................................................................................................................56
8.1.- Conceptos básicos.........................................................................................................56
8.2.- Declaración de punteros................................................................................................57
8.3.- Paso de punteros a una función.....................................................................................57
8.4.- Punteros y arrays unidimensionales..............................................................................58
8.5.- Operaciones con punteros ............................................................................................59
8.6.- Punteros y arrays bidimensionales................................................................................60
8.7.- Arrays de punteros.........................................................................................................60
Ejercicios resueltos..................................................................................................................62
9.- ESTRUCTURAS Y UNIONES..............................................................................................63
9.1.- Definición de una estructura...........................................................................................63
9.2.- Referencia a los elementos de una estructura...............................................................64
9.3.- Arrays de estructuras.....................................................................................................64
9.4.- Uniones..........................................................................................................................65
9.5.- Definición de nuevos tipos de datos...............................................................................66
9.6.- Tipos enumerados de datos...........................................................................................66
Ejercicios resueltos..................................................................................................................68
10.- FICHEROS DE DATOS......................................................................................................69
10.1.- Introducción..................................................................................................................69
10.2.- Apertura y cierre de un fichero.....................................................................................69
10.3.- Creación de un fichero.................................................................................................70
10.4.- Funciones para la manipulación de ficheros................................................................71
10.4.1 fopen...................................................................................................................71
10.4.2 fclose..................................................................................................................71
10.4.3 fgetc....................................................................................................................72
10.4.4 fputc....................................................................................................................72
10.4.5 feof......................................................................................................................72
10.4.6 fgets....................................................................................................................73
10.4.7 fputs....................................................................................................................73
10.4.8 fread...................................................................................................................73
10.4.9 fwrite...................................................................................................................73
10.4.10 fprintf.................................................................................................................74
10.4.11 fscanf................................................................................................................41
10.4.12 fflush.................................................................................................................74
Ejercicios resueltos..................................................................................................................76
11.- LIBRERIAS.........................................................................................................................80
9.1.- Definición de una estructura...........................................................................................80
9.2.- Algunas librerías y funciones importantes en ANSI C....................................................81
9.3.- Arrays de estructuras.....................................................................................................38
9.4.- Uniones..........................................................................................................................38
BIBLIOGRAFIA
FRANCISCO JAVIER CEBALLOS 1989. Lenguaje de programación C. Profesor en la universidad
politécnica de Alcalá de Henares. Editorial rama.
HANSEN, A. 1994. Aprenda C ya Anaya.
Fundamentos de
programación 1
1.1 DEFINICIONES:
Según su nivel
• Lenguaje maquina
• Lenguaje de bajo nivel (ensamblador)
• Lenguajes de alto nivel
Lenguajes máquina. Se llama lenguaje máquina a las instrucciones que se dan directamente a la
computadora, utilizando una serie de dígitos binarios o bits, representados por los números 0 y 1 que
especifican una operación. Aunque este lenguaje es el que entiende la computadora, es muy difícil
de manejar en la comunicación humana. Las instrucciones en lenguaje maquina dependen del
hardware de la computadora y, por lo tanto, diferirán de una computadora a otra.
Lenguajes de bajo nivel (ensamblador).Estos lenguajes son más fáciles de utilizar que los lenguajes
máquina, pero, al igual que ellos, dependen de la máquina en particular. El lenguaje de bajo nivel por
excelencia es el ensamblador (assembler lenguaje). Las instrucciones en lenguaje ensamblador son
conocidas como mnemotécnicos. Por ejemplo, mnemotécnicos típicos de operaciones aritméticas
son: en ingles, ADD, SUB, DIV, etc. en español, SUM, RES, DIV, etc.
Lenguajes de alto nivel Los lenguajes de alto nivel son los más utilizados por los programadores.
Están diseñados para que las personas escriban y entiendan los programas de un modo mucho más
fácil que los lenguajes máquina y ensambladores. Otra razón es que un programa escrito en un
lenguaje de alto nivel es independiente de la máquina; esto es, las instrucciones del programa de la
computadora no dependen del diseño del hardware o de una computadora en particular. Por ello, los
programas escritos en estos lenguajes son portables, lo que significa que podemos ejecutarlos con
poca o ninguna modificación en diferentes tipos de computadoras; al contrario que los programas en
lenguaje máquina o ensamblador que sólo se pueden ejecutar en un determinado tipo de
computadora.
Para poder compilar un programa, será necesario tener instalado el compilador y un editor o entorno
de desarrollo que permitan escribir el código fuente a compilar.
El código a compilar debe guardarse con un nombre que represente al programa en cuestión
y la extensión .c. Para su edición, podemos hacer uso del editor que suele venir integrado en el
propio compilador, o cualquier otro como puede ser el blog de notas.
1.4.1 LINUX
Si bien existen otros compiladores, lo más usual y más sencillo para compilar un programa
en GNU/Linux es el compilador gcc, ya que es el que se incluye en todas las distribuciones. Esta
compilación es posible realizarla desde la línea de comandos o desde el entorno gráfico.
Para poder realizarla desde línea de comandos, será necesario abrir una terminal. En ella
deberemos teclear :
gcc nombre_programa.c
En el caso que no existiesen errores en el código, este comando nos creará un archivo
ejecutable, que por defecto se llama "a.out", el cual podemos ejecutar desde la línea de comandos de
la siguiente forma :
./a.out
La opción -Wall nos mostrará todos los avisos que produzca el compilador, no solamente los
errores. Los avisos nos indican dónde y/o porqué podría surgir algún error en nuestro programa.
1.4.2 WINDOWS
Para compilar un programa C en entornos Windows, debemos seguir una serie de pasos que
varían según el compilador de C que queramos utilizar.
El archivo objeto
hola.obj
El archivo ejecutable
hola.exe
Este último es el que nos interesa, puesto a que es el código ejecutable, el programa en sí. Al
ejecutarlo se producirá la salida deseada en una ventana de consola.
En el siguiente esquema de bloques, se detallan los pasos desde que se edita un programa hasta
que se obtiene el ejecutable.
E Program
Programa E
D a objeto
fuente N
I COMPILADOR
T hola.c DE “C” hola.obj L
A hola.exe
O
Z
R
A
uno.lib D
O
R
mi.lib
Figura 1 Diagrama de bloques desde edición hasta la compilación.
Historia de C 2
2.1. UN POCO DE HISTORIA
El lenguaje C fue creado en los años setenta por Dennis Ritchie, de los Laboratorios Bell. Su
propósito era ser un lenguaje para el sistema operativo UNIX. Surgió a partir de los lenguajes de
programación BCPL y B.
En este periodo de tiempo, muchos fabricantes meten mejoras, las cuales evalúa un comité
de estandarización ANSI y así se establecen unas especificaciones de lo que hoy se conoce como
'ANSI C'.
C pertenece a lo que se conoce como lenguajes de nivel intermedio entre Pascal y lenguaje
ensamblador. Pretende ser una lenguaje de alto nivel con la versatilidad de bajo nivel.
Se diseñó junto con el sistema operativo UNIX y está muy orientado a trabajar en su entorno.
Estas y otras características lo hacen adecuado para la programación en áreas tales como:
• programación de sistemas
• estructuras de datos y sistemas de bases de datos
• aplicaciones científicas
• software gráfico
• análisis numérico
Sin embargo, posee algunas desventajas que suscitaron algunas críticas, dentro de las se
pueden destacar:
• Comprobación de datos: Lo poco estricto que es el lenguaje con esta tarea, dejando
esta muchas veces en manos del programador.
• El no verificar automáticamente los límites de los vectores.
• Sobrecarga de operadores.
• El no poder anidar funciones : con lo que se dificulta la estructuración y la abstracción
de datos.
• La incertidumbre existente en el orden de evaluación de las listas de expresiones y
parámetros.
Introducción al
lenguaje C 3
3.1 EL CONJUNTO DE CARACTERES C.
A la hora de elaborar programas en C se pueden utilizar para crear los elementos básicos
(constantes, variables, operadores y expresiones) las letras mayúsculas de la A a la Z, las minúsculas
de la a a la z , los dígitos del 0 al 9 y ciertos caracteres especiales.
Los identificadores son nombres que se les da a varios elementos de un programa, como
variables, constantes o funciones.
Hay ciertas palabras reservadas, denominadas palabras clave, que tienen en C un significado
estándar y por tanto no pueden ser utilizadas como identificadores definidos por el programador. Las
palabras clave están en minúsculas.
Caracteres especiales
! * + \ “ <
# ( = | { >
% ) ~ ; } /
^ - [ : , ?
& _ ] ' . (blanco)
C tiene un total de 32 palabras reservadas, que no pueden ser definidas por el usuario. Son
las que se exponen a continuación.
Palabras reservadas
En el lenguaje C estándar, existen cinco tipos de datos básicos que son: los caracteres, los
números enteros, los números reales,los números reales en doble precisión y void.
Estos tipos de datos son parte del lenguaje, y por ello se los considera primitivos.
Adicionalmente, podremos ver como a partir de este tipo de datos primitivos podemos crear tipos
compuestos de datos como son las estructuras y las uniones.
En este tema veremos los enteros, los reales y los caracteres. Más adelante se verán otros
tipos de datos más complejos, como son los arrays o vectores, las cadenas de caracteres, y los
punteros en general. Los más destacados son:
int : Números enteros
char : Caracteres
float : Número de coma flotante (con punto decimal y/o exponente)
double : Número de coma flotante de doble precisión (más cifras significativas y mayor valor posible
del exponente)
Existen una serie de calificadores: short, long, signed y unsigned que sirven para ampliar o
reducir el rango de los diferentes tipos de datos.
La sintaxis para declarar variables o constantes con los diferentes tipos de datos es:
tipo_dato nombre_variable
A continuación, se muestra una tabla resumen de los tipos de datos:
Tipos de datos
3.3.1 Caracteres
Los caracteres se representan utilizando el tipo char, que tiene sólo 1 byte de tamaño. Este
tipo se utiliza para representar los 255 caracteres de la tabla de caracteres del sistema. El tipo char
es también un tipo entero, ya que puede tomar valores de 0 a 255.
Ejemplos de declaraciones de variables de tipo char:
char car;
char car = 'a';
char car = 25;
3.3.2 Enteros
Los enteros son el tipo de dato más primitivo en C. Se usan para representar números
enteros.
C hace la distinción de si el entero es con signo o sin signo (signed o unsigned). La forma de
declarar un entero es con uno de los tipos de datos que sean enteros según el tamaño que se quiera.
En caso de que no se declare si es con signo o sin signo, se toma con signo.
Algunos ejemplos de declaraciones de enteros:
int a;
int b;
unsigned int c;
3.4 CONSTANTES
Las constantes son datos referenciados a través de un identificador cuyo valor no varía a lo
largo de toda la ejecución de un programa.
SECUENCIA SIGNIFICADO
'\a' Sonido (campana)
'\b' backscape
'\t' Tabulación horizontal
'\v' Tabulación vertical
'\n' Nueva línea
'\f' Form feed
'\r' Retorno de carro
'\”' Comillas
'\'' Comilla simple
'\?' Signo de interrogación
'\\' Backslash (\)
'\0' Nulo
Una variable es un identificador que se utiliza para representar cierto tipo de información
dentro del programa. En algún punto del programa se le asigna a la variable un valor que después se
puede recuperar en cualquier momento sin más que hacer referencia la nombre de la variable.
int a;
a=25;
3.6 DECLARACIONES
Una declaración implica asociar un tipo concreto de datos a una variable o grupo de variables.
En esencia, consiste en un tipo de datos, seguido de uno o más nombres de variables, finalizando con
un punto y coma. Todas las variables deben ser declaradas antes de ser utilizadas.
3.7 EXPRESIONES
Una expresión representa una unidad de datos simple, tal como un número o un carácter.
Puede consistir en una constante, una variable o una combinación de ellas mediante operadores.
numero = 5;
Una sentencia o instrucción hace que el ordenador lleve a cabo alguna acción. En C hay tres
tipos de sentencias: de expresión, de control y compuestas.
Una sentencia de expresión consiste en una expresión seguida de un punto y coma. Su
ejecución hace que se evalúe la expresión:
a = 25;
c = a+b;
Una sentencia compuesta está formada por varias sentencias individuales encerradas entre
llaves. Las sentencias individuales pueden ser de cualquiera de los tres tipos mencionados.
Las sentencias de control se utilizan para realizar bucles o ramificaciones.
3.9 OPERADORES
Operadores aritméticos
int a,b,c;
a = 1;
b = 5;
c = a+b;
El operador % es el de resto y requiere que los dos operandos sean enteros y el segundo no
nulo.
El operador de división requiere que el segundo operando no sea nulo. La división de dos
cantidades enteras da como resultado el cociente entero truncado.
Operadores lógicos
Además, existen operadores que operan a nivel de bit para poder manipular internamente las
variables.
If((a==c) && (b<a)) realiza acción x
OPERADOR SIGNIFICADO
& AND
| OR
^ OR EXCLUSVA
<< Rotación a la izquierda
>> Rotación a la derecha
~ Complemento A UNO (C1)
En C no existe un tipo lógico o booleano, y se establece que una expresión lógica es cierta si
su valor es distinto de 0 y falsa si su valor es 0.
Operadores relacionales
OPERADOR SIGNIFICADO
< Menor que
> Mayor que
<= Menor o igual que
>= Mayor o igual que
== Igual que
!= Distinto que
Operador de asignación
OPERADOR SIGNIFICADO
= Asigna dato a variable
Se utiliza para formar expresiones de asignación en las que se asigna el valor de una expresión
a un identificador. Una expresión de asignación recibe el nombre de sentencia de asignación y es de la
forma : identificador = expresión
int numero;
numero = 5;
Operador de dirección
OPERADOR SIGNIFICADO
* Operador de contenido
& Operador de dirección
OPERADOR
()[]
! ~ ++ -- * & sizeof (tipo dato)
*/%
+-
<< >>
< <= > >=
== !=
&
^
|
&&
||
?:
= += -= *= /= %=
#include stdio.h
main()
{
printf(“ Hola Mundo\n”);
}
EJERCICIOS RESUELTOS
#include “stdio.h”
#include “conio.h”
main()
{
int nun;
printf("Introduce el número\n");
scanf(“%d”,&nun);
printf("\nEl doble de %d es %d\n”,nun,nun*2;
getch();
}
2.- Programa que pide dos dos números por teclado e intercambia sus valores
#include “stdio.h”
#include “conio.h”
main()
{
int nun1,nun2,aux;
printf("Introduce los números: a,b\n");
scanf(“%d,%d”,&nun1,&nun2);
aux=nun1;
nun1=nun2;
nun2=aux;
printf("\n Los nuevos valores son : nun1 = %d nun2 = %d\n”,nun1,nun2);
getch();
}
3- Programa que lea un número entero por teclado y que calcule su factorial
#include “stdio.h”
main()
{
int x;
double fact;
fact=1;
printf("Introduce el número: \n");
scanf(“%d”,&x);
while(x>1)
{
fact=fact*x;
x--;
}
printf("\n Factorial = %lf\n”,fact);
4. Escriba un programa que imprima una tabla con las cuatro primeras potencias de los
números 1 a 10.
#include <stdio.h>
main()
{
int a, b, i;
for (a=0; a<256; a++)
{
printf("%2c",
}
}
Tenemos que distinguir también entre entrada y salida con formato o sin formato.
#include “stdio.h”
main()
{
char car;
car=getchar();
putchar(car);
}
Realiza un programa que lea una cadena de caracteres con la función gets() y a continuación
cuente el número de ellos. La cadena debe finalizarse con un control+N
#include <stdio.h>
#include <string.h>
main()
{
char cad[20],ch;
int n;
n=0;
printf(“Introduzca la cadena de caracteres\n”);
gets(cad);
do
{
ch = cad[n];
n++;
}while(ch!='\0');
printf("numero de caracteres : %d\n",n-1);
4.3.1 scanf()
Esta función se puede utilizar para la introducción de cualquier combinación de valores
numéricos o caracteres.
En términos generales la función scanf se escribe:
int i;
float j;
scanf("%d %f",&i,&j);
Al introducir dos o más datos, éstos deben ir separados por caracteres de espaciado (el
carácter de nueva línea se considera como un carácter de espaciado).
Los caracteres consecutivos que no sean de espaciado componen un dato. Es posible limitar el
número de los caracteres especificando una longitud máxima para ese dato. El dato puede estar
compuesto por menos caracteres de los que especifique la longitud y no se leerán los caracteres que
estén más allá de dicha longitud. Hay que tener en cuenta que en este caso los caracteres sobrantes
pueden ser interpretados de manera errónea para el siguiente dato.
Si los datos se introducen: 1 2 3 las asignaciones que se llevan a cabo son: a=1, b=2, c=3
Si se introducen 123 456 789 las asignaciones son: a=123, b=456, c=789
4.3.2 printf()
COMANDO SIGNIFICADO
%c Carácter
%d Entero decimal
%e Flotante con valor exponencial
%f Flotante sin valor exponencial
%p Valor del puntero
%o Entero en formato octal
%u Entero decimal sin signo
%x Entero en formato hexadecimal
%s Cadena de caracteres
#include “stdio.h”
#include “conio.h”
main()
{
char car;
printf("Introduce un carácter\n");
car=getchar();
printf("\nEl carácter introducido es %c.\n",car);
getch();
}
2.- Escribe un programa que imprima un mensaje de presentación, pregunte como te llamas y
te salude.
#include “stdio.h”
#include “conio.h”
main()
{
char nombre[20];
printf("Introduce tu nombre\n");
scanf("%s",&nombre[0]);
printf("Hola %s\n",nombre);
}
2.- Escribe un programa que calcule el área de un triángulo rectángulo, dada la altura y la
base.
#include “stdio.h”
#include “conio.h”
main()
{
Se utiliza para terminar la ejecución de bucles o salir de una sentencia switch. Si se incluye
break en un bucle while, do-while o for, entonces se transfiere el control fuera del bucle en el momento
en que se encuentra la sentencia break. Esto proporciona una forma conveniente de terminar un bucle
cuando se detecta un error o alguna otra condición. En el caso de varias sentencias while, do-while, for
o switch anidadas, una sentencia break causa la transferencia de control fuera de la sentencia más
interna en la que se encuentre, pero no de las sentencias más externas.
char color;
switch (color) {
case 'a':
case 'A': printf("AMARILLO\n");
break;
case 'r':
case 'R': printf("ROJO\n");
case 'b':
case 'B': printf("BLANCO\n");
default: printf("OTRO\n");
}
5.2.1 Sentencia if
if (condición)
sentencia;
…......
if (condición)
sentencia1;
else
sentencia2;
….....
if (condicion1)
sentencia1;
else if (condicion2)
sentencia2;
else if (condicion3)
sentencia3;
….....
else
sentencian;
#include “stdio.h”
main()
{
int a,b,c;
........
if (a>0)
{
b=c;
.......
}
else
{
b=a;
.......
}
}
5.1.2 Sentencia switch
Esta sentencia hace que se seleccione un grupo de sentencias entre varios grupos disponibles.
La selección se basa en el valor de una expresión que se incluye en la sentencia switch. Su forma
general es:
switch (variable)
{
case constante1:
secuencia de sentencias
break;
case constante2:
secuencia de sentencias
break;
case constante3:
secuencia de sentencias
break;
...
default:
secuencia de sentencias
}
Se puede etiquetar como default a uno de los grupos de sentencias dentro de la sentencia
switch. Este grupo se seleccionará si ninguna de las etiquetas case coincide con el valor de expresión.
Si ninguna de las etiquetas case coincide con el valor de expresión y no se encuentra presente el grupo
default, la sentencia switch no hará nada
La sentencia switch se puede concebir como una alternativa al uso de sentencias if-else
anidadas, aunque sólo puede sustituir a aquellas sentencias if-else que comprueben igualdades. En
tales situaciones es más conveniente utilizar la sentencia switch. Un ejemplo de esta sentencia es:
switch(vocales)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
numvocales++;
break;
case ' ':
numesp++;
break;
default:
numotras++;
break;
}
Es la sentencia más usada para crear bucles en C. Incluye una expresión que especifica el
valor inicial de un índice, otra expresión que determina cuándo se continúa o no el bucle y una
tercera expresión que permite que el índice se modifique al final de cada pasada. La forma general
de la sentencia es:
expresion1;
while (expresion2)
{
sentencia;
expresion3;
}
Desde el punto de vista sintáctico no es necesario que se encuentren presentes las tres
expresiones en la sentencia for, aunque deben aparecer los puntos y coma. Las expresiones primera y
tercera se pueden suprimir si se inicializa y/o altera el índice de alguna otra forma. Si se omite la
segunda expresión, se asume que ésta tiene un valor permanente de cierto y, por tanto, el bucle
continuará ejecutándose de forma indefinida a no ser que finalice mediante otro método como u na
sentencia break o return.
Ejemplo de un bucle for que imprime los primeros diez números naturales.
int i;
for (i = 0; i < 19; i++)
printf(“ numero %d: %d”,i+1,i);
La sentencia while se utiliza para generar bucles. El formato general de la sentencia es:
donde sentencia puede ser una sentencia vacía, una sentencia única o un bloque de sentencias que
se repetirán. Cuando el flujo del programa llega a esta instrucción, primero se revisa si la condición
es verdad para ejecutar la(s) sentencia(s), y después el ciclo while se repetirá mientras la condición
sea verdadera. Cuando llega a ser falsa, el control del programa pasa a la línea que sigue al ciclo.
Un ejemplo de un bucle while que nos imprime los primeros diez números naturales que anteriormente
hicimos con el bucle for, sería.
int i=0;
while (i < 19)
{
printf(“ numero %d: %d”,i+1,i);
i++;
}
Cuando se construye un bucle utilizando la sentencia while el test para la continuación del
bucle se realiza al inicio del bucle. Con la sentencia do-while dicho test se realiza al final de cada
pasada, con el siguiente formato:
do
{
sentencia;
} while (condición);
Aunque no son necesarias las llaves cuando sólo está presente una sentencia, se usan
normalmente por legibilidad y para evitar confusión.
El ejemplo de imprimir por pantalla los diez primeros números naturales, podría realizarse con el
bucle do while de la siguiente forma:
int i=0;
do
{
printf(“ numero %d: %d”,i+1,i);
i++;
}while(i<19);
Un uso común de la estructura do ... while es una rutina de selección en un menú, ya que siempre se
requiere que se ejecute al menos una vez.
#include “stdio.h”
main()
{
int op;
printf("1. Suma\n");
printf("2. Resta\n");
printf("3. Multiplicación\n");
do
{
printf(" Teclea una opcion: ");
scanf("%d", &opc);
switch(op)
{
case 1:
printf("\tOpcion 1 seleccionada\n\n");
break;
case 2:
printf("\tOpcion 2 seleccionada\n\n");
reak;
case 3:
printf("\tOpcion 3 seleccionada\n\n");
break;
default:
printf("\tOpcion no disponible\n\n");
break;
}
} while( opc != 1 && opc != 2 && opc != 3);
}
EJERCICIOS RESUELTOS
1.- Escribir un programa que pida por pantalla dos números enteros y un operador y nos
muestre el resultado de su operación.
#include <stdio.h>
main()
{
int a,b,resul;
char op;
printf("introduce los números : a,b,operacion\n");
scanf("%d,%d,%c",&a,&b,&op);
switch(op)
{
case '+':
resul = a + b;
break;
case '-':
resul = a - b;
break;
case '*':
resul = a * b;
break;
case '/':
resul = a / b;
break;
default:
printf("Operacion no valida\n");
}
printf("\nEl resultado de %d %c %d = %d\n",a,op,b,resul);
2.- Escribir un programa que pida por pantalla dos números enteros, nos presente un menú de
operaciones y a continuación nos muestre el resultado.
#include <stdio.h>
main()
{
int a,b,op,resul;
char resp;
do
{
printf("introduce los números : a,b\n");
scanf("%d,%d",&a,&b);
printf("Seleccione una de las operaciones:\n");
printf("(1) Sumar a,b\n");
printf("(2) Restar a,b\n");
printf("(3) Multiplicar a,b\n");
printf("(4) Dividir a,b\n");
scanf("%d",&op);
switch(op)
{
case 1:
resul = a + b;
break;
case 2:
resul = a - b;
break;
case 3:
resul = a * b;
break;
case 4:
resul = a / b;
break;
default:
printf("Operacion no valida\n");
}
printf("\nResultado = %d\n",resul);
printf("Volver ejecutar (s/n?)\n");
fflush(stdin);
resp = getchar();
}while(resp == 's');
}
3.- Escribir un programa que pida al usuario un carácter y un número de repeticiones. Luego
imprima el carácter el número de veces especificado.
}
Funciones 6
C utiliza funciones de biblioteca con el fin de realizar un cierto número de operaciones o
cálculos de uso común. Sin embargo, C también permite al programador definir sus propias funciones
que realicen determinadas tareas. Esto permite dividir un programa en cierto número de
componentes más pequeñas.
Hay tres razones fundamentales para el uso de funciones en C:
Al igual que las variables, las funciones deben declararse y definirse. Una declaración es
simplemente una presentación, mientras que una definición contiene las instrucciones con las que
realizará su trabajo la función.
Esta declaración sirve para indicar al compilador los tipos que devuelve así como sus parámetros, de
forma que este compruebe si son del tipo correcto cada vez que se use dentro del programa , o para
hacer las conversiones de tipo cuando sea necesario. Los nombres de los parámetros son opcionales
en la declaración, y se incluyen como documentación y ayuda en la interpretación y comprensión del
programa .
Si por ejemplo hacemos una declaración del prototipo de función siguiente:
int mayor(int,int,int);
Por medio de esta directiva, indicamos al compilador, que en algún lugar del programa se definirá
una función cuyo nombre es mayor, la cual admite tres parámetros de tipo entero ”int” y que
devolverá también un valor de tipo entero “int” . No es necesario escribir nombres para los
parámetros, ya que el prototipo no los usa. En otro lugar del programa habrá una definición completa
de la función. Esta definición normalmente se hará al final del programa principal, es decir, después
de la última llave de la función main().
6.2.2 Definición
El especificador_de_tipo indica el tipo del valor que la función devolverá mediante el uso de return.
El valor puede ser de cualquier tipo válido. Si no se específica un valor, entonces la computadora
asume por defecto que la función devolverá un resultado entero. Si anteponemos la palabra void al
nombre de la función, significa que no devolverá ningún valor. No se tienen siempre que incluir
parámetros en una función. La lista de parámetros puede estar vacía.
Los parámetros formales de una función son los valores de entrada de dicha función. Para dicha
función, estos parámetros se comportan exactamente igual que variables, y de hecho, cada
parámetro se declara igual que una variable. Estos parámetros, en caso de ser varios, van separados
por comas. No siempre se tienen que incluir parámetros en una función. Por lo tanto la lista de
parámetros puede estar vacía. En este caso, podríamos poner el nombre de la función y en el lugar
de sus parámetros la palabra void.
El cuerpo de la función es el conjunto de sentencias necesarias para su tarea que van encerradas
entre llaves.
Las funciones terminan y regresan automáticamente al procedimiento que las llamó cuando
se encuentra la última llave }, o bien, se puede forzar el regreso antes usando la sentencia return.
Cuando una función retorna un resultado, lo hace con la sentencia return.
Una función muy especial es la función main(). Se trata de la función de entrada, y debe de
existir siempre. Será la que tome el control cuando se ejecute un programa en C. Como mínimo, un
programa en C deberá tener una función, y esta será la función main().
Vamos a realizar como ejemplo, la función calcula_mayor que calculará el mayor de tres
números introducidos por teclado. Estos tres números se le pasarán como parámetros desde el
programa principal, por lo tanto, en la lista de argumentos deberemos declarar tres variables del tipo
de datos que vamos a manejar, en este caso tipo entero “int” (int,int,int). De la misma forma, la
función retornará al programa principal el mayor de los tres números, por lo tanto el tipo de datos que
devolverá será también tipo entero. Debiendo declarar la función como int calcula_mayor. Su código
será el siguiente:
Ahora, supongamos que queremos utilizar nuestra función y llamarla desde nuestro
programa principal. Para ello, definimos la estructura del programa principal, declarando dicha
función junto con sus parámetros formales, y haciendo una llamada en el momento que la
necesitemos.
#include “stdio.h”
#include “conio.h”
int calcula_mayor(int a,int b,int c);
main()
{
int a,b,c,resul;
printf("Programa que calcula el mayor …\n");
printf("Introduzca los números:a,b,c\n");
scanf(“%d %d %d”,&a,&b,&c”);
resul=calcula_mayor(a,b,c);
printf("\nEl mayor de %d %d %d es:%d\n”,a,b,c,resul);
getch();
}
Por lo tanto, el programa deberá retornar el mayor de los tres números introducidos por teclado.
En el caso de que la función mayor no recibiese ningún parámetro, pero si retorne el mayor de los
tres números, el programa completo quedaría de la siguiente forma:
#include “stdio.h”
#include “conio.h”
int calcula_mayor(void);
main()
{
int resul;
printf("Programa que calcula el mayor …\n");
resul=calcula_mayor();
printf("\nEl mayor de %d %d %d es:%d\n”,a,b,c,resul);
getch();
}
int calcula_mayor(void)
{
int a,b,c,max;
printf("Introduzca los números:a,b,c\n");
scanf(“%d %d %d”,&a,&b,&c”);
if(a>b)
if(a>c)
max=a;
else
max=c;
else
if(b>c)
max=b;
else
max=c;
return(max);
}
Cabe destacar que en este ejemplo, es la propia función la que se encarga de la recogida de
datos. Esto podríamos realizarlo desde la función principal teniendo la habilidad de declarar las
variables a,b y c como globales, es decir, fuerza de la función main() para que tuviese acceso.
Supongamos ahora que la función no devuelve ni recibe ningún parámetro. Una solución par
la toma de datos sería como se comentó anteriormente, es decir, definir a,b y c como globales. Para
la presentación de resultado también tendremos varias opciones. Optaremos por que sea la función
principal la que nos presente el resultado. En este caso, main() debe tener acceso a la variable que
contiene el mayor de los tres números, por lo que deberá se la propia función calcula_mayor la que
se encargue de esa tarea. Veamos el ejemplo:
#include “stdio.h”
#include “conio.h”
void calcula_mayor(void);
int a,b,c,resul;
main()
{
printf("Programa que calcula el mayor …\n");
printf("Introduzca los números:a,b,c\n");
scanf(“%d %d %d”,&a,&b,&c”);
calcula_mayor();
printf("\nEl mayor de %d %d %d es:%d\n”,a,b,c,resul);
getch();
}
int calcula_mayor(void)
{
int max;
if(a>b)
if(a>c)
max=a;
else
max=c;
else
if(b>c)
max=b;
else
max=c;
resul=max;
}
EJERCICIOS RESUELTOS
1.- Escribir un programa que calcule el menor de dos números mediante una función. El
programa principal leerá los dos números y se los pasará a la función como argumentos,
posteriormente la función calculará el menor devolviéndoselo al programa principal, siendo
éste el encargado de presentarlo por pantalla.
{
if(a<b) return(a);
else return(b);
}
2.- Escribir un programa que calcule el cuadrado de un número por medio de una función.
#include<stdio.h>
#include<conio.h>
int calcula_cuadrado(int);
main()
{
int result,a;
printf("Dame el numero\n");
scanf ("%d",&a);
result=calcula_cuadrado(a);
printf ("el cuadrado del numero %d es: %d\n",a,result);
}
int calcula_cuadrado(int a)
{
int resul;
resul=a*a;
return(resul);
getch();
}
3.- Escribir un programa que calcule el cuadrado de un número por medio de una función. La
función no recibe ni devuelve ningún parámetro.
void calcula_cuadrado(void)
{
int result,a;
printf("Dame el numero\n");
scanf ("%d",&a);
result=a*a;
printf ("el cuadrado del numero %d es: %d\n",a,result);
getch();
}
4. Escriba un programa que dándole el importe exacto de una cantidad te indica el mínimo
número de monedas que podrías tener. Las monedas son de 1, 5, 10, 25, 50, 100, 200 y 500
pesetas.
#include <stdio.h>
#define LIM 8
int monedas[LIM]= {500, 200, 100, 50, 25, 10, 5, 1};
main()
{
int num, cantidad, numonedas;
printf ("Introduzca el importe: ");
scanf ("%d", &cantidad);
printf ("El cambio optimo es el siguiente: \n");
for (num=0; num<LIM; num++)
{
numonedas=cantidad/monedas[num];
if (numonedas != 0)
printf ("%d de %d.\n", numonedas, monedas[num]);
cantidad= cantidad % monedas[num];
}
}
5.-Escriba un programa que imprima una tabla con las áreas del círculo y de la esfera para un
radio en el rango de 0 hasta 2 en incrementos de 0.2.
}
Arrays 7
Muchas aplicaciones requieren el procesado de múltiples datos que tienen características
comunes. En tales situaciones es a menudo conveniente colocar los datos en un array, donde todos
comparten el mismo nombre. Los datos individuales pueden ser caracteres, enteros, números en coma
flotante, etc. Pero todos tienen que ser del mismo tipo y con el mismo tipo de almacenamiento.
Cada elemento del array es referido especificando el nombre del array seguido por uno o más
índices, con cada índice encerrado entre corchetes. Cada índice debe ser expresado como un entero
no negativo: una constante entera, una variable entera o una expresión entera más compleja.
Al definirse, cada array debe acompañarse de una especificación de tamaño (número de elementos).
En términos generales, un array unidimensional puede expresarse como:
tipo_datos nombre_array[tamaño]
Aquí tenemos definido un array unidimensional llamado lista de diez elementos tipo entero, Int
lista[10], donde:
si queremos asignar valores a los elementos del array, podríamos hacerlo de la siguiente forma:
lista[0] = 3
lista[4] = 9
lista[9] = 25
De esta forma, lo que estamos haciendo, es asignar al primer, quinto y último elemento los
valores enteros 3,9 y 25 respectivamente.
Int lista[10]={2,5,3,5,9,8,9,7,4,1}
int tabla[5][5];
Para acceder los elementos se procede de forma similar al ejemplo del array de una dimensión, es
decir :
Int tabla[4][3]={4,3,5,7,9,0,8,7,5,3,4,5}
Veamos un programa que hace uso del array unidimensional lista cargando los diez primeros
números naturales en su interior.
#include “stdio.h”
#include “conio.h”
main()
{
int lista[10],i;
printf("Programa que almacena …\n");
for(i=0;i<10;i++)
{
printf(“Dame lista[%d]”,i);
scanf(“%d”,&lista[i]);
}
getch();
}
#include “stdio.h”
#include “conio.h”
main()
{
int tabla[3][4],i,j;
tabla[3][4]={1,2,3,4,5,6,7,8,9,0,11};
printf("Programa que visualiza en pantalla...\n");
for(i=0;i<10;i++)
{
for(i=0;i<10;i++)
printf(“tabla[%d][%d] = %d\n”,i,j,lista[i][j]);
}
}
En el siguiente ejemplo, asignaremos los valores de un array unidimensional a otro del mismo
tamaño multiplicados por el número 3.
#include “stdio.h”
#include “conio.h”
main()
{
int lista1[10],lista2[10],i;
printf("Programa que asigna valores de lista 1…\n");
for(i=0;i<10;i++)
{
printf(“Dame elemento[%d]”,i+1);
scanf(“%d”,&lista1[i]);
lista2[i] = lista1[i] * 3;
}
printf("Impresión elementos lista1 y lista 2\n”);
for(i=0;i<10;i++)
{
printf(“\tlista1[%d] = %d , lista2[%d] = %d\n);
}
getch();
}
Los arrays automáticos, a diferencia de las variables automáticas, no pueden ser inicializados.
Sin embargo las definiciones de arrays estáticos y externos pueden incluir, si se desea, la asignación
de valores iniciales. Los valores iniciales deben aparecer en el orden en que serán asignados a los
elementos individuales del array, encerrados entre llaves y separados por comas. La forma general es:
La presencia de tamaño, que indica el número de elementos del array, es opcional cuando los
valores iniciales están presentes.
Todos los elementos del array que no tienen asignados valores iniciales explícitos serán
puestos automáticamente a cero.
char cadena[11];
char cadena[5]={'h','o','l','a','\0'};
Para asignar la entrada estándar a una cadena se puede usar la función scanf con la opción
%s (observar que no se requiere usar el operador &), de igual forma para mostrarlo en la salida
estándar.
Por ejemplo:
#include “stdio.h”
#include “conio.h”
main()
{
char nombre[15], apellidos[30];
printf("Introduce tu nombre: ");
scanf("%s",nombre);
printf("Introduce tus apellidos: ");
scanf("%s",apellidos);
printf("Usted es %s %s\n",nombre,apellidos);
}
1.- Escribir un programa que reciba un array de N valores enteros y aumente en uno el valor
de cada elemento situado en las posiciones pares del array.
#include <stdio.h>
#define N 10
int main()
{
int i;
int lista[N];
for (i = 0; i < N; i++)
scanf("%d", &lista[i]);
2.- Escribir un programa que inicialice un array de enteros. Calcule e imprima su suma, media,
mínimo y máximo.
51
3. Escriba un programa que ordene un vector (de dimensión máxima 15) por el método de la
burbuja.
4. Escriba un programa que contenga dos arrays y utilizando punteros genere un tercer array
con la suma de los otros dos.
52
int arr2 [FILAS] [COLS] = { {1,2,5,1,4},{1,6,1,8,9},{0,2,2,3,2},
{5,2,7,8,9} };
int arr3 [FILAS] [COLS];
printf("\nArray 1\n");
for (j=0; j<FILAS; j++)
{
for (k=0; k<COLS; k++)
{
printf("%d ", arr1[j][k]);
}
printf("\n");
}
printf("\nArray 2 \n");
for (j=0; j<FILAS; j++)
{
for (k=0; k<COLS; k++)
{
printf("%d ", arr2[j][k]);
}
printf("\n");
}
printf("\nArray suma\n");
for (j=0; j<FILAS; j++)
{
for (k=0; k<COLS; k++)
{
*(*(arr3+j)+k) = *(*(arr1+j)+k) + *(*(arr2+j)+k);
printf("%d ", *(*(arr3+j)+k));
}
printf("\n");
}
}
5. Escriba un programa que pida una cadena por el teclado y la imprima después de convertir
el primer carácter en mayúscula y el resto en minúsculas.
53
while (*pc != '\0')
{
*pc = tolower(*pc);
++pc;
}
return(cadena);
}
6. Escriba un programa que inserte un carácter en una determinada posición de una cadena.
#include <string.h>
#include <stdio.h>
main()
{
char car, cadena[80], *ptr;
printf("Introduzca la cadena donde se va a buscar:\n");
gets(cadena);
printf("Escriba el carácter a buscar:\n");
car=getchar();
ptr=strchr(cadena, car);
if (ptr==0)
printf("El carácter %c no se encuentra en la
cadena.\n",car);
else
printf("La posicion del carácter es %d.\n", ptr-
cadena+1);
}
54
8. Escriba un programa que lea una cadena desde el teclado y cuente el número de caracteres
de tres categorías: letras (a-z y A-Z), dígitos (0-9) y otros caracteres. Utilice las funciones
isdigit() e isalpha() definidas en la librería ctype.h.
#include <stdio.h>
#include <ctype.h>
#define MAXCAD 80
main()
{
char linea[MAXCAD], *pc=linea;
int digitos=0, letras=0, otros=0;
printf("\nEscriba una cadena (<%d caracteres):\n", MAXCAD);
gets(linea);
while (*pc != '\0')
{
if (isdigit(*pc))
++digitos;
else if (isalpha(*pc))
++letras;
else
++otros;
++pc;
}
printf("\n\tDigitos = %d\n\tLetras = %d\n\tOtros =
%d\n",digitos,letras,otros);
}
55
Punteros 8
8.1 CONCEPTOS BÁSICOS
Los punteros son una de las características más útiles y a la vez más peligrosas de que
dispone el lenguaje C. C permite declarar una variable que contiene la dirección de otra variable, es
decir, un puntero. Cuando se declara un puntero éste contiene una dirección arbitraria, si leemos a
dónde apunta nos dará un valor indefinido y si se escribe en tal dirección estamos variando el contenido
de una posición de memoria que no conocemos por lo que podemos hacer que el sistema tenga
comportamientos no deseados.
En el interior de la memoria de la computadora cada dato almacenado ocupa una o más celdas
contiguas de memoria. El número de celdas de memoria requeridas para almacenar un dato depende
de su tipo.
El operador dirección (&) sólo puede actuar sobre variables ordinarias o elementos simples de
un array. El operador indirección (*) sólo puede actuar sobre operandos que sean punteros.
56
8.2 DECLARACIÓN DE PUNTEROS
Los punteros, como cualquier otra variable, deben declararse antes de ser usados. Cuando se
define una variable tipo puntero, el nombre de la variable debe ir precedida por un *. Este identifica que
la variable es un puntero. El tipo de dato que aparece en la declaración se refiere al tipo de objeto del
puntero, el tipo de dato que se almacena en la dirección representada por el puntero, en vez del
puntero mismo. Así, una declaración de puntero general es:
tipo_dato *nombre;
donde nombre es la variable puntero y tipo_dato el tipo de dato apuntado por el puntero.
Dentro de la declaración, una variable puntero puede inicializarse asignándole la dirección de otra
variable (ésta debe estar previamente declarada).
int *p, a;
p = &a;
p = (T*)malloc(sizeof(T));
A continuación, vemos un ejemplo en donde por medio de una función f2 a la que le pasamos
la dirección de la variable a y f2 por medio de un puntero modifica su valor. La función f1 no tiene
acceso a modificarlo.
57
#include <stdio.h>
void f1(int a);
void f2(int *a);
main()
{
int a=7;
int *pa;
f1(a);
printf("inicialmente a = %d\n",a);
f2(&a);
printf("despues de llamada a f2: a = %d \n",a);
}
void f1(int a)
{
a=0;
}
void f2(int *pa)
{
*pa=5;
}
Si &x[i] y (x+i) representan la dirección del i-ésimo elemento de x, x[i] y *(x+i) representan el
contenido de esa dirección: el valor del i-ésimo elemento de x.
Si el array se define como una variable puntero, no se le pueden asignar valores iniciales numéricos.
int *x;
x = (int *) malloc (10 * sizeof(int));
58
La función malloc devuelve un puntero a carácter y, en este caso, reserva un bloque de memoria para
10 enteros.
A una variable puntero a carácter sí se le puede asignar una cadena como una parte de la declaración
de la variable ( y además sin tener que se declarada static).
#include <stdio.h>
main()
{
int *p;
int a[3]={1,2,3};
printf("%d,%d,%d",a[0],a[1],a[2]);
p=a;
*p=5;
*(p+1)=6;
*(p+2)=7;
printf("\n%d,%d,%d",a[0],a[1],a[2]);
}
Ya se ha dicho que un valor entero se puede sumar al nombre de un array para acceder a
uno de sus elementos. El valor entero es interpretado como el índice del array; representa la
localización relativa del elemento deseado con respecto al primero. Esto funciona porque todos los
elementos del array son del mismo tipo y por tanto cada elemento ocupa un mismo número de celdas
de memoria. El número de celdas que separan a dos elementos del array dependerá del tipo de
datos del array, pero de esto se encarga el compilador automáticamente.
Este concepto se puede extender a variables puntero. En particular, un valor entero puede
ser sumado o restado a una variable puntero, pero el resultado de la operación debe ser interpretado
con cuidado. Supongamos que px es una variable puntero que representa la dirección de una
variable x. Se pueden escribir expresiones como ++px, --px, (px+3). Cada expresión representa una
dirección localizada a cierta distancia de la posición original representada por px. La distancia exacta
será el producto de la cantidad entera por el número de bytes que ocupa cada elemento al que
apunta px.
• Se le puede asignar el valor de otra variable puntero, siempre que ambas apunten al
mismo tipo de dato.
• 5. Se le puede restar otro puntero con tal de que ambos apunten a elementos del
mismo array.
59
• 6. Dos variable puntero pueden ser comparadas siempre que ambas apunten a datos
del mismo tipo.
Ejemplo: Suponer que x es un array bidimensional de enteros con 10 filas y 20 columnas. Podemos
declara x como:
tipo_dato *nom_array[expresión1]
en vez de
tipo_dato nom_array[expresión1][expresión2]
Notar que el nombre del array precedido por un asterisco no está cerrado entre paréntesis. Se asocia
primero el par de corchetes con nom_array definiéndolo como un array. El asterisco que lo precede
establece que el array contendrá punteros.
Ejemplo: Suponer que x es un array bidimensional de 10 filas y 20 columnas. Se puede definir x como
un array unidimensional de punteros escribiendo
int *x[10];
60
Aquí x[0] apunta al primer elemento de la primera fila, x[1] al primer elemento de la segunda
fila, y así sucesivamente. Notar que el número de elementos dentro de cada fila no está especificado
explícitamente. Un elemento individual del array, tal como x[2][5] puede ser accedido escribiendo
*(x[2]+5)
En esta expresión x[2] es un puntero al primer elemento en la fila 2, de modo que (x[2]+5)
apunta al elemento 5 de la fila 2. El objeto de este puntero, *(x[2]+5), refiere, por tanto, a x[2][5].
Los arrays de punteros ofrecen un método conveniente para almacenar cadenas. En esta
situación cada elemento del array es un puntero que indica dónde empieza cada cadena.
61
EJERCICIOS RESUELTOS
1.Escriba un programa que intercambio de valores usando llamada por valor y por referencia
# include <stdio.h>
void IntercambioValor(int v1, int v2);
void IntercambioReferencia(int *pv1, int *pv2);
main()
{
int val1=10, val2=20;
printf("Valores iniciales:\n\tval1 = %d; val2 = %d\n",val1,val2);
IntercambioValor(val1, val2);
printf("\nPaso de parametros por valor:\n\tval1 = %d; val2 =
%d\n",val1,val2);
IntercambioReferencia(&val1, &val2);
printf("\nPaso de Parametros por Referencia:\n\tval1 = %d; val2 =
%d\n",val1,val2);
}
void IntercambioValor(int v1, int v2)
{
int tmp;
tmp = v1;
v1 = v2;
v2 = tmp;
}
void IntercambioReferencia(int *pv1, int *pv2)
{
int tmp;
tmp = *pv1;
*pv1 = *pv2;
*pv2 = tmp;
}
62
Estructuras y uniones
9
Muchas veces necesitamos tener agrupados una serie de datos heterogéneos bajo un mismo
nombre de variable. Es por ello,que C nos proporciona lo que se conoce como estructuras de datos.
Estos datos pertenecen a una entidad común que bien podrían ser sus atributos. Así, por ejemplo, si
tenemos la entidad alumno, esta podría estar formada por los atributos nombre, apellidos, edad,
fecha de nacimiento, dirección y teléfono.
struct tipo_estructura
{
tipo miembro_1;
tipo miembro_2;
.
tipo miembro_n;
} variable_estructura;
donde tipo_estructura o variable_estructura pueden omitirse pero no ambos. Las estructuras ayudan
a agrupar información relacionada, por ejemplo los datos de un alumno, las coordenadas de un punto,
etc.
De esta forma, la declaración de una estructura alumno con sus datos relacionados sería:
#include <stdio.h>
main()
{
struct alumno
{
int edad;
char nombre[20];
};
struct alumno cmedio,csuperior;
printf("datos campos alumno cmedio\n");
printf("nombre alumno cmedio\n");
gets(cmedio.nombre);
printf("edad alumno cmedio\n");
scanf("%d",&cmedio.edad);
printf("datos campos alumno csuperior\n");
printf("nombre\n");
gets(csuperior.nombre);
printf("edad\n");
63
scanf("%d",&csuperior.edad);
printf(" Impresión pantalla datos alumno cmedio y csuperior\n”);
printf("%s %d",cmedio.nombre,cmedio.edad);
printf("%s %d",csuperior.nombre,csuperior.edad);
struct fecha
{
int dia;
int mes;
int año;
};
struct alumno
{
char nombre[20];
char apellidos[30];
char fecha nacimiento;
int teléfono;
char direccion [100];
};
struct alumno fp
Los elementos individuales de una estructura se referencian utilizando el operador punto (.)
entre el nombre de la variable de tipo estructura y el nombre del miembro de la estructura. A los
elementos de una estructura se les denomina miembros.
Continuando con las estructuras de los ejemplos anteriores, se pueden tener las siguientes
referencias a miembros:
cmedio.nombre
cmedio.edad
csuperior.nombre
csuperior.edad
alumno.nacimiento.dia
alumno.nacimiento.mes
alumno.nacimiento.año
En el caso del ejemplo de la estructura struct alumno cmedio, struct alumno csuperior,
solamente podremos meter los datos de un alumno. Si cada curso tuviese 20 alumnos, sería necesario
dotar a dichas estructuras de la capacidad para poder almacenar esos 20 registros con sus respectivos
nombres y sus edades. Para ello, necesitamos definir un array de estructuras. Esto se hace de forma
similar a los arrays, con la particularidad de que lleva la palabra struct y sus identificadores, es decir,
Si queremos dotar a las estructuras de dicho ejemplo con capacidad para almacenar 20
registros cada una, quedaría:
#include <stdio.h>
main()
{
struct alumno
{
int edad;
char nombre[20];
};
struct alumno cmedio[20],csuperior[20];
int i;
printf("datos campos alumnos cmedio\n");
for(i=0;i<20;i++)
{
printf("nombre alumno %d cmedio\n",i+1);
gets(cmedio[i].nombre);
printf("edad alumno cmedio\n");
scanf("%d",&cmedio[i].edad);
}
printf("datos campos alumnos csuperior\n");
for(i=0;i<20;i++)
{
printf("nombre alumno %d csuperior\n",i+1);
gets(csuperior[i].nombre);
printf("edad alumno csuperior\n");
scanf("%d",&csuperior[i].edad);
}
printf("Impresion pantalla datos alumno cmedio y csuperior\n");
printf("\ncmedio:\n");
printf("\nNOMBRE \t\tEDAD\n");
for(i=0;i<20;i++)
{
printf("%s\t\t%d\n",cmedio[i].nombre,cmedio[i].edad);
}
printf("\ncsuperior:\n");
printf("\nNOMBRE \t\tEDAD\n");
for(i=0;i<20;i++)
{
printf("%s\t\t
%d\n",csuperior[i].nombre,csuperior[i].edad);
}
9.4 UNIONES
Las uniones tienen una sintaxis similar a las estructuras, pero se diferencian de éstas en que
sus miembros comparten almacenamiento. Una variable unión define a un conjunto de valores
alternos que pueden almacenarse en una porción compartida de memoria.
65
{
tipo miembro1;
tipo miembro2;
...
} identificador1, identificador2, ...;
union persona{
char nombre[10];
char nif[12];
};
Una unión sólo puede ser inicializada con un valor del tipo de su primer miembro.
La creación de nuevos nombres de tipos de datos se realiza utilizando la palabra reservada typedef:
Ejemplos:
Con tipos simples:
typedef int ENTERO
typedef float REAL
ENTERO a,b;
REAL c;
Con tipos estructurados:
typedef struct
{
int dia;
int mes;
int anio;
} FECHA;
FECHA a;
donde vali son identificadores de constantes. Si no se les asigna ningún valor se inicializan con los
valores enteros 0,1,2,... Se pueden asignar otros valores indicándolo en la enumeración
enum color{rojo=-1,azul,amarillo,verde,negro=0};
• No se puede leer una variable de tipo enum. Se puede leer un entero y asignárselo a
una variable.
67
EJERCICIOS RESUELTOS
1. Escriba un programa que guarde los datos de un alumno en una estructura. Los campos de
la estructura son : edad, nombre y apellidos.
#include<stdio.h>
#include<conio.h>
main()
{
struct ficha
{
int edad;
char nombre[15];
char apellidos[25];
} alumno;
printf("Edad :\n");
scanf("%d",&alumno.edad);
printf("Nombre :\n");
scanf("%s",&alumno.nombre);
printf("Apellidos :\n");
scanf("%s",&alumno.apellidos);
printf("%d %s %s",alumno.edad,alumno.nombre,alumno.apellidos);
}
2. Escriba un programa que imprima una lista de amigos guardados en una agenda (tipo
estructura).
#include <stdio.h>
#define N 3
main()
{
struct agenda
{
char nombre[25];
char telefono[10];
int edad;
};
struct agenda
amigos[N]={{"Pepe","913472314",18},{"Juan","915547623",19},
{"Rosa","917456778",21}};
int i;
for (i=0; i<N; ++i)
{
printf("\nAmigo %s\t telefono %s\t edad %d",amigos[i].nombre,
amigos[i].telefono,amigos[i].edad);
}
printf("\n");
}
}
68
Ficheros de datos 10
10.1 INTRODUCCIÓN
A veces, necesitamos almacenar la información procesada por el programa o bien la que este
capture a través del teclado o puertos de comunicaciones. En ese caso, necesitamos valernos de de
estructuras que nos permitan el almacén de forma permanente de dicha información. Estas
estructuras de datos se las denomina ficheros
En C un fichero puede ser cualquier cosa, desde una impresora, la pantalla, el teclado, etc.
Los ficheros son archivos de datos que nos permiten almacenar información de modo permanente,
para ser accedida o alterada cuando sea necesario.
En C existe un conjunto extenso de funciones de biblioteca para crear y procesar ficheros.
Cuando se trabaja con ficheros de datos, el primer paso es establecer un área de buffer, donde
la información se almacena temporalmente mientras se está transfiriendo entre la memoria y el archivo
de datos. Este área de buffer permite leer y escribir información del archivo más rápidamente de lo que
sería posible de otra manera. El área de buffer se establece escribiendo:
FILE *pf;
donde FILE es un tipo de estructura que establece el área de buffer y pf es un puntero al fichero que
nos indica el comienzo de este área. El tipo de estructura FILE está definido en stdio.h.
Un archivo de datos debe ser abierto antes de ser creado o procesado. Esto asocia el nombre
del archivo con el área de buffer. También se especifica cómo se va a usar el archivo.
69
Operadores sobre ficheros
OPERACIÓN SIGNIFICADO
"r" Abrir un archivo existente sólo para lectura.
"w" Abrir un nuevo archivo sólo para escritura. Si ya existe, será destruido y
creado uno nuevo en su lugar.
"a" Abrir un archivo para añadir. Si no existe, se crea uno nuevo
"r+" Abrir un archivo existente para lectura y escritura
"w+" Abrir un archivo nuevo para lectura y escritura. Si ya existe, será destruido
y creado uno nuevo en su lugar
"a+" Abrir un archivo existente para leer y añadir. Si no existe, se crea uno
nuevo
La función fopen retorna un puntero al principio del área de buffer asociada con el archivo. Se
retorna un valor NULL si no se puede abrir el archivo.
Por ejemplo, si queremos abrir un archivo llamado prueba en modo escritura, su código será:
file pf;
pf=fopen(”prueba”,”w”);
Un fichero de datos debe cerrarse al final del programa. Para ello usamos la función
fclose(pf);
fclose() escribe toda la información depositada en el buffer del disco y realiza un cierre formal del
archivo a nivel del sistema operativo.
Un fichero de datos puede crearse de dos formas distintas. Una es crear el archivo
directamente, usando un editor. La otra es escribir un programa que introduzca información en la
computadora y la deposite en un archivo.
Por ello, para la manipulación de ficheros existe una amplia colección e funciones que se
detalla en el punto siguiente.
70
10.4 FUNCIONES PARA LA MANIPULACIÓN DE FICHEROS
FUCIÓN SIGNIFICADO
fopen() Abre un fichero
fclose() Cerrar un fichero
fgetc() Lee un carácter desde un fichero
fputc() Escribe un carácter a un fichero.
feof() Comprueba si se ha alcanzado el final del fichero
fgets() Lee cadenas de caracteres
fputs() Escribe una cadena en un fichero
fread() Leer registros de un fichero
fwrite() Escribir registros en un fichero
fscanf() Escribir registros en un fichero
fprintf() Lee con con formato desde un fichero
fflush() Vacía el buffer
10.4.1 fopen()
Esta función sirve para abrir y crear ficheros en disco. El valor de retorno es un puntero a una
estructura FILE.
FILE *fopen(char *nombre, char *modo)
10.4.2 fclose()
Debemos cerrar cerrar los ficheros abiertos antes de abandonar la aplicación. Esta función
sirve para ello. Cerrar un fichero, almacena los datos que aún están en el buffer de memoria, y
actualiza algunos datos de la cabecera del fichero que mantiene el sistema operativo. Además,
permite que otros programas puedan abrir el fichero para su uso.
71
Un valor de retorno cero indica que el fichero ha sido correctamente cerrado, si ha habido algún
error, el valor de retorno es la constante EOF. El parámetro es un puntero a la estructura FILE del
fichero que queremos cerrar.
10.4.3 fgetc()
El valor de retorno es el carácter leído como un unsigned char convertido a int. Si no hay
ningún carácter disponible, el valor de retorno es EOF. El parámetro es un puntero a una estructura
FILE del fichero del que se hará la lectura.
10.4.4 fputc()
10.4.5 feof()
#include <stdio.h>
int main()
{
FILE *pf;
pf = fopen("datos.c", "r");
while(!feof(pf)) fputc(fgetc(pf), stdout);
rewind(pf);
while(!feof(pf)) fputc(fgetc(pf), stdout);
fclose(pf);
getchar();
return 0;
}
72
10.4.6 fgets()
Esta función está diseñada para leer cadenas de caracteres. Leerá hasta n-1 caracteres o
hasta que lea un retorno de línea. En este último caso, el carácter de retorno de línea también es leído.
El parámetro n nos permite limitar la lectura para evitar desbordar el espacio disponible en la
cadena. El valor de retorno es un puntero a la cadena leída, si se leyó con éxito, y es NULL si se
detecta el final del fichero o si hay un error. Los parámetros son: la cadena a leer, el número de
caracteres máximo a leer y un puntero a una estructura FILE del fichero del que se leerá.
10.4.7 fputs()
La función fputs escribe una cadena en un fichero. No se añade el carácter de retorno de línea
ni el carácter nulo final.
10.4.8 fread()
Esta función está pensada para trabajar con registros de longitud constante. Es capaz de leer
desde un fichero uno o varios registros de la misma longitud y a partir de una dirección de memoria
determinada. El usuario es responsable de asegurarse de que hay espacio suficiente para contener la
información leída.
10.4.9 fwrite()
Esta función también está pensada para trabajar con registros de longitud constante y forma
pareja con fread. Es capaz de escribir hacia un fichero uno o varios registros de la misma longitud
almacenados a partir de una dirección de memoria determinada.
73
// copiamos el contenido del fichero datos.txt
// en datos1.txt. Datos.txt debe existir.
#include <stdio.h>
main() {
FILE *pf1, *pf2;
char lista[2048];
int bytesLeidos;
10.4.10 fprintf()
La función fprintf funciona igual que printf en cuanto a parámetros, pero la salida se dirige a
un fichero en lugar de a la pantalla.
10.4.11 fscanf()
La función fscanf funciona igual que scanf en cuanto a parámetros, pero la entrada se toma de un
fichero en lugar del teclado.
10.4.12 fflush()
Esta función fuerza la salida de los datos acumulados en el buffer de salida del fichero. Para
mejorar las prestaciones del manejo de ficheros se utilizan buffers, almacenes temporales de datos en
memoria, las operaciones de salida se hacen a través del buffer, y sólo cuando el buffer se llena se
realiza la escritura en el disco y se vacía el buffer. En ocasiones nos hace falta vaciar ese buffer de un
modo manual, para eso sirve ésta función.
74
int fflush(FILE *fichero)
El valor de retorno es cero si la función se ejecutó con éxito, y EOF si hubo algún error. El
parámetro de entrada es un puntero a la estructura FILE del fichero del que se quiere vaciar el buffer.
Si es NULL se hará el vaciado de todos los ficheros abiertos.
75
EJERCICIOS RESUELTOS
printf("Datos alumno\n");
printf("Edad :\n");
fflush(stdin);
scanf("%d",&alumno.edad);
printf("Nombre :\n");
fflush(stdin);
scanf("%s",&alumno.nombre);
printf("Apellidos :\n");
fflush(stdin);
scanf("%s",&alumno.apellidos);
printf("%d %s %s\n",alumno.edad,alumno.nombre,alumno.apellidos);
printf("Grabamos datos fichero\n");
pf=fopen("alumno.txt","a+");
fwrite(&alumno,sizeof(struct ficha),1,pf);
fclose(pf);
pf=fopen("alumno.txt","r");
fread(&alumno, sizeof(struct ficha), 1, pf);
printf("\nEdad \tNombre \tApellidos");
while(!feof(pf))
{
printf("\n%d \t%s \t
%s",alumno.edad,alumno.nombre,alumno.apellidos);
fread(&alumno, sizeof(struct ficha), 1, pf);
}
fclose(pf);
}
/* Fichero */-----------------------
#include <stdio.h>
void menu();
void Crea_Fichero(FILE *pf);
void Insertar_Datos(FILE *pf);
void Visualiza_Datos(FILE *pf);
76
struct alumno
{
char Nombre[25];
char Apellidos[50];
int Edad;
int Telefono;
} ciclo_superior;
while (!exit)
{
menu();
printf("\nElije una opcion: ");
scanf("%d", &opcion);
switch(opcion)
{
case 1:
Crea_Fichero(pf);
break;
case 2:
Insertar_Datos(pf);
break;
case 3:
Visualiza_Datos(pf);
break;
case 4:
exit = 1;
break;
default:
printf("\nopcion no valida");
}
}
return 0;
}
void menu()
{
printf("\nMenu:");
printf("\n\t1. Crear fichero");
printf("\n\t2. Insertar datos");
printf("\n\t3. Visualizar datos");
printf("\n\t4. Salir");
}
77
pf = fopen("fichero.txt", "w");
printf("\nEl fichero ha sido creado!");
}
else
{
printf("\nEl fichero ya existe!");
}
fclose (pf);
return;
}
printf("\nNombre: ");
scanf("%s", &ciclo_superior.Nombre);
printf("\nApellidos: ");
scanf("%s", &ciclo_superior.Apellidos);
printf("\nEdad: ");
scanf("%d", &ciclo_superior.Edad);
printf("\nTelefono: ");
scanf("%d", &ciclo_superior.Telefono);
fwrite(&ciclo_superior, sizeof(struct alumno), 1, pf);
fclose(pf);
return;
}
return;
}
79
Librerías 11
11.1. INTRODUCCIÓN
#include nombre_fichero
donde el nombre_fichero es el nombre de la librería que incluye las funciones que nosotros vamos a
necesitar. nombre_fichero se coloca entre ángulos (<nombre_fichero>) o entre comillas dobles
("nombre_fichero") según el lugar en que haya que buscar el fichero sea en los directorios asignados
por defecto a los ficheros 'include' o en el actual.
Por otra parte, utilizando la directiva #include se puede hacer inclusión de ficheros de código
del mismo modo que en cualquier otro lenguaje.
• #include <stdio.h>
Incluye la cabecera para usar las librerías de entrada/salida desde el directorio estándar
• #include "stdio.h"
• #include "a:\librería\milib.h"
80
11.2. ALGUNAS LIBRERÍAS Y FUNCIONES IMPORTANTES EN ANSI C
El estándar ANSI C define un conjunto de funciones, así como tipos relacionados y macros,
que son proporcionados para la implementación. Todas las librerías son declaradas en un fichero
cabecera. Para que sea visible al programa, se añade el comando del preprocesador #include. Por
ejemplo: #include <stdio.h>;
Librerías ANSI C
LIBRERÍA SIGNIFICADO
stdio.h Contiene funciones para tareas de E/S.
81
A continuación se detallan lagunas funciones contenidas en las librerías mas comunes.
FUNCIÓN SIGNIFICADO
printf() Imprimir salidas de datos con formato
gets () lee caracteres de entrada hasta que encuentra un salto de línea, y los
almacena en un único argumento.
Estas mismas funciones son válidas para trabajar con ficheros anteponiendo la palabra “f” a
dichas funciones
FUNCIÓN SIGNIFICADO
strcat() añade una cadena al final de otra
82
Funciones de la librería stdlib.h
FUNCIÓN SIGNIFICADO
malloc() Para reserva de memoria dinámica.
FUNCIÓN SIGNIFICADO
sin() Función seno.
83
Funciones de la librería ctype.h
FUNCIÓN SIGNIFICADO
tolower() Convierte un carácter a minúscula
84