¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Desarrollo informático
  3. Los punteros
Extrait - Desarrollo informático Aprenda a diseñar antes de programar
Extractos del libro
Desarrollo informático Aprenda a diseñar antes de programar Volver a la página de compra del libro

Los punteros

Objetivos del capítulo

Desarrollar aplicaciones que utilicen punteros.

Desarrollar aplicaciones que utilicen la asignación dinámica de memoria.

Definición

Un puntero es una variable destinada a contener una dirección. Como una dirección es un entero, un puntero es una variable de tipo entero.

Ejemplos

1. Puntero sobre un entero

La declaración int* p reserva un entero en memoria, destinado a contener la dirección de una variable de tipo entero.

La escritura int* p (la estrella pegada a int) sugiere que la variable p es del tipo puntero sobre un entero. También podríamos escribir int *p (la estrella pegada a la p), que sugiere que la variable *p es de tipo entero, lo que también es cierto.

  • La declaración int n reserva un entero en memoria.

int main()  
{  
  int* p;  
  int n; 
images/01033a.PNG
   n = 17;  
   printf("n  = %d\n\n", n); 
images/01033b.PNG

La siguiente instrucción inserta la dirección de la variable n en p (el operador & devuelve la dirección de n). Se dice que p apunta a n.

   p = &n;   
   printf("p  = %p\n\n", p); 
images/01033c.PNG

El formato %p del printf permite mostrar el entero p en hexadecimal.

Visualización del valor apuntado por p:

   printf("*p = %d\n\n", *p); 

Incremento del valor apuntado por p, es decir, n:

   (*p)++;  
   printf("n  = %d\n\n", n);  
  
   return 0;  
} 

A continuación se muestra el resultado de la ejecución de este programa:

images/01033d.png

El operador & devuelve la dirección de una variable.

Es posible almacenar esta dirección en una variable...

Punteros: un error clásico

La utilización directa de direcciones de memoria puede ser peligrosa y obliga a prestar atención al programador. El siguiente ejemplo ilustra este peligro.

int main()  
{  
   int* p; 

La siguiente instrucción inserta la dirección 0 en el puntero. En general, esta dirección se reserva a los programas del sistema.

    p = 0; 

La siguiente instrucción intenta insertar el valor 10 en la dirección 0; por lo tanto, eliminar un fragmento de programa del sistema (aquí, Windows):

   *p = 10;  
  
   return 0;  
} 

Windows se defiende y muestra una pequeña ventana de información:

images/a00a.png

Este error se califica como Access Violation.

Asignación dinámica de una tabla

La asignación dinámica de memoria consiste en reservar espacio de memoria para variables a lo largo de la ejecución del programa. Por ejemplo, la asignación dinámica de una tabla puede ser útil si su dimensión no se conoce al inicio del programa.

1. Tabla de una dimensión

Las siguientes declaraciones reservan dos zonas de memoria que pueden contener un entero.

int main()  
{  
   double* tabla;  
   int i; 
images/a37.png

La función calloc() reserva en memoria un número de bytes igual al producto de sus argumentos.

   tabla = (double*) calloc(3, sizeof(double));  
   printf("tabla  = %p\n\n", tabla); 

Aquí: 3 * sizeof(double), es decir, 3 * 8 = 24 bytes; es decir, el espacio correspondiente a tres variables de tipo double.

La función calloc() devuelve una dirección no tipada (void*). El «cast» en double* garantiza una coherencia con la declaración del puntero tabla. La dirección devuelta por calloc() se almacena en tabla, que apunta a la zona de memoria asignada:

images/a38.png

Sin embargo, la tabla se utiliza como una tabla normal:

   tabla[0] = 5.1;  
   tabla[1] = 17.3;  
   tabla[2] = 13.4;  
  
   for (i = 0; i < 3; i++)  
   {  ...

Trabajo práctico: triángulo de Pascal

1. Objetivo

Constituir una tabla que contenga el triángulo de Pascal usando la asignación dinámica de tablas.

2. Tema

La corrección del trabajo práctico: triángulo de Pascal (cf. capítulo Las tablas) propone una solución que utiliza dos tablas de una dimensión. Retomando este programa, se asignan dinámicamente las dos tablas.

images/a41.png

3. Triángulo de Pascal: proposición de corrección

Esta solución retoma la solución con dos tablas de una fila. Las tablas se asignan dinámicamente. Las variables l1 y l2 se declaran como punteros:

int main()  
{  
   int* l1;  
   int* l2; 
   int* permut;  
   int fila,col;  
   int numl;  
  
   printf("Indique el número de fila(s) de la tabla: ");  
   scanf("%d", &numl); 

Asignación dinámica de las dos tablas:

   l1 = (int*) calloc(numl, sizeof(int));  
   l2 = (int*) calloc(numl, sizeof(int)); 

El número de filas del triángulo de Pascal no está limitado a 16.

   l1[0] = 1;  
   printf("%-5d\n", l1[0]);  
  
   for (fila = 1; fila < numl; fila++)  
   {  ...