Actualizado el 20 de Mayo del 2018 (Publicado el 18 de Enero del 2017)
799 visualizaciones desde el 18 de Enero del 2017
211,5 KB
8 paginas
Creado hace 16a (26/09/2008)
Algoritmos y Estructuras de Datos
2º de Ingeniería Informática, Curso 2008/2009
SEMINARIO “C para programadores java”
(este seminario forma parte de las actividades del proyecto piloto)
Sesión 3
Contenidos:
1. Funciones
2. Gestión dinámica de memoria.
3. Funciones de E/S.
Ejercicios
Algoritmos y Estructuras de Datos, 2007/2008
Seminario de C – Sesión 3
1. Funciones
• Estructura de definición de funciones:
tipo_devuelto nombre_función ( parámetros ) { cuerpo }
2/8
int suma (int a, int b) {
Ej.: int r= a+b;
return r;
}
• Una función no se puede declarar dentro de otra (no se pueden anidar), aunque sí
se pueden definir y anidar bloques: { … { … } … { { } … } …}
• Valor devuelto.
o Sólo puede haber 1 tipo devuelto (como en Módula o Pascal).
o Si no devuelve nada se pone: void
o Por defecto, si no se pone nada, se supone que devuelve un int.
o Se puede devolver un struct o union, pero no un array. En su lugar, se
o Acabar la ejecución del procedimiento: return;
o Acabar y devolver un valor: return expresion;
puede devolver un puntero al array.
• Parámetros.
o Lista de pares: (tipo1 nombre1, tipo2 nombre2, ...)
o Cada nombre debe llevar su tipo (aunque se repitan).
o El paso es siempre por valor.
o Simulación del paso por referencia: usar punteros.
r= a + *b;
void suma2 (int a, int *b) {
int r;
*b= r;
}
o OJO: no devolver variable local por referencia: la variable local está
en la pila, y desaparece al acabar la ejecución de la función. Ejemplo:
void suma3 (int a, int b) {
int r;
r= a + *b;
return &r;
}
o Paso de arrays:
float media (int array[], int tamanno) ...
• no se especifica el tamaño del array a recibir;
• el paso de parámetros array es por referencia: se accede al array
original a través de la variabl-parámetro
• alternativa: usar punteros (int * array en vez de int array[])
• Ejemplo de función recursiva:
int factorial(int n) {
if (n=0) return 1;
return n*factorial(n-1);
}
Algoritmos y Estructuras de Datos, 2007/2008
Seminario de C – Sesión 3
• Variables locales.
3/8
llamada. Insistimos: no devolver por referencia.
o Se crean en la pila para cada llamada y se eliminan al acabar la
o Se llaman variables auto; auto es la opción por defecto, no hace falta
o Deben ir siempre al principio del cuerpo de la función, justo después de
o Variables locales static:
las llaves, {. Nunca entre líneas de código. En C++ sí se puede.
indicarla.
primero: olvidar significado de variable static en java1 (variable
de clase compartido por todos los objetos de esa clase);
en C, son variables:
locales en cuanto a visibilidad
•
• globales en cuanto a tiempo de vida:
o existen haya o no haya en marcha una ejecución
o conservan sus valores entre distintas llamadas
de la función;
Inicializar en declaración; se ejecutará sólo en la primera llamada.
OJO: no usar junto con recursividad: hay una sóla instancia de la
variable para todas las llamadas recursivas a la función; ejemplo:
pensar función factorial, implementada con variable static ¿?
Ejemplo de uso:
int ticket(void) {
static int turno=1;
return turno++;
}
o Variables locales register: sugiere al compilador que la variable sea
almacenada en un registro de la CPU (a ser posible).
float media (int array[], int tam) {
static float acum;
register int i;
for (i= 0, acum= 0; i<tam; i++)
acum+= array[i];
return acum/tamanno;
}
• Declaración de una función. En algunos casos puede ser necesario declarar la
sintaxis de la función antes de definirla (p. ej. si hay doble recursividad).
tipo_devuelto nombre_función ( parámetros );
o En la lista de parámetros se pueden poner sólo los tipos (omitir los
int suma (int, int);
float media (int [], int);
nombres).
1 ¿sabéis lo que son las variables static en java?
Algoritmos y Estructuras de Datos, 2007/2008
Seminario de C – Sesión 3
• Parámetros y valor devuelto por la función main.
4/8
o Valor devuelto. Si existe, debe ser un int. Es el valor devuelto por el
o Parámetros. Indican los argumentos escritos por el usuario en la línea
programa al sistema operativo, como código de error.
de comandos.
Primero: de tipo int. Número de argumentos introducidos.
Segundo: array de cadenas (char *). Indica el contenido de
esos argumentos.
main(int num_arg, char *str_arg[]){
int i;
printf("Hay %d argumentos.\n", num_arg);
for(i=0; i<num_arg; i++)
printf("Argumento %d: %s\n", i, str_arg[i]);
}
• Paso de funciones como parámetros.
o Es posible definir punteros a funciones, pasarlas como parámetros de
una función y aplicar los operadores de dirección e indirección (llamar a
la función apuntada).
o Declaración de parámetro de tipo puntero a función:
valor_devuelto (*nombre_parametro) (tipo1, tipo2, ...)
o Ejemplo.
#include <stdio.h>
#include <stdlib.h>
int suma (int a, int b)
{return a+b;}
int mult (int a, int b)
{return a*b;}
int opera (int a, int b, int (*op)(int,int))
{
return(*op)(a, b);
}
main(int argc, char *argv[]) {
int a, b;
if (argc<3) return -1; /* ERROR: faltan operandos */
a= atoi(argv[1]);
b= atoi(argv[2]);
printf("Suma: %d\n",opera(a, b, &suma));
printf("Prod: %d\n",opera(a, b, &mult));
}
Algoritmos y Estructuras de Datos, 2007/2008
Seminario de C – Sesión 3
2. Gestión dinámica de memoria
5/8
• Se puede reservar memoria en tiempo de ejecución. Las funciones para
reserva de memoria están en: stdlib.h
• Toda la memoria reservada debe ser liberada antes de acabar. Es decir, no hay
liberación automática de memoria, NO HAY RECOLECTOR DE BASURA.
• El manejo de memoria dinámica se hace usando punteros.
int *arrayDimanico;
float **matrizDinamica= NULL;
• Reserva de memoria: malloc
void * malloc (unsigned tamano)
o Reserva tamano bytes de memoria y devuelve un puntero a la zona
reservada.
arrayDinamico = (int *) malloc (100*sizeof(int));
o Devuelve NULL si no se ha podido reservar esa cantidad.
o No se inicializa la memoria.
• Reserva e inicialización de memoria: calloc
void * calloc (unsigned ndatos, unsigned size)
o Reserva ndatos*size bytes de memoria y devuelve un puntero a la
zona reservada. Se supone que size es el tamaño del tipo de datos a
escribir y ndatos el número de datos.
arrayDinamico = (int *) calloc (100, sizeof(int));
o Devuelve NULL si no se ha podido reservar esa cantidad.
o Se inicializa la memoria reservada con 0.
• Relocalizar de memoria: realloc
void * realloc (void *ptr, unsigned tamano)
cantidad de bytes dada en tamano.
o Redimensiona la cantidad de memoria reservada previamente a la nueva
o Si el nuevo tamaño es mayor, espacio nuevo no se inicializa.
o Devuelve NULL si no se pudo satisfacer la demanda.
• Liberar memoria: free
void free(void *ptr)
o Libera una zona de memoria reservada antes. No usar si ptr == NULL.
o OJO: no hay recolector de basura; liberar la memoria reservadada cuando
ya no se vaya a usar. Buena costumbre: “liberar donde se reserva”.
o No hacer free sobre puntero no inicializado o ya liberado.
o No basta con hacer ptr=NULL: eso haría que la memoria se pierda.
Algoritmos y Estructuras de Datos, 2007/2008
Seminario de C – Sesión 3
• Ejemplo.
6/8
#include <stdio.h>
#include <stdlib.h>
char *memoria= NULL;
int main() {
char c;
long i, tam= 0;
do {
tam+= 1000000;
memoria= (char *) malloc (tam);
if (!memoria) {
printf("Error. Imposible reservar más memoria.\n");
return 0;
}
printf("Reservados %ld bytes...\n", tam);
for (i= 0; i<tam; i++)
memoria[i]= (char) i;
printf("Pulse s para seguir saturando la máquina.\n");
while ((c= getchar())=='\n');
free(memoria);
} while (c=='s' || c=='S');
return 0;
}
• Otro ejemplo: páginas 310 y 311 del texto guía.
IMPORTANTE: No acceder a lo apuntado por un puntero:
- antes de que apunte a una dirección válida (variable estática, local, o de
memoria dinámica reservada previamente)
- después de haber liberado la memoria a la que apuntaba
- después de haber asignado NULL al puntero
3. Funciones de E/S
• No forman parte del lenguaje, están en librería estándar: #include <stdio.h>
• Escribir por pantalla: printf
printf ( <cadena> );
printf ( <cadena con formato>, <expresión 1>, <expresión 2>, ...);
printf("¡Buenos días!");
printf("Un entero: %d y un real: %f\n", 27*12, 3.1416);
En lugar de
System.out.println(“Un entero:“ + 27*12 + “y un real:“ +3.1416”);
Algoritmos y Estructuras de Datos, 2007/2008
Seminario de C – Sesión 3
7/8
• Especificación de formato en printf:
% [flags] [width] [.prec] [h|l|L] caracter_tipo
• Caracteres de tipo:
d, i (decimal), o (octal), u (unsigned), x, X (hexadecimal), f (float con la forma
[-]dddd.dddd), e, E, (float con la forma [-]d.dddd e[+/-]ddd), g, G (float
“inteligente”), c (char), s (string), p (puntero).
• sprintf. Igual que printf, pero en lugar de escribir en pantalla escribe el
resultado en una cadena (el primer parámetro).
char resultado[100];
sprintf(resultado, "Probando sprintf con el número %u.\n", -1);
printf(resultado);
• Leer de teclado: scanf (en lugar de
Comentarios de: SEMINARIO “C para programadores java” - Sesión 3 (0)
No hay comentarios