Está en la página 1de 84

INDICE

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:

• Se denomina algoritmo a una secuencia de instrucciones que permiten obtener un resultado


en particular. No necesariamente son programas de computadora, una receta de cocina, o
las instrucciones para cambiar un neumático son ejemplos de algoritmos de la vida real.
• Las computadoras, son maquinas sin inteligencia propia, cuya única finalidad es interpretar
el código que se les provee.
• El lenguaje de máquina es el único lenguaje que la computadora "entiende" y es capaz de
ejecutar.
• Los lenguajes de programación son el medio de comunicación entre el programador y una
computadora. El programador escribe en algún lenguaje de programación y utiliza las
herramientas provistas por ese lenguaje para transformarlo en lenguaje de máquina.

• Programa es una secuencia de órdenes a ser ejecutadas por una computadora. Un


programa debe estar escrito en algún lenguaje de programación, y puede incluir uno o más
algoritmos.

1.2 TIPOS DE LENGUAJES

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.

Según la forma en que se ejecutan sus órdenes


• Lenguajes compilados
• Lenguajes interpretados

Lenguajes interpretados, cuyas órdenes pasan a través de un intérprete que se encarga de


ejecutarla a partir del código fuente en el mismo momento en que están siendo leídas. Algunos de los
lenguajes interpretados son java y perl entre otros.
Lenguajes compilados, como es el caso de C que se diferencian en que las órdenes son
transformadas a lenguaje de máquina para posteriormente almacenarlas en un fichero ejecutable.
Ese archivo puede ejecutarse luego, sin recurrir al compilador.
Los lenguajes compilados tienen la ventaja de la velocidad y la eficiencia, pero los interpretados
tienen la ventaja de que, generalmente, son muy portables y de más alto nivel.

1.3 REQUISITOS PARA LA COMPILACIÓN DE PROGRAMAS

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 COMPILACIÓN DE PROGRAMAS SEGÚN LA PLATAFORMA

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

Es recomendable especificar el nombre que queremos dar al archivo ejecutable, pasando


como parámetro al compilador la opción -o, de la siguiente forma :
gcc hola.c -o hola
De esta forma, el nombre del fichero creado será hola. Este fichero no tiene extensión ya que
es la forma usual de llamar a los archivos ejecutables en los entornos UNIX y GNU/Linux, sin
embargo funcionaría de la misma forma si se llamara hola.exe.
Para poder ejecutarlo, haremos :
./hola

El compilador, contiene otros parámetros que podemos especificarle en la línea de


comandos, dependiendo del tipo de programa, y en función de la complejidad del mismo. Por
ejemplo, podemos agregar las siguientes opciones:
gcc hola.c -o hola -Wall -pedantic

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.

Compilación del código fuente


● Si se utiliza un entorno de desarrollo, será posible compilar directamente desde el entorno,
mediante un botón o una combinación de teclas.
● Si se ejecuta el compilador desde la línea de comandos, la línea será distinta según el
compilador utilizado.
● Una vez compilado el código fuente se genera un archivo llamado archivo objeto o programa
objeto que es luego enlazado mediante el enlazador, para generar el archivo ejecutable.
● Los compiladores actuales suelen hacer dos funciones de una vez, compilando y enlazando
todo en una sola función, aunque es posible pedirles que no lo hagan mediante parámetros
adicionales.
Según el compilador y la configuración utilizada, se obtendrán dos o tres archivos:
El archivo fuente
hola.c

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 el año 1978 Kernighan e Ritchie publican su descripción en el libro "The C Programming


Language", versión que hoy se llama 'K&R C'.

A lo largo de los años ochenta, el mercado ya disponía de numerosos compiladores de C, y


muchas aplicaciones fueron reescritas para aprovechar sus ventajas.

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'.

2.2. CARACTERÍSTICAS DEL LENGUAJE

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.

En su desarrollo se siguieron una serie de líneas generales tales como:

• Es un lenguaje estructurado. Con lo que facilita la legibilidad y entendimiento de los


programas.

• La entrada/salida se hace a través de funciones de librería. La entrada/salida no


se considera parte del lenguaje en sí, sino que se realiza a través de funciones de librería.
La misma política se sigue con cualquier otro tipo complejo de instrucciones.

• Reducido número de palabras reservadas. Para escribir un programa se debe


poder escribir poco texto. Para lograr esto se reduce el número de palabras claves.

• Eficiencia. Con ello se llegó a un compilador con un poderoso juego de


instrucciones, que permite aumentar la productividad/día de los programadores.

• Fácil de aprender. C es un lenguaje rápido de aprender, que deriva en compiladores


sencillos de diseñar, robustos, y que generan objetos pequeños y eficientes.
• Gran portabilidad. Una de las características más apreciadas de C es su gran
portabilidad, gracias a que deja en manos de librerías las funciones dependientes de la
máquina, ¡y todo ello sin restringir el acceso a dicha máquina!

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.

3.2 IDENTIFICADORES,PALABRAS RESERVADAS Y CARACTERES ESPECIALES.

Los identificadores son nombres que se les da a varios elementos de un programa, como
variables, constantes o funciones.

Un identificador puede estar compuesto de cualquier combinación de letras (minúsculas y


mayúsculas), dígitos y el símbolo subrayado '_'. La única restricción es que el primer carácter debe ser
una letra o un subrayado.

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.

Identificadores válidos Identificadores no válidos


a 7aux (primer carácter
v5 no es letra)
funci_suma “x” (carácter ilegal “)
_b funci-resta (carácter ilegal -)
ARRAY TABLA UNO (espacio ilegal)

Figura 2 Ejemplos de identificadores legales e ilegales

● No se limita la longitud de los identificadores. Pero algunas implementaciones sólo


reconocen los 8 primeros y otras (ANSI) los 31 primeros caracteres.
● Se diferencia entre mayúsculas y minúsculas.

Existe un conjunto de caracteres que tienen un significado especial en el lenguaje C. Se


muestran en la siguiente figura.

Caracteres especiales

! * + \ “ <
# ( = | { >
% ) ~ ; } /
^ - [ : , ?
& _ ] ' . (blanco)

Tabla 1 Caracteres especiales.

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

auto extern sizeof


break float static
case for struct
char goto switch
const if typedef
continue int union
default long unsigned
do register void
double return volatile
else short while
enum signed

Tabla 2 Palabras reservadas de C

3.3 TIPOS DE DATOS

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.

char Representa un carácter en código ASCII, también se puede


interpretar como un entero. Sólo ocupa 1 byte

int Entero. Ocupa como máximo de 2 bytes

short int Indica un entero de tamaño corto.

long int Entero largo. Ocupa como máximo 4 bytes

unsigned short int Como short int pero sin signo.

unsigned int Como int pero sin signo.

unsigned long int Como long int pero sin signo.

float Flotante corto. Para representar números reales Ocupa 4 bytes

double Flotante largo. Ocupa 8 bytes

void No indica ningún tipo. Es el tipo de las funciones que no


devuelven nada.

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

TIPO RANGO BYTES


char -127....127(ASCII) 1
int 32768.....32767 2
long -2.127.483.648...-2.127.483.647 4
float 3,4 * 10 ^-38...3,4 * 10 ^-38 4
double 1,7 * 10 ^-308...1,7 * 10 ^-308 8
void Valor nulo nulo
Tabla 3 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.3.3 Números reales


Los tipos de datos en coma flotantes son los tipos de datos que representan a los números
reales, ya que utilizan un sistema de representación basado en la técnica de coma flotante, que
permite operar con números reales de diversas magnitudes, mediante un número decimal llamado
mantisa y un exponente que indica el orden de magnitud.
El tipo de dato flotante en lenguaje C sólo tiene dos tamaños: el float y el double, que son 4
bytes y 8 bytes respectivamente. Se los puede utilizar tanto para representar números decimales,
como para representar números enteros con un orden de magnitud muy grande.
La forma de declarar una variable flotante es escribiendo en una línea uno de los tipos de
datos flotantes y a continuación el nombre de la variable y tal vez algún valor que se les quiera dar.
Algunos ejemplos de números en coma flotante:
double a,b;
double c = 25;
double d = 3.1416;
float e = 2e-3;
double f = -33;

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.

3.4.1 Constantes enteras


Una constante entera es un número con un valor entero que se puede escribir en tres sistemas
numéricos: decimal, octal o hexadecimal.
Se pueden escribir en decimal (número que no empieza por 0), octal (el primer dígito es 0) y
hexadecimal (comienza con 0x ó 0X). Además,pueden ser con signo o sin signo. Si es sin signo se
les añade el sufijo U. El tamaño de las constantes puede ser normal o largo, en este caso se añade
el sufijo L.

3.4.2 Constantes en coma flotante


Una constante de coma flotante es un número en base 10 que contiene un punto decimal y/o
un exponente.

3.4.3 Constantes de caracteres


Una constante de carácter es un sólo carácter o una secuencia de escape encerrado con comillas
simples.
Char car = 'a'

Ciertos caracteres no imprimibles se pueden expresar en términos de secuencias de escape.


Una secuencia de escape siempre comienza por una barra \ y siempre representa un solo carácter.
Secuencias de escape

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

Tabla 4 Secuencias de escape

Mediante secuencias de escape se puede expresar cualquier carácter ASCII indicando su


código en octal (\ooo) o en hexa (\xhh). Donde los símbolos 'o' representan dígitos octales y las 'h'
dígitos hexadecimales.

3.4.4 Constantes de cadenas de caracteres


Constan de cualquier número de caracteres o secuencias de escape consecutivos encerrados
entre comillas dobles. También se admite ausencia de caracteres (""). El carácter nulo no puede
aparecer en medio de una constante de cadena de caracteres puesto que se usa para indicar fin de
cadena. El carácter de fin de cadena '\0' se coloca de forma automática en las cadenas literales; así en
la cadena "abc" hay 4 caracteres: a, b, c y '\0'.

char nombre[25] = “José Luis”;

3.4.5 Constantes enumeradas


Son las definidas de tipo enum
3.5 VARIABLES

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.

Int a,b,c; Tres variables enteras.


float uno,dos ; Dos variables de tipo real.
char car, cadena[25]; Un carácter y una cadena de 25.
short int a; Entero corto.
char cadena[3] = "uno"; Declaración e inicialización
char a = '\n'; Inicialización con Return.
char cadena[] = "uno"; Sin especificar tamaño.

Figura 10 Ejemplos de declaración de variables.

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;

3.8 SENTENCIAS O INSTRUCCIONES

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

C es un lenguaje muy rico en operadores. Se definen seis tipos de operadores: aritméticos,


relacionales, de asignación, lógicos, de dirección y de movimiento.
Existe otro tipo de operador denominado cast o molde.
3.9.1 Operadores Aritméticos

Operadores aritméticos

OPERADOR EJEMPLO SIGNIFICADO


+ a+b Suma
- a-b Resta
* a*b Multiplicación
/ a/b Cociente de una división
% a%b Resto de una división
++ a++ Incremento unitario
-- a-- Decremento unitario

Tabla 5 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.

3.9.2 Operadores lógicos

Operadores lógicos

OPERADOR EJEMPLO SIGNIFICADO


! !(a<b) Not logico (NOT )
&& (a<b) && (c>b) AND lógico (Y )
|| (a<b) || (c>b) OR lógico ( O)

Tabla 6 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

Operadores lógicos a nivel de bit

OPERADOR SIGNIFICADO
& AND
| OR
^ OR EXCLUSVA
<< Rotación a la izquierda
>> Rotación a la derecha
~ Complemento A UNO (C1)

Tabla 7 Operadores lógicos a nivel de bit

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.

3.9.3 Operadores relacionales

Operadores relacionales

OPERADOR SIGNIFICADO
< Menor que
> Mayor que
<= Menor o igual que
>= Mayor o igual que
== Igual que
!= Distinto que

Tabla 8 Operadores relacionales

3.9.4 Operador de asignación

Operador de asignación

OPERADOR SIGNIFICADO
= Asigna dato a variable

Tabla 9 Operadores de asignación

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;

3.9.6 Operadores de dirección

Operador de dirección

OPERADOR SIGNIFICADO
* Operador de contenido
& Operador de dirección

Tabla 10 Operadores de dirección

3.9.7 Precedencia de los operadores

De mayor a menor precedencia

OPERADOR
()[]
! ~ ++ -- * & sizeof (tipo dato)
*/%
+-
<< >>
< <= > >=
== !=
&
^
|
&&
||
?:
= += -= *= /= %=

Tabla 11 precedencia de operadores


3.10 ESTRUCTURA DE UN PROGRAMA EN C

Un programa en C tiene básicamente la siguiente estructura.

#include stdio.h /* directivas del preprocesador.*/


int a,b; /* definición de variables globales.*/
int suma(int,int); /* declaración prototipo funciones.*/
main() /* función principal.*/
{ /* inicio del programa principal.*/
int resul; /* declaración variables locales.*/

… /* código del programa.*/

resul=suma(a,b); /* llamadas a funciones.*/

… /* código del programa.*/

} /* fin del programa principal.*/
int suma(int,int) /* definición funciones*/
{

… /* código de la función.*/

}

Un ejemplo de un programa simple es el popular Hola Mundo:

#include stdio.h
main()
{
printf(“ Hola Mundo\n”);
}
EJERCICIOS RESUELTOS

1.- Calcular el doble de un número que se pide por teclado

#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.

/* Imprime la tabla de las primera 4 potencias del 1 al 10 */


#include <stdio.h>
main()
{
int n;
puts(" numero\t exp2\t exp3\t exp4");
puts("------\t-----\t-----\t-----");
for (n=0; n<=10; ++n)
printf("%2d\t%5d\t%5d\t%5d\n",n,n*n,n*n*n,n*n*n*n);
}

5. Escriba un programa que calcule el factorial de un número.


/* Factorial de un numero */
#include <stdio.h>
main()
{
int i, numero, factorial=1;
printf("\nEscriba un numero entero para calcular su factorial: ");
scanf("%d",&numero);
for (i=numero; i>1; --i) factorial *= i;
printf("\n%d! = %d\n",numero,factorial);
}

6. Escriba un programa que muestre la tabla ASCII

#include <stdio.h>
main()
{
int a, b, i;
for (a=0; a<256; a++)
{
printf("%2c",
}
}

7. Escriba un programa que muestre una tabla de conversiones de temperatura de


grados Farenheit a grados Celsius, de 0ºF a 300ºF de 20 en 20ºF.
#include <stdio.h>
main()
{
int i;
float c;
for (i=0;i<=300;i+=20)
{
c=(5./9)*(i-32);
printf("%3d grados Farenheit equivalen a %4.4f grados Celsius\n",i,c);
}
}
Funciones básicas
de E/S 4
En C, la entrada y salida de datos se realiza a través de funciones de biblioteca. Esta
biblioteca es la stdio.h. Contiene todas las funciones de entrada y salida estándar El fichero estándar
de entrada o lectura de datos es el teclado, mientras que el fichero de salida o escritura de datos es
la pantalla.

Los ficheros estándar definidos en todo sistema C son:

stdin (entrada estándar, asociado al teclado)


stdout (salida estandar, asociado a la pantalla)
stderr (error estándar, asociado a la pantalla)
stdaux (auxiliar estándar)
stdprn (impresora estándar)

Tenemos que distinguir también entre entrada y salida con formato o sin formato.

Entrada sin formato: getchar() y gets()


Salida sin formato: putchar() y puts()
Entrada con formato:scanf()
Salida con formato:printf()

4.1 getchar() y putchar()


Sus formatos son:
putchar(char c)
char getchar(void)
La función getchar() lee un carácter del teclado sin formato. Espera hasta que se pulse una
tecla y entonces devuelve su valor. La función putchar() imprime un carácter por pantalla en la
posición del cursor.
El siguiente ejemplo, nos muestra como se lee un carácter por teclado y a continuación, lo
imprimimos por pantalla.

#include “stdio.h”
main()
{
char car;
car=getchar();
putchar(car);
}

4.2 gets() y puts()


gets() lee una cadena de caracteres introducida por el teclado y la sitúa en una dirección
apuntada por su argumento de tipo puntero a carácter. Puts() escribe su argumento de tipo cadena
en la pantalla seguida de un carácter de salto de linea.
Veamos como funcionan. En el siguiente ejemplo, leemos una cadena de caracteres por
teclado y a continuación la imprimimos por pantalla. Es importante destacar, que como límite al
tamaño de la cadena, definimos un array de caracteres de tamaño 20.
#include “stdio.h”
main()
{
char cad[20];
gets(cad);
puts(cad);
}

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 printf() y scanf()

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:

scanf(secuencia de control, arg1,arg2,...,argn);


Donde secuencia de control hace referencia a una cadena de caracteres que contiene cierta
información sobre el formato de los datos y arg1,arg2,...,argn son argumentos que representan los
datos. (En realidad los argumentos representan punteros que indican las direcciones de memoria en
donde se encuentran los datos. Esto se verá más adelante).
En la secuencia de control se incluyen grupos de caracteres, uno por cada dato de entrada.
Cada grupo debe comenzar con el signo de porcentaje, que irá seguido, en su forma más sencilla, de
un carácter de conversión que indica el tipo de dato correspondiente.
Cada nombre de variable debe ir precedido por un ampersand (&). Los datos que se
introducen deben corresponderse en tipo y orden con los argumentos de la función scanf. Ejemplo de
utilización de scanf:

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.

Ejemplos: scanf("%3d %3d %3d",&a,&b,&c);

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()

Se pueden escribir datos en el dispositivo de salida stándar utilizando la función de biblioteca


printf. Es análoga a la función scanf, con la diferencia que su propósito es visualizar datos en vez de
introducirlos. En general la función printf se escribe:

printf(cadena de control, arg1,arg2,...,argn);

En contraste con la función scanf los argumentos en la función printf no representan


direcciones de memoria y por tanto no van precedidos de ampersands. Se puede especificar una
longitud mínima anteponiendo al carácter de conversión un entero sin signo. Si el número de caracteres
del dato correspondiente es menor que la longitud especificada, entonces el dato será precedido por los
espacios en blanco necesarios para que se consiga la longitud especificada. Si el número de caracteres
del dato excede la longitud especificada, se visualizará el dato completo. Esto es justo lo contrario al
comportamiento del indicador de longitud en la función scanf, que especifica una longitud máxima.
También es posible especificar el máximo número de cifras decimales para un valor de coma flotante.
Esta especificación se denomina precisión. La precisión es un entero sin signo que siempre es
precedido por un punto decimal. Un número en coma flotante se redondeará si se debe recortar para
ajustarse a la precisión especificada.
Comandos de formato

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

Tabla 12 Caracteres de conversión para printf y scanf


EJERCICIOS RESUELTOS

1.- Escribe un programa que lea y escriba un carácter.

#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()
{

float altura, base;


double area;
printf("\nBase del triangulo = ");
scanf("%f",&base);
printf("\nAltura del triangulo = ");
scanf("%f",&altura);
area= 0.5 *( (double) altura * base);
printf("\nArea = %g\n",area);
}
Sentencias de
control de flujo 5
Son aquellas sentencias que hacen que se altere el orden normal de ejecución de un
programa.

Las sentencias de control de flujo son:

● las de bucle (for, while, y do-while)

● la condicional (if y switch)

● las de salto (goto, continue y break).

5.1 SENTENCIAS DE SALTO

5.1.1 Sentencia break

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.1.1.2 Sentencia continue


Se utiliza para saltarse el resto de la pasada actual a través de un bucle. El bucle no termina
cuando se encuentra una sentencia continue, sencillamente no se ejecutan las sentencias que se
encuentran a continuación en él y se salta directamente a la siguiente pasada a través del bucle.

5.2 SENTENCIAS CONDICIONALES

5.2.1 Sentencia if

Su formato general responde a la siguiente expresión:

if (expresión) sentencia1 else sentencia2

Las tres formas como se puede emplear la sentencia if son:

if (condición)
sentencia;

…......

if (condición)
sentencia1;
else
sentencia2;

….....

if (condicion1)
sentencia1;
else if (condicion2)
sentencia2;
else if (condicion3)
sentencia3;
….....
else
sentencian;

Un ejemplo de uso de esta sentencia sería:

#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;
}

5.3 SENTENCIAS DE BUCLE O ITERATIVAS


Estas sentencias se utilizan cuando es necesario repetir un conjunto de sentencias hasta
que deje de cumplirse una condición.
5.3.1 Sentencia for

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:

for (expresion1;expresion2;expresion3) sentencia;


Donde expresion1 se utiliza para inicializar el bucle (denominado índice) que controla la
repetición del bucle, expresion2 representa una condición que debe satisfacerse para que continúe la
ejecución del bucle y expresion3 se utiliza para incrementar o decrementar el índice del bucle.
Cada vez que se ejecuta la sentencia for, expresion2 se evalúa y se comprueba antes de
cada pasada a través del bucle, y expresion3 es evaluada al final de cada pasada. Por tanto, la
sentencia for es equivalente a:

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);

5.3.2 Sentencia while

La sentencia while se utiliza para generar bucles. El formato general de la sentencia es:

while (expresión) sentencia;

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++;
}

5.3.2 Sentencia do-while

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);

La sentencia se ejecutará repetidamente mientras el valor de expresión no sea 0. Nótese que


la sentencia se ejecutará al menos una vez, ya que el test de la condición de repetición no se realiza
hasta el final del bucle. La sentencia puede ser simple o compuesta.

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.

/* Repetir un carácter un numero de veces */


main()
{
char ch;
int num_rep;
printf("\nEscriba el carácter a repetir: ");
scanf("%c",&ch);
printf("\nEscriba el numero de repeticiones: ");
scanf("%d",&num_rep);
while (num_rep>0)
{
printf("%c",ch);
--num_rep;
}
printf("\n");

}
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:

• Evitar la repetición innecesaria de código.


• Separando el código en funciones modulares se facilita el diseño y la comprensión de los
programas.
• Independencia. El realizar funciones independientes de la función principal e independientes
entre sí es una gran ventaja. Las funciones pueden tener sus propias variables "privadas", es
decir, estas variables no pueden ser accedidas desde fuera de la función. Esto significa que
el programador no necesita preocuparse por el uso accidental de los mismos nombres de
variables en otros puntos del programa.

6.1 QUÉ ES UNA FUNCIÓN

Una función es un conjunto de declaraciones, definiciones, expresiones y sentencias que


realizan una tarea específica. Por lo tanto, una función es una secuencia de código independiente,
con nombre, que ejecuta una tarea específica y opcionalmente devuelve un valor al programa que la
llamó. En general, toma unos valores de entrada, llamados parámetros y proporciona un valor o
valores de salida; aunque tanto unos como otros pueden no existir.

6.2 PARTES DE UNA FUNCIÓN

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.

El formato general de una función en C es :

tipo_funcion nombre_función( lista_parámetros)


{
variables locales
código de la función
}
6.2.1 Declaración

En C es recomendable usar la declaración de prototipos. Un prototipo es una declaración de


una función. Consiste en una definición de la función sin cuerpo y terminado en “;“. La estructura de
un prototipo es:

tipo_funcion nombre_función( lista_parámetros)

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

En general, la definición de una función se compone de las siguientes partes:

• El tipo de valor que devuelve


• El nombre de la función
• Los parámetros formales de la función.
• Cuerpo de la funció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.

El nombre de la función, es costumbre además de recomendable, poner nombres que indiquen lo


más claramente posible que es lo que hace la función permitiendo de esta forma interpretar que hace
el programa con solo leerlo. Por ejemplo, si tenemos una función que nos calcule el mayor de tres
números introducidos por teclado, podríamos llamarla mayor o calcula_mayor.

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:

int calcula_mayor(int a,int b,int c)


{
int max;
if(a>b)
if(a>c)
max=a;
else
max=c;
else
if(b>c)
max=b;
else
max=c;
return(max);
}

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.

/* menor de dos numeros con una funcion*/


#include<stdio.h>
#include<conio.h>
int menor(int a,int b);
main()
{
int n1,n2;
printf("Dame dos numeros\n");
scanf("%d,%d",&n1,&n2);
if(n1==n2)
printf("son iguales \n");
else
printf("el menor es:%d\n", menor(n1,n2));
getch();
}

int menor (int a,int b)

{
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.

/* programa que calcula el cuadrado de un numero mediante una


funcion*/

#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.

/* programa que calcula el cuadrado de un numero mediante una


funcion*/
#include<stdio.h>
#include<conio.h>
void calcula_cuadrado(void);
main()
{
calcula_cuadrado();
}

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.

/* Area del circulo y de la esfera para un radio desde 0 hasta 2 con


incremento de 0.2 */
#include <stdio.h>
#include <string.h>
#define MAX_RADIO 2.0
#define PI 3.141592
double AreaCirculo(double radio);
double AreaEsfera(double radio);
main()
{
double radio;
puts("\n\t=== Tabla de Areas ===\n");
puts("\tRadio\tCirculo\tEsfera");
puts("\t-----\t-------\t------");
for (radio=0.0; radio <= (double) MAX_RADIO; radio +=0.2)
printf("\t%6.2lf\t%6.3lf\
%6.3lf\n",radio,AreaCirculo(radio),AreaEsfera(radio));
}
double AreaCirculo(double radio)
{
double area;
area = PI * (radio * radio);
return(area);
}
double AreaEsfera(double radio)
{
double area;
area = 4.00 * PI * (radio * radio);
return(area);

}
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.

En un array x de n elementos los elementos del array son x[0], x[1],...,x[n-1].

El número de índices determina la dimensionalidad del array.

7.1 DEFINICION DE UN ARRAY


Es una colección de elementos del mismo tipo que se referencian por el mismo nombre. Sus
elementos están en posiciones contiguas de memoria. La posición mas baja corresponde al primer
elemento y la mas alta al último elemento. Un array puede tener una o varias dimensiones. Para
acceder a un elemento concreto del array utilizamos un índice.

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]

• tipo_datos es el tipo de datos que alojará el array.


• nombre_array es un identificador para poder referirnos a el desde nuestro programa.
• tamaño es un número entero que nos dice la cantidad de elementos que va a contener.

7.2 ARRAYS UNIDIMENSIONALES

Aquí tenemos definido un array unidimensional llamado lista de diez elementos tipo entero, Int
lista[10], donde:

lista[0] primer elemento


lista[1] segundo elemento
lista[2] tercer elemento
…..............
lista[9] ultimo elemento

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.

Otra forma de inicializar los elementos del array anterior sería:

Int lista[10]={2,5,3,5,9,8,9,7,4,1}

7.3 ARRAYS BIDIMENSIONALES

C permite arrays con más de una dimensión , el formato general es:

tipo nombre_arr [ tam1 ][ tam2 ] ... [ tamN];

Por ejemplo un array de enteros bidimensionales se escribirá como:

int tabla[5][5];

Para acceder los elementos se procede de forma similar al ejemplo del array de una dimensión, es
decir :

tabla[2][3] = 15; Asigna 15 al elemento de la 3ª fila y la 4ª columna

num = tabla[2][3]; asignamos a la variable nun el contenido del elemento


tabla[2][3] , en este caso 15.

Si queremos inicializarlo con unos valores predeterminados, haríamos:

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();
}

Otro ejemplo, donde inicializamos un array de dos dimensiones y posteriormente visualizamos su


contenido por pantalla.

#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:

tipo_datos nombre_array[tamaño] = {valor1,valor2,...,valorn};

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.

El compilador no comprueba la longitud del array a la hora de acceder. Es responsabilidad


del programador controlar los accesos fuera de rango.

7.4 CADENAS DE CARACTERES

A diferencia de otros lenguajes de programación que emplean un tipo denominado cadena


string para manipular un conjunto de símbolos, en C, se debe simular mediante un array
unidimensional de caracteres, en donde la terminación de la cadena se debe indicar con carácter
nulo “\0”.
Por lo tanto, cuando se declare un array de caracteres se debe considerar un carácter
adicional a la cadena más larga que se vaya a guardar, ya que el último elemento será el “\0” . Por
ejemplo, si se quiere declarar un array cadena que guarde una cadena de diez caracteres, se hará
como:

char cadena[11];

Se pueden hacer también inicializaciones de arrays de caracteres en donde automáticamente


C asigna el carácter nulo al final de la cadena, de la siguiente forma:

char cadena[ tam ]="Hola";

Este código es equivalente a:

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);
}

Algunos problemas requieren que los caracteres de la cadena sean procesados


individualmente. No obstante, hay muchos otros problemas en los que se requiere que las cadenas se
procesen como entidades completas. Tales problemas pueden simplificarse considerablemente usando
funciones especiales de biblioteca orientadas a cadenas. Esta biblioteca es la “stdlib.h”.

• gets: Su forma general es gets(cadena_de_caracteres) y lo que hace es tomar de teclado un


texto (hasta que se pulse enter) y guardarlo en cadena_de_caracteres. En la cadena
automáticamente se guarda como último elemento el carácter nulo:'\0'.
• puts: Su forma general es puts(cadena_de_caracteres) y lo que hace escribir en pantalla el
contenido de cadena_de_caracteres terminando con un salto de línea.

Las funciones especificadas a continuación para el tratamiento de cadenas de caracteres se


encuentran en el fichero de cabecera string.h:

• strcmp: Su forma general strcmp(cadena1,cadena2) y lo que hace es comparar


alfabéticamente dos cadenas. Devuelve:
- un valor negativo si cadena1 precede alfabéticamente a cadena2.
- el valor 0 si las dos cadenas son idénticas.
- un valor positivo si cadena2 precede alfabéticamente a cadena1.
• strcpy: Su forma general es strcpy(cadena1,cadena2) y lo que hace es copiar el valor de
cadena2 en cadena1.
• strlen: Su forma general es strlen(cadena) y retorna el número de caracteres de la cadena.
EJERCICIOS RESUELTOS

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]);

for (i = 0; i <= N; i=i+2)


lista[i]=lista[i+1];

printf("Los nuevos valores del array son:\n ");

for (i = 0; i < N; i++)


printf("%3d",lista[i]);
}

2.- Escribir un programa que inicialice un array de enteros. Calcule e imprima su suma, media,
mínimo y máximo.

/* Calculo de la suma, media, mínimo y máximo de un vector de enteros


*/
#include <stdio.h>
#define MIN(a,b) ((a < b) ? a : b)
#define MAX(a,b) ((a > b) ? a : b)
main()
{

int valores[] = {10,1,3,4,15,6,7,8,9,10};


int i, tam, suma=0, minimo=valores[0], maximo=valores[0];
float media;
tam=sizeof(valores)/sizeof(int);
for (i=0; i<tam;++i)
{
printf(" %d ",valores[i]);
minimo=MIN(minimo,valores[i]);
maximo=MAX(maximo,valores[i]);
suma+=valores[i];
}
media=(float) suma / tam;
printf("\nSuma= %d; Media= %f\nMinimo= %d; Maximo=
%d\n",suma,media,minimo,maximo);
}

51
3. Escriba un programa que ordene un vector (de dimensión máxima 15) por el método de la
burbuja.

/* Algoritmo de la burbuja (ordenación de un ARRAY */


#include <stdio.h>
#define LIM 15
main ()
{
int i=0, j, tam, aux;
int lista[LIM];printf("Longitud del vector a ordenar ");
scanf ("%d",&tam);
if(tam > LIM)
{
printf("El limite del vector se ha excedido");
printf(", por favor cambie el limite en el código\n");
}
while (i<tam)
{
i++;
printf("Numero %d: ",i);
scanf("%d",&lista[i-1]);
}
printf("\n El vector introducido es el siguiente:\n");
for (i=0; i<tam; i++) printf("%d ",lista[i]);
for (i=0; i<tam-1; i++)
{
for (j=i+1; j<tam; j++)
{
if (lista[i] > lista[j])
{
aux=lista[i];
lista[i]=lista[j];
lista[j]=aux;
}
}
}
printf("\n El vector ordenado es el siguiente:\n");
for (i=0; i<tam; i++)
printf("%d ",lista[i]);
printf("\n");
}

4. Escriba un programa que contenga dos arrays y utilizando punteros genere un tercer array
con la suma de los otros dos.

/* Suma de arrays por punteros */


#include <stdio.h>
#define FILAS 4
#define COLS 5
main()
{
int j,k;
int arr1 [FILAS] [COLS] = { {1,9,7,3,4},{5,2,4,6,8},{1,3,3,7,9},
{0,2,4,6,4} };

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.

/* Primera letra mayúscula y demás minúscula */


#include <stdio.h>
#include <ctype.h>
#define MAXCADENA 20
char *ConversionLetra(char *cadena);
main()
{
char tmp[MAXCADENA+1];
/* Se suma 1 para el byte NUL */
printf("\ nEscriba una cadena (de %d caracteres maximo) y teclee
INTRO:\n",MAXCADENA);
gets(tmp);
printf("\n%s\n", ConversionLetra(tmp));
}
char *ConversionLetra(char *cadena)
{
char *pc;
pc=cadena;
*pc=toupper(*pc);
++pc;

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.

/* Insertar carácter en una posición en una cadena */


#include <stdio.h>
#include <string.h>
void insertar(char *cadena, char ca, int n);
main()
{
char car, cadena[81];
int posicion;
printf("\nEscriba una cadena [Intro], carácter [Intro], posicion\n");
gets(cadena);
scanf("%c\n%d",&car,&posicion);
insertar(cadena,car,posicion);
puts(cadena);
}
void insertar(char *cadena, char ca, int n)
{
char temporal[81];
strcpy(temporal,&cadena[n-1]);
cadena[n-1]=ca;
strcpy(&cadena[n], temporal);
}

7. Escriba un programa que lea una cadena y busque un carácter en ella.


/* Buscar un carácter en 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.

Si a es una variable que representa un determinado dato, el compilador automáticamente


asigna celdas de memoria para ese dato. Dicho dato puede ser accedido si conocemos su localización
(la dirección) de la primera celda de memoria. La dirección de a se determina mediante &a, donde & es
un operador unario, llamado operador dirección, que proporciona la dirección del operando. Si la
dirección de a se le asigna a otra variable pa = &a; esta nueva variable es un puntero a dicha variable
a: el cual representa la dirección de a y no su valor. El dato representado por a puede ser entonces
accedido mediante *pa, donde * es un operador unario, llamado operador indirección, que opera sólo
sobre una variable puntero.

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.

Las variables puntero pueden apuntar a variables numéricas o de caracteres, arrays,


funciones u otras variables puntero. También pueden apuntar a otros tipos de estructuras de datos.
Por lo tanto, a una variable puntero se le puede asignar la dirección de una variable ordinaria.
También se le puede asignar la dirección de otra variable puntero, siempre que ambas apunten al
mismo tipo de dato.

#include <stdio.h> #include <stdio.h>


main() main()
{ {
int a,*p; char car,*p;
printf("dame a\n"); printf("dame dato\n");
scanf("%d",&a); scanf("%c",&car);
p=&a; p=&car;
printf("%d",*p); printf("%c",*p);
} }

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).

Hay 3 formas de inicializar un puntero:

• a) Inicializarlo con el valor NULL (definido en un fichero header). De este modo


estamos indicando que el puntero no apunta a ninguna memoria concreta.

• b) Inicializarlo haciendo que tome como valor la dirección de una variable.

int *p, a;
p = &a;

A partir de estas sentencias, *p y a apuntan a la misma dirección.

• c) Asignarle memoria dinámica a través de una función de asignación de memoria. Las


funciones más habituales son calloc y malloc, definidas en el fichero alloc.h o bien en stdlib.h

void *malloc(size_t size)


void *calloc(size_t n_items, size)

Una inicialización de un puntero a un tipo T tendría la forma:

p = (T*)malloc(sizeof(T));

8.3 PASO DE PUNTEROS A UNA FUNCIÓN


El lenguaje C sólo admite paso de parámetros por valor, pero tiene una forma de simular un
paso por referencia (variable), pasando un puntero que es la dirección donde están los datos (p. ej. &a).
En realidad se pasa un valor que es una dirección de una variable.
Por ello, a menudo los punteros son pasados a las funciones como argumentos. Esto permite
que datos de la porción de programa desde el que se llama a la función sean accedidos por la función,
alterados dentro de ella y devueltos de forma alterada. Este uso de los punteros se conoce como paso,
de argumentos por dirección o referencia. Cuando los punteros son usados como argumento de una
función, es necesario tener cuidado con la declaración de los argumentos formales dentro de la función.
Los argumentos formales que sean punteros deben ir precedidos por un asterisco.

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;
}

La salida del programa:


inicialmente a =7
después de llamada a f2: a=5

8.4 PUNTEROS Y ARRAYS UNIDIMENSIONALES

El nombre de un array es puntero al su primer elemento. Sin embargo, si x es un array


undimensional, la dirección del primer elemento puede ser expresada tanto como &x[0] o simplemente
como x. La dirección del elemento (i+1) se puede expresar como &x[i] o como (x+i).

En la expresión (x+i) x representa una dirección e i un número entero. Además x es el


nombre de un array cuyos elementos pueden ser caracteres, enteros, números en coma flotante, etc.
Por tanto, no estamos simplemente añadiendo valores numéricos. Más bien estamos especificando
una localización que está i elementos del array detrás del primero, con lo cual la expresión (x+i) es
una representación simbólica de una dirección en vez de una expresión aritmética.

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.

Ya que un nombre de array es en realidad un puntero a su primer elemento, es posible definir


un array como una variable puntero en vez de como un array convencional. La definición convencional
de un array produce la reserva de un bloque fijo de memoria al principio de la ejecución del programa,
mientras que esto no ocurre si se representa el array mediante una variable puntero. En este caso, se
necesita algún tipo de asignación inicial de memoria antes de que los elementos del array sean
procesados. Tales tipos de reserva se realizan mediante la función malloc.

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]);
}

En este ejemplo, cambiamos el contenido de todos los elementos con el puntero.

8.5 OPERACIONES CON PUNTEROS

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.

Resumen de operaciones que se pueden realizar sobre punteros:

• Se le puede asignar la dirección de una variable ordinaria (pv=&v).

• Se le puede asignar el valor de otra variable puntero, siempre que ambas apunten al
mismo tipo de dato.

• 3.Se le puede asignar el valor nulo (NULL).

• 4. Se le puede sumar o restar una cantidad entera.

• 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.

• 7. No se permiten operaciones aritméticas con punteros. Así una variable puntero no


puede ser multiplicada por una constante, dos punteros no pueden sumarse, etc.

8.6 PUNTEROS Y ARRAYS MULTIDIMENSIONALES


Un array bidimensional es en realidad una colección de arrays unidimensionales. Por tanto, se
puede definir un array bidimensional como un puntero a un grupo contiguo de arrays unidimensionales.
Una declaración de array bidimensional puede ser escrita como

tipo_dato (*ptvar) [expresión2]


en vez de
tipo_dato array [expresión1][expresión2]

Los paréntesis que rodean al puntero deben estar presentes.

Ejemplo: Suponer que x es un array bidimensional de enteros con 10 filas y 20 columnas. Podemos
declara x como:

int (*x)[20] en vez de int x[10][20];

En la primera declaración x se define como un puntero a un grupo contiguo de array


unidimensionales de 20 elementos enteros. Así x apunta al primero de los arrays de 20 elementos, que
es en realidad la primera fila (fila 0) del array bidimensional original. Del mismo modo (x+1) apunta al
segundo array de 20 elementos, y así sucesivamente.
El elemento de la fila 2 columna 5 es accedido +(*(x+2)+5)
(x+2) es un puntero a la fila 2
*(x+2) es el objeto de ese puntero y refiere a toda la fila. Como la fila 2 es un array unidimensional
*(x+2) es realmente un puntero al primer elemento de la fila 2.
(*(x+2)+5) es un puntero al elemento 5 de la fila 2.
El objeto de este puntero *(*(x+2)+5) refiere al elemento en la columna 5 de la fila 2.

8.7 ARRAYS DE PUNTEROS


Un array multidimensional puede ser expresado como un array de punteros en vez de como un
puntero a un grupo contiguo de arrays. En términos generales un array bidimensional puede ser
definido como un array unidimensional de punteros escribiendo:

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.

9.1 DEFINICIÓN DE UNA ESTRUCTURA


En C una estructura es una colección de variables heterogénea que se referencian bajo el
mismo nombre, permitiendo de esta forma un manejo más cómodo de la agrupación de la
información. La forma general de definición es:

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);

Estructuras anidadas: se producen cuando algún miembro de la estructura es a su vez otra


estructura.

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

9.2 REFERENCIA A LOS ELEMENTOS DE UNA ESTRUCTURA

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

Si el acceso es a una estructura anidada, sería:

alumno.nacimiento.dia
alumno.nacimiento.mes
alumno.nacimiento.año

9.3 ARRAYS DE ESTRUCTURAS

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,

struct alumno cmedio[20]


64
struct alumno csuperior[20]

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.

modificador union nombre

65
{
tipo miembro1;
tipo miembro2;
...
} identificador1, identificador2, ...;

El compilador asigna una porción de almacenamiento para almacenar el miembro mas


grande de los miembros especificados. La notación para acceder a un miembro de la unión es
idéntica a la que se emplea para acceder a un miembro de una estructura. Un ejemplo de unión es el
siguiente:

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.

union persona pepe={123};

9.5 DEFINICIÓN DE NUEVOS TIPOS DE DATOS

La creación de nuevos nombres de tipos de datos se realiza utilizando la palabra reservada typedef:

typedef tipo nombre

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;

9.6 TIPOS ENUMERADOS DE DATOS

Es un tipo que es listado explícitamente por el programador. Es similar a una estructura o a


una unión cuyos miembros son constantes de valor entero, escritas como identificadores. Las
constantes representan los valores que pueden ser asignados a las variables declaradas del tipo del
enum.
enum nombre {val1,val2,...,valn}

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 nombre {val1=0,val2=10,val3=13,...);


66
Puede suceder que más de una constante de enumeración tengan el mismo valor entero.

enum color{rojo=-1,azul,amarillo,verde,negro=0};

• Las variables de enumeración pueden utilizarse como enteros; asignándoles valores,


compararlas, pero son utilizadas sólo internamente.

• No se puede leer una variable de tipo enum. Se puede leer un entero y asignárselo a
una variable.

• No se puede escribir más que el valor entero de la variable enum. No se puede


escribir su nombre

• Los tipos enumerados no aportan capacidades nuevas al lenguaje, pero aumentan la


claridad de los programas

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.

10.2 APERTURA Y CIERRE DE UN FICHERO

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.

Para abrir un archivo se usa la función fopen:

pf = fopen ( nombre_fichero, tipo_acceso_fichero);

donde nombre_fichero y tipo_acceso_fichero son cadenas. Los tipos de acceso al fichero y su


significado son:

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

Tabla 13 operaciones sobre ficheros

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.

10.3 CREACIÓN DE UN FICHERO

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

Funciones para ficheros:

Funciones para 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

Tabla 14 funciones para ficheros

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)

Los parámetros de entrada son:


1. nombre: una cadena que contiene un nombre de fichero válido, esto depende del sistema
operativo que estemos usando. El nombre puede incluir el camino completo.
2. modo: especifica en tipo de fichero que se abrirá o se creará y el tipo de datos que puede
contener, de texto o binarios.

10.4.2 fclose()

Esta función sirve para cerrar ficheros.

int fclose(FILE *fichero)

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()

Esta función lee un carácter desde un fichero.


int fgetc(FILE *fichero)

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()

Esta función escribe un carácter a un fichero.

int fputc(int carácter, FILE *fichero)


El valor de retorno es el carácter escrito, si la operación fue completada con éxito, en caso
contrario será EOF. Los parámetros de entrada son el carácter a escribir, convertido a int y un
puntero a una estructura FILE del fichero en el que se hará la escritura.

10.4.5 feof()

Esta función sirve para comprobar si se ha alcanzado el final del fichero.

int feof(FILE *fichero)

. Frecuentemente, trabajamos con todos los valores almacenados en un archivo de forma


secuencial, la forma que suelen tener los bucles para leer todos los datos de un archivo es de leer
mientras no se detecte el fin de fichero. Esta función suele usarse como prueba para verificar si se ha
alcanzado o no ese punto.

El valor de retorno es distinto de cero sólo si no se ha alcanzado el fin de fichero. El


parámetro es un puntero a la estructura FILE del fichero que queremos verificar.

#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.

char *fgets(char *cadena, int n, FILE *fichero

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.

int fputs(const char *cadena, FILE *stream)

El valor de retorno es un número no negativo o EOF en caso de error. Los parámetros de


entrada son la cadena a escribir y un puntero a la estructura FILE del fichero donde se realizará la
escritura.

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.

size_t fread(void *puntero, size_t tamaño, size_t nregistros, FILE *fichero

El valor de retorno es el número de registros leídos, no el número de bytes. Los parámetros


son: un puntero a la zona de memoria donde se almacenarán los datos leídos, el tamaño de cada
registro, el número de registros a leer y un puntero a la estructura FILE del fichero del que se hará la
lectura.

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.

size_t fwrite(void *puntero, size_t tamaño, size_t nregistros, FILE *fichero

El valor de retorno es el número de registros escritos, no el número de bytes. Los parámetros


son: un puntero a la zona de memoria donde se almacenarán los datos leídos, el tamaño de cada
registro, el número de registros a leer y un puntero a la estructura FILE del fichero del que se hará la
lectura.

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;

// Abrir el fichero de lectura


pf1 = fopen("datos.txt", "r");
if(!pf1) {
printf("El fichero no existe o no puede ser abierto.\n");
return 1;
}
// Crear o sobreescribir el fichero de escritura
pf2 = fopen("datos1.txt", "w");
if(!pf2) {
printf("El fichero no puede ser creado.\n");
fclose(pf2);
return 1;
}
// Bucle de copia:
while((bytesLeidos = fread(lista, 1, 2048, pf1)))
fwrite(lista, 1, bytesLeidos, pf2);
// Cerrarmos ficheros:
fclose(pf1);
fclose(pf2);
return 0;
}

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.

int fprintf(FILE *fichero, const char *formato, …)

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.

int fscanf(FILE *fichero, const char *formato, …)

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

1. Escriba un programa que imprima los campos de una estructura en un fichero.


/* estructura un registro */
#include<stdio.h>
#include<conio.h>
FILE *pf;
main()
{
struct ficha
{
int edad;
char nombre[15];
char apellidos[25];
}alumno;

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;

int main(int argc, char** argv)


{
int opcion;
int exit = 0;
FILE *pf;

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");
}

void Crea_Fichero(FILE *pf)


{
pf = fopen("fichero.txt", "r");
if(!pf)
{

77
pf = fopen("fichero.txt", "w");
printf("\nEl fichero ha sido creado!");
}
else
{
printf("\nEl fichero ya existe!");
}
fclose (pf);
return;
}

void Insertar_Datos(FILE *pf)


{
pf = fopen("fichero.txt", "a");
if(pf == NULL)
{
printf("\nEl fichero no existe! \nPor favor debe
crearlo");
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;
}

void Visualiza_Datos(FILE *pf)


{
int numero = 1;
pf = fopen("fichero.txt", "r");
if(pf == NULL)
{
printf("\nFichero no existe! \nPor favor creelo");
return;
}
fread(&ciclo_superior, sizeof(struct alumno), 1, pf);
printf("\nNumero \tNombre \t\tApellidos \t\tEdad
\t\tTelefono");
while(!feof(pf))
{
printf("\n%d \t%s \t\t%s \t\t%d \t\t%d", numero,
ciclo_superior.Nombre,
ciclo_superior.Apellidos,ciclo_superior.Edad,
ciclo_superior.Telefono);
fread(&ciclo_superior, sizeof(struct alumno), 1,
pf);
numero++;
}
78
fclose(pf);

return;
}

79
Librerías 11
11.1. INTRODUCCIÓN

En el lenguaje C toda la entrada y salida de un programa se realiza a través de funciones


definidas en librerías. También se encuentran definidas en librerías otros tipos de funciones. Dichas
librerías, o la mayoría, son estándar (las funciones en ellas definidas tienen nombres estándar) lo que
facilita la portabilidad de los programas. Al inicio de cada fichero se debe indicar las declaraciones de
las librerías que se utilizarán. Esto se realiza utilizando la directiva #include, cuya sintaxis es:

#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.

Estos ficheros de definiciones suelen tener la extensión .h (de header, cabeceras) y


contienen definiciones necesarias para la utilización de las funciones contenidas en las librerías.

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"

Igual al anterior pero las busca en el directorio actual

• #include "a:\librería\milib.h"

Incluye el fichero milib.h desde la unidad a:

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>;

Cada fichero de cabecera se denomina librería. En la siguiente lista mostraremos la Librería


junto con la Descripción:

Librerías ANSI C

LIBRERÍA SIGNIFICADO
stdio.h Contiene funciones para tareas de E/S.

string.h Contiene funciones para la manipulación de cadenas de caracteres.

stdlib.h Contiene funciones para la conversión numérica, generación de números


aleatorios, búsquedas y ordenación, gestión de memoria y tareas similares.

math.h Contiene funciones matemáticas.

ctype.h Contiene varias funciones para comprobación de tipos y transformación de


caracteres.

time.h Contiene funciones para la la manipulación de información sobre fechas y


horas.

errno.h Contiene varias macros usadas para informar de errores.

Tabla 15 librerías ANSI C

81
A continuación se detallan lagunas funciones contenidas en las librerías mas comunes.

Funciones de la librería stdio.h

FUNCIÓN SIGNIFICADO
printf() Imprimir salidas de datos con formato

scanf() Lectura de datos con formato

gets () lee caracteres de entrada hasta que encuentra un salto de línea, y los
almacena en un único argumento.

puts() Imprime una cadena de caracteres

puchar() Imprime un carácter

getchar() Lee un carácter

fflush() Limpia el buffer

Estas mismas funciones son válidas para trabajar con ficheros anteponiendo la palabra “f” a
dichas funciones

Tabla 16 funciones de la librería stdio.h

Funciones de la librería string.h

FUNCIÓN SIGNIFICADO
strcat() añade una cadena al final de otra

strncat() añade los n primeros de una cadena al final de otra

strchr() localiza un carácter en una cadena, buscando desde el principio

strcmp() Compara dos cadenas de caracteres

strcnmp() Compara los n primeros caracteres de dos cadenas

strcpy() Copia una cadena de caracteres en otra

strncpy() Copia los n primeros caracteres de una cadena en otra

strlen() Devuelve la longitud de una cadena

Tabla 17 funciones de la librería string.h

82
Funciones de la librería stdlib.h

FUNCIÓN SIGNIFICADO
malloc() Para reserva de memoria dinámica.

rand() Genera números pseudoaleatorios.

free() Libera memoria reservada dinámicamente.

exit() Terminar ejecución de programa

system() Ejecutar un comando externo.

Tabla 18 funciones de la librería stdlib.h

Funciones de la librería math.h

FUNCIÓN SIGNIFICADO
sin() Función seno.

sinh() Seno hiperbólico.

cos() Función coseno.

cosh() Coseno hiperbólico

tan() Función tangente

tanh() Tangente hiperbólica

asin() Función arco seno.

acos() Función arco coseno.

atan() Función arco tangente

log() Logaritmo natural

log10() Logaritmo en base 10

sqrt() Raíz cuadrada

fabs() Valor absoluto de un numero

Tabla 19 funciones de la librería math.h

83
Funciones de la librería ctype.h

FUNCIÓN SIGNIFICADO
tolower() Convierte un carácter a minúscula

toupper() Convierte un carácter a mayúscula

Tabla 20 funciones de la librería ctype.h

84

También podría gustarte