Está en la página 1de 20

JAIRO ENRIQUE MARTINEZ BANDA

Asignación dinámica de tablas

1. Asignar dinámicamente una tabla con un


puntero

A continuación se muestra una asignación dinámica para un entero:

int *ptr;
ptr=(int*)malloc(sizeof(int) );

lo que es idéntico a:

ptr=(int*)malloc(sizeof(int) * 1);

Si ptr contiene la dirección del primer elemento de la tabla de 1 elemento, se


puede escribir indiferentemente:

*ptr=10;
// o
ptr[0]=10;

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA -1-
JAIRO ENRIQUE MARTINEZ BANDA

Ambas notaciones son equivalentes.

Y para tener más de un elemento en la tabla, basta con asignar más memoria,
proporcionalmente al número de elementos. Por ejemplo, para tener una
tabla de 16 enteros:

int *ptr
ptr=(int*)malloc(sizeof(int)*16);

El recorrido de la tabla es el habitual:

int i,
for (i=0; i<16; i++){
ptr[i]=rand()%100; // inicializacin
printf("ptr[%d]=%d",i, ptr[i]); // visualizacin
}

También es posible obtener el tamaño de la tabla de forma aleatoria:

int*ptr, tam;
tam=rand();
ptr=(int*)malloc(sizeof(int)*tam);

Si se teme que haya un desbordamiento de la memoria RAM en el

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA -2-
JAIRO ENRIQUE MARTINEZ BANDA

momento de la asignación, se puede controlar el retorno de la función


malloc(), que devuelve NULL si no se ha podido realizar la operación
solicitada. Por ejemplo:

ptr=(int*)malloc(sizeof(int)*tam;
if ( ptr==NULL)
exit(EXIT_FAILURE);

En caso de error, el programa finaliza con EXIT_FAILURE como valor de


retorno (EXIT_FAILURE vale 1 e indica al sistema operativo que un problema
se ha producido en la ejecución del programa).

2. Asignar una matriz con un puntero de


punteros

¿Qué es una matriz? Una matriz es una tabla de tablas de objetos de un tipo
determinado. Por ejemplo, una matriz de enteros:

int mat[4][7]

mat es una tabla de 4 tablas de 7 enteros. Debido a la equivalencia tabla-


puntero, la matriz puede ser reemplazada por un puntero de tablas, es decir,
por un puntero de punteros, que se escribe de la siguiente manera:

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA -3-
JAIRO ENRIQUE MARTINEZ BANDA

int**mat;

El primer nivel de puntero sirve para asignar una tabla de punteros. Es la tabla
de las filas y tiene el tamaño del número de filas deseado. Por ejemplo, si se
pretende crear una matriz de enteros de 4 filas por 7 columnas, a
continuación se muestra cómo crear una tabla de punteros para hacer 4 filas:

// 1) una tabla de punteros

int**mat;
mat=(int**)malloc(sizeof(int*)*4);

Representada gráficamente:

Esta llamada de la función malloc() asigna un espacio de memoria para 4


punteros de enteros. Es una tabla de 4 punteros de enteros. Ahora solo nos
falta asignar la tabla correspondiente a cada fila según el número de
columnas deseado. Si hay 7 columnas, se debe escribir:

// 2) cada puntero de la tabla se asigna en una tabla de int

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA -4-
JAIRO ENRIQUE MARTINEZ BANDA

for (i=0; i<4; i++)


mat[i]=(int*)malloc(sizeof(int)*7);

Representada gráficamente:

Escasoposible tener filas de distintos tamaños, pero en este


hay que conservar el tamaño de cada fila en otra parte
o tener un centinela en cada fila para que indique el final
(por ejemplo, el carácter ’\0’ de las cadenas de caracteres).

El siguiente programa crea una matriz de tamaño aleatorio y la inicializa con


los valores 0 o 1:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])


{
int**mat; // 1
int tx,ty,i,j,fin=;
0

srand(time(NULL));
© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA -5-
JAIRO ENRIQUE MARTINEZ BANDA

do{

tx=1+rand()%30; // 2
ty=1+rand()%10;
mat=(int**)malloc(sizeof(int*)*ty);
for (i=0; i<ty; i++){
mat[i]=(int*)malloc(sizeof(int)*tx);

for (j=0; j<tx; j++){


mat[i][j]=rand()%;
2
printf("%2d",mat[i][j]);
}
putchar(\n);
}

for (i=0; i<ty; i++) // 3


free(mat[i]);
free(mat);

printf("\n¿Otra matriz? (s/n)\n\n"


);
fin=getch();
}while(fin==o);

return 0;
}

(1) Declaración de variables del programa. "mat" para la matriz, que es un


puntero a punteros a entero, y ty y tx para su número de filas y columnas.

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA -6-
JAIRO ENRIQUE MARTINEZ BANDA

(2) Inicialización aleatoria de las variables tx y ty en los rangos respectivos de


1 a 30 y 1 a 10 y, a continuación:

ˇ
Asignación dinámica de la tabla de punteros de ty filas.
ˇ
Asignación dinámica de cada fila de la tabla con tx columnas.

(3) Destrucción de la matriz; el programa no usará más esta matriz. El


objetivo es solamente comprobar la creación dinámica de una matriz y la
memoria que acaba de ser asignada se libera justo después de la creación y
la visualización de la matriz.

También podríamos mencionar la creación dinámica de tablas de tres


dimensiones, o n dimensiones. El principio de asignación sería exactamente
el mismo. Por ejemplo, a continuación se muestra un cubo de 10 matrices de
20 filas por 30 columnas de enteros:

int ***tab;
tab=(int***)malloc(sizeof(int**)*10);
for (z=0; z<10;z++){
tab[z]=(int**)malloc(sizeof(int*)*20);
for (y=0; y<20; y++)
tab[z][y]=(int*)malloc(sizeof(int)*30);
}

Sin embargo, no es muy frecuente. En general, son sobre todo las tablas de
una o dos dimensiones las que reciben una asignación dinámica.

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA -7-
JAIRO ENRIQUE MARTINEZ BANDA

3. Diferencias entre tablas estáticas y tablas


dinámicas

El puntero es una variable que puede recibir diferentes direcciones


correspondientes a diferentes bloques de memoria. Una tabla estática es
constante. El tamaño del bloque correspondiente y su dirección se asignan
automáticamente y no pueden modificarse nunca.

Además, el operador sizeof() aplicado a un puntero devuelve el tamaño en


bytes de la variable puntero (4 bytes), mientras que si se aplica a una tabla
estática, devuelve el tamaño en bytes de la tabla. Si es a una tabla, el número
de elementos puede hallarse de la siguiente manera:

int num_elementos =sizeof(a) / sizeof(a[0]);

La tabla (estática) es un tipo en sí. La conversión de una tabla a un puntero


que apunta al primer elemento de la tabla no tiene lugar cuando una
expresión de tipo tabla es el operando de un operador unario como sizeof. Es
por este motivo por lo que sizeof(a) devuelve el tamaño de a, y no un puntero
al primer elemento de a.

4. Otras funciones de asignación de memoria


dinámica

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA -8-
JAIRO ENRIQUE MARTINEZ BANDA

Aparte de la función malloc() anteriormente presentada, la librería estándar


de C <stdlib.h> proporciona dos funciones más para asignar la memoria
dinámicamente: son las funciones calloc() y realloc().

a. Función calloc()

void * calloc(size_t num_elementos,size_t tam_elementos)


;

La función calloc() asigna un espacio de memoria del número de elementos


multiplicado por el tamaño de un elemento: num_elementos*tam_elementos.
El espacio asignado se inicializa con todos los bits a cero y la función
devuelve una dirección genérica void*. Ejemplo de uso:

#include <stdio.h>
#include <stdlib.h>

int main()
{
int num,i;
int*tab;
printf("entrar el tamaæo de la tabla:\n"
); // 1
scanf("%d",&num);
tab=(int*)calloc(num,sizeof(int)); // 2
for (i=0; i<num; i++){ // 3

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA -9-
JAIRO ENRIQUE MARTINEZ BANDA

tab[i]=rand()%256;
printf("tab[%d]=%d\n"
,i,tab[i]);
}
return 0;
}

(1) Se solicita al usuario que introduzca el tamaño de la tabla obteniendo el


valor con la función scanf().

(2) Asignación dinámica de la tabla según el valor entrado.

(3) La tabla se inicializa a continuación con valores aleatorios comprendidos


entre 0 y 255. Se muestran todos los valores.

b. Función realloc()

void* realloc(void*ptr, size_t nuevo_tam);

La función realloc() modifica el tamaño del espacio de memoria apuntado


por ptr. El puntero ptr debe ser NULL, o bien debe contener la dirección de un
espacio de memoria previamente asignado. El parámetro nuevo_tam es el
nuevo tamaño del espacio de memoria. Si es más pequeño, los datos de la
parte suprimida se eliminan y los de la parte restante se conservan. Si es
más grande, todos los datos del espacio inicial de memoria se conservan y la
parte añadida no se inicializa (contenido indeterminado). Cuando la dirección
inicial es NULL, se asigna un espacio de tamaño

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA - 10 -
JAIRO ENRIQUE MARTINEZ BANDA

nuevo_tam. La función devuelve un puntero genérico; hay que hacer un


casting en función del tipo deseado. Ejemplo de uso:

#include <stdio.h>
#include <stdlib.h>

int main()
{
int num,i,k;
int *tab=NULL; // 1

for (i=0; i<10; i++){ // 2


printf("entre un nuevo tamaæo de tabla:\n"
);
scanf("%d",&num);
tab=(int*)realloc(tab,sizeof(int)*num);
for (k=0; k<num; k++){ // 3
if(tab[k]!=k)
tab[k]=k;
printf("%d ",tab[k]);
}
}
return 0;
}

(1) Declaración de variables, el puntero tab se pone a NULL.

(2) El programa reasigna diez veces el espacio de memoria apuntado por tab.
Cada vez se solicita al usuario que entre un nuevo tamaño, se obtiene el valor
introducido mediante la función

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA - 11 -
JAIRO ENRIQUE MARTINEZ BANDA

scanf() y se reasigna el espacio con realloc().

(3) Una vez el espacio de memoria ha sido reasignado, se inicializa. Cada


elemento de la tabla toma por valor su índice correspondiente. La
inicialización de los elementos solo se produce para los elementos del
espacio de memoria añadido, cuyos valores serán probablemente distintos a
los índices de la tabla.

5. Puesta en práctica: asignación dinámica de


memoria

a. Asignar dinámicamente tablas

Ejercicio 1

Escribir un programa en el que:

ˇ
El usuario entra el tamaño para una tabla de enteros.
ˇ
Una función asigna dinámicamente memoria para la tabla.
ˇ
Una función inicializa la tabla con números aleatorios crecientes.
ˇ
Una función muestra la tabla.
ˇ
Se permita salir o volver a comenzar (si se vuelve a comenzar hay
que liberar la memoria).

Ejercicio 2

Considere la tupla t_tabla que contiene la dirección de una tabla y el

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA - 12 -
JAIRO ENRIQUE MARTINEZ BANDA

número de elementos de la tabla:

typedef struct{
int num_elem; // nœmero de elementos
int*tab; // tabla potencial
}t_tabla;

1) Escribir la función:

t_tabla asigna_mem_tabla(int n);

que crea una tabla de n elementos.

2) Escribir la función:

void destruye_tabla(t_tabla tab)


;

que libera la memoria ocupada por una tabla.

3) Escribir la función:

void inicializa_tabla(t_tabla tab)


;

que inicializa una tabla con valores.

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA - 13 -
JAIRO ENRIQUE MARTINEZ BANDA

4) Escribir la función:

void muestra_tabla(t_tabla tab)


;

que muestra el contenido de una tabla.

5) Escribir la función:

t_tabla copia_tabla (t_tabla tab)


;

que crea una nueva tabla de igual tamaño que tab, pero inicializada con la
copia de los valores de tab.

Escribir un programa con un menú que permita invocar estas distintas


operaciones.

Ejercicio 3

En un programa:

ˇ
Escribir una función de entrada de una cadena de caracteres; la
función no tiene parámetros.
ˇ
Escribir una función de concatenación de dos cadenas de caracteres;
la función tiene dos parámetros que son las cadenas que se
concatenarán y devuelve una tercera cadena que es la
concatenación.
ˇ
Introducir dos cadenas y mostrar la concatenación.

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA - 14 -
JAIRO ENRIQUE MARTINEZ BANDA

ˇ
Salir o volver a empezar (ojo con la memoria).

Ejercicio 4 (requiere conocer el uso de archivos)

Se propone realizar una función de carga de un archivo de texto en la


memoria principal. El formato del archivo es el siguiente:

- la primera fila tiene el nœmero de elementos en el archivo,


- las siguientes filas contienen cada una de ellas un nœmero real.
Por ejemplo:
3
4.98
123.76
45.99

ˇ
Escribir la función de carga que reciba por parámetro una tabla del
tamaño exacto.
ˇ
Escribir una función de visualización de la tabla.
ˇ
Comprobar en un programa. Iniciar varias veces el programa
modificando cada vez el contenido del archivo de texto.

Ejercicio 5

En un programa:

ˇ
Introducir una frase.
ˇ
Pasar esta frase a una función que devuelva una de las palabras de la
frase al azar.

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA - 15 -
JAIRO ENRIQUE MARTINEZ BANDA

ˇ
Mostrar la frase y la palabra seleccionada.
ˇ
Salir o volver a empezar.

b. Asignar memoria dinámicamente a matrices

Ejercicio 6

En un programa:

ˇ
El usuario introduce las dos dimensiones de una matriz de enteros.
ˇ
Una función asigna la memoria dinámicamente a la matriz.
ˇ
Una función inicializa la matriz con números aleatorios crecientes.
ˇ
Una función muestra la matriz.
ˇ
Salir o volver a comenzar (si se vuelve a comenzar, liberar la
memoria).

Ejercicio 7

Considerar la tupla t_matriz siguiente, que contiene la dirección de una


matriz, el número de filas y el número de columnas:

typedef struct{
int ty, tx; // filas, columnas
int**tab; // matriz
}t_matriz;

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA - 16 -
JAIRO ENRIQUE MARTINEZ BANDA

1) Escribir la función:

t_matriz asigna_mem_matriz(int tx, int ty);

que crea una matriz de ty*tx elementos.

2) Escribir la función:

void destruye_matriz(t_matriz mat)


;

que libera la memoria ocupada por la matriz.

3) Escribir la función:

void inicializa_matriz(t_matriz mat)


;

que inicializa la matriz con valores.

4) Escribir la función:

void muestra_matriz(t_matriz mat)


;

que muestra el contenido de una matriz.

5) Escribir la función:

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA - 17 -
JAIRO ENRIQUE MARTINEZ BANDA

t_matriz copia_matriz(t_matriz mat)


;

que crea una nueva matriz de un tamaño idéntico al de mat e inicializa los
valores de la copia con los valores de mat, simplemente copiándolos.

Escribir un programa con un menú que permita realizar estas operaciones.

Ejercicio 8 (requiere conocer el uso de archivos)

Se propone realizar una función de carga de un archivo de texto en memoria


principal. El formato del archivo es el siguiente:

- la primera lnea tiene los nœmeros de filas y de columnas de una matriz


- a continuacin cada lnea tiene num columnas de elementos
Por ejemplo:
3 4
abcd
efgh
ijkl

ˇ
Escribir la función de carga que reciba por parámetro una matriz del
tamaño adecuado.
ˇ
Escribir una función de visualización de la matriz.
ˇ
Comprobar en un programa. Iniciar varias veces el programa

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA - 18 -
JAIRO ENRIQUE MARTINEZ BANDA

modificando cada vez el contenido del archivo de texto.

c. Asignación dinámica de memoria con calloc() y realloc()

Ejercicio 9

En un programa, se forma una agenda de contactos que incluye nombre,


apellidos, teléfono y dirección.

Primera parte:

ˇ
Definir un tipo para almacenar un contacto.
ˇ
El usuario introduce el número de contactos que quiere añadir.
ˇ
Asignar dinámicamente una tabla para almacenar los contactos. Al
finalizar todos los contactos serán 0.
ˇ
Escribir una función de inicialización de un contacto y rellenar la
tabla.
ˇ
Mostrar la tabla rellenada.
ˇ
Guardar en binario la tabla y su tamaño (si conoce el uso de
archivos).

Ejercicio 10 (requiere conocer el uso de archivos)

En un programa, retomar el tipo definido en el ejercicio 1. El objetivo esta vez


es poder modificar la base de datos de contactos registrada en un archivo
binario, o bien añadiendo o bien quitando contactos. El programa ofrece
ahora un menú con cuatro opciones:

ˇ
Cargar: obtener toda la base de datos en una tabla del

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA - 19 -
JAIRO ENRIQUE MARTINEZ BANDA

tamaño adecuado.
ˇ
Añadir: aumentar el tamaño de la tabla y añadir un contacto.
ˇ
Eliminar: elegir el contacto que se eliminará, eliminarlo y disminuir el
tamaño de la tabla.
ˇ
Guardar: archivo binario, tabla y su tamaño.

Ejercicio 11

En un programa, en el bucle principal, el tamaño t de una tabla se da al azar:

ˇ
Una función asigna memoria dinámicamente a una tabla de t
punteros de enteros. La primera vez, todos los punteros serán NULL,
es decir, serán ((int*) 0).
ˇ
Una función inicializa valores y otra función los muestra.
ˇ
El programa finaliza o vuelve a empezar a decisión del usuario.

© Éditions ENI - Todos los derechos reservados - Copia personal de JAIRO ENRIQUE MARTINEZ BANDA - 20 -

También podría gustarte