viernes, 11 de abril de 2008

Capítulo 7

.
Punteros y Alocación Dinámica de Memoria

Indirectamente en los capítulos anteriores tuvimos que ver algo sobre punteros en C ya que las cadenas de caracteres se implementan sobre arrays o char* y los parámetros por referencia deben pasarse como punteros.

En C los punteros se identifican con un " * " (asterisco).

Veamos algunos ejemplos.

testPtr1.c
   1:
2:#include<stdio.h>
3:
4:int main()
5:{
6: // defino un puntero a int
7: int *a;
8:
9: // aloco memoria y asigno la direccion
10: // de la memoria alocada al puntero a
11: a = malloc(sizeof(int));
12:
13: // al contenido de a le asigno 10
14: *a = 10;
15:
16: // muestro el contenido de a
17: printf("El condenido de a es %d\n",*a);
18:}
19:

En este ejemplo definimos una variable de tipo int* llamada p. En la línea 9 le asignamos la dirección de la memoria que alocamos con la función malloc (similar al procedimiento new de Pascal). Luego, en la línea 12 asignamos el valor 10 en el espacio de memoria direccionado por p. Se dice "Asignamos 10 al contenido de p".

En general cuando vemos *a hablamos de "el contenido de a" y cuando vemos &a hablamos de "la dirección de a".

Puede resultar confuso el hecho de que el asterisco se usa tanto para definir un tipo puntero como para hacer referencia al contenido del mismo (o mejor dicho: al valor contenido en la memoria direccionada por el puntero).

Como siguiente ejemplo volveremos a analizar la función permutar. Esta función recibe dos argumentos y su objetivo es permutar sus valores así que los argumentos tienen que ser punteros ya que no existe en C un modificador var como el de Pascal que indique que los parámetros se reciben por referencia.

testPtr2.c
   1:
2:#include<stdio.h>
3:
4:// a y b son dos parametros de tipo
5:// puntero a int.
6:void permutar(int *a, int *b)
7:{
8: // a aux le asigno el contenido de a
9: int aux=*a;
10:
11: // al contenido de a le asigno el contenido de b
12: *a=*b;
13:
14: // al contenido de b le asigno el valor de aux
15: *b=aux;
16:}
17:
18:int main()
19:{
20: // defino dos variables tipo int
21: int x=10, y=20;
22:
23: // la funcion permutar recibe dos int* entonces
24: // le paso la direcciones de x e y
25: permutar(&x,&y);
26:
27: // mostramos que se pudieron cambiar sus valores
28: printf("x=%d, y=%d\n",x,y);
29:}
30:

En la línea 6, en el encabezado de la función se definen los parámetros a y b como punteros a entero (int*). Luego, en la línea 9 asignamos a la variable aux "el contenido del puntero a".

Es muy importante notar esta diferencia: a es el puntero, *a es el contenido de a y (en la línea 6) int *a define que la función recibe un parámetro de tipo puntero a entero llamado a.

En la línea 21 de la función main definimos la variable x de tipo int. En la línea 25 invocamos a la función permutar y le pasamos un puntero a x. Este puntero (o dirección de x) la obtenemos con &x.


Alocar Arrays Dinámicamente

Un array representa la dirección del primer elemento de un conjunto de variables del mismo tipo cuyas direcciones de memoria son contiguas.

La función malloc permite alocar tanta memoria contigua como necesitemos así que si alocamos (por ejemplo) n por sizeof(int) bytes estaremos (en definitiva) alocando un array de n enteros.

testPtr3.c
   1:
2:#include<stdio.h>
3:
4:int main()
5:{
6: // definimos un puntero a int
7: int *arr;
8: int i, n;
9:
10: // el usuario ingresa un valor por teclado
11: printf("Ingrese un valor: ");
12: scanf("%d",&n);
13:
14: // alocamos n enteros consecutivos
15: arr = (int*) malloc( n * sizeof(int) );
16:
17: // dado que arr apunta al primero de los n enteros
18: // podemos acceder al contenido de cada uno
19: // mediante el subindice i.
20: for( i=0; i<n; i++ )
21: {
22: // asignamos un valor a cada elemento del array
23: arr[i] = 2*i;
24: }
25:
26: // recorremos el array y mostramos su contenido
27: for( i=0; i<n; i++ )
28: {
29: printf("arr[%d]=%d\n",i,arr[i]);
30: }
31:}
32:

Si arr representa la dirección del primer elemento del array entonces arr+1 representa la dirección del segundo, arr+2 representa la dirección del tercero y así arr+i representa la dirección del i-ésimo elemento del array. Entonces *(arr+i) representa el contenido del i-ésimo elemento del array. *(arr+i) es equivalente de arr[i].

Esta una notación quizás un poco más complicada que la notación tradicional de arrays pero en C es válida. Veamos el mismo ejemplo pero codificado de esta manera.

testPtr3ver2.c
   1:
2:#include<stdio.h>
3:
4:int main()
5:{
6: int *arr;
7: int i, n;
8:
9: printf("Ingrese un valor: ");
10: scanf("%d",&n);
11:
12: arr = (int*) malloc( n * sizeof(int) );
13:
14: for( i=0; i<n; i++ )
15: {
16: // arr es la direccion del primer elemento
17: // arr+i sera la direccion del
18: // elemento 0, 1, 2,...,n-2, n-1
19: // entonces *(arr+1) apunta al contenido del
20: // elemento i, es sinonimo de arr[i]
21: *(arr+i) = 2*i;
22: }
23:
24: for( i=0; i<n; i++ )
25: {
26: printf("arr[%d]=%d\n",i,*(arr+i));
27: }
28:}
29:






.


No hay comentarios: