Acceder

Transcripción

Acceder
Introducción al lenguaje C
Marta Zorrilla
Universidad de Cantabria
1
Marta Zorrilla – Universidad de Cantabria
Introducción al C
„
Objetivos:
„
„
„
Presentar la historia del lenguaje C y sus
características principales.
Presentar la estructura de un programa en C
mediante ejemplos sencillos.
Contenidos:
„
„
„
1. La historia del C.
2. Características.
3. Mi primer programa en C.
2
Marta Zorrilla – Universidad de Cantabria
Historia del C
„
„
„
„
„
„
„
„
Muchas ideas provienen de BCPL (Martin Richards, 1967) y de B (Ken
Thompson, 1970).
C fue diseñado originalmente en 1972 para el SO UNIX en el DEC PDP-11 por
Dennis Ritchie en los Laboratorios Bell.
Primer Libro de referencia de C: The C Programming Language (1978) de
Brian Kernighan y Dennis Ritchie.
En los 80, gran parte de la programación se realiza en C.
En 1983 aparece C++ (orientado a objetos).
En 1989 aparece el estándar ANSI C.
En 1990 aparece el estándar ISO C (actual estándar de C). WG14 se
convierte en el comité oficial del estándar ISO C.
En década de los 90, WG14 trabaja en el estándar C9X/C99 que resuelve
problemas de fiabilidad del ANSI C, amplia su funcionalidad con nuevos tipos
de dato, funciones matemáticas, arrays irrestringidos, etc.
3
Marta Zorrilla – Universidad de Cantabria
Características del C
„
„
„
„
„
„
Lenguaje de programación de propósito general, muy adecuado para
programación de sistemas (unix fue escrito en C).
Lenguaje relativamente pequeño: solo ofrece sentencias de control
sencillas y funciones.
La E/S no forma parte del lenguaje, sino que se proporciona a través
de una biblioteca de funciones.
Permite la agrupación de instrucciones. Programación estructurada.
Permite la separación de un programa en módulos que admiten
compilación independiente. Diseño modular.
Programas portables.
4
Marta Zorrilla – Universidad de Cantabria
Inconvenientes del C
„
„
„
„
No es un lenguaje fuertemente tipado.
Es bastante permisivo con la conversión de datos.
Sin una programación metódica puede ser propenso a errores
difíciles de encontrar.
La versatilidad de C permite crear programas difíciles de leer.
#define _ -F<00||--F-OO--;
int F=00,OO=00;
main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{…..}
5
Marta Zorrilla – Universidad de Cantabria
Primer programa en C
/* Ejemplo 1. Programa DOCENA.C */
#include <stdio.h>
main ()
{
int docena;
docena = 12;
printf ("Una docena son %d unidades\n", docena);
}
6
Marta Zorrilla – Universidad de Cantabria
Segundo programa en C
/* Ejemplo 1. Programa saludo.c*/
#include <stdio.h>
#define MENSAJE “alumnos”
/*prototipo funciones*/
int imprimir_saludo (char * destino);
int main (void)
{
int error=0;
error=imprimir_saludo (MENSAJE);
return(0);
}
int imprimir_saludo (char * destino)
{
printf (“hola %s \n", destino);
return(0);
}
7
Marta Zorrilla – Universidad de Cantabria
Crear, compilar y ejecutar un
programa C
„
„
Crear un fichero con extensión .c con un editor de texto
Mandato de compilación básico:
cc ejemplo.c
- Genera el código objeto ejemplo.o
- Genera el ejecutable a.out
- El programa se ejecuta tecleando a.out
„
„
El mandato cc -c ejemplo.c genera el fichero objeto
ejemplo.o
El mandato cc ejemplo.o -o ejemplo genera el
ejecutable ejemplo
- El programa se ejecuta tecleando ejemplo.
8
Marta Zorrilla – Universidad de Cantabria
Modelo de compilación C
9
Marta Zorrilla – Universidad de Cantabria
Entorno desarrollo IDE
10
Ejercicio
Marta Zorrilla – Universidad de Cantabria
Sean dos cuadrados de lados L1 y L2 inscritos uno en
otro. Calcula el área de la zona comprendida entre
ambos, utilizando para ello una función (que se llamará
AreaCuadrado) que devuelve el área de un cuadrado
cuyo lado se pasa como argumento
#include <stdio.h>
int cuadrado (int);
int main (void)
{
int lado2, lado1;
printf ("dame lado del cuadrado 1:");
scanf( "%d",&lado1);
printf ("dame lado del cuadrado 2:");
scanf(" %d",&lado2);
printf ("El resultado de la diferencia es %d", cuadrado(lado1)-cuadrado(lado2));
return(0);
}
int cuadrado (int lado)
{
return(lado*lado);
}
11
Elementos de un programa
en C
12
Marta Zorrilla – Universidad de Cantabria
Elementos de un programa C
„
Objetivos:
„
„
„
„
„
Mostrar la utilidad de documentar el código utilizando los
comentarios.
Explicar los conceptos de variable y tipo de dato.
Conocer los identificadores válidos y tipos de constantes.
Enseñar las instrucciones de lectura y escritura junto con el formato
de los datos.
Contenidos:
1. Comentarios
2. Identificadores y palabras reservadas
3. Constantes
4. Variables y tipos de dato
5. Escritura de datos con printf()
6. Lectura de datos con scanf()
13
Marta Zorrilla – Universidad de Cantabria
Elementos de un programa C
„
Básicamente el C está compuesto por los
siguientes elementos:
• Comentarios
• Identificadores
• Palabras reservadas
• Variables y tipos de datos
• Constantes
• Operadores
14
Marta Zorrilla – Universidad de Cantabria
Comentarios
„
„
Sirven para incrementar la legibilidad de los programas.
No se pueden anidar. Dentro de un comentario no puede
aparecer el símbolo /*
/* Este es un comentario que
ocupa más de una línea */
// Este comentario ocupa una sola línea
15
Marta Zorrilla – Universidad de Cantabria
Identificador
„
„
Nombre que se asigna a los distintos elementos del
programa (variables, funciones,…).
Identificadores NO válidos:
„
„
„
„
Empezar por –
Empezar por un número
Utilizar la "
Ejemplos válidos:
numero
area_circulo
valor_1
16
Marta Zorrilla – Universidad de Cantabria
Palabras reservadas
auto
break
case
char
const
continue
default
do
double
else
enum
extern
float
for
goto
if
int
long
register
return
short
sizeof
static
struct
switch
typedef
union
unsigned
void
volatile
while
Es preciso insistir en que C hace distinción entre mayúsculas y minúsculas.
Por lo tanto, la palabra reservada for no puede escribirse como FOR,
pues el compilador no la reconoce como una instrucción,
sino que la interpreta como un nombre de variable.
17
Marta Zorrilla – Universidad de Cantabria
Variables
„
„
„
Identificador utilizado para representar un
cierto tipo de información.
Cada variable es de un tipo de dato
determinado.
Una variable puede almacenar diferentes
valores en distintas partes del programa.
18
Marta Zorrilla – Universidad de Cantabria
Tipos de datos básicos
TIPO
PALABRA
RESERVADA
TAMAÑO EN
BYTES
sin valor
void
0
carácter
char
1
int
2
coma flotante (simple
precisión)
float
4
coma flotante (doble
precisión)
double
8
entero
19
Marta Zorrilla – Universidad de Cantabria
Tipos de datos. Modificadores
Modificadores
Tipo
char
int
short
long
Rango
Ocupa
unsigned
0 a 255
1 byte
signed
-128 a 127
1 byte
unsigned
0 a 65.535
2 bytes
signed
-32.768 a 32.767
2 bytes
unsigned
0 a 4.294.967.295
4 bytes
signed
-2.147.483.648 a 2.147.483.647 4 bytes
float
±3,4*10-38 a ±3,4*10+38
4 bytes
double
±1,7*10-308 a ±1,7*10+308
8 bytes
±3,4*10-4932 a ±1,1*10+4932
10 bytes
long
El tipo de dato int coincide con el tamaño de palabra del procesador,
generalmente 4 bytes
20
Marta Zorrilla – Universidad de Cantabria
Declaración de variables
„
Una declaración asocia un tipo de datos determinado a una o
más variables.
„
El formato de una declaración es:
tipo_de_dato var1, var2, ..., varN;
„
Ejemplos:
int a, b, c;
float numero_1, numero_2;
char letra;
unsigned long entero;
„
Deben declararse todas las variables antes de su uso.
„
Deben asignarse a las variables nombres significativos.
int temperatura;
int k;
21
Marta Zorrilla – Universidad de Cantabria
Tipos definidos
„
Permite dar nuevo nombre a tipos de datos que ya existen,
siendo estos más acordes con aquello que representan.
„
Sintaxis:
typedef tipo_basico nombre;
„
Declaración :
typedef float Kg;
typedef float Mts;
„
Y su uso al declarar variables:
Kg peso;
Mts longitud;
22
Marta Zorrilla – Universidad de Cantabria
La función printf()
„
Permite imprimir información por la salida
estándar (pantalla)
„
Formato:
printf(formato, argumentos);
„
Ejemplos:
printf("Hola mundo\n");
printf("El numero 28 es %d\n", 28);
printf("Imprimir %c %d %f\n", 'a', 28, 3.0e+8);
23
Marta Zorrilla – Universidad de Cantabria
La función printf() (y 2)
„
Formatos.
TIPO DE
ARGUMENTO
Numérico
Carácter
Punteros
CARÁCTER
DE FORMATO
%d
%i
%o
%u
%x
%X
%f
%e
%g
%E
%G
%c
%s
%%
%n
%p
FORMATO DE
SALIDA
signed decimal int
signed decimal int
unsigned octal int
unsigned decimal int
unsigned hexadecimal int (con a, ..., f)
unsigned hexadecimal int (con A, ..., F)
[-]dddd.dddd
[-]d.dddd o bien e[+/-]ddd
el más corto de %e y %f
[-]d.dddd o bien E[+/-]ddd
el más corto de %E y %f
carácter simple
cadena de caracteres
el carácter %
se refieren a punteros y se
estudiarán en el Capítulo 14
7
24
Marta Zorrilla – Universidad de Cantabria
La función printf() (y 3)
„
Secuencias de escape.
CARÁCTER BARRA
SIGNIFICADO
\a
Alarma (Beep)
\b
Retroceso (BS)
\t
Tabulador Horizontal (HT)
\n
Nueva Línea (LF)
\v
Tabulador Vertical (VT)
\f
Nueva Página (FF)
\r
Retorno
\"
Comillas dobles
\'
Comilla simple
\\
Barra invertida
25
Marta Zorrilla – Universidad de Cantabria
La función printf (y 4)
„
Especificadores de ancho de campo:
printf("Numero entero = %5d \n", 28);
produce la salida:
Numero entero = 28
printf("Numero real = %5.4f \n", 28.2);
produce la salida:
Numero real = 28.2000
26
Marta Zorrilla – Universidad de Cantabria
Función scanf()
„
„
„
Permite leer datos del usuario.
La función devuelve el número de datos que se han
leído bien.
No va texto
Formato:
scanf(formato, argumentos);
„
Especificadores de formato igual que printf().
„
Ejemplos:
scanf("%f", &numero);
&
scanf("%c\n", &letra);
scanf("%f %d %c", &real, &entero, &letra);
scanf("%ld", &entero_largo);
no &
scanf("%s", cadena);
27
Marta Zorrilla – Universidad de Cantabria
Función scanf() (y 2)
„
Ejemplo: lee un número entero y lo eleva al
cuadrado:
#include <stdio.h>
void main()
{
}
Comenzar
ESCRIBIR
Dame numero
LEER
numero
cuadrado=numero * numero
int numero;
int cuadrado;
ESCRIBIR
numero y cuadrado
printf("Introduzca un numero:");
scanf("%d", &numero);
FIN
cuadrado = numero * numero;
printf("El cuadrado de %d es %d\n", numero,cuadrado);
28
Marta Zorrilla – Universidad de Cantabria
Constantes simbólicas
„
„
Para evitar el uso de valores constantes dentro
del código, se definen las constantes simbólicas
Suele escribirse en mayúsculas.
#define
#define
#define
#define
PI 3.141593
CIERTO 1
FALSO 0
AMIGA "Marta"
no acaba en ;
29
Marta Zorrilla – Universidad de Cantabria
Constantes o literales
„
Caracteres:
„
„
Valores enteros:
„
„
„
„
„
„
„
„
Ejemplos: "Marta ", " barco"
Notación decimal: 987
Notación hexadecimal: 0x25 ó 0X25
Notación octal: 034
Enteros sin signo: 485U
Enteros de tipo long: 485L
Enteros sin signo de tipo long: 485UL
Valores negativos (signo menos): -987
Valores reales (coma flotante):
„
„
„
Ejemplos: 12, 14, 8., .34
Notación exponencial: .2e+9, 1.04E-12
Valores negativos (signo menos): -12 -2e+9
30
Marta Zorrilla – Universidad de Cantabria
Ejemplo.
„
Programa que lee el radio de un círculo y calcula su área
#include <stdio.h>
#define PI 3.141593
void main()
{
float radio;
float area;
printf("Introduzca el radio: ");
scanf("%f", &radio);
area = PI * radio * radio;
printf("El area del circulo es %5.4f \n", area);
}
Comenzar
PI =3.141593
ESCRIBIR
Dame radio
LEER radio
area = PI * radio * radio
ESCRIBIR
area
FIN
31
Marta Zorrilla – Universidad de Cantabria
Ejercicios
„
Encuentra errores
include studio.h
/* Programa que dice cuántos días hay en una semana /*
main {}
(
int d
d := 7;
print (Hay d días en una semana);
32
Marta Zorrilla – Universidad de Cantabria
Ejercicios
„
Indica cuál sería la salida de cada uno de los
siguientes grupos de sentencias:
a) printf ("Historias de cronopios y famas.");
printf ("Autor: Julio Cortázar");
b) printf ("¿Cuántas líneas \nocupa esto?");
c) printf ("Estamos \naprendiendo /naprogramar en C");
d) int num;
num = 2;
printf ("%d + %d = %d", num, num, num + num);
33
Operadores y expresiones
34
Marta Zorrilla – Universidad de Cantabria
Operadores y expresiones
„
Objetivos:
„
„
„
Mostrar el concepto de expresión, operador y sentencia.
Mostrar el repertorio de operadores de C y el orden de precedencia.
Contenidos:
1. Expresiones y sentencias
2. Operador asignación. Conversión de tipos
3. Operadores aritméticos
4. Operadores relacionales
5. Operadores lógicos
6. Operadores de asignación compuestos
7. Precedencia
35
Marta Zorrilla – Universidad de Cantabria
Expresiones y sentencias
„
Sentencia: especifica una acción a realizar
„
„
printf()
Expresión: secuencia de operadores y operandos que
especifican un valor
„
„
Ej.
Ej.
4+5
Una expresión se convierte en una sentencia cuando va seguida de
un punto y coma. Cuando un grupo de sentencias se encierran entre
llaves { }, forman un bloque, sintácticamente equivalente a una
sentencia.
36
Marta Zorrilla – Universidad de Cantabria
Operador de asignación
„
„
Forma general: identificador = expresión ;
Ejemplos:
a = 3;
area = lado * lado;
„
El operador de asignación = y el de igualdad ==
„
Asignaciones múltiples:
id_1 = id_2 = ... = expresión
„
Las asignaciones se efectúan de derecha a izquierda.
En i = j = 5
1. A j se le asigna 5
2. A i se le asigna el valor de j
37
Marta Zorrilla – Universidad de Cantabria
Reglas de asignación
„
Si los dos operandos en una sentencia de asignación son de tipos
distintos, entonces el valor del operando de la derecha será
automáticamente convertido al tipo del operando de la izquierda.
Además:
„
„
„
„
1. Un valor en coma flotante se puede truncar si se asigna a una variable
de tipo entero.
2. Un valor de doble precisión puede redondearse si se asigna a una
variable de coma flotante de simple precisión.
3. Una cantidad entera puede alterarse si se asigna a una variable de tipo
entero corto o a una variable de tipo carácter.
Es importante en C utilizar de forma correcta la conversión de tipos.
38
Marta Zorrilla – Universidad de Cantabria
Conversión de tipos
(tipo de dato) expresión
int x;
x = 5;
y = x / 2;
„
el valor asignado a la variable y será 2, pues / realiza una división entera.
int x;
x = 5;
y = (float) x / 2;
„
Ahora, la variable y almacena el valor 2.5.
int x;
x = 5;
y = (float) (x / 2);
„
no se asigna a y el valor 2.5, sino 2, ya que los paréntesis que envuelven a la expresión
x / 2 hacen que primero se efectúe la división entera y luego la conversión a flotante
39
Marta Zorrilla – Universidad de Cantabria
Operadores aritméticos
• División entera ( / ): división de una cantidad entera por otra ⇒ se desprecia la parte
decimal del cociente.
• El operador % requiere que los dos operandos sean enteros.
• La mayoría de las versiones de C asignan al resto el mismo signo del primer operando.
• Valores negativos con el signo OPERADOR
UNARIOS
BINARIOS
-
DESCRIPCIÓN
Cambio de signo
--
Decremento
++
Incremento
-
Resta
+
Suma
*
Producto
/
División
%
Resto de división entera
40
Marta Zorrilla – Universidad de Cantabria
Ejemplo
int x, y;
x = 9;
y = 2;
„
„
la operación x / y devuelve el valor 4, mientras que la
operación x % y devuelve 1. Sin embargo, después de las
sentencias
float x;
int y;
x = 9.0;
y = 2;
la operación x / y devuelve 4.5, no pudiéndose aplicar, en este
caso, el operador % puesto que uno de los operandos no es
entero.
41
Marta Zorrilla – Universidad de Cantabria
Operadores incremento, decremento
„
La expresión
es equivalente a
i++;
++i;
i--;
--i;
„
„
i
i
i
i
=
=
=
=
i
i
i
i
+ 1;
+ 1;
- 1;
- 1;
Si el operador sigue al operando el valor del operando se modificará después
de su utilización. Si el operador precede al operando el valor del operando se
modificará antes de su utilización.
Ejemplo: si a = 1
printf("a
printf("a
printf("a
printf("a
=
=
=
=
%d
%d
%d
%d
\n",
\n",
\n",
\n",
Imprime:
a);
++a);
a++);
a);
a
a
a
a
=
=
=
=
1
2
2
3
42
Marta Zorrilla – Universidad de Cantabria
Operadores relacionales
• Se utilizan para formar expresiones lógicas.
• El resultado es un valor entero que puede ser:
ƒ cierto, se representa con un 1
ƒ falso, se representa con un 0
BINARIOS
Ejemplo 1: Si a = 1 y b = 2
Expresión
a<b
a>b
(a + b) ! = 3
a == b
a == 1
Valor
1
0
0
0
1
Interpretación
cierto
falso
falso
falso
cierto
OPERADOR
DESCRIPCIÓN
>
Mayor que
>=
Mayor o igual que
<
Menor que
<=
Menor o igual que
==
Igual que
!=
Diferente que
43
Marta Zorrilla – Universidad de Cantabria
Operadores lógicos
Actúan sobre operandos que son a su vez expresiones lógicas que se
interpretan como:
• cierto, cualquier valor distinto de 0
• falso, el valor 0
Tabla de verdad
a
b
!a
a && b
a || b
F
F
V
F
F
F
V
V
F
V
V
F
F
F
V
V
V
F
V
V
OPERADOR DESCRIPCIÓN
UNARIOS
BINARIOS
!
&&
||
not
and
or
44
Marta Zorrilla – Universidad de Cantabria
Ejemplo
„
„
&& y || se evalúan de izquierda a derecha.
! se evalúa de derecha a izquierda.
„ Ejemplos:
si a = 7 y b = 3
Expresión
(a + b) < 10
!((a + b) < 10)
(a ! = 2) || ((a +b) <= 10)
(a > 4) && (b < 5)
Valor
0
1
1
1
Interpretación
falso
cierto
cierto
cierto
45
Operadores de asignación
compuestos
Marta Zorrilla – Universidad de Cantabria
„
El operador de asignación se puede combinar con otros
operadores como *, /, %, +, -, <<, >>, &, |, ^ para
operaciones acumulativas
es equivalente a
m *= 5;
m = m * 5;
m += b;
m = m + b;
m += y - 3;
m = m + y - 3;
m - = (y = 5);
m = m - (y = 5);
46
Marta Zorrilla – Universidad de Cantabria
Precedencia
Evaluación a
igual nivel de
prioridad
Nivel de
prioridad
Operadores
→
1º
()
←
2º
!
→
3º
→
[]
.
->
~
++
--
*
/
%
4º
+
-
→
5º
<<
→
6º
<
→
7º
==
→
8º
&
→
9º
^
→
10º
|
→
11º
&&
→
12º
||
←
13º
?:
←
14º
operadores de asignación
→
15º
,
(cast)
* & sizeof
>>
<=
>
>=
!=
47
Marta Zorrilla – Universidad de Cantabria
Ejercicios
„
Indica cuáles de los siguientes identificadores no son correctos y por
qué.
a)
e)
„
contador
dias2
b) CONTADOR c) _hola
d) hola_
f) 2dias
g) Suma_Total h) Suma-Total
Sean x, y, z, u, v y t, variables que contienen, respectivamente, los
valores 2, 3, 4, 5, 6 y 7, ¿qué almacenarán después de ejecutar las
siguientes sentencias?
x++;
y = ++z;
t = - -v;
v = x + (y *= 3) / 2;
u = x + y / 2;
48
Marta Zorrilla – Universidad de Cantabria
Ejemplo
Programa que convierte grados Fahrenheit a grados centígrados.
C = (5/9) * (F - 32)
#include <stdio.h>
void main()
{
float centigrados;
float fahrenheit;
}
printf("Introduzca una temperatura en grados fahrenheit: ");
scanf("%f", &fahrenheit);
centigrados = 5.0/9 * (fahrenheit - 32);
printf("%f grados fahrenheit = %f grados centigrados \n", fahrenheit, centigrados);
49
Marta Zorrilla – Universidad de Cantabria
ERRORES COMUNES
„
„
„
„
„
Olvidar que el resultado de dividir dos enteros es entero
Realizar división por cero
Olvidar la prioridad de los operadores
Errores en la conversión de tipos
Confundir el operador de igualdad y el de asignación
50
Funciones
51
Marta Zorrilla – Universidad de Cantabria
Introducción a funciones
„
Objetivos:
„
„
„
„
Introducir al alumno en el diseño estructurado.
Presentar el concepto de función.
Mostrar la definición y declaración de funciones en C.
Contenidos:
1. Introducción al diseño estructurado. Concepto de función
2. Definición de funciones
o Argumentos
o Valor de retorno
o Llamada a función
3. Declaración de funciones. Prototipos
4. Ejemplos
52
Marta Zorrilla – Universidad de Cantabria
Introducción
„
Una función es un segmento de programa que realiza una
determinada tarea.
„
Todo programa C consta de una o más funciones.
„
Una de estas funciones se debe llamar main()
„
Todo programa comienza su ejecución en la función main()
„
El uso de funciones permite la descomposición y desarrollo
modular. Permite dividir un programa en componentes más
pequeños. Æ reutilización
53
Marta Zorrilla – Universidad de Cantabria
Definición de una función
tipo nombre_func (tipo1 arg1, ..., tipoN argN)
{
/* CUERPO DE LA FUNCION */
}
„
„
Los argumentos se denominan parámetros formales.
La función devuelve un valor de tipo de dato tipo
„
„
„
Si se omite tipo se considera que devuelve un int
Si no devuelve ningún tipo ⇒ void
Si no tiene argumentos ⇒ void
void explicacion(void)
„
Entre llaves se encuentra el cuerpo de la función (igual que main()).
La sentencia return finaliza la ejecución y devuelve un valor a la función que
realizó la llamada.
return(expresion);
„
En C no se pueden anidar funciones
„
54
Marta Zorrilla – Universidad de Cantabria
Declaración de funciones:
prototipos
„
„
No es obligatorio pero si aconsejable.
Permite la comprobación de errores entre las llamadas a
una función y la definición de la función correspondiente.
tipo nombre_func (tipo1 arg1, ..., tipoN argN);
55
Marta Zorrilla – Universidad de Cantabria
Llamadas a funciones
„
Para llamar a una función se especifica su nombre y la lista de argumentos
sin poner el tipo de dato.
nombre_func (var1,var2,…,varN);
„
„
„
„
Parámetros formales: los que aparecen en la definición de la función.
Parámetros reales: los que se pasan en la llamada a la función.
En una llamada habrá un argumento real por cada argumento formal,
respetando el orden de la declaración.
Los parámetros reales pueden ser:
„
„
„
„
„
Constantes.
Variables simples.
Expresiones complejas.
Deben ser del mismo tipo de datos que el argumento formal
correspondiente.
Cuando se pasa un valor a una función se copia el argumento real en el
argumento formal.
56
Marta Zorrilla – Universidad de Cantabria
Paso de parámetros por valor
„
„
„
En las llamadas por valor se hace una copia del valor del
argumento en el parámetro formal.
La función opera internamente con estos últimos.
Como las variables locales a una función (y los parámetros
formales lo son) se crean al entrar a la función y se
destruyen al salir de ella, cualquier cambio realizado por la
función en los parámetros formales no tiene ningún efecto
sobre los argumentos.
57
Marta Zorrilla – Universidad de Cantabria
Ejemplo
Programa que calcula el máximo de dos números.
58
Marta Zorrilla – Universidad de Cantabria
Ejemplo:
„
Función que calcula x elevado a y (con y entero)
#include <math.h>
float potencia (float x, int y); /* prototipo */
float potencia (float x, int y) /* definición */
{
int i;
float prod = 1;
prod = pow(x,y);
return(prod);
}
59
Marta Zorrilla – Universidad de Cantabria
Ejemplo 3
„
Programa que indica si un número es cuadrado perfecto.
#include <stdio.h>
#include <math.h>
#define TRUE 1
#define FALSE 0
void explicacion(void);
int cuadrado_perfecto(int x);
void main()
{
int n, perfecto;
explicacion();
scanf("%d", &n);
perfecto = cuadrado_perfecto(n);
if (perfecto)
printf("%d es cuadrado perfecto.\n", n);
else
printf("%d no es cuadrado perfecto.\n", n);
}
60
Marta Zorrilla – Universidad de Cantabria
Ejemplo 3 - Continuación
void explicacion(void)
{
printf("Este programa dice si un numero ");
printf("es cuadrado perfecto \n");
printf("Introduzca un numero: );
}
int cuadrado_perfecto(int x)
{
int raiz;
int perfecto;
raiz = (int) sqrt(x);
}
if (x == raiz * raiz)
perfecto = TRUE; /* cuadrado perfecto */
else
perfecto = FALSE; /* no es cuadrado perfecto */
return(perfecto);
61
Marta Zorrilla – Universidad de Cantabria
Paso de parámetros por
referencia
„
Hasta ahora las funciones solo devolvían un valor, pero ¿qué pasa si
tienen que devolver más?
„
En este caso, se requiere pasar parámetros por referencia
„
La declaración de una función en este caso sería
void nombreFunc (tipo in1, ..., tipo inN, tipo *out1, …tipo *outN)
{
/* CUERPO DE LA FUNCION */
}
„
La llamada a la función
nombre_func (in1, ..., inN, &out1, …, &outN);
62
Marta Zorrilla – Universidad de Cantabria
Paso de parámetros por
referencia (II)
„
En este tipo de llamadas los argumentos contienen direcciones de
variables.
„
Dentro de la función la dirección se utiliza para acceder al argumento
real.
„
„
„
En las llamadas por referencia cualquier cambio en la función tiene
efecto sobre la variable cuya dirección se pasó en el argumento. No
hay un proceso de creación/destrucción de esa dirección.
Aunque en C todas las llamadas a funciones se hacen por valor,
pueden simularse llamadas por referencia utilizando los operadores &
(dirección) y * (en la dirección).
Mediante & podemos pasar direcciones de variables en lugar de
valores, y trabajar internamente en la función con los contenidos,
mediante el operador *.
63
Marta Zorrilla – Universidad de Cantabria
Ejemplo 3 – con parámetros por
referencia
void explicacion ( int *numero)
{
printf("Este programa dice si un numero ");
printf("es cuadrado perfecto \n");
printf("Introduzca un numero: );
scanf("%d", *&n);
}
void main()
{
int n, perfecto;
explicacion(&n);
perfecto = cuadrado_perfecto(n);
……..
}
64
Marta Zorrilla – Universidad de Cantabria
Ejercicio 4
„
„
Programa que calcula la hipotenusa de un
triángulo rectángulo.
h = √(a2 + b2)
Pasos a seguir:
„
„
„
1. Leer a y b ⇒ función leer
2. Calcular h según la fórmula dada ⇒ definimos
una función hipotenusa
3. Imprimir el valor de h ⇒ usar printf().
65
Marta Zorrilla – Universidad de Cantabria
Solución
#include <stdio.h>
#include <math.h>
void hipotenusa(float a, float b, float *h)
{
*h = sqrt(pow(a,2) + pow(b, 2));
}
void main()
{
float a, b, h;
leer (&a,&b);
hipotenusa(a,b,&h);
printf("La hipotenusa es %f\n", h);
}
void leer (float *a, float *b)
{
printf("Dame valores a y b:\n");
scanf("%f %f", *&a, *&b);
}
66
Marta Zorrilla – Universidad de Cantabria
Recapitulación
„
Antes de escribir un programa:
„
„
„
„
„
Leerlo detenidamente
Hacer pseudocódigo o diagrama de flujo
Decidir división en funciones
Determinar parámetros de entrada y salida
Desde main() invocar a las funciones
67
Sentencias de control
68
Marta Zorrilla – Universidad de Cantabria
Estructuras de control
„
Objetivos:
„
„
„
Introducir los tres tipos básicos de sentencias de control: secuencia,
selección e iteración.
Explicar la sintaxis y la semántica de las sentencias de control
dedicadas a definir estructuras de selección.
Contenidos:
1. Tipos de estructuras
2. Estructuras condicionales
o Instrucción if - else
o Instrucción switch
3. Instrucción break
69
Marta Zorrilla – Universidad de Cantabria
Tipos de estructuras
„
„
„
Secuencia: ejecución
sucesiva de dos o más
operaciones.
Selección: se realiza
una u otra operación,
dependiendo de una
condición.
Iteración: repetición de
una operación mientras
se cumpla una
condición.
70
Marta Zorrilla – Universidad de Cantabria
If - else
if (expresión) sentencia;
o bien
if (expresión) sentencia;
else sentencia;
71
Marta Zorrilla – Universidad de Cantabria
Ejemplo if - else
„
Programa que lee un número y dice si es par o impar.
#include <stdio.h>
main()
{
int numero;
/* Leer el numero */
printf("Introduzca un numero: ");
scanf("%d", &numero);
if ((numero % 2) == 0)
printf("El numero %d es par.\n", numero);
else
printf("El numero %d es impar.\n", numero);
}
72
Marta Zorrilla – Universidad de Cantabria
Operador condicional
„
Se utiliza para sentencias if-else simples
y=(x>9 ? 100 : 200);
if (x > 9) {
y=100;
}
else {
y=200;
LO MISMO
}
73
Marta Zorrilla – Universidad de Cantabria
switch
Tipo entero o letra
switch (variable) {
case cte1: sentencia;
break;
case cte2: sentencia;
break;
...
...
default: sentencia;
}
74
Marta Zorrilla – Universidad de Cantabria
Ejemplo switch
#include <stdio.h>
void main()
{
char letra;
printf("Introduzca una letra: ");
scanf("%c", &letra);
switch(letra)
{
case 'a':
case 'A':
printf("Vocal %c\n", letra);
break;
case 'e':
case 'E':
printf("Vocal %c\n", letra);
break;
}
}
case 'i':
case 'I':
printf("Vocal %c\n", letra);
break;
case 'o':
case 'O':
printf("Vocal %c\n", letra);
break;
case 'u':
case 'U':
printf("Vocal %c\n", letra);
break;
default:
printf("Consonante %c\n",
letra);
75
Marta Zorrilla – Universidad de Cantabria
Bucles
„
Objetivos:
„
„
„
Explicar la sintaxis y la semántica de las sentencias de control
dedicadas a definir estructuras de iteración.
Mostrar patrones habituales de concatenación de sentencias de
control con vistas a su utilización en el seno de un programa real.
Contenidos:
1. Bucles
a. Instrucción for
b. Instrucción while
c. Instrucción do - while
2. Instrucciones break y continue
3. Bucles anidados
76
Marta Zorrilla – Universidad de Cantabria
Instrucción for
for (inicialización; condición; incremento)
sentencia;
„
„
„
„
„
„
„
Inicialización: se inicializa algún parámetro que controla la repetición
del bucle.
Condición: es una condición que debe ser cierta para que se ejecute
sentencia.
Incremento: se utiliza para modificar el valor del parámetro.
El bucle se repite mientras condición no sea cero (falso).
Si sentencia es compuesta se encierra entre { }
incialización e incremento se pueden omitir.
Si se omite condición se asumirá el valor permanente de 1 (cierto) y el
bucle se ejecutará de forma indefinida.
77
Marta Zorrilla – Universidad de Cantabria
Ejemplo for
„
Programa que imprime los 100 primeros números
#include <stdio.h>
void main()
{
int numero;
for (numero=0; numero <100; numero++)
printf("%d\n", numero);
}
78
Marta Zorrilla – Universidad de Cantabria
Instrucción while
while (expresión)
sentencia;
„
„
„
„
sentencia se ejecutará mientras el valor de expresión
sea verdadero (distinto de 0).
Primero se evalúa expresión.
Lo normal es que sentencia incluya algún elemento
que altere el valor de expresión, proporcionando la
condición de salida del bucle.
Si la sentencia es compuesta se encierra entre { }
79
Marta Zorrilla – Universidad de Cantabria
Ejemplo while
„
lee un número N y calcula 1 + 2 + 3 + … + N
#include <stdio.h>
void main()
{
int N;
int suma = 0;
/* leer el numero N */
printf("N: ");
scanf("%d", &N);
while (N > 0)
{
suma = suma + N;
N = N - 1; /* equivalente a N-- */
}
printf("1 + 2 +...+ N = %d\n", suma);
}
80
Marta Zorrilla – Universidad de Cantabria
do - while
do
sentencia;
while (expresión);
„
„
„
„
„
sentencia se ejecutará mientras el valor de expresión sea verdadero
(distinto de 0).
sentencia siempre se ejecuta al menos una vez (diferente a while).
Lo normal es que sentencia incluya algún elemento que altere el
valor de expresión, proporcionando la condición de salida del bucle.
Si la sentencia es compuesta se encierra entre { }
Para la mayoría de las aplicaciones es mejor y más natural
comprobar la condición antes de ejecutar el bucle (while).
81
Marta Zorrilla – Universidad de Cantabria
Ejemplo do -while
„
Programa que lee de forma repetida un número e indica si es par o
impar. El programa se repite mientras el número sea distinto de cero.
#include <stdio.h>
void main()
{
int numero;
do
{
/* se lee el numero */
printf("Introduzca un numero: ");
scanf("%d", &numero);
if ((numero % 2) == 0)
printf("El numero %d es par.\n", numero);
else
printf("El numero %d es par.\n", numero);
}
while (numero != 0)
}
82
Marta Zorrilla – Universidad de Cantabria
Bucles anidados
„
„
Los bucles se pueden anidar pero es importante estructurarlos de forma correcta.
Ejemplo: Calcular 1 + 2 + …N mientras N sea distinto de 0.
#include <stdio.h>
main()
{
int N, suma, j;
do
{
}
/* leer el numero N */
printf("Introduzca N: ");
scanf("%d", &N);
suma = 0;
for (j = 0; j <= N; j++)
/* bucle anidado */
suma = suma + j;
printf("1 + 2 + ... + N = %d\n", suma);
} while (N > 0);
/* fin del bucle do */
83
Marta Zorrilla – Universidad de Cantabria
Instrucción break
„
Se utiliza para terminar la ejecución de bucles o salir de una
sentencia switch.
„
Es necesaria en la sentencia switch para transferir el control fuera de
la misma.
„
En caso de bucles anidados, el control se transfiere fuera de la
sentencia más interna en la que se encuentre, pero no fuera de las
externas.
„
No es aconsejable el uso de esta sentencia en bucles pues es
contrario a la programación estructurada.
„
Puede ser útil cuando se detectan errores o condiciones anormales.
84
Ej.
#include <stdio.h>
Marta Zorrilla – Universidad de Cantabria
void main()
{
int opcion;
printf ("1 - Mensaje pantalla \n");
printf ("2 - salir \n");
printf (" cualquier carácter, no hace nada\n");
printf("Elija la opción: ");
scanf("%d", &opcion);
while (opcion)
{
switch(opcion)
{
case 1:
printf("Hola, selecciono opcion %d\n" , opcion);
break;
case 2:
printf ("Adios \n");
return;
break;
default:
printf("Seleccion invalida. Intentelo de nuevo\n");
}
printf("Elija la opcion: ");
scanf("%d", &opcion);
}
}
85
Marta Zorrilla – Universidad de Cantabria
Sentencia continue
„
„
Esta sentencia se utiliza en los bucles for,
while y do/while.
Cuando se ejecuta, fuerza un nuevo ciclo del
bucle, saltándose cualquier sentencia
posterior.
86
Marta Zorrilla – Universidad de Cantabria
Ejemplo continue
#include <stdio.h>
#include <conio.h>
void main ()
{
int n;
int positivos = 0;
do {
}
„
printf ("\n Teclea un número (-99 finaliza): ");
scanf ("%d", &n);
if (n <= 0) continue;
positivos++;
} while (n != -99);
printf ("\n Has tecleado %d números positivos", positivos);
La sentencia positivos++ sólo se ejecuta cuando n es un número
positivo. Si n es negativo o vale 0, se ejecuta continue que fuerza una
87
nueva evaluación de la condición de salida del bucle.
Marta Zorrilla – Universidad de Cantabria
Tabla de comparativas
Valores
iniciales,
operaciones
previas
Cond. para
seguir
repitiendo
Cuando se
comprueba
for
1º campo
2º campo
Antes de cada 3º campo
vuelta
si
while
Hay que ponerlo
fuera, antes del
ciclo
En el while entre
paréntesis
Antes de cada Dentro del ciclo
vuelta
después de las
instrucciones a
repetir
No
do
while
Hay que ponerlo
fuera, antes del
ciclo
En el while entre
paréntesis
Después de
cada vuelta
no
Cambios que
hay que hacer
Dentro del ciclo
después de las
instrucciones a
repetir
¿pueden
quedar
campos
vacíos?
88
Marta Zorrilla – Universidad de Cantabria
Ejercicios
Escriba un programa
que calcule xn, siendo
x y n dos números que
se introducen por
teclado
#include <stdio.h>
void main()
{
int n,x,i;
float potencia=1;
printf("Dame x y n \n: ");
scanf("%d %d", &x, &n);
for (i=0; i<n ; i++) {
potencia=potencia * x;
}
printf("El resultado es: %f\n", potencia);
}
89
Marta Zorrilla – Universidad de Cantabria
Escriba un
programa que calcule e imprima la
suma de los pares y de los impares comprendidos
entre dos valores que se piden por teclado (x y n)
#include <stdio.h>
void leer (int *a, int *b)
{
do{
printf("Solicito dos numeros a<b \n");
printf("Dame a y b \n: ");
scanf("%d %d", *&a , *&b);
} while (a>b);
}
void main()
{
int n,x;
leer (&x,&n);
calcula(x,n);
}
void calcula (int x, int n)
{
int i, int par=0, impar=0;
for (i=x; i<=n; i++ ) {
if ((i%2)==0) par+=i;
else impar+=i;
}
printf("El resultado suma par: %d e impar: %d \n", par, impar);
}
90
Marta Zorrilla – Universidad de Cantabria
Ejemplo - funciones y bucles
#include <stdio.h>
mensaje ()
{
printf ("\nTeclee un número (0 finaliza): ");
}
int lee_numero ()
{
int n;
scanf ("%d", &n);
return n;
}
cuadrado (int x)
{
printf ("\nEl cuadrado es %d", x * x);
}
void main ()
{
int t;
for (mensaje (); t = lee_numero (); cuadrado (t));
}
91
Recursividad
92
Marta Zorrilla – Universidad de Cantabria
Recursividad
„
Objetivos:
„
„
„
Repaso: paso de parámetros por valor y por referencia a
una función.
Mostrar la capacidad de la recursión y las funciones
recursivas.
Contenidos:
1.Paso de parámetros a una función
2.Recursividad
93
Marta Zorrilla – Universidad de Cantabria
Paso de parámetros por valor
„
„
„
En las llamadas por valor se hace una copia del valor del
argumento en el parámetro formal.
La función opera internamente con estos últimos.
Como las variables locales a una función (y los parámetros
formales lo son) se crean al entrar a la función y se
destruyen al salir de ella, cualquier cambio realizado por la
función en los parámetros formales no tiene ningún efecto
sobre los argumentos.
94
Marta Zorrilla – Universidad de Cantabria
Ejemplo
95
Marta Zorrilla – Universidad de Cantabria
Paso de parámetros por
referencia
„
En este tipo de llamadas los argumentos contienen direcciones de
variables.
„
Dentro de la función la dirección se utiliza para acceder al argumento
real.
„
„
„
En las llamadas por referencia cualquier cambio en la función tiene
efecto sobre la variable cuya dirección se pasó en el argumento. No
hay un proceso de creación/destrucción de esa dirección.
Aunque en C todas las llamadas a funciones se hacen por valor,
pueden simularse llamadas por referencia utilizando los operadores &
(dirección) y * (en la dirección).
Mediante & podemos pasar direcciones de variables en lugar de
valores, y trabajar internamente en la función con los contenidos,
mediante el operador *.
96
Marta Zorrilla – Universidad de Cantabria
Ejemplo
x, y punteros
#include <stdio.h>
void funcion(int *a, int *b); /* prototipo */
main()
{
int x = 2;
int y = 5;
printf("Antes x = %d, y = %d\n", x, y);
funcion(&x, &y);
printf("Despues x = %d, y = %d\n", x, y);
}
void funcion(int *a, int *b)
{
*a = 0;
*b = 0;
printf("Dentro *a = %d, *b = %d\n", *a, *b);
return;
}
97
Marta Zorrilla – Universidad de Cantabria
Ejemplo
„
Función que intercambia el valor de dos variables.
#include <stdio.h>
void swap_ref (int *a, int *b); /* prototipo */
void main()
{
int x = 2;
int y = 5;
printf("Antes x = %d, y = %d\n", x, y);
swap(&x, &y);
printf("Despues x = %d, y = %d\n", x, y);
}
void swap_ref (int *a, int *b)
{
int temp;
temp = *b;
*b = *a;
*a = temp;
}
98
Marta Zorrilla – Universidad de Cantabria
Recursividad
„
Una función se llama a sí misma de forma
repetida hasta que se cumpla alguna condición.
Ejemplo: el factorial de un número:
long int factorial(int n)
{
if (n <= 1)
return(1);
else
return(n * factorial(n-1));
}
99
Marta Zorrilla – Universidad de Cantabria
Ejemplo “torres de Hanoi”
#include <stdio.h>
void transferir( int n, char desde, char hacia, char temp);
void main()
{
int n;
printf ("Bienvenido a las torres de Hanoi \n");
printf ("¿Cuántos discos?\n");
scanf("%d", &n);
transferir(n,'I','D','C');
}
Izquierda
Centro
Derecha
100
Marta Zorrilla – Universidad de Cantabria
Ejemplo “torres de Hanoi” (y 2)
void transferir(int n, char desde, char hacia, char temp)
{
/* transferir n discos de un pivote a otro*/
/* n = numero de discos
desde = origen
hacia = destino
temp = almacenamiento temporal */
if (n>0)
{
transferir (n-1, desde, temp, hacia);
printf ("mover disco %d desde %c hasta %c\n", n, desde, hacia);
transferir (n-1, temp, hacia,desde);
}
return;
}
101
Arrays (listas y tablas)
102
Marta Zorrilla – Universidad de Cantabria
Arrays (listas y tablas)
„
Objetivos:
„
„
„
„
Introducir el concepto de tipo de dato estructurado.
Mostrar la representación de datos mediante arrays unidimensionales y
multidimensionales.
Conocer la representación de cadenas de caracteres y las funciones de manipulación.
Contenidos:
1. Arrays
o
o
o
o
Declaración
Subíndices
Almacenamiento en memoria
Tamaño de los arrays
2. Inicialización de un array
3. Array de caracteres y cadenas de texto
4. Arrays multidimensionales
103
Marta Zorrilla – Universidad de Cantabria
Listas
„
Conjunto de datos del mismo tipo a los que se da un nombre común
y a los que se accede a través de un índice
tipo_dato variable_lista[num_elementos];
int numeros[20];
float temperaturas[100];
„
„
En un vector de N elementos, el primero se referencia con el índice 0
y el último con el índice N-1
Inicialización
int numeros[2]={0,1}
int numeros[]={0,1} el compilador asume array de 2 elementos
„
El procesamiento se debe hacer elemento a elemento
104
Marta Zorrilla – Universidad de Cantabria
Listas
„
¿cómo se utilizan?
„
„
Usar un elemento de la lista
variable_lista[posicion];
Empieza en 0
temperaturas[10];
Pasar a funciones
„
en la declaración
void nombreFuncion (int variable)
„
en la llamada a la función
nombreFuncion (variable_lista[posicion])
105
Marta Zorrilla – Universidad de Cantabria
Listas de números
„
¿cómo se utilizan?
„
Usar toda la lista. Podemos:
„
Copiar una lista en otra
memcpy (listadestino,listaorigen,tamaño)
„
Pasar la lista a una función
Sean de entrada o
salida, no requieren *
void nombreFuncion (int nombreLista[TAMAÑO])
nombreFuncion ( nombreLista );
Ojo, corchetes
106
Marta Zorrilla – Universidad de Cantabria
Listas de números
„
¿cómo se utilizan?
„
Usar toda la lista. Podemos:
„
Pasar la lista a una función de tamaño ajustado
void nombreFuncion (int tamano, int nombreLista[tamano])
nombreFuncion ( tamano, nombreLista );
„
„
„
Se debe declarar la lista dentro de un bloque
Antes debe ser conocida la variable tamano
La lista sólo es conocida dentro del bloque
107
Marta Zorrilla – Universidad de Cantabria
Ejemplo lista tamaño fijo
#include <stdio.h>
#define TAM_VECTOR 10
void leer (int vector_a[TAM_VECTOR])
{
int j; /* variable utilizada como indice */
for (j = 0; j < TAM_VECTOR; j++)
{
printf("Elemento %d: ", j);
scanf("%d", &vector_a[j]);
}
}
void copiar (int vector_a[TAM_VECTOR], int
vector_b[TAM_VECTOR])
{
int j;
for (j = 0; j < TAM_VECTOR; j++)
vector_b[j] = vector_a[j];
}
void escribir (int vector[TAM_VECTOR])
{
int j;
for (j = 0; j < TAM_VECTOR; j++)
printf("El elemento %d es %d \n", j, vector[j]);
}
void main()
{
int vector_a[TAM_VECTOR];
int vector_b[TAM_VECTOR];
leer ( vector_a);
copiar (vector_a, vector_b);
escribir (vector_b);
}
108
Marta Zorrilla – Universidad de Cantabria
Ejemplo lista tamaño variable
#include <stdio.h>
void leer (int cuantos, float lista[cuantos])
{
int i;
printf ("teclealos :\n");
for (i=0 ; i< cuantos ; i++)
{
scanf("%f", &lista[i]);
}
}
void pintar(int cuantos, float lista[cuantos])
{
int i;
for (i=0 ; i< cuantos ; i++)
{
printf("%i\n", lista[i]);
}
}
void main()
{
int cuantos;
printf ("dame cuantos \t");
scanf("%i", &cuantos);
{
float lista[cuantos];
}
leer(cuantos,lista);
pintar (cuantos, lista);
}
109
Marta Zorrilla – Universidad de Cantabria
Ordenación elementos de lista
#include <stdio.h>
#include <stdlib.h>
int comparar (int *num1, int *num2)
return ((*num1)-(*num2));
}
{
void main()
{
int cuantos;
printf ("dame cuantos \t");
scanf("%i", &cuantos);
{
float lista[cuantos];
leer(cuantos,lista);
qsort(lista,cuantos, sizeof(lista[0],comparar);
pintar (cuantos, lista);
}
}
110
Marta Zorrilla – Universidad de Cantabria
La función sizeof()
„
Devuelve el tamaño en bytes que ocupa un tipo o
variable en memoria.
#include <stdio.h>
main()
{
char cadena[10];
printf("un int ocupa %d bytes\n", sizeof(int));
printf("un char ocupa %d bytes\n", sizeof(char));
printf("un float ocupa %d bytes\n", sizeof(float));
printf("un double ocupa %d bytes\n", sizeof(double));
printf(" cadena ocupa %d bytes\n", sizeof(cadena));
}
111
Algoritmos de ordenación y
búsqueda
Transparencias en pdf aparte
112
Marta Zorrilla – Universidad de Cantabria
Cadenas de caracteres
„
Un caso particular de lista es la cadena de caracteres. Se declara:
char nombre[num_car];
„
y permite almacenar num_car-1 caracteres y el carácter nulo '\0' de terminación.
char frase[21];
„
es apta para almacenar 20 caracteres y el nulo.
„
C permite la inicialización de cadenas de caracteres en la declaración, mediante
sentencias del tipo
char cadena[ ] = "Esto es una cadena de caracteres";
„
en la que no es necesario añadir el nulo final ni indicar el tamaño, pues lo hace
automáticamente el compilador.
„
Generalmente se utiliza tamaño por exceso, no se suele preguntar al usuario cuántos
caracteres va a introducir
113
Marta Zorrilla – Universidad de Cantabria
Cadenas de caracteres
„
¿Cómo se utilizan?
„
„
Usar un elemento de la lista. Igual que lista de números.
Usar toda la lista. Hay diferencias:
Leer una lista de letras con una sola instrucción
scanf (“%s”, palabra)
coge hasta espacio o fin de línea
scanf (“%[^\n]”, frase)
coge hasta fin de línea
„
Escribir una lista de letras
printf (“%s”, palabra)
„
Copiar una lista de letras <string.h>
strcpy (str_destino, str_origen)
„
114
Marta Zorrilla – Universidad de Cantabria
biblioteca estándar string.h
char *strcat (char *cad1, const char *cad2) Concatena cad2 a cad1 devolviendo la
dirección de cad1. Elimina el nulo de terminación de cad1 inicial.
char *strcpy (char *cad1, const char *cad2) Copia la cadena cad2 en cad1,
sobreescribiéndola. Devuelve la dirección de cad1. El tamaño de
cad1 debe ser suficiente para albergar a cad2.
int strlen (const char *cad)
Devuelve el número de caracteres que almacena cad
(sin contar el nulo final).
int isalnum (int ch)
Devuelve 1 si ch es alfanumérico (letra del alfabeto o dígito) y 0
en caso contrario.
int isalpha (int ch)
Devuelve 1 si ch es una letra del alfabeto y 0 en caso contrario.
int isdigit (int ch)
Devuelve 1 si ch es un dígito del 0 al 9, y 0 en caso contrario.
int islower (int ch)
Devuelve 1 si ch es un letra minúscula y 0 en caso contrario.
int isupper (int ch)
Devuelve 1 si ch es una letra mayúscula y 0 en caso contrario.
int tolower (int ch)
Devuelve el carácter ch en minúscula. Si ch no es una letra
mayúscula la función devuelve ch sin modificación.
int toupper (int ch)
Devuelve el carácter ch en mayúscula. Si ch no es una letra
minúscula la función devuelve ch sin modificación.
115
Marta Zorrilla – Universidad de Cantabria
Ejemplo: lectura y escritura de cadenas de
caracteres
#include <stdio.h>
#define TAM_CADENA 80
main()
{
char cadena[TAM_CADENA];
printf("Introduzca una cadena: ");
scanf("%s", cadena);
printf("La cadena es %s\n", cadena);
}
„
„
no requiere
&
scanf deja de buscar cuando encuentra un blanco ⇒ si se
introduce Hola a todos, solo se leerá Hola.
No es necesario el operador de dirección (&) ya que cadena
representa de forma automática la dirección de comienzo.
116
Marta Zorrilla – Universidad de Cantabria
Ejemplo: lectura y escritura de cadenas
de caracteres (y 2)
„
„
La función gets lee una línea completa hasta que encuentre el retorno
de carro incluyendo los blancos.
La función puts escribe una cadena de caracteres junto con un salto de
línea.
#include <stdio.h>
#define TAM_LINEA 80
main()
{
char linea[TAM_LINEA];
printf("Introduzca una linea: \n");
gets(linea);
puts("La linea es");
puts(linea);
}
Son equivalentes:
puts("La linea es:");
„
≡
printf("La linea es: \n");
117
Marta Zorrilla – Universidad de Cantabria
Ej.
Programa que lee una palabra y la escribe al revés
#include <stdio.h>
#include <string.h>
#define MAXLETRAS 20
void leer (char palabra[MAXLETRAS])
{
printf ("\nTeclee una cadena de caracteres: ");
scanf(“%s”, palabra);
}
void escribir (char palabra[MAXLETRAS])
{
int primera=0, ultima=0, i;
ultima=strlen(palabra)-1;
}
for (i=ultima; i>=primera; i--)
printf(“%c”,palabra[i]);
void main (void)
{
char palabra[MAXLETRAS];
leer(palabra);
escribir(palabra);
}
118
Marta Zorrilla – Universidad de Cantabria
Ej.
El programa siguiente hace uso de alguna de las funciones
anteriores para examinar una cadena de caracteres y
convertir las minúsculas a mayúsculas y viceversa. Además
cuenta cuántos caracteres son dígitos numéricos.
#include <stdio.h>
#include <string.h>
#define MAXLETRAS 100
void leer (char cadena [MAXLETRAS])
{
printf ("\nTeclee una cadena de caracteres: ");
gets (cadena);
}
void escribir (char cadena[MAXLETRAS])
{
int i, contador=0;
for (i = 0; i <= strlen (cadena); i++) {
if (isupper (cadena[i])) cadena[i] = tolower (cadena[i]);
else if (islower (cadena[i])) cadena[i] = toupper (cadena[i]);
else if (isdigit (cadena[i])) contador++;
}
printf ("\nLa cadena tiene %d dígitos numéricos\n", contador);
puts (cadena);
}
void main (void)
{
char frase[MAXLETRAS];
leer(frase);
escribir(frase);
}
119
Marta Zorrilla – Universidad de Cantabria
Vectores multidimensionales
„
Un vector multidimensional se declara:
tipo_dato vector[exp1] [exp2] ... [expN];
„
Matrices o vectores de 2 dimensiones:
int matriz[20][30];
define una matriz de 20 filas por 30 columnas.
„
Generalmente se declaran por exceso.
„
La numeración comienza en 0.
120
Marta Zorrilla – Universidad de Cantabria
Tablas
„
¿Cómo se utilizan?
„
Usar un elemento de la tabla
tabla[fila][columna]
„
Pasar un elemento a una función.
„
„
„
llamada
nombreFuncion (arg1,.., nombretabla[fila][columna])
declaración
void nombreFuncion (tipo arg1,…, tipo variablesimple)
Usar una columna de la tabla: NO SE PUEDE EN C
121
Marta Zorrilla – Universidad de Cantabria
Tablas
„
Usar un vector de la tabla como argumento a una función:
tabla[fila]
„
„
„
declaración
void nombreFuncion (tipo arg1,…, tipo lista[COLUMNAS])
llamada
nombreFuncion (arg1,.., nombretabla[fila]);
Usar una tabla completa
„
„
Copiar
memcpy(destino, origen,tamaño)
Ej: memcpy ( clientes2, clientes1, sizeof(int)*filas*columnas)
Parámetro de una función
„
Declaración de función
void nombreFuncion (tipo arg1,…, tipo tabla[FILAS][COLUMNAS])
„
Llamada a una función
nombreFuncion (arg1,…, tabla)
122
Marta Zorrilla – Universidad de Cantabria
Ejemplo
Leer dos matrices de
dimensiones indicadas por el
usuario y escribir su suma
#include <stdio.h>
void sumar(int filas, int columnas, float tabla1[filas][columnas], float tabla2[filas][columnas])
{
int i,j, acumulador=0;
for (i=0;i<filas;i++)
{
for (j=0;j<columnas;j++)
{
printf("%f \t", tabla1[i][j]+tabla2[i][j]);
}
printf("\n");
}
}
void main()
{
int filas, columnas;
printf("dame filas y columnas: \n");
scanf("%i %i", &filas, &columnas);
void leer(int filas, int columnas, float tabla[filas][columnas])
{
{
float tabla1[filas][columnas], tabla2[filas][columnas];
int i,j;
printf("dame tabla:\n");
leer(filas,columnas, tabla1);
leer(filas,columnas, tabla2);
for (i=0;i<filas;i++)
sumar(filas, columnas,tabla1, tabla2);
{
}
for (j=0;j<columnas;j++)
{
}
scanf("%f", &tabla[i][j]);
}
}
}
123
Marta Zorrilla – Universidad de Cantabria
Ejemplo
„
Función que calcula el producto de dos matrices cuadradas.
void multiplicar(float a[DIM][DIM], float b[DIM][DIM], float c[DIM][DIM])
{
int i, j, k;
for(i = 0; i < DIM; i++)
for(j = 0; j < DIM; j++)
{
c[i][j] = 0.0;
for(k = 0; k < DIM; k++)
c[i][j] += a[i][k] * b[k][j];
}
}
124
Marta Zorrilla – Universidad de Cantabria
Ej.:
Leer lista de palabras y contar el nº de veces que está
una palabra que solicita el usuario
#include <stdio.h>
#include <string.h>
#define MAX 30 /*incluye el fin de línea*/
void main()
{
int numpal;
void leer(int numpal, int columnas, char tabla[numpal][MAX], char pal[MAX]) printf("dame nº palabras: \n");
{
scanf("%i", &numpal);
int i;
printf("dame palabras:\n");
{
char tabla[numpal][MAX], pal[MAX];
for (i=0;i<numpal;i++)
{
leer(numpal, tabla, pal);
scanf("%s",tabla[i]);
calcular(numpal,tabla,pal);
}
}
printf("dame palabra a buscar:\n");
}
scanf("%s",pal);
}
void calcular(int numpal, int columnas, char tabla[numpal][MAX], char pal[MAX])
{
int i,suma=0;
for (i=0;i<numpal;i++)
{
if (strcmp(listapal[i],pal)==0)
{
suma ++;
}
}
printf(“la palabra buscada %s, aparece %d veces\”,pal, suma);
}
125
Estructuras y uniones
126
Marta Zorrilla – Universidad de Cantabria
Estructuras y uniones
„
Objetivos:
„
„
„
„
Conocer la posibilidad de definir tipos de datos estructurados con campos
heterogéneos mediante el uso de estructuras.
Explicar la posibilidad de combinar tipos de datos estructurados.
Mostrar los tipos union.
Contenidos:
1. Estructuras
2.
3.
4.
5.
o Concepto de campo
o Declaración e inicialización
Acceso a estructuras
Declaración typedef
Combinación de datos estructurados
Campos variables con el uso de union
127
Marta Zorrilla – Universidad de Cantabria
Estructuras
„
„
„
Es una estructura de datos compuesta de elementos individuales que
pueden ser de distinto tipo.
Cada uno de los elementos de una estructura se denomina miembro.
Declaración de una estructura:
struct nombre_estructura
{
tipoDato1 miembro_1;
tipoDato2 miembro_2;
.
.
tipoDatoN miembro_N;
};
„
Los miembros pueden ser de cualquier tipo excepto void
128
Marta Zorrilla – Universidad de Cantabria
Ejemplo
„
„
„
Declaración de una estructura denominada CD.
struct CD
{
char titulo[100];
char artista[50];
int num_canciones;
int anio;
Euros precio;
};
Declaración de una variable denominada cd1 de tipo struct CD.
struct cd1 CD;
Se pueden copiar estructuras, pero NO comparar:
struct CD cd1,cd2;
cd2 = cd1;
129
Marta Zorrilla – Universidad de Cantabria
Inicialización de una estructura
„
Dos formas:
„
En la declaración:
struct CD
{
char titulo[100];
char artista[50];
int num_canciones;
int anio;
Euros precio;
} cd1= {“Un sueño de verano”,”Miguel Rios”,1989,10};
„
En el programa:
struct CD cd1;
strcpy(cd1.titulo, “Un sueño de verano");
strcpy(cd1.artista, “Miguel Rios");
cd1.num_canciones = 2;
c1.anio = 1989;
130
Marta Zorrilla – Universidad de Cantabria
Acceso a una estructura
„
„
Los miembros de una estructura se procesan individualmente.
Para hacer referencia a un miembro determinado, se utiliza el operador
. si la variable es de tipo estructura
variable_estructura.miembro
„
O, se utiliza el operador -> si la variable es de tipo puntero a estructura
variable_estructura->miembro
„
Ejemplo: imprimir la fecha de hoy
struct fecha {
int dia, mes, anio;
};
struct fecha hoy;
struct fecha *ayer;
printf("%d: %d: %d\n", hoy.dia,hoy.mes, hoy.anno);
printf("%d: %d: %d\n", ayer->dia, ayer-> mes, ayer-> anno);
131
Marta Zorrilla – Universidad de Cantabria
Ejemplo
#include <stdio.h>
struct fecha
{
int dia;
int mes;
int anno;
};
struct cuenta
{
int cuenta_no;
char nombre[80];
float saldo;
struct fecha ultimo_pago;
};
132
Marta Zorrilla – Universidad de Cantabria
Ejemplo (y 2)
main()
{
struct cuenta c1, c2;
/* rellena la estructura c1 */
c1.cuenta_no = 2;
strcpy(c1.nombre, "Pepe");
c1.saldo = 100000;
c1.ultimo_pago.dia = 12;
c1.ultimo_pago.mes = 5;
c1.ultimo_pago.anno = 1997;
/* asignacion de estructuras */
c2 = c1;
printf("No. Cuenta %d \n", c2.cuenta_no);
printf("Nombre %s \n", c2.nombre);
printf("Saldo %f \n", c2.saldo);
printf("Fecha de ultimo pago: %d:%d:%d \n", c2.ultimo_pago.dia,
c2.ultimo_pago.mes, c2.ultimo_pago.anno);
}
133
Marta Zorrilla – Universidad de Cantabria
Combinación de datos estructurados:
vector de estructuras
#include <stdio.h>
#include <string.h>
#define NUMCAJAS 3
Programa que permita introducir las
piezas de un almacén (tipo, nombre,
nro, precio) e imprimirlas
Caja N
caja ...
Caja 1
typedef struct
{
char pieza[20];
/* Tipo de pieza.
*/
int cantidad;
/* Número de piezas.
*/
float precio_unitario; /* Precio de cada pieza.
*/
char existe;
/* Comprobar si el registro existe. */
} registro_piezas;
134
Marta Zorrilla – Universidad de Cantabria
main()
{
registro_piezas cajas[NUMCAJAS];
int registro=0;
int i;
do
{
/* Leer el nombre de la pieza. */
printf("Nombre de la pieza => ");
scanf("%s", cajas[registro].pieza);
/* Leer el número de piezas. */
printf("Numero de piezas => ");
scanf("%d", &cajas[registro].cantidad);
/* Leer el precio de cada pieza. */
printf("Precio de cada pieza => ");
scanf("%f", &cajas[registro].precio_unitario);
/* Indicar que el registro tiene datos, V */
cajas[registro].existe = 'V';
registro ++;
} while (registro < NUMCAJAS);
135
Marta Zorrilla – Universidad de Cantabria
Cont.
/* Imprimir la información. */
for(registro = 0; registro < NUMCAJAS; registro++)
{
if(cajas[registro].existe == 'V')
{
printf("La caja %d contiene:\n", registro + 1);
printf("Pieza => %s\n", cajas[registro].pieza);
printf("Cantidad => %d\n",
cajas[registro].cantidad);
printf("Precio unitario => $%f\n",
cajas[registro].precio_unitario);
}
} /* Fin for. */
} /*fin main*/
136
Marta Zorrilla – Universidad de Cantabria
Paso de estructuras a funciones
„
„
„
Una función puede devolver una estructura.
Se pueden pasar miembros individuales y estructuras
completas a una función. Si la estructura es grande, el
tiempo para copiar un estructura (paso por valor) es
prohibitivo, por eso se aconseja pasarlo por referencia.
Paso de miembros individuales
struct punto
{
float x;
float y;
};
void imprime_x (float x)
{
printf ("el valor de x %f", x);
}
/*llamada a función*/
imprime_x (p1.x);
137
Marta Zorrilla – Universidad de Cantabria
Paso de estructuras a funciones por
valor
Ej.: leer y escribir una fecha.
struct fecha leer_fecha(void)
{
struct fecha f;
printf("Dia: ");
scanf("%d", &(f.dia));
printf("Mes: ");
scanf("%d", &(f.mes));
printf("Anno: ");
scanf("%d", &(f.anno));
return(f);
#include <stdio.h>
struct fecha
{
int dia;
int mes;
int anno;
};
void imprimir_fecha(struct fecha f)
{
printf("Dia: %d\n", f.dia);
printf("Mes: %d\n", f.mes);
printf("Anno: %d\n", f.anno);
return;
}
}
main()
{
struct fecha fecha_de_hoy;
fecha_de_hoy = leer_fecha();
imprimir_fecha(fecha_de_hoy);
138
}
Marta Zorrilla – Universidad de Cantabria
Paso de estructuras a funciones por
referencia
void leer_punto(struct punto *p);
void imprimir_punto(struct punto p);
struct punto
{
float x;
float y;
};
main()
{
struct punto p1;
void leer_punto(struct punto *p)
{
printf("x = ");
scanf("%f", &(p->x));
printf("y = ");
scanf("%f", &(p->y));
}
void imprimir_punto(struct punto p)
{
printf("x = %f\n", p.x);
printf("y = %f\n", p.y);
}
leer_punto(&p1);
imprimir_punto(p1);
}
139
Marta Zorrilla – Universidad de Cantabria
Uniones
„
„
Una union contiene miembros cuyos tipos de datos pueden ser
diferentes (igual que las estructuras).
Su declaración es similar a las estructuras:
union nombre_estructura
{
tipoDato1 miembro_1;
tipoDato2 miembro_2;
.
.
tipoDatoN miembro_N;
};
„
„
Todos los miembros que componen la union comparten la misma
zona de memoria → ahorro de memoria.
Una variable de tipo union sólo almacena el valor de uno de sus
miembros.
140
Marta Zorrilla – Universidad de Cantabria
Ejemplo
#include <stdio.h>
#include <stdlib.h>
union numero
{
int entero;
float real;
};
main()
{
union numero num;
/* leer un entero e imprimirlo */
printf("Entero: ");
scanf("%d", &(num.entero));
printf("El entero es %d\n", num.entero);
/* leer un real e imprimirlo */
printf("Real: ");
scanf("%f", &(num.real));
printf("El entero es %f\n", num.real);
}
0
1
2
3
entero
real
141
Marta Zorrilla – Universidad de Cantabria
Combinación de datos estructurados:
vector de estructuras y union
struct ALUMNO {
char grupo[15];
int asignat;
char repite;
};
struct PROFESOR {
char nrp[16];
char cargo[21];
};
union AL_PR {
struct ALUMNO al;
struct PROFESOR pr;
};
Persona n
Persona ...
Persona 1
struct DATOS {
char tipo;
char nombre[40];
int edad;
char direccion[40];
char telefono[15];
union AL_PR ambos;
} personal[100];
142
Marta Zorrilla – Universidad de Cantabria
El siguiente segmento de programa
muestra los datos de la matriz personal.
for (i = 0; i < 100; i++) {
printf ("\nNombre: %s", personal[i].nombre);
printf ("\nEdad: %d", personal[i].edad);
printf ("\nDirección: %s", personal[i].direccion);
printf ("\nTeléfono: %s", personal[i].telefono);
if (personal[i].tipo == 'A') {
printf ("\nALUMNO");
printf ("\nGrupo: %s", personal[i].ambos.al.grupo);
printf ("\nNº de Asignaturas: %d", personal[i].ambos.al.asignat);
printf ("\nRepite: %d", personal[i].ambos.al.repite); }
else {
printf ("\nPROFESOR");
printf ("\nN.R.P.: %s", personal[i].ambos.pr.nrp);
printf ("\nCargo: %s", personal[i].ambos.pr.cargo);
}
143
}
Marta Zorrilla – Universidad de Cantabria
Tipos enumerados
„
„
„
Un tipo enumerado es similar a las estructuras.
Sus miembros son constantes de tipo int.
Es útil definir nuevos literales para
„
„
„
„
Asociar un nombre a un valor numérico
Limitar los valores que puede tomar una variable entera
Hacer el código más legible
Definición:
enum nombre {m1, m2, ..., mN};
„
Ejemplo:
enum color {negro, blanco, rojo};
144
Marta Zorrilla – Universidad de Cantabria
Ejemplo
#include <stdio.h>
enum semaforo {rojo, amarillo, verde};
main()
{
enum estado semaforo;
for(estado =rojo; estado <=verde; estado ++)
switch(estado )
{
case rojo:
printf(“Parar, sino multa\n");
break;
case amarillo:
printf(“Parar si no tienes vehículo encima\n");
break;
case verde:
printf(“Circular\n");
break;
}
}
145
Definición de tipos de datos
(typedef)
Marta Zorrilla – Universidad de Cantabria
„
Permite dar nuevo nombre a tipos de datos que ya existen:
typedef tipoDato nuevo_tipo;
„
Ejemplos:
typedef char letra;
letra c;
typedef struct{
int dia;
int mes;
int anio;
} FECHA;
FECHA a;
146
Marta Zorrilla – Universidad de Cantabria
Combinación de typedef y enum
„
„
Usando typedef y enum se pueden definir tipos que sólo pueden
tomar ciertos valores
Ej. tipo booleano en C
typedef enum {false, true} boolean;
...
boolean f=false;
...
if(f)
printf("f es verdadero\n");
else
printf("f es falso\n");
...
f=45; /* Error, no debería tomar ese valor */
147
Ficheros
Marta Zorrilla
148
Marta Zorrilla – Universidad de Cantabria
Ficheros
„
Objetivos:
„
„
„
„
Presentar el tipo de dato FILE y los tipos de fichero.
Explicar las instrucciones para abrir, cerrar y gestionar ficheros.
Capacitar al alumno a trabajar con ficheros de texto y binarios.
Contenidos:
1. Concepto de ficheros y sus tipos
2. Declaración de una variable tipo fichero
3. Operaciones con ficheros:
o Abrir y cerrar ficheros
o Control de errores y fin de fichero
o Lectura/escritura de ficheros de texto: caracteres, cadenas de
caracteres y con formato
o Lectura/escritura de ficheros binarios
o Acceso directo a información de archivos
149
Marta Zorrilla – Universidad de Cantabria
Canales y ficheros
„
„
„
El sistema de E/S del ANSI C proporciona un intermediario entre el
programa y el dispositivo al que se accede (pantalla, cinta, disco,...).
Este intermediario se llama canal o flujo (stream) y es un buffer
independiente del dispositivo al que se conecte.
Existen dos tipos de canales:
„
„
Canales de texto: Son secuencias de caracteres. Dependiendo del
entorno puede haber conversiones de caracteres (LF ⇔ CR + LF). Esto
hace que el número de caracteres escritos/leídos en un canal pueda no
coincidir con el número de caracteres escritos/leídos en el dispositivo.
Canales binarios: Son secuencias de bytes. A diferencia de los canales de
texto, en los canales binarios la correspondencia de caracteres en el
canal y en el dispositivo es 1 a 1, es decir, no hay conversiones.
150
Marta Zorrilla – Universidad de Cantabria
Canales y ficheros ( y 2)
„
Hay 3 canales que se abren siempre que comienza un programa C:
„
„
„
„
„
stdin
stdout
stderr
(ANSI)
Canal estándar de entrada. Por defecto el teclado. (ANSI)
Canal estándar de salida. Por defecto la pantalla. (ANSI)
Canal estándar de salida de errores. Por defecto la pantalla.
Un canal se asocia a un archivo cuando se abre o se crea éste para lo cual se
utilizan funciones de la biblioteca stdio.h.
También incluye funciones para realizar las operaciones de lectura/escritura
así como para desasociar un canal de un archivo (operación de cierre).
151
Marta Zorrilla – Universidad de Cantabria
Apertura de un archivo
„
Para abrir un archivo:
desc = fopen(nombre_archivo, modo)
„
donde desc, el descriptor, se declara como:
FILE *desc;
„
„
y modo especifica la forma de apertura del archivo.
si fopen devuelve NULL, el fichero no se pudo abrir.
152
Marta Zorrilla – Universidad de Cantabria
Parámetros para abrir un fichero
DESCRIPCIÓN
MODO
r
Abre un fichero sólo para lectura. Si el fichero no existe fopen() devuelve
un puntero nulo y se genera un error.
w
Crea un nuevo fichero para escritura. Si ya existe un fichero con este
nombre, se sobreescribe, perdiéndose el contenido anterior.
a
Abre o crea un fichero para añadir. Si el fichero existe, se abre apuntando
al final del mismo. Si no existe se crea uno nuevo.
r+
Abre un fichero para leer y escribir. Si el fichero no existe fopen()
devuelve un puntero nulo y se genera un error. Si existe, pueden
realizarse sobre él operaciones de lectura y de escritura.
Crea un nuevo fichero para leer y escribir. Si ya existe un fichero con este
nombre, se sobreescribe, perdiéndose el contenido anterior. Sobre el
archivo pueden realizarse operaciones de lectura y de escritura.
w+
a+
Abre o crea un fichero para leer y añadir. Si el fichero ya existe se abre
apuntando al final del mismo. Si no existe se crea un fichero nuevo.
Modo TEXTO: añadir letra t. Ej: si modo es rt, se está abriendo el fichero en modo texto sólo para lectura
Modo BINARIO: añadir letra b. Ej: modo es w+b se abrirá o creará un fichero en modo binario para lectura y escritura153
Marta Zorrilla – Universidad de Cantabria
Cierre de un fichero
„
Para cerrar un fichero y liberar el canal previamente
asociado con fopen(), se debe usar la función fclose()
int fclose (FILE *canal);
„
Esta función devuelve 0 si la operación de cierre ha
tenido éxito, y distinto de 0 en caso de error.
154
Marta Zorrilla – Universidad de Cantabria
Ejemplo
#include <stdio.h>
main()
{
FILE *desc;
desc = fopen("ejemplo.txt", “w");
if (desc == NULL)
{
printf("Error, no se puede abrir el archivo \n");
}
else
{
/* se procesa el archivo */
/* al final se cierra */
fclose(desc);
}
exit(0);
}
155
Marta Zorrilla – Universidad de Cantabria
Control de errores
„
Cada vez que se realiza una operación de lectura o de
escritura sobre un fichero debemos comprobar si se ha
producido algún error. Para ello disponemos de la función
ferror()
int ferror (FILE *canal);
„
Esta función devuelve 0 si la última operación sobre el
fichero se ha realizado con éxito.
156
Marta Zorrilla – Universidad de Cantabria
Final de fichero
„
„
Cada vez que se realiza una operación de lectura sobre un fichero, el
indicador de posición del fichero se actualiza.
Es necesario, pues, controlar la condición de fin de fichero. Por ello,
debemos saber que cuando se intentan realizar lecturas más allá del
fin de fichero, el carácter leído es siempre EOF. Sin embargo en los
canales binarios un dato puede tener el valor EOF sin ser la marca
de fin de fichero. Es aconsejable, por ello, examinar la condición de
fin de fichero mediante la función feof()
int feof (FILE *canal);
„
Esta función devuelve un valor diferente de cero cuando se detecta
el fin de fichero.
157
Marta Zorrilla – Universidad de Cantabria
Ficheros de texto
„
„
„
Se trata de archivos cuyo contenidos son caracteres en
formato ASCII, por tanto, son legibles y editables por
cualquier editor de texto. Usualmente tienen la extensión
“txt”.
Para abrir un archivo en modo texto se debe emplear el
modificador “t” en el modo de apertura del archivo.
Existen dos formas de tratar ficheros de texto:
„
„
„
Carácter a carácter (fgetc y fputc)
Cadenas de caracteres (fgets y fputs)
Con formato (fprintf y fscanf)
158
Marta Zorrilla – Universidad de Cantabria
Funciones de manejo carácter a carácter
„
Lectura:
int fgetc(FILE *fich)
Lee un carácter del archivo (EOF si estamos al final del
mismo)
„
Escritura:
int fputc(char c, FILE *fich)
Escribe el carácter c en el archivo. Si es correcto devuelve
el mismo carácter y si no EOF.
159
Marta Zorrilla – Universidad de Cantabria
Ejemplo
„
Ejemplo que realiza la lectura de un archivo carácter a carácter
empleando un buffer:
char buffer[255], lineas[100][80], c;
int n, t;
FILE *entrada;
entrada = fopen(“ejemplo.txt”, “rt”);
while (!feof(entrada)) {
t = 0;
do {
c = fgetc(entrada);
buffer[t] = c;
t++;
} while (c!=EOF && c!=’\n’); //fin de fichero o de línea
strcpy(lineas[n], buffer);
n++;
}
fclose(salida);
160
Marta Zorrilla – Universidad de Cantabria
Funciones de manejo cadenas de
caracteres
„
Lectura:
char *fgets(const char *s, int n, FILE *fich)
Lee n-1 caracteres o hasta carácter de fin de línea (que también se almacena
en s). Si no se produce error, la función devuelve un puntero a char; en caso
contrario, devuelve un puntero nulo.
„
Escritura:
int fputs(char *s, FILE *fich)
Escribe la cadena s en el archivo. Si es correcto devuelve un valor no
negativo y si no EOF. No copia el carácter nulo ni añade el carácter de fin
de línea.
161
Marta Zorrilla – Universidad de Cantabria
Ejemplo
#include <stdio.h>
int main(void)
{
FILE *fent;
FILE *fsal;
char car[120];
int res = 0;
char * ret;
/* Apertura del archivo de entrada */
fent = fopen("./entrada.txt", "r");
if (fent == NULL)
{
fprintf(stderr, "Error abriendo entrada.txt \n");
return(0);
}
/* Apertura, con creación si no existe, del archivo de salida */
fsal = fopen("./salida.txt", "w");
if (fsal == NULL)
{
fprintf(stderr, "Error creando salida.txt \n");
fclose(fent);
return(0);
}
162
Marta Zorrilla – Universidad de Cantabria
Ejemplo (y 2)
/* Bucle de lectura y escritura con líneas */
do
{
/* Lectura de la línea siguiente */
ret = fgets(car, 110, fent);
if ( car == NULL)
fprintf(stderr, "Error al leer \n");
else
fprintf(stdin, "Longitud linea leida: %d \n", strlen(car));
/* Escritura de la línea */
if (ret != NULL) {
res = fputs(car, fsal);
if (res == EOF)
fprintf(stderr, "Error al escribir %s \n", car);
}
} while (ret != NULL);
/* Cierre de los streams de entrada y de salida */
fclose(fent);
fclose(fsal);
return(0);
}
163
Marta Zorrilla – Universidad de Cantabria
Funciones de manejo con formato
„
Lectura:
int fscanf(FILE *fich, char *formato, arg1,arg2,…argN)
Su uso es el mismo que scanf pero con la salvedad de que lee desde
un archivo, en vez desde el teclado.
„
Escritura:
int fprintf(FILE *fich, char *formato, arg1,arg2,…argN)
Su uso es igual al de printf pero con la salvedad de que escribe en
un archivo en vez de en la pantalla.
164
Marta Zorrilla – Universidad de Cantabria
Ejemplo
„
Veamos un ejemplo para escribir una cadena de
caracteres en un fichero:
char cadena[255];
FILE *salida;
…
salida = fopen(“salida.txt”, “wt”);
strcpy(cadena, “Prueba de escritura”);
fprintf(salida,”%s”,cadena);
fclose(salida);
165
Marta Zorrilla – Universidad de Cantabria
Ficheros binarios
„
„
„
Son archivos cuyo contenido son caracteres en formato binario,
por tanto NO son legibles ni editables. Para asegurarnos que la
apertura de un archivo se hace en modo binario se debe emplear
el modificador “b” en el modo de apertura del archivo. Si no
ponemos nada se asume el modo binario por defecto.
Las funciones básicas de escritura y lectura asociadas a este
modo son: fwrite y fread.
Generalmente se utilizan para leer estructuras
166
Marta Zorrilla – Universidad de Cantabria
Escribir a fichero binario
„
Escritura
int fwrite(void *datos, int tam, int ndatos, FILE *fich);
„
„
Devuelve:
Número de elementos (no bytes) escritos en el archivo.
Parámetros:
*ptr = puntero al origen de los datos.
tam = tamaño de cada elemento.
ndatos = número de elementos.
*fich = puntero a FILE (archivo donde escribir).
167
Marta Zorrilla – Universidad de Cantabria
Ejemplo
FILE *archivo;
int valor;
Tficha ficha;
int n;
…
archivo=fopen(“c:\archivo.dat”,”w”);
n = fwrite(&valor, sizeof(int), 1, archivo);
if (n!=1) printf(“Error: escritura incompleta.”);
n = fwrite(&ficha, sizeof(TFicha), 1, archivo);
if (n!=1) printf(“Error: escritura incompleta.”);
168
Marta Zorrilla – Universidad de Cantabria
Lectura de fichero binario
„
Sintaxis:
int fread(void *datos, int tam, int ndatos, FILE *fich);
„
Devuelve el número de elementos (no bytes) leídos del archivo.
„
Parámetros:
*ptr = puntero al destino de los datos.
tam = tamaño de cada elemento.
ndatos = número de elementos.
*fich = puntero a FILE (archivo de donde leer).
169
Marta Zorrilla – Universidad de Cantabria
Ejemplo
TFicha fichas[100];
int nfichas;
FILE *agenda;
nfichas =0;
agenda = fopen(“agenda.dat”, “rb”);
while (!feof(agenda)) {
fread(&fichas[nfichas], sizeof(TFicha), 1, agenda);
nfichas ++;
}
fclose(agenda);
170
Marta Zorrilla – Universidad de Cantabria
Ejemplo agenda
„
El registro de ese archivo constará de los siguientes campos:
Nombre
Domicilio
Población
Provincia
Teléfono
„
40 caracteres
40 caracteres
25 caracteres
15 caracteres
10 caracteres
El programa crea el fichero llamado LISTIN.TEL con los datos
suministrados por el usuario
171
Marta Zorrilla – Universidad de Cantabria
Ejemplo
#include <stdio.h>
typedef struct {
char nom[41];
char dom[41];
char pob[26];
char pro[16];
char tel[11];
} REG;
void main (void)
{
FILE *f;
REG var;
if (!(f = fopen ("LISTIN.TEL", "wb"))) {
perror ("LISTIN.TEL");
return;
}
printf ("Nombre: ");
gets (var.nom);
172
Marta Zorrilla – Universidad de Cantabria
Ejemplo (y 2)
while (var.nom[0]) {
printf ("\nDomicilio: ");
gets (var.dom);
printf ("\nPoblación: ");
gets (var.pob);
printf ("\nProvincia: ");
gets (var.pro);
printf ("\nTeléfono: ");
gets (var.tel);
fwrite (&var, sizeof (var), 1, f);
if (ferror (f)) {
puts ("No se ha almacenado la información");
getch ();
}
printf ("Nombre: ");
gets (var.nom);
}
}
fclose (f);
173
Marta Zorrilla – Universidad de Cantabria
Ejemplo: Lectura en bloques
#include <stdio.h>
typedef struct {
char nom[41];
char dom[41];
char pob[26];
char pro[16];
char tel[11];
} REG;
void main (void)
{
FILE *f;
REG var[4];
int i, n;
if (!(f = fopen ("LISTIN.TEL", "rb"))) {
perror ("LISTIN.TEL");
exit (1);
}
do {
n = fread (var, sizeof (REG), 4, f);
for (i = 0; i < n; i++) printf ("\n%-41s %s", var[i].nom, var[i].tel);
puts ("\nPulse una tecla ...");
getch ();
} while (!feof (f));
fclose (f);
}
174
Marta Zorrilla – Universidad de Cantabria
Acceso directo
„
El acceso directo a un archivo, se realiza con la ayuda de la
función fseek() que permite situar el indicador de posición del
archivo en cualquier lugar del mismo.
int fseek (FILE *canal, long nbytes, int origen);
„
„
„
Esta función sitúa el indicador de posición del fichero nbytes
contados a partir de origen.
La función devuelve 0 cuando ha tenido éxito. En caso contrario
devuelve un valor diferente de 0.
Esta función simplemente maneja el indicador de posición del
fichero, pero no realiza ninguna operación de lectura o
escritura. Por ello, después de usar fseek() debe ejecutarse
una función de lectura o escritura.
175
Marta Zorrilla – Universidad de Cantabria
Acceso directo (y 2)
int fseek (FILE *canal, long nbytes, int origen);
„
Los valores posibles del parámetro origen y sus macros asociadas
ORIGEN
VALOR
MACRO
Principio del fichero
0
SEEK_SET
Posición actual
1
SEEK_CUR
Fin del fichero
2
SEEK_END
176
Marta Zorrilla – Universidad de Cantabria
Ejemplo:
Se crea un archivo llamado FRASE.TXT con una cadena de
caracteres. Posteriormente lee un carácter de la cadena cuya posición se teclea.
#include <stdio.h>
#include <string.h>
void main (void)
{
FILE *f;
int nbyte, st;
char frase[80], caracter;
if (!(f = fopen ("FRASE.TXT", "w+t"))) {
perror ("FRASE.TXT");
return;
}
}
printf ("Teclee frase: ");
gets (frase);
fwrite (frase, strlen (frase) + 1, 1, f);
printf ("\nLeer carácter nº: ");
scanf ("%d", &nbyte);
st = fseek (f, nbyte, SEEK_SET);
if (st) puts ("Error de posicionamiento");
else {
caracter = getc (f);
if (caracter != EOF) printf ("\nEl carácter es: %c", caracter);
else puts ("Se sobrepasó el fin de fichero");
}
fclose (f);
177
Marta Zorrilla – Universidad de Cantabria
Ejemplo:
programa escribe registros ayudándose de fseek()
.
#include <stdio.h>
typedef struct {
char nombre[40];
int edad;
float altura;
} REGISTRO;
void main (void)
{
FILE *f1;
REGISTRO mireg;
int num;
long int puntero;
if (!(f1 = fopen ("REGISTRO.DAT", "r+b"))) {
puts ("Error de apertura");
return;
}
printf ("Escribir registro nº: ");
scanf ("%d", &num);
178
Marta Zorrilla – Universidad de Cantabria
Ejemplo:
programa escribe registros ayudándose de fseek()
.
(y2)
while (num > 0) {
getchar ();
printf ("Nombre: ");
gets (mireg.nombre);
printf ("Edad: ");
scanf ("%d", &mireg.edad);
printf ("Altura: ");
scanf ("%f", &mireg.altura);
puntero = (num - 1) * sizeof (REGISTRO);
if (fseek (f1, puntero, SEEK_SET)) puts ("Error de posicionamiento");
else {
fwrite (&mireg, sizeof (mireg), 1, f1);
if (ferror (f1)) {
puts ("ERROR de escritura");
getch ();
}
}
printf ("Escribir registro nº: ");
scanf ("%d", &num);
}
fclose (f1);
}
179
Programación modular
Tema 13
180
Marta Zorrilla – Universidad de Cantabria
Tema 13
„
Objetivos:
„
„
„
Explicar el ámbito de las variables del programa.
Familiarizar al alumno con la creación de programas
modularizados y la creación de librerías de funciones propias.
Contenidos:
1. Variables globales y locales
2. Variables estáticas
3. El preprocesador C: #include y #define.
4. Programas modulares
5. Bibliotecas de funciones
181
Marta Zorrilla – Universidad de Cantabria
Ámbito de las variables y tipos de
almacenamiento
„
Existen dos formas de caracterizar una variable:
„
„
„
„
„
El tipo de dato se refiere al tipo de información que representa la
variable (int, char, . . . ).
El tipo de almacenamiento se refiere a su permanencia y a su ámbito.
El ámbito de una variable es la porción del programa en la cual se
reconoce la variable.
Según el ámbito, las variables pueden ser:
„
„
„
Por su tipo de dato
Por su tipo de almacenamiento
Variables locales.
Variables globales.
Según el tipo, las variables pueden ser:
„
„
„
„
Variables
Variables
Variables
Variables
automáticas.
estáticas.
externas.
de tipo registro.
182
Marta Zorrilla – Universidad de Cantabria
Variables globales
„
„
Se declaran fuera de las funciones y antes de su uso.
Pueden ser accedidas desde cualquier función.
#include <stdio.h>
void funcion1(void);
int a = 1000; /* variable global */
main()
{
int b = 2; /* variable local */
funcion1();
printf("a = %d, b = %d \n", a, b);
}
void funcion1(void)
{
int c = 4; /* variable local */
printf("a = %d, c = %d \n", a, c);
return;
}
183
Marta Zorrilla – Universidad de Cantabria
Variables globales (y 2)
„
„
Mantienen los valores que se les asignan en las funciones.
Es mejor hacer uso de variables locales para evitar efectos secundarios
o laterales.
#include <stdio.h>
void funcion1(void);
int a=10; /* variable global */
main()
{
printf("Antes a = %d\n", a);
funcion1();
printf("Despues a = %d\n", a);
}
void funcion1(void)
{
a = 1000;
return;
}
184
Marta Zorrilla – Universidad de Cantabria
Variables locales
„
„
„
„
„
Las variables locales que se definen en las funciones.
Su ámbito es local.
Su vida se restringe al tiempo en el que esta activa la función.
Los parámetros formales se tratan como variables automáticas.
Se pueden especificar con la palabra reservada auto aunque no
es necesario.
#include <stdio.h>
main()
{
auto int valor; /* equivalente a int valor */
valor = 5;
printf("El valor es %d\n", valor);
}
185
Marta Zorrilla – Universidad de Cantabria
Variables estáticas
„
„
„
Su ámbito es local a la función.
Su vida coincide con la del programa ⇒ retienen sus valores durante toda la vida del
programa.
Se especifican con static.
#include <stdio.h>
void funcion(void);
main()
{
funcion();
funcion();
funcion();
}
void funcion(void)
{
static int veces = 0;
veces = veces + 1;
printf("Se ha llamado %d veces a funcion\n", veces);
}
186
Marta Zorrilla – Universidad de Cantabria
Variables de tipo registro
„
„
„
Informan al compilador que el programador desea que la variable
se almacene en un lugar de rápido acceso, generalmente en
registros.
Si no existen registros disponibles se almacenará en memoria.
Se especifican con register
#include <stdio.h>
main()
{
register int j;
for (j = 0; j < 10; j++)
printf("Contador = %d\n", j);
}
187
Marta Zorrilla – Universidad de Cantabria
Variables de tipo externas
„
„
„
„
„
Variables globales.
Hay que distinguir entre definición y declaración de variable
externa.
La definición se escribe de la misma forma que las variables
normales y reserva espacio para la misma en memoria.
Una declaración no reserva espacio de almacenamiento ⇒ se
especifica con extern.
Se emplean cuando un programa consta de varios módulos. En uno
de ellos se define la variable. En los demás se declara (extern)
188
Marta Zorrilla – Universidad de Cantabria
Ejemplo
„
Modulo principal (main.c)
#include <stdio.h>
extern int valor; /* se declara */
void funcion(void);
main()
{
funcion();
printf("Valor = %d\n", valor);
}
„
- Se compila por separado:
gcc -c -Wall
main.c
gcc -c -Wall
aux.c
- Se obtienen dos módulos
objetos: main.o y aux.o.
- El ejecutable (prog) se genera:
gcc main.o aux.o -o prog
Modulo auxiliar (aux.c)
int valor; /* se define la variable */
void funcion(void)
{
valor = 10;
}
189
Marta Zorrilla – Universidad de Cantabria
Recomendaciones
„
„
„
Evitar el uso de variables globales.
Mantener las variables lo más locales que se
pueda.
Cuando se precise hacer accesible el valor de una
variable a una función, se pasará como
argumento.
190
Marta Zorrilla – Universidad de Cantabria
Macros
„
Una macro es un identificador equivalente a una expresión,
sentencia o grupo de sentencias.
#include <stdio.h>
#define maximo(a,b) ((a > b) ? a : b)
main()
{
int x, y;
int max;
printf("Introduzca dos numeros: ");
scanf("%d %d", &x, &y);
max = maximo(x,y); /* uso de la macro */
printf("El maximo es %d\n", max);
}
191
Marta Zorrilla – Universidad de Cantabria
Macros (y 2)
„
„
„
No puede haber blancos entre el identificador y el
paréntesis izquierdo.
Una macro no es una llamada a función.
El preprocesador sustituye todas las referencias a la
macro que aparezcan dentro de un programa antes
de realizar la compilación:
„
„
No se produce llamada a función ⇒ mayor velocidad.
Se repite el código en cada uso de la macro ⇒ mayor código
objeto.
192
Marta Zorrilla – Universidad de Cantabria
Directiva #include
„
„
Indica al preprocesador que incluya un archivo fuente
nom_fich. El formato es:
#include "nom_fich"
o bien,
#include <nom_fich>
„
El uso de comillas dobles " " o ángulos < > indica dónde debe
buscar el preprocesador el fichero nom_fich.
• comillas dobles " " : en el directorio de trabajo o en el camino
absoluto que se especifique en la sentencia include
• ángulos < >: en los directorios donde se encuentran las bibliotecas
que proporciona el compilador
193
Marta Zorrilla – Universidad de Cantabria
Archivos de cabecera (.h)
„
„
Permiten modularizar el código y favorecer la ocultación de
información.
Puede contener:
„
„
„
„
„
„
„
Definiciones de macros #define MIL 1000
Declaraciones de variables extern int dia;
Declaraciones de funciones extern void f(void);
Otras directivas de inclusión #include “a.h”
Comentarios
Definiciones de tipos de dato (typedef)
Nunca debe tener:
„
„
Definiciones de variables int dia;
Definiciones de funciones void f(void);
194
Marta Zorrilla – Universidad de Cantabria
Compilación prog. varios módulos
preprocesador
leyOhm.h
prog_ppal.c
leyOhm.c
leyOhm.h
compilador
leyOhm.o
Inclusión del
archivo leyOhm.c
prog_ppal.c
prog_ppal.o
enlazador
prog_ppal.exe
195
Marta Zorrilla – Universidad de Cantabria
La biblioteca de funciones
LENGUAJE
ARCHIVO
DE CABECERA
DESCRIPCIÓN
ALLOC.H
Define funciones de asignación dinámica de memoria
ANSI C
ASSERT.H
Declara la macro de depuración assert
C++
BCD.H
Define la clase bcd
BIOS.H
Define funciones utilizadas en rutinas de ROM-BIOS
C++
COMPLEX.H
Define las funciones matemáticas complejas
C++
CONIO.H
Define varias funciones utilizadas en las llamadas a rutinas de E/S por consola
en DOS
ANSI C
CTYPE.H
Contiene información utilizada por las macros de conversión y clasificación de
caracteres
DIR.H
Contiene definiciones para trabajar con directorios.
DOS.H
Declara constantes y da las declaraciones necesarias para llamadas
específicas del 8086 y del DOS
ERRNO.H
Declara mnemónicos constantes para códigos de error
FCNTL.H
Declara constantes simbólicas utilizadas en conexiones con la biblioteca de
rutinas open()
FLOAT.H
Contiene parámetros para rutinas de coma flotante
ANSI C
ANSI.C
196
Marta Zorrilla – Universidad de Cantabria
La biblioteca de funciones
LENGUAJE
ARCHIVO
DE CABECERA
DESCRIPCIÓN
C++
FSTREAM.H
Define los flujos de C++ que soportan E/S de archivos
C++
GENERIC.H
Contiene macros para declaraciones de clase genéricas
C++
GRAPHICS.H
Define prototipos para las funciones gráficas
IO.H
Declaraciones de rutinas de E/S tipo UNIX
C++
IOMANIP.H
Define los gestores de flujos de E/S de C++ y contiene macros para creación de
gestores de parámetros
C++
IOSTREAM.H
Define rutinas básicas de flujo de E/S de C++ (v2.0)
ANSI C
LIMITS.H
Parámetros y constantes sobre la capacidad del sistema
ANSI C
LOCALE.H
Define funciones sobre el país e idioma
ANSI C
MATH.H
Define prototipos para las funciones matemáticas
MEM.H
Define las funciones de gestión de memoria
PROCESS.H
Contiene estructuras y declaraciones para las funciones spawn(), exec()
SETJMP.H
Declaraciones para dar soporte a saltos no locales
SHARE.H
Parámetros utilizados en funciones que utilizan arhivos-compartidos
SIGNAL.H
Declara constantes y declaraciones para utilizarlos en funciones signal() y
197
raise()
ANSI C
ANSI C
Marta Zorrilla – Universidad de Cantabria
La biblioteca de funciones
LENGUAJE
ARCHIVO
DE CABECERA
DESCRIPCIÓN
ANSI C
STDARG.H
Soporte para aceptar un número variable de argumentos
ANSI C
STDDEF.H
Declara varios tipos de datos y macros de uso común
ANSI C
STDIO.H
Declara tipos y macros para E/S estándar
C++
STDIOSTR.H
Declara las clases de flujo para utilizar con estructuras del archivo stdio.h
ANSI C
STDLIB.H
Define algunas de las rutinas comúnmente utilizadas
C++
STREAM.H
Define las clases de flujo de C++ para utilizarlas con arrays de bytes en
memoria
ANSI C
STRING.H
Define varias rutinas de manipulación de cadenas y de memoria
SYS\STAT.H
Declara constantes simbólicas utilizadas para abrir y crear archivos
SYS\TIMEB.H
Define la función ftime() y la estructura timeb
C++
SYS\TYPES.H
Define el tipo time_t
ANSI C
TIME.H
Estructuras y prototipos para funciones de tiempo
VALUES.H
Declara constantes dependientes de la máquina
198
Punteros y arrays
Tema 14
199
Marta Zorrilla – Universidad de Cantabria
Punteros y arrays
„
Objetivos:
„
„
„
„
„
Introducir el concepto de puntero.
Introducir el concepto de tipo de dato estructurado.
Mostrar la representación de datos mediante arrays unidimensionales y
multidimensionales.
Conocer la representación de cadenas de caracteres y las funciones de manipulación.
Contenidos:
1. Punteros
o Declaración
o Operadores
2. Arrays
o
o
o
o
Declaración
Subíndices
Almacenamiento en memoria
Tamaño de los arrays
3. Inicialización de un array
4. Array de caracteres y cadenas de texto
5. Arrays multidimensionales
200
Marta Zorrilla – Universidad de Cantabria
Punteros
„
Un puntero es una variable que contiene una
dirección de memoria. Por ejemplo, la
dirección de otra variable .
201
Marta Zorrilla – Universidad de Cantabria
Punteros (y 2)
„
Las variables puntero se declaran de la siguiente forma:
tipo *nombre;
„
siendo nombre el identificador de la variable puntero, y tipo el
tipo de variable a la que apunta. Por ejemplo:
char *m;
int *n;
float *p;
„
En estas declaraciones, las variables m, n y p son punteros que
apuntan, respectivamente, a datos de tipo char, int y float.
202
Marta Zorrilla – Universidad de Cantabria
Punteros (y 3)
„
Los operadores de punteros son:
„
„
&
*
dirección de
en la dirección de
„
El operador * sólo se puede aplicar a punteros
„
Las operaciones permitidas con punteros son:
„
„
„
„
Asignación
Incremento / Decremento
Suma / Resta
Comparación
203
Marta Zorrilla – Universidad de Cantabria
Asignación punteros
„
Dadas las declaraciones
float x;
float *p, *q;
„
la forma de asignar a p y q la dirección de x es:
p = &x;
q = &x;
„
„
Ahora p y q almacenan la misma dirección de memoria: la de la
variable x. El mismo efecto se consigue con la asignación
directa entre punteros:
p = &x;
q = p;
No es correcta una sentencia como
p = x;
204
Marta Zorrilla – Universidad de Cantabria
Ejemplo
#include <stdio.h>
main()
{
int x; /* variable entera */
int y; /* variable entera */
int *px; /* variable puntero a entero */
int x;
int y;
int *px;
1
(&x) 1000
(&x) 1200
x = 5;
px = &x; /* asigna a px la direccion de x */
y = *px; /* asigna a y el contenido de la
direccion almacenada en px */
(&px) 3000
printf("x = %d\n", x);
printf("y = %d\n", y);
printf("*px = %d\n", *px);
}
5
px=&x;
3
5
x=5;
y=*px;
2
100
0
205
Marta Zorrilla – Universidad de Cantabria
Ejercicio
„
Dado el siguiente fragmento de código:
float n1;
float n2;
float *p1;
float *p2;
n1 = 4.0;
p1 = &n1;
p2 = p1;
n2 = *p2;
n1 = *p1 + *p2;
¿Cuánto vale n1 y n2?
206
Marta Zorrilla – Universidad de Cantabria
Incremento / Decremento
„
Los operadores ++ y -- actúan de modo diferente según el tipo
apuntado por el puntero.
„
Si p es un puntero a caracteres (char *p) la operación p++
incrementa el valor de p en 1.
„
Si embargo, si p es un puntero a enteros (int *p), la misma
operación p++ incrementa el valor de p en 2 para que apunte
al siguiente elemento, pues el tipo int ocupa dos bytes.
„
Del mismo modo, para el tipo float la operación p++
incrementa el valor de p en 4.
„
Lo dicho para el operador ++ se cumple exactamente igual,
pero decrementando, para el operador --.
207
Marta Zorrilla – Universidad de Cantabria
Suma / Resta
„
„
„
Ocurre exactamente lo mismo que con las operaciones de
incremento y decremento. Si p es un puntero, la operación
p = p + 5;
hace que p apunte 5 elementos más allá del actual.
Si p estaba definido como un puntero a caracteres, se
incrementará su valor en 5, pero si estaba definido como
un puntero a enteros, se incrementará en 10.
208
Marta Zorrilla – Universidad de Cantabria
Comparación
„
Pueden compararse punteros del mismo modo que
cualquier otra variable, teniendo siempre presente que
se comparan direcciones y NO contenidos.
int *p, *q;
if (p == q) puts ("p y q apuntan a la misma
posición de memoria");
209
Marta Zorrilla – Universidad de Cantabria
Puntero NULL
„
„
„
„
Cuando se asigna 0 a un puntero, este no apunta a ningún objeto o
función.
La constante simbólica NULL definida en stdio.h tiene el valor 0 y
representa el puntero nulo.
Es una buena técnica de programación asegurarse de que todos los
punteros toman el valor NULL cuando no apuntan a ningún objeto o
función.
int *p = NULL;
Para ver si un puntero no apunta a ningún objeto o función:
if (p == NULL)
printf("El puntero es nulo\n");
else
printf("El contenido de *p es\n", *p);
210
Marta Zorrilla – Universidad de Cantabria
Arrays
„
Conjunto de datos del mismo tipo a los que se da un nombre común
y a los que se accede a través de un índice
tipo_dato variable_array[num_elem];
int numeros[20];
float temperaturas[100];
„
„
En un vector de N elementos, el primero se referencia con el índice 0
y el último con el índice N-1
Inicialización
int numeros[2]={0,1}
int numeros[]={0,1} el compilador asume array de 2 elementos
„
El procesamiento se debe hacer elemento a elemento
211
Marta Zorrilla – Universidad de Cantabria
Ejemplo arrays
#include <stdio.h>
#define TAM_VECTOR 10
main()
{
int vector_a[TAM_VECTOR];
int vector_b[TAM_VECTOR];
int j; /* variable utilizada como indice */
/* leer el vector a */
for (j = 0; j < TAM_VECTOR; j++)
{
printf("Elemento %d: ", j);
scanf("%d", &vector_a[j]);
}
/* copiar el vector */
for (j = 0; j < TAM_VECTOR; j++)
vector_b[j] = vector_a[j];
/* escribir el vector b */
for (j = 0; j < TAM_VECTOR; j++)
printf("El elemento %d es %d \n", j, vector_b[j]);
}
212
Marta Zorrilla – Universidad de Cantabria
Cadenas de caracteres
„
Un caso particular de vector es la cadena de caracteres. Se declara:
char nombre[num_car];
„
y permite almacenar num_car-1 caracteres y el carácter nulo '\0' de
terminación.
char frase[21];
„
es apta para almacenar 20 caracteres y el nulo.
„
C permite la inicialización de cadenas de caracteres en la declaración,
mediante sentencias del tipo
char cadena[ ] = "Esto es una cadena de caracteres";
„
en la que no es necesario añadir el nulo final ni indicar el tamaño, pues
lo hace automáticamente el compilador.
213
Marta Zorrilla – Universidad de Cantabria
Cadenas de caracteres
„
Una forma de asignar un valor a una cadena es la siguiente:
char cadena[10];
strcpy(cadena, "Hola");
214
Marta Zorrilla – Universidad de Cantabria
biblioteca estándar string.h
char *strcat (char *cad1, const char *cad2) Concatena cad2 a cad1 devolviendo la
dirección de cad1. Elimina el nulo de terminación de cad1 inicial.
char *strcpy (char *cad1, const char *cad2) Copia la cadena cad2 en cad1,
sobreescribiéndola. Devuelve la dirección de cad1. El tamaño de
cad1 debe ser suficiente para albergar a cad2.
int strlen (const char *cad)
Devuelve el número de caracteres que almacena cad
(sin contar el nulo final).
int isalnum (int ch)
Devuelve 1 si ch es alfanumérico (letra del alfabeto o dígito) y 0
en caso contrario.
int isalpha (int ch)
Devuelve 1 si ch es una letra del alfabeto y 0 en caso contrario.
int isdigit (int ch)
Devuelve 1 si ch es un dígito del 0 al 9, y 0 en caso contrario.
int islower (int ch)
Devuelve 1 si ch es un letra minúscula y 0 en caso contrario.
int isupper (int ch)
Devuelve 1 si ch es una letra mayúscula y 0 en caso contrario.
int tolower (int ch)
Devuelve el carácter ch en minúscula. Si ch no es una letra
mayúscula la función devuelve ch sin modificación.
int toupper (int ch)
Devuelve el carácter ch en mayúscula. Si ch no es una letra
minúscula la función devuelve ch sin modificación.
215
Marta Zorrilla – Universidad de Cantabria
Lectura y escritura de cadenas de caracteres
#include <stdio.h>
#define TAM_CADENA 80
main()
{
char cadena[TAM_CADENA];
printf("Introduzca una cadena: ");
scanf("%s", cadena);
printf("La cadena es %s\n", cadena);
}
„
„
scanf deja de buscar cuando encuentra un blanco ⇒ si se
introduce Hola a todos, solo se leerá Hola.
No es necesario el operador de dirección (&) ya que cadena
representa de forma automática la dirección de comienzo.
216
Marta Zorrilla – Universidad de Cantabria
Lectura y escritura de cadenas de
caracteres (y 2)
„
„
La función gets lee una línea completa hasta que encuentre el retorno de carro
incluyendo los blancos.
La función puts escribe una cadena de caracteres junto con un salto de línea.
#include <stdio.h>
#define TAM_LINEA 80
main()
{
char linea[TAM_LINEA];
printf("Introduzca una linea: \n");
gets(linea);
puts("La linea es");
puts(linea);
}
puts("La linea es:");
„
es equivalente a:
printf("La linea es: \n");
217
Marta Zorrilla – Universidad de Cantabria
Ejemplo
„
El programa siguiente hace uso de alguna de las funciones anteriores para examinar una
cadena de caracteres y convertir las minúsculas a mayúsculas y viceversa. Además cuenta
cuántos caracteres son dígitos numéricos.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>
void main (void)
{
char cadena[100];
int contador = 0;
register int i;
clrscr ();
printf ("\nTeclee una cadena de caracteres: ");
gets (cadena);
for (i = 0; i <= strlen (cadena); i++) {
if (isupper (cadena[i])) cadena[i] = tolower (cadena[i]);
else if (islower (cadena[i])) cadena[i] = toupper (cadena[i]);
else if (isdigit (cadena[i])) contador++;
}
printf ("\nLa cadena tiene %d dígitos numéricos\n", contador);
puts (cadena);
}
218
Marta Zorrilla – Universidad de Cantabria
La función sizeof()
„
Devuelve el tamaño en bytes que ocupa un tipo o
variable en memoria.
#include <stdio.h>
main()
{
char cadena[10];
printf("un int ocupa %d bytes\n", sizeof(int));
printf("un char ocupa %d bytes\n", sizeof(char));
printf("un float ocupa %d bytes\n", sizeof(float));
printf("un double ocupa %d bytes\n", sizeof(double));
printf(" cadena ocupa %d bytes\n", sizeof(cadena));
}
219
Marta Zorrilla – Universidad de Cantabria
Vectores multidimensionales
„
Un vector multidimensional se declara:
tipo_dato vector[exp1] [exp2] ... [expN];
„
Matrices o vectores de 2 dimensiones:
int matriz[20][30];
„
„
define una matriz de 20 filas por 30 columnas.
El elemento de la fila i columna j es matriz[i][j]
220
Marta Zorrilla – Universidad de Cantabria
Ejemplo
„
Función que calcula el producto de dos matrices cuadradas.
void multiplicar(float a[][DIMENSION], float b[][DIMENSION], float c[][DIMENSION])
{
int i, j, k;
for(i = 0; i < DIMENSION; i++)
for(j = 0; j < DIMENSION; j++)
{
c[i][j] = 0.0;
for(k = 0; k < DIMENSION; k++)
c[i][j] += a[i][k] * b[k][j];
}
return;
}
221
Funciones y argumentos de
tipo puntero
Tema 16
222
Marta Zorrilla – Universidad de Cantabria
Tema 16
„
Objetivos:
„
„
„
Mostrar el paso de estructuras y arrays a funciones, enfatizando la
conveniencia de realizarlo por referencia.
Indicar cómo se pasan parámetros al programa principal.
Contenidos:
1. Matrices como argumentos de funciones
2. Estructuras como argumentos de funciones
3. Argumentos de la función main()
223
Marta Zorrilla – Universidad de Cantabria
Paso de vectores a funciones
„
„
„
„
Un vector se pasa a una función especificando su nombre sin corchetes.
El nombre representa la dirección del primer elemento del vector ⇒ los vectores se
pasan por referencia y se pueden modificar en las funciones.
El argumento formal correspondiente al vector se escribe con un par de corchetes
cuadrados vacíos. El tamaño no se especifica.
Programa que calcula la media de los componentes de un vector.
#include <stdio.h>
#define MAX_TAM 4
void leer_vector(int vector[]);
int media_vector(int vector[]);
main()
{
int v_numeros[MAX_TAM];
int media;
leer_vector(v_numeros);
media = media_vector(v_numeros);
printf("La media es %d\n", media);
}
224
Marta Zorrilla – Universidad de Cantabria
Paso de vectores a funciones (y2)
void leer_vector(int vector[])
{
int j;
for(j=0; j<MAX_TAM; j++)
{
printf("Elemento %d: ", j);
scanf("%d", &vector[j]);
}
return;
}
int media_vector(int vector[])
{
int j;
int media = 0;
for(j=0; j<MAX_TAM; j++)
media = media + vector[j];
return(media/MAX_TAM);
}
225
Marta Zorrilla – Universidad de Cantabria
Punteros y vectores
„
El nombre del vector representa la dirección del primer elemento
del vector
float vector[MAX_TAM];
vector == &vector[0]
„
El nombre del vector es realmente un puntero al primer elemento
del vector
&x[0]
&x[1]
&x[2]
&x[i]
„
⇒
⇒
⇒
⇒
x
(x+1)
(x+2)
(x+i)
Es decir, &x[i] y (x+i) representan la dirección del i-esimo elemento
del vector x ⇒ x[i] y *(x+i) representan el contenido del i-esimo
elemento del vector x.
226
Marta Zorrilla – Universidad de Cantabria
Punteros y vectores (y 2)
„
„
„
„
„
„
Cuando un vector se define como un puntero no se le pueden
asignar valores ya que un puntero no reserva espacio en memoria.
float x[10] define un vector compuesto por 10 números reales ⇒
reserva espacio para los elementos.
float *x declara un puntero a float. Si se quiere que float x se
comporte como un vector ⇒ habrá que reservar memoria para los
10 elementos:
x = (float *) malloc(10 * sizeof(float));
malloc(nb) (stdlib.h) reserva un bloque de memoria de nb bytes.
Para liberar la memoria asignada se utiliza free() (stdlib.h)
free(x);
El uso de punteros permite definir vectores de forma dinámica.
227
Marta Zorrilla – Universidad de Cantabria
Ejemplo.
Programa que calcula la media de un
vector de tamaño especificado de forma dinámica.
#include <stdio.h>
#include <stdlib.h>
void leer_vector(int vector[], int dim);
int media_vector(int vector[], int dim);
main()
{
int *v_numeros;
int dimension;
int media;
printf("Dimension del vector: ");
scanf("%d", &dimension);
v_numeros = (int *) malloc(dimension*sizeof(int));
leer_vector(v_numeros, dimension);
media = media_vector(v_numeros, dimension);
printf("La media es %d\n", media);
free(v_numeros);
}
228
Marta Zorrilla – Universidad de Cantabria
Ejemplo.
Programa que calcula la media de un
vector de tamaño especificado de forma dinámica. (y 2)
void leer_vector(int vector[], int dim)
{
int j;
for(j=0; j<dim; j++)
{
printf("Elemento %d: ", j);
scanf("%d", &vector[j]);
}
return;
}
int media_vector(int vector[], int dim)
{
int j;
int media = 0;
for(j=0; j<dim; j++)
media = media + vector[j];
return(media/dim);
}
229
Marta Zorrilla – Universidad de Cantabria
Vectores y cadenas de caracteres
„
„
Una cadena de caracteres es un vector de caracteres ⇒ cada elemento del
vector almacena un carácter.
Ejemplo: Función que copia una cadena en otra:
void copiar(char *destino, char *fuente)
{
while (*fuente != '\0')
{
*destino = *fuente;
destino++;
fuente++ ;
}
*destino = '\0';
return;
}
230
Marta Zorrilla – Universidad de Cantabria
Punteros a estructuras
„
„
Igual que con el resto de variables.
struct punto
{
float x;
float y;
};
main()
{
struct punto punto_1;
struct punto *punto_2;
punto_1.x = 2.0;
punto_1.y = 4.0;
punto_2 = &punto_1;
printf("x = %f \n", punto_2->x);
printf("y = %f \n", punto_2->y);
}
231 ->
En una variable de tipo puntero a estructura los miembros se acceden con
Marta Zorrilla – Universidad de Cantabria
Paso de estructuras a funciones (ej. por valor)
„
„
„
Se pueden pasar miembros individuales y estructuras
completas.Por valor o por referencia.
Una función puede devolver una estructura.
Ejemplo: leer y escribir una fecha.
void imprimir_fecha(struct fecha f)
{
printf("Dia: %d\n", f.dia);
printf("Mes: %d\n", f.mes);
printf("Anno: %d\n", f.anno);
return;
}
232
Marta Zorrilla – Universidad de Cantabria
Paso de estructuras a funciones (y 2)
struct fecha leer_fecha(void)
{
struct fecha f;
printf("Dia: ");
scanf("%d", &(f.dia));
printf("Mes: ");
scanf("%d", &(f.mes));
printf("Anno: ");
scanf("%d", &(f.anno));
return(f);
}
main()
{
struct fecha fecha_de_hoy;
fecha_de_hoy = leer_fecha();
imprimir_fecha(fecha_de_hoy);
}
233
Marta Zorrilla – Universidad de Cantabria
Paso de estructuras a funciones (ej. por
referencia)
void leer_punto(struct punto *p);
void imprimir_punto(struct punto p);
main()
{
struct punto *p1;
p1 = (struct punto *)malloc(sizeof(struct punto));
leer_punto(p1);
imprimir_punto(*p1);
free(p1);
}
234
Marta Zorrilla – Universidad de Cantabria
Paso de estructuras a funciones (ej. por
referencia) (y 2)
void leer_punto(struct punto *p)
{
printf("x = ");
scanf("%f", &(p->x));
printf("y = ");
scanf("%f", &(p->y));
}
void imprimir_punto(struct punto p)
{
printf("x = %f\n", p.x);
printf("y = %f\n", p.y);
}
235
Marta Zorrilla – Universidad de Cantabria
Argumentos de la función main()
„
Ejecutar un programa con parámetros
entrada (en línea de comandos)
de
main (int argc, char *argv[ ])
argc: Entero que indica el número de parámetros tecleados (incluye
el nombre del programa).
argv[ ]: Matriz de cadenas de caracteres. Cada uno de los elementos
argv[i] es una cadena que almacena un argumento.
236
Marta Zorrilla – Universidad de Cantabria
Argumentos de la función main()
La variable argc vale 1 como mínimo, puesto que se cuenta el
nombre del programa. Los parámetros se identifican mediante argv
de la siguiente manera:
• argv[0]
• argv[1]
• argv[2]
...
...
• argv[argc]
cadena que almacena el nombre del programa.
cadena que almacena el primer parámetro.
cadena que almacena el segundo parámetro.
vale cero (En realidad es un puntero nulo).
Para que los argumentos sean tratados como diferentes tienen que
ir separados por uno o varios espacios blancos
237
Marta Zorrilla – Universidad de Cantabria
Ejemplo
„
Programa que lista los parámetros, si los hay, de la línea de órdenes.
#include <stdio.h>
void main (int argc, char *argv[ ])
{
register int i;
printf ("\nNombre del programa: %s", argv[0]);
if (argc == 1) printf ("\nNo se han introducido parámetros");
else {
printf ("\nParámetros en la línea de órdenes: ");
for (i = 1; i < argc; i++) printf ("\n%d: %s", i, argv[i]);
}
}
238

Documentos relacionados