Introducción a la Programación en C.

Anuncio
Introducción a la
Programación en C.
Informática Industrial (3º I.T.I.)
Introducción a la Programación en C.
•
•
•
•
•
•
•
•
•
•
•
Introducción.
Tipos de datos, variables y constantes.
Tiras de caracteres (string), printf() y scanf().
getchar() , getch() y putchar();
Operadores, expresiones y sentencias.
Condicionales.
Bucles.
Funciones y punteros.
El preprocesador C.
Arrays , estructuras y uniones.
Librerías.
1
Introducción
• Creado por Dennis Ritchie en 1972.
• Lenguaje Compilado (frente a interprete).
– Creación del programa ⇒ Código fuente.
– Compilación del programa ⇒ Código objeto.
– Enlazado del programa con funciones de librería
utilizadas ⇒ Fichero ejecutable.
• Lenguaje de Nivel Medio (frente a alto y bajo
nivel).
• Lenguaje Estructurado (frente a no estructurado).
Introducción
• Estructura general de un programa escrito en C.
Declaraciones globales
tipo_devuelto main (lista de parámetros)
{
Secuencia de sentencias
}
tipo_devuelto funcion_1 (lista de parámetros)
{
Secuencia de sentencias
}
......
tipo_devuelto funcion_n (lista de parámetros)
{
Secuencia de sentencias
}
2
Introducción
• Ejemplo1:
/*Fichero Incluido*/
#include <stdio.h>
/*Variable Global*/
int numero = 1;
/*Prototipo de la Funcion*/
void escribe(void);
/*Funcion Main*/
void main(void)
{
/*Variable Local*/
int numero = 0;
printf("Esto es una variable local. Numero = %d\n", numero);
/*LLamada a la funcion escribe*/
escribe();
}
/*Funcion escribe*/
void escribe(void)
{
printf("Esto es una variable global. Numero = %d\n", numero);
}
Tipos de datos, variables y constantes.
• Cinco tipos de datos básicos:
– Carácter (char): 8 bits ⇒ -128 a 127.
– Entero (int): 32 bits ⇒ -2.147.483.648 a 2.147.483.647.
– Coma flotante (float): 32 bits ⇒ 3.4·10e-38 a
3.4·10e+38.
– Coma flotante de doble precisión (double): 64 bits ⇒
1.7·10e-308 a 1.7·10e+308.
– Sin valor (void).
• Modificación de los tipos básicos para int y char:
– signed: por defecto
– unsigned
– long: también aplicable a double. 80 bits ⇒ 3.4 x 10e4932 a 1.1·10e+4932
– short
3
Tipos de datos, variables y
constantes.
• Variable: posición de memoria al que se le asigna
un nombre y que se usa para almacenar un valor
que puede ser modificado por el programa.
• Definición de variables:
tipo <lista de variables separadas por coma>;
• Ejemplos:
– int a;
– unsigned char caracter1, caracter2;
– double valor1 = 1.2, VALOR1 = 1e-4;
Tipos de datos, variables y
constantes.
• Tipos de Variables:
– Variables locales: son las variables definidas dentro de
una función o bloque {}. Sólo son conocidas dentro de
ese bloque. Tras salir del bloque se destruye.
– Variables globales: son aquellas variables que se
conocen a lo largo de todo el programa y se pueden
usar en cualquier parte del código.
• Ejemplos:
– ejemplo1.c
– ejemplo2.c
4
Tipos de datos, variables y
constantes.
/*
*
*/
EJEMPLO2.C
/*Fichero Incluido*/
#include <stdio.h>
/*Variable Global*/
int numero = 1;
/*Prototipo de la Funcion*/
void escribe(void);
/*Funcion Main*/
void main(void)
{
/*Variable Local*/
int numero = 0;
printf("Esto es una variable local de main. Numero = %d\n", numero);
if (1)
{
int numero = 2;
printf("Esto es una variable local del if de main. Numero = %d\n", numero);
}
printf("Esto es una variable local de main. Numero = %d\n", numero);
/*LLamada a la funcion escribe*/
escribe();
}
Tipos de datos, variables y
constantes.
/*Funcion escribe*/
void escribe(void)
{
printf("Esto es una variable global. Numero = %d\n", numero);
if (1)
{
int numero = 2;
printf("Esto es una variable local del if de escribe. Numero = %d\n", numero);
}
printf("Esto es una variable global. Numero = %d\n", numero);
}
5
Tipos de datos, variables y
constantes.
• Especificadores de clase de almacenamiento:
– Variables externas (extern): se utilizan para definir
variable globales que deben ser conocidos por los
distintos módulos de código que forman un proyecto.
– Variables estáticas (static): son variables permanentes
dentro de su propia función o archivo.
• Variables estáticas locales: Se crea un almacenamiento
permanente para ellas, pero su contenido es conocido
únicamente dentro de su bloque.
• Variables estáticas globales: Se indica de esta forma al
compilador que cree una variable global que únicamente puede
ser conocido dentro del archivo en el que se ha declarado.
– Variables registro (register): Son variables que deben
tener un acceso “los más rápido posible”
Tipos de datos, variables y
constantes.
• Constantes: Valores fijos que no pueden ser
modificados por el programa.
• Definición de las constantes:
const tipo nombre_constate = valor;
• Ejemplos:
– const char a = ‘p’;
– const float constante = 2.5;
• Constantes hexadecimales: 0xa02.
• Constantes octales : 072
• Constantes de cadenas, o tira de caracteres:
“hola”.
6
Tipos de datos, variables y
constantes.
• Constantes de caracteres especiales:
\b
\f
\n
\r
\t
\”
\’
\0
\\
\v
\a
\N
\xN
Espacio atrás
Salto de página
Salto de línea
Salto de carro
Tabulación horizontal
Comillas dobles
Comilla simple
Nulo
Barra invertida
Tabulación vertical
Alerta
Constante octal (N es cte. octal)
Constante hexadecimal (N es cte.
hexadecimal)
Tiras de caracteres (string), printf() y
scanf().
• Una tira de caracteres es una serie de uno o más
caracteres.
• No existe ningún tipo especial para ellos. Se
almacenan como un array de caracteres.
• Ejemplo:
– char tira[]=“Esto es un string”;
E s t o
e s
u n
s t r i n g \0
– El carácter nulo se utiliza en C para marcar el fin de un
string. Dicho carácter no es el cero, sino un carácter no
imprimible que le corresponde el codigo ASCII 0.
7
Tiras de caracteres (string), printf() y
scanf().
• Printf() y scanf() nos permite comunicarnos con el
exterior a traves de la pantalla y el teclado
respectivamente (entradas y salidas estandar).
• Formato de printf():
printf(“tira de control[Identificadores]”,variables);
• Identificadores:
%d ⇒ Entero decimal.
%c ⇒ Carácter.
%s ⇒ String.
%e ⇒ Número de coma flotante en formato notación
exponencial.
– %f ⇒ Número de coma flotante en notación decimal.
–
–
–
–
Tiras de caracteres (string), printf() y
scanf().
• Identificadores (continuación):
–
–
–
–
%g ⇒ usa %f o %e, el que sea más corto.
%u ⇒ Entero decimal sin signo.
%o ⇒ Entero octal sin signo.
%x ⇒ Entero hexadecimal sin signo.
• Ejemplos:
1.- printf(“Lo mas sencillo”); ⇒ Lo mas sencillo.
2.- int x = 3;
⇒ x=3
printf(“ x = %d”,x);
3.- double x = 2.0, y = 3.0;
printf(“x = %f, “, x);
x = 2.0, y = 0.3e+001
⇒
x*y = 6.0
printf(“y = %e.\n”, y);
printf(“x*y = %f.”, x*y);
8
Tiras de caracteres (string), printf() y
scanf().
• scanf() se utiliza para introducir información a
través del teclado.
• scanf() usa una tira de caracteres de control y una
lista de argumentos, donde la tira de caracteres
indica los tipos de las variables, y la lista de
argumentos son los punteros (direcciones) a dichas
variables.
• Forma de representar los punteros a una variables:
– Si variable es: tipo x; ⇒ su dirección es &x;
– Si variable es: tipo x[]; (es decir, es un array) ⇒ su
dirección es x.
Tiras de caracteres (string), printf() y
scanf().
• Las tiras de control son idénticas a las de printf(),
con las siguientes excepciones:
– No existe la opción %g.
– Las opciones %f y %e son equivalentes.
– Existe una opción %h para leer enteros short.
• Ejemplos:
– int dia; float hora; scanf(“%d %f”, &dia, &hora);
– char nombre[30]; scanf(“%s”, nombre);
• Realizar un programa que calcule la longitud de
un circulo y el área de una circunferencia. El radio
debe ser una variable global. Los dos calculos
deben hacerse en funciones separadas.
9
getchar(), getch() y putchar()
• getchar() y putchar() tienen cierta semejanza con
scanf() y printf(). El primero toma un carácter de
teclado, y el segundo manda un carácter a la
pantalla.
• getch() toma también un carácter, pero a
diferencia del anterior, no produce eco en la
pantalla y no es necesario pulsar la tecla ENTER.
• Esta última instrucción nos puede servir para
hacer una pausa en la ejecución de nuestro
programa.
Operadores, expresiones y
sentencias.
• Operadores básicos:
– Operador de asignación: =
• No es del todo equivalente al igual matemático. A la derecha
siempre estará el valor a asignar, mientras a la izquierda
tenemos el nombre de la variable ⇒ La asignación se realiza
de derecha a izquierda.
• Es válido la siguiente expresión: i = i +1;
• Son validas multiples asignaciones: a = b = c = 1.0;
– Operador de adición: +
– Operador de sustracción: – Operador signo: • Sirve, además de para indicar el signo negativo, para cambiar
el signo algebraico de un valor.
10
Operadores, expresiones y
sentencias.
• Operadores básicos (continuación):
– Operador de multiplicación: *
– Operador de división: /
• El resultado de una división de valores enteros da como
resultado un entero, por ejemplo, 5/2 = 2. El redondeo que se
produce es siempre por defecto.
• Precedencia en los operadores básicos:
Operador
Asociatividad
()
- (unario)
*/
+ - (sustracción)
=
Izquierda a Derecha
Izquierda a Derecha
Izquierda a Derecha
Izquierda a Derecha
Derecha a Izquierda
Operadores, expresiones y
sentencias.
• Otro operadores adicionales:
– Operador módulo: %
• Proporciona el resto de la división de dos números enteros. Por
ejemplo: 13%5 = 3.
• Sólo es valido para números enteros.
– Operadores incremento y decremento: ++ y -• Aumenta o disminuye en uno el valor de su operando.
• Existen dos variadades:
– postincremento (postdecremento): a++ (a--)
– preincremento (predecremento): ++a (--a)
• El primero es usado antes de cambiar: valor = 2 * a++;
• El segundo cambia antes de usar: valor = 2 * ++a;
• La precedencia de estos operadores sólo es superada por la de
los paréntesis.
11
Operadores, expresiones y
sentencias.
• La expresiones son las combinaciones de los
operandos.
• Ejemplos: 4; -6, 4*2, a*(b+c/3)-4/3, a=(3+b++)/c,
a = q > 3, 6 + (a = 4 + 3)
• En C cada expresión tiene un valor.
• Las sentencias son los elementos con los que se
construyen los programas. Además, es una
instrucción completa para el ordenador y, por lo
tanto, completa una acción.
• En C una sentencia se representa acabandolas en
punto y coma. Por lo tanto, a=3 es una expresión,
mientras a=3; es una sentencia.
Operadores, expresiones y
sentencias.
• Una sentencia implica una instrucción, pero una
instrucción no tiene porque implicar una
sentencia. Por ejemplo: x = 6 + (y = 3 + 2); es una
sentencia pero dos instrucciones.
• Se denomina sentencia compuesta a un conjunto
de dos o más sentencias agrupadas y encerradas
entre llaves. Se le denomina también bloque. Se
utilizan en condicionales y bucles.
12
Condicionales
• Las condicionales nos van a permitir tomar
decisiones durante la ejecución de nuestro
programa. Dos ordenes: if y switch.
• Formato de if:
• Ejemplos:
if (condicional1)
{
sentencias;
}
else if (condicional2)
{
sentencias;
}
else
{
sentencias;
}
1.- if (a > 3)
x=5;
2.- if (condicion1)
{
if (condicion2)
a = 0;
b=1;
condicion1 = 0;
}
else
condicion1 = 1;
Condicionales
• Siempre que la condición sea verdadera, se
ejecutará las sentencias que tenga asociada.
• Las condicionales son expresiones, y
consideraremos que es verdadera siempre que su
valor sea distinto de 0. En caso de ser 0 la
condicional es falsa.
• Para escribir las condicionales usaremos los
operadores de relación y los operadores lógicos.
• Operadores de relación
–
–
–
–
–
–
< ⇒ menor que.
<= ⇒ menor o igual que.
= = ⇒ igual a.
>= ⇒ mayor o igual que.
> ⇒ mayor que.
!= ⇒ distinto de.
13
Condicionales
• Los operadores de relación no sirven para
comparar tiras de caracteres.
• Se pueden usar con números en coma flotante,
pero se aconseja exclusivamente > y/o <.
• La prioridad de los operadores de relación es
menor que el de + y -, pero mayor que el de
asignación. Por ejemplo: x = 8 > 3+2 es
equivalente a x = 8 > (3+2) y da como resultado
x=0, es decir, falso.
• Dentro de los propios operadores,los más
prioritarios son: <, <=, >= y >. Son menos
prioritarios = = y !=. La asociatividad se realiza de
izquierda a derecha.
Condicionales
• Operadores lógicos:
– && ⇒ Y
– || ⇒ O
– ! ⇒ NOT
• La prioridad de ! es la misma que la los
operadores incremento (++) y decremento (--),
sólo superada por los paréntesis.
• La prioridad de && es mayor que la de || estando
ambos situados por debajo de los operadores de
relación.
• La asociatividad de todos ellos es de izquierda a
derecha.
14
Condicionales
• Ejemplo4:
/*
* EJEMPLO$.c
*/
#include <stdio.h>
#define TRUE 1
#define FALSE 0
void main(void)
{
int ch;
/*introducción de caracteres*/
long nc = 0;
/*Número de caracteres*/
int nl = 0;
/*Número de líneas*/
int np = 0;
/*Número de palabras*/
int palabra = TRUE;
/*Número de palabras*/
int terminar = FALSE; /*Condicion de fin de bucle*/
terminar = (ch = getchar()) == '-';
Condicionales
while ( !terminar )
{
nc++;
if (ch == '\n')
nl++;
if ( ch != ' ' && ch != '\n' && ch != '\t' && palabra == FALSE)
{
palabra = TRUE;
np++;
}
if ( (ch == ' ' || ch == '\n' || ch == '\t') && palabra == TRUE)
palabra = FALSE;
terminar = (ch = getchar()) == '-';
}
printf("Caracteres = %ld.\nPalabras = %d.\nLineas = %d.\n", nc, np, nl);
}/*main*/
15
Condicionales
• En C existe una forma compacta de expresar la
sentencia if-else. Es el operador condicional.
• Formato del operador condicional ?:
– var = expresión1 ? expresión2 : expresión3;
– var toma el valor expresión2 si expresión1 es cierta. Si
es falsa, entonces var toma el valor de expresión3.
– Ejemplo:
• x = (a>b) ? c:d; es equivalente a
• if (a>b)
x = c;
else
x = d;
Condicionales.
• La otra instrucción en C para representar una
condicional es switch.
• Es una forma de simplificar las instrucciones ifelse if-else if -...- else.
• Formato de switch:
switch (valor){
case constante1: sentencias;
break;
case constante2: sentencias;
break;
...
case constanten: sentencias;
break;
default: sentencias;
}
16
Condicionales
• Algunas características:
– Sólo puede comprobar la igualdad.
– No puede haber dos constantes case que tengan los
mismos valores.
– Se puede utilizar las misma sentencias para distintos
case de la siguiente forma:
switch (ch){
case ‘a’:
case ’b’:
case ‘c’: sentencias;
break;
...
Default: sentencias;
}
– Está permitido el uso de switch anidados.
Condicionales.
• Ejemplo5: Realizar un programa que ofrezca unas
determinadas opciones al usuario (por ejemplo,
realizar distintas operaciones matemáticas) y que
en función de la opción solicitada realice dicha
tarea.
17
Bucles
• Los bucles son estructuras que nos permiten
repetir una parte de código las veces que
necesitemos. (Por ejemplo: multiplicación de
matrices).
• Dos tipos:
– while y do...while
– for
• while tiene el siguiente formato:
– while (condicion)
{
sentencias;
}
Bucles
• La condición es una expresión de test, de tal forma
que si es verdadera se ejecutará dicho bucle y si es
falsa no se ejecutará. Este hecho implica que dicha
condición de test se debe modificar durante la
ejecución del bloque asignado al bucle. En caso de
no ser así nos encontrariamos con un bucle
infinito.
• Para la condición de test se pueden usar todos los
operadores vistos hasta ahora (aritmético, de
relación y condicionales).
18
Bucles
• do...while tiene el siguiente formato:
– do{
sentencias;
} while (condición);
• La estructura do...while siempre se ejecuta, al
menos, una vez, mientras que while puede o no
ejecutarse depediendo del valor de la condición.
• Excepto esta situación, no existe ninguna
diferencia entre ambas estructuras.
Bucles
• Ejemplo6:
/*
*
*/
EJEMPLO5.c
#include <stdio.h>
#include <conio.h>
void main (void)
{
int datos[] = {1,4,5,7,9,10,22,25,27,30,33,34,35,37,39,40,50,55,60}; /*array
de 19 datos de tipo entero ordenados de menor a
mayor*/
int entrada; /*Variables para definir numero a buscar*/
int maximo = 18,minimo = 0; /*Rango de busqueda*/
int posicion; /*variable utilizada para definir la posicion de busqueda*/
int k = 0; /*variable utilizada para mostrar en pantalla los posibles valores
a buscar y para definir el numero de pasos utilizado para buscar
la entrada*/
19
Bucles
printf("Selecciona un valor de los mostrados a continuacion:\n");
while (k<19)
{
printf("%d ", datos[k]);
k++;
}/*fin while*/
printf("\n");
scanf("%d", &entrada);
k = 1;
posicion =(maximo-minimo+1)/2;
while ( entrada != datos[posicion] )
if (datos[posicion] > entrada)
{
k++;
maximo = posicion;
posicion = posicion - (maximo - minimo+1)/2;
}/*fin if*/
else if (datos[posicion] < entrada)
{
k++;
minimo = posicion;
posicion = posicion + (maximo - minimo+1)/2;
}/*fin else if*/
printf("\nEl dato encontrado ha sido el %d.\nEl numero de pasos para"
"encontrarlo ha sido %d", datos[posicion], k);
getch();
}/*fin main*/
Bucles
• Modificar el programa anterior para que, en caso
de que el numero introducido no pertenezca a la
lista, lo indique. Además añadir la opción de que
el usuario pueda repetir la búsqueda las veces que
desee.
• Formato de for:
– for (inicialización variable; condicion de test; expresión
de modificación de la variable)
{
sentencias;
}
• La inicialización se realiza sólo una vez al
comienzo del bucle.
20
Bucles
• La condición de test se realiza antes de cada
posible ejecución del bucle. Si la condición es
falsa, el bucle finaliza.
• La expresión de modificación de la variable se
evalúa al final de la ejecución de cada bucle.
• Ejemplo:
– for(n=1; n<=1000;n++);
{
sentencias;
}
• El bucle for da mucha flexibilidad:
– for (n = 10; n > 0; n--)
Bucles.
• El bucle for da mucha flexibilidad (continuación):
–
–
–
–
–
for (n = 1; n < 60; n + = 10)
for (n = 1; n < 1000; n *= 10)
for (ch = ‘a’; ch <= ‘z’; ch++)
for (n = 1; n*n < 1000; n++)
for (n = 1; n*n > 10; ) ⇒ Hay que introducir la
expresión de modificación de la variable dentro del
bucle.
– for (printf(“Introducir numero”); n = 10; )
scanf(“%d”, &n);
– for (n = 0, m = 1; n < 10; n++, n *= 10)
• Las dos estructuras de bucles ( while y for)
permiten anidamiento;
21
Bucles
• Ejemplo6:
/*
*
*/
EJEMPLO6.c
#include <stdio.h>
#include <conio.h>
void main(void)
{
float a[100][100], b[100][100]; /*Matriz a y b de entrada*/
int filas = -1, columnas = -1; /*Numero de filas y columnas de las matrices*/
int f, c; /*Indices del for*/
char matriz;
while ( ((filas == -1) && (columnas == -1)) || ((filas >= 100) || (columnas >= 100)) )
{
printf("Numero de filas? (maximo = 100)\n");
scanf("%d", &filas);
printf("Numero de columas? (maximo = 100)\n");
scanf("%d", &columnas);
}
Bucles
for(matriz = 'a'; matriz < 'c'; matriz++)
for(f = 0; f < filas; f++)
for(c = 0; c < columnas; c++)
switch (matriz){
case 'a': printf("a[%d,%d] = ", f+1, c+1);
scanf("%f", &a[f][c]);
printf("\n");
break;
case 'b': printf("b[%d,%d] = ", f+1, c+1);
scanf("%f", &b[f][c]);
printf("\n");
}
for(f = 0; f < filas; f++)
for(c = 0; c < columnas; c++)
printf("s[%d,%d] = %f\n", f+1, c+1, a[f][c]+b[f][c]);
getch();
}
22
Funciones y Punteros.
• Hasta ahora funciones implementadas en las
librerías estándar de C: printf, scanf ...
• Formato de una función:
tipo_función nombre_función (lista de parámetros)
{
Cuerpo de la función;
}
• Con tipo_función especificamos el tipo del dato
que devuelve la función. Para devolver el dato
desde la función hay que utilizar la sentencia
return(dato_devuelto); En el caso de que la
función no devuelva ningún dato se utiliza el tipo
void.
Funciones y Punteros.
• La lista de parámetros es la lista de nombres de
variables, separadas por comas, con sus tipos
asociados que reciben los valores de los
argumentos cuando se llama a la función. En el
caso de que no existan parámetros de entrada a la
función se utiliza void.
• Ejemplo:
int EsMayor(int x, int y)
{
if (x > y)
return(1);
else
return(0);
}
23
Funciones y Punteros.
• Dos métodos para pasar argumentos a las
funciones:
– Llamada por valor.
– Llamada por referencia.
• Cuando se hace una llamada por valor, lo que se
hace es copiar el valor de un argumento en el
parámetro formal de la función (ejemplo anterior).
Este método se utiliza cuando no se pueden, o no
necesitamos, modificar las variables usadas para
llamar a la función.
Funciones y Punteros.
• Con la llamada por referencia lo que se hace es
copiar la dirección del argumento en el parámetro
formal de la función. Dentro de la función se usa
esta dirección para acceder al argumento usado en
la llamada.
Debido al hecho de que dentro de la función no
trabajamos con la variable, sino con su dirección
en memoria, vamos a poder modificar los valores
de dichos parámetros.
• Ejemplo de llamada por referencia:
24
Funciones y Punteros.
void main(void)
{
int mayor, menor, igual;
...
igual = Ordena(&mayor, &menor);
...
}
int Ordena(int *x, int *y)
{
int auxiliar;
if (*x < *y)
{
auxiliar = *x;
*x = *y;
*y = auxiliar;
return(0);
}
else if (*x == *y)
return(1);
}
Funciones y Punteros.
• Un puntero es una variable que contiene una
posición de memoria
• Declaración de variable puntero:
tipo *nombre_variable;
• tipo es cualquier tipo válido de C y define el tipo
válido al que puede apuntar el puntero.
• Operadores de punteros:
– &
– *
• El operador & es un operador monario que
devuelve la dirección de memoria de su operando.
Por ejemplo: m = &cuenta;
25
Funciones y Punteros.
• El operador * es el complemento de &. Es un
operador monario, que devuelve el valor de la
variable localizada en la dirección que marca su
operando. Por ejemplo: q = *m;
• Un puntero puede utilizarse a la derecha de una
operación de asignación`para asignar su valor a
otro puntero. Por ejemplo:
int x;
int *p1, *p2;
p1 = &x;
p2 = p1;
Funciones y Punteros.
• Arimética de punteros: sólo es valido el uso de la
suma y la resta con enteros.
• Cuando realizamos una suma o una resta sobre un
puntero lo que hacemos es que dicho puntero
apunte a la posición de memoria posterior o
anterior indicada por la operación, teniendo en
cuenta los bytes que ocupan su tipo asociado.
• Ejemplo:
char *p1 = 0x2000; /* 1 char = 1 byte */
int *p2 = 0x3000; /* 1 int = 4 bytes */
p1++; /* p1 = 2001 */
p2++; /* p2 = 0x2004 */
26
Funciones y Punteros.
• Es valido la utilización de operadores de relación
con los punteros.
• Está permitida la indirección múltiple, es decir, un
puntero que apunte a otro puntero.
• Ejemplo:
void main(void)
{
int x = 10, *p1, **p2;
p1 = &x;
p2 = &p2;
printf(“%d”, **p2);
}
Funciones y Punteros.
• La inicialización de un puntero es una fase crítica,
ya que en el caso de no inicializarlo bien, vamos a
acceder a posiciones de memoria no validas, lo
cual llevará o, al mal funcionamiento del
programa, o a un error grave en el sistema.
• Por convenio se asigna el valor nulo (\0) para
inicializarlo, indicado que no apunta a nada.
• Los punteros es una de las herramientas más
potente de C, pero es también la que nos puede
producir los errores más complicados de
encontrar.
27
Funciones y Punteros.
• Es necesario siempre que usemos una función
definir su prototipo.
• El prototipo de una función no es más que la
declaración del número y tipos de los argumentos
utilizados en dicha función. De esta forma se
puede realizar una comprobación de estos
parámetros para evitar errores.
• Formato para la definición del prototipo de una
función:
tipo_función nombre_función (tipo parámetro 1, ..., tipo
parámetro n);
• Por ejemplo:
– int Ordena(int *, int *);
Funciones y Punteros.
• Ejemplo7:
/*
*
*/
EJEMPLO7.c
#include <stdio.h>
#include <conio.h>
void Numeros(int *, int *);
int Compara(int *, int *);
void Muestra(int, int, int);
void main(void)
{
int mayor = 0, menor = 0;
int es_igual;
Numeros(&mayor, &menor);
es_igual = Compara(&mayor, &menor);
Muestra(es_igual, mayor, menor);
getch();
}
28
Funciones y Punteros.
void Numeros(int *x, int *y)
{
printf("x = ");
scanf("%d", x);
printf("y = ");
scanf("%d", y);
}
int Compara(int *x, int *y)
{
int auxiliar;
if (*x == *y)
return(1);
if (*x < *y)
{
auxiliar = *x;
*x = *y;
*y = auxiliar;
}
return(0);
}
void Muestra(int iguales, int mayor, int menor)
{
if (iguales)
printf("Ambos numeros son iguales");
else
printf("El valor %d es mayor que el valor %d", mayor, menor);
}
El Preprocesador de C
• Se pueden incluir varias instrucciones dirigidas al
compilador en el código fuente. Se denominan
directivas de preprocesamiento.
• El preprocesador contiene las siguientes
directivas:
#if
#else
#define
#error
#ifdef
#elif
#undef
#pragma
#ifndef
#include
#line
• Todas empiezan con #.
• Cada directiva de preprocesamiento debe estar en
su propia línea.
29
El Preprocesador de C
• La directiva #define, define un identificador y una
cadena que será sustituida por el identificador cada
vez que se encuentre en el archivo fuente.
• Formato:
#define nombre_de_macro cadena
• Ejemplos:
– #define TRUE 1
– #define UNO 1
#define DOS UNO+UNO
• El nombre de macro puede tener argumentos
• Ejemplos:
– #define ABS(a) (a) < 0 ? -(a) : (a)
– #define CUADRADO(x) x*x
El Preprocesador de C.
• La directiva #include hace que el compilador
incluya otro archivo fuente al propio que tiene a
esta directiva.
• Formato:
#include <fichero>
#include “fichero”
• Lo normal es incluir lo que se denominan ficheros
de cabecera. Estos ficheros tienen definidos otras
directivas así como prototipos de funciones.
• Ejemplos:
– #include <stdio.h> (está definido el prototipo de printf
y scanf).
– #include <conio.h> (está definido el prototipo de getch)
30
El Preprocesador de C.
• Si el fichero de cabecera esta definido entre < y >
el compilador busca el fichero en un directorio
definido por defecto.
• Si el fichero de cabecera esta definido entre
comillas dobles el compilador busca el fichero en
el mismo directorio donde se encuentra el resto de
código fuente. Se utiliza cuando hemos creado
nosotros mismo el fichero de cabecera.
• Siempre se puede especificar el directorio donde
se encuentra el fichero de cabecera.
El Preprocesador de C.
• La directiva #error fuerza al compilador a parar la
compilación y se muestra el mensaje de error
definido en la propia directiva. (#error mensaje de
error)
• Si la constante que sigue a #if es cierta, se compila
el código que hay entre el #if y el #endif. En caso
contrario se ignora este código. Al evaluarse en
tiempo de compilación no pueden utilizarse
variables para la evaluación. Sólo pueden usarse
constantes e identificadores definidos
anteriormente.
• #else es equivalente a else.
• #elif es equivalente a else if.
31
El Preprocesador de C.
• #ifdef (si definido) e #ifndef (si no definido) es
otro método de compilación condicional. Chequea
si se ha definido o no una macro con #define,
compilandose el bloque de sentencias en caso de
ser cierto. Al igual que con #if el bloque a
compilar termina con #endif. Puede usarse
también #else, aunque no #elif
• La directiva #undef elimina una definición de
macro definida anteriormente con #define.
• #line modifica los contenidos de los
identificadores predefinidos _LINE_ y _FILE_
• #pragma es una directiva definida por la
implementación del compilador y que permite que
se le de ordenes a este.
Arrays , Estructuras y Uniones.
• Un array en una serie de datos del mismo tipo.
• A la hora de definirlo es necesario especificar no
sólo el tipo de dato a almacenar, sino el número a
almacenar.
• Definición e inicialización de un array:
tipo_dato nombre_array[número de datos] = {primer
elemento, segundo elemento,...};
tipo_dato nombre_array[] = {primer elemento, segundo
elemento,...};
• Llamada a un elemento de un array: x[i], donde i
es el índice. Para el primer elemento i = 0 y para el
último i =numero de datos-1.
int x[3] = {1, 2, 3};
printf(“x = %d, y = %d, z = %d”, x[0], x[1], x[2]);
32
Arrays , Estructuras y Uniones.
• Los arrays y los punteros están muy relacionados,
ya que el nombre de un array es también un
puntero que apunta al primer elemento del array.
Es decir, si tenemos definido un array x de tres
elementos ⇒ x = = &x[0], x + 1 = = &x[1], x + 2
= = &x[2], *x = = x[0], *(x+1) = = x[1] y *(x+2)
= = x[2].
• El uso de punteros sobre arrays es más mucho
eficiente.
• La llamada a una función que trabaja sobre un
array se realiza pasandole como argumento el
nombre del array, es decir, le pasamos un puntero.
La función usa este puntero para realizar los
cambios sobre el array original.
Arrays , Estructuras y Uniones.
• Ejemplo: int x[3]; funcion(x);
• Existen dos formas de definir la variable puntero
que trabajará sobre el array:
tipo_función nombre_función (tipo *nombre_array)
{
Cuerpo función
}
tipo_función nombre_función (tipo nombre_array[])
{
Cuerpo función
}
33
Arrays , Estructuras y Uniones.
• Ejemplo 8:
/*
*
*/
Ejemplo8.c
#include <stdio.h>
#include <conio.h>
#define NUMERO_DATOS 10
float Maximo(float *);
float Suma(float *);
void main(void)
{
float datos[]={1.9, 5.9, 8.7, 3.6, 23.6, -2.9, -12.1, 33.4, 42.7, -56.5};
printf("El maximo valor de la lista es el %f\n", Maximo(datos));
printf("La suma de los elementos de la lista es %f\n", Suma(datos));
getch();
}
Arrays , Estructuras y Uniones.
float Maximo(float *datos)
{
int k;
float max = 0.0;
for(k = 0; k < NUMERO_DATOS; k++)
if ( *(datos+k) > max )
max = *(datos+k);
return(max);
}
float Suma(float *datos)
{
int k;
float suma;
for(k = 0; k < NUMERO_DATOS; k++)
suma += *(datos+k);
return(suma);
}
34
Arrays , Estructuras y Uniones.
• Es posible la definición de arrays multidimensionales (array de array).
• Definición e inicialización :
tipo_array nombre_array[n1] [n2]...[nm];
tipo_array nombre_array[] []...[] = {{elem111, elem112,
..., elem11m}, {elem121, elem122,..., elem12m},...};
• Ejemplo:
– int x[2] [2] = {{1,2}, {3,4}};
• La llamada a un elemento del array se hace de
forma equivalente a un array unidimensional:
x[i][j].
Arrays , Estructuras y Uniones.
• Con respecto a los punteros se verifica que:
– x == x[0] == &x [0][0]
– x [1] == &x [1] [0]
• La definición de un puntero equivalente al array
anterior sería:
– int (*x) [2] ;
• Una estructura es una colección de variables que
se referencia bajo un único nombre.
• La definición de una estructura forma una plantilla
que puede utilizarse para crear variables de
estructura.
• Las variables que forman una estructura deben
estar relacionadas.
35
Arrays , Estructuras y Uniones.
• Definición de una estructura:
– struct nombre_estructura{
tipo nombre_variable_1;
tipo nombre_variable_2;
...
tipo nombre_variable_n;
};
struct nombre_estructura nombre_variable_estructura;
– struct nombre_estructura{
tipo nombre_variable_1;
tipo nombre_variable_2;
...
tipo nombre_variable_n;
} nombre_variable_estructura_1, nombre_variable_estructura_2,...;
Arrays , Estructuras y Uniones.
• Ejemplos:
– struct ficha{
char nombre[20];
char apellidos [60];
int edad;
};
struct ficha PrimeraFicha;
– struct ficha{
char nombre[20];
char apellidos [60];
int edad;
} PrimeraFicha;
36
Arrays , Estructuras y Uniones.
• La forma de referenciar a un elemento de la
estructura es:
– PrimeraFicha.nombre[0];
– PrimeraFicha.edad;
• Es posible definir arrays de estructuras. Para ello
debe estar definido en primer lugar la estructura y
luego definir una variable array de dicho tipo.
• Ejemplo:
– struct ficha Fichas[100];
• En este caso la referencia se realiza de la siguiente
forma:
– Fichas[0].edad;
Arrays , Estructuras y Uniones.
• Para pasar un elemento de una estructura a una
función se hace de forma equivalente a como
hemos visto hasta ahora.
• Para pasar una estructura completa como
argumento a una función se hace mediante una
llamada por valor o por referencia.
• En el primer caso los cambios realizados en la
función no afectan al valor original de la
estructura.
37
Arrays , Estructuras y Uniones.
• Ejemplo:
struct estructura{
char ch;
int x, y;
} nombre;
void main (void)
{
...
funcion(nombre);
...
}
void funcion(struct estructura arg)
{
...
}
Arrays , Estructuras y Uniones.
• Para realizar una llamada por referencia es
necesario definir un puntero a una estructura.
• Para definir la variable puntero a la estructura se
hace deforma equivalente ha lo visto hasta ahora:
– struct nombre_estructura *nombre_variable;
• Una vez definido el puntero a la estructura, el
acceso a los elementos de dicha estructura se
realiza de la siguiente forma:
struct estuctura{
char ch;
int x, y;
} *nombre;
nombre->ch;
nombre->x;
38
Arrays , Estructuras y Uniones.
• Ejemplo 9:
/*
*
*/
EJEMPLO9.C
#include <stdio.h>
#include <conio.h>
struct fichas{
char nombre[15];
char apellidos[50];
int edad;
};
void IncluirDatos(struct fichas *, int);
void MostrarDatos(struct fichas *, int);
void main(void)
{
struct fichas Fichas[2];
IncluirDatos(Fichas,2);
MostrarDatos(Fichas,2);
getch();
}
Arrays , Estructuras y Uniones.
void IncluirDatos(struct fichas *Fichas, int nfichas)
{
int k;
for(k=0; k < nfichas; k++)
{
printf("Nombre = ");
scanf("%s", &((&Fichas[k])->nombre));
printf("Apellidos = ");
scanf("%s", &((&Fichas[k])->apellidos));
printf("Edad = ");
scanf("%d", &((&Fichas[k])->edad));
printf("\n");
}
}
void MostrarDatos(struct fichas *Fichas, int nfichas)
{
int k;
for(k=0; k < nfichas; k++)
{
printf("Nombre = %s\n", (Fichas+k)->nombre );
printf("Apellidos = %s\n", (Fichas+k)->apellidos);
printf("Edad = %d\n\n", (Fichas+k)->edad);
}
}
39
Arrays , Estructuras y Uniones.
• Una unión es una posición de memoria que es
compartida por dos o más variable diferentes,
generalmente de distinto tipo, en distintos
momentos.
• La definición es similar a la de estructura:
union nombre{
tipo variable_1;
tipo variable_2;
...
tipo variable_n;
} nombre_variable_union;
• El acceso a las variables y los puntero son
identicos que con las estructuras.
40
Descargar