PROGRAMACIÓN EN ANSI C José L. Ayala Departamento de Ingeniería Electrónica jayala@die.upm.es Punteros Gestión dinámica de memoria C permite crear de forma dinámica espacio para cualquier tipo de variable y obtener su dirección en un puntero Funciones de la librería estándar (<stdlib.h>) void *malloc(size_t size) void free(void *p) void *calloc(size_t elem, size_t size) void *realloc(void *p, size_t size) Punteros Gestión dinámica de memoria #include <stdio.h> #include <malloc.h> main(){ int size; int *arr; int i = 0; printf(“Introduzca el numero de elementos del array\n"); scanf("%d",&size); if ( (arr = (int *) malloc(size*sizeof(int))) == NULL){ printf("Error: No hay memoria suficiente\n"); exit(-1); } while (i< size) { printf(”Introduzca numero %d:\n", i); scanf("%d", arr + i); ++i; } } Punteros Gestión dinámica de memoria /* Implementación de una cola con punteros */ #include <stdio.h> #define FALSE 0 #define NULL 0 typedef struct { int dataitem; struct listelement *link; } listelement; void Menu (int *choice); listelement * AddItem (listelement * listpointer, int data); listelement * RemoveItem (listelement * listpointer); void PrintQueue (listelement * listpointer); void ClearQueue (listelement * listpointer); Punteros Gestión dinámica de memoria main () { listelement listmember, *listpointer; int data, choice; listpointer = NULL; do { Menu (&choice); switch (choice) { case 1: printf ("Enter data item value to add "); scanf ("%d", &data); listpointer = AddItem (listpointer, data); break; Punteros Gestión dinámica de memoria case 2: if (listpointer == NULL) printf ("Queue empty!\n"); else listpointer = RemoveItem (listpointer); break; case 3: PrintQueue (listpointer); break; case 4: break; default: printf ("Invalid menu choice - try again\n"); break; } } while (choice != 4); ClearQueue (listpointer); } Punteros Gestión dinámica de memoria void Menu (int *choice) { char local; printf ("\nEnter\t1 to add item,\n\t2 to remove item\n\ \t3 to print queue\n\t4 to quit\n"); do { local = getchar (); if ((isdigit (local) == FALSE) && (local != '\n')) { printf ("\nyou must enter an integer.\n"); printf ("Enter 1 to add, 2 to remove, 3 to print, 4 to quit\n"); } } while (isdigit ((unsigned char) local) == FALSE); *choice = (int) local – '0'; } Punteros Gestión dinámica de memoria listelement * AddItem (listelement * listpointer, int data) { listelement * lp = listpointer; if (listpointer != NULL) { while (listpointer -> link != NULL) listpointer = listpointer -> link; listpointer -> link = (struct listelement *) malloc (sizeof (listelement)); listpointer = listpointer -> link; listpointer -> link = NULL; listpointer -> dataitem = data; return lp; } else { listpointer = (struct listelement *) malloc (sizeof (listelement)); listpointer -> link = NULL; listpointer -> dataitem = data; return listpointer; } Punteros Gestión dinámica de memoria listelement * RemoveItem (listelement * listpointer) { listelement * tempp; printf ("Element removed is %d\n", listpointer -> dataitem); tempp = listpointer -> link; free (listpointer); return tempp; } void PrintQueue (listelement * listpointer) { if (listpointer == NULL) printf ("queue is empty!\n"); else while (listpointer != NULL) { printf ("%d\t", listpointer -> dataitem); listpointer = listpointer -> link; } printf ("\n"); } Punteros Gestión dinámica de memoria void ClearQueue (listelement * listpointer) { while (listpointer != NULL) { listpointer = RemoveItem (listpointer); } } Punteros Errores frecuentes No asignar memoria antes de usar int *x; int *x; *x = 40; MAL x = &y; *x = 40; BIEN Reservar la memoria en la variable apuntada *x = (int *)malloc(200); x = (int *)malloc(200); MAL BIEN Punteros EJERCICIOS PROPUESTOS 1. Reescribir el ejercicio 5.1 usando punteros y gestión dinámica de memoria. Definir una función que devuelve el puntero a un expediente. 2. Reescribir el programa presentado para gestionar una cola, de manera que ahora gestione los registros en forma de pila. Punteros EJERCICIOS PROPUESTOS 1. Comprobar si un array contenido en una estructura se pasa por valor o por referencia cuando se pasa la estructura a una función. 2. Escribir un programa que almacene una lista de expedientes de alumnos en un array de estructuras. Contemplar las opciones de alta/baja y consulta (completa y por campo). No usar punteros. 3. Realizar el ejercicio 2 empleando punteros y gestión dinámica de memoria. 4. Escribir un programa que ordene de forma ascendente un fichero de texto por líneas. 5. Escribir 5 funciones que procesan 2 enteros de formas diferentes para devolver otro entero. Declarar un array de puntero a funciones que devuelven enteros. Escribir un programa que acepte dos enteros en línea de comandos y los procese con las funciones apuntadas en el array. Preprocesador de C Visión general Constantes y macros Inclusión de ficheros Selección Opciones en la llamada Preprocesador de C Visión general /usr/lib/cpp es el preprocesador en Unix Utilizable con otros compiladores de C Procesa un fichero de entrada y genera otro de salida Puede invocarse de forma independiente (no recomendable !!) Además de intrerpretar las directivas del fichero, admite opciones en la llamada Preprocesador de C Constantes y macros #define FALSE 0 #define TRUE !FALSE #define MAX(A,B) ( (A > B) ? (A) : (B) ) #define IGUAL == #define SIN_FIN while(1) #define cuadrado(x) (x)*(x) cuadrado (z+1); /* (z+1)*(z+1) */ cuadrado (z++); /* (z++)*(z++) */ Preprocesador de C Constantes y macros Las definiciones pueden eliminarse #undef FALSE int FALSE = 0; Los argumentos de una macro pueden concatenarse #define Concatena(a1, a2) a1 ## a2 Concatena(123, 45) genera 123452 Preprocesador de C Inclusión de ficheros Cualquier tipo de fichero de texto El directorio de búsqueda depende de < > ó #include <stdio.h> #include “funciones.h” Inclusión condicional #if defined STANDARD #include <stdio.h> #else #include “miio.h” #endif