42
PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA 2011 UNAN – LEON Departamento de Computación Autor: Ing. Juan Carlos Antón Soto Asignatura: Programación Estructurada

PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

Embed Size (px)

Citation preview

Page 1: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACIÓN

DINÁMICA DE MEMORIA

2011

UNAN – LEON Departamento de Computación Autor: Ing. Juan Carlos Antón Soto Asignatura: Programación Estructurada

Page 2: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

1

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

Un puntero es una variable que representa la dirección de memoria de otro dato, tal

como una variable o un elemento de un array.

Los punteros están muy relacionados con los arrays y proporcionan una alternativa de

acceso a los elementos individuales del array. Proporcionan una forma conveniente para

representar arrays multidimensionales, permitiendo que un array multidimensional sea

reemplazado por un array de punteros de menor dimensión. Esta característica permite

que una colección de cadenas de caracteres sea representada con un solo array, incluso

cuando las cadenas pueden tener distintas longitudes.

Un puntero puede apuntar a un objeto de cualquier tipo, incluyendo estructuras,

funciones, etc. Los punteros se pueden utilizar para crear y manipular estructuras de

datos, para asignar memoria dinámicamente y para proveer el paso de argumentos por

referencia en las llamadas a funciones.

CREACION DE PUNTEROS

Un puntero se declara precediendo el identificador que referencia al puntero, por el

operador de indirección (*), el cual significa “puntero a”. Un puntero siempre apunta a un

tipo particular. Un puntero no inicializado tiene un valor desconocido.

tipo *identificador;

� tipo Tipo de dato del objeto referenciado por el puntero.

� identificador

Identificador de la variable de tipo puntero.

Page 3: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

2

Ejemplo:

int *pa; //declara una variable puntero a un tipo de dato entero

Cuando se declara un puntero se reserva memoria para albergar una dirección de memoria, pero NO PARA ALMACENAR EL DATO AL QUE APUNTA EL PUNTERO.

El espacio de memoria reservado para almacenar un puntero es el mismo independientemente del tipo de dato al que apunte.

OPERADORES

Al hablar de punteros, se distinguen dos operadores:

� Operador dirección de : &

� Operador de indirección : *

El operador &, devuelve como resultado la dirección de su operando.

El operador *, toma su operando como una dirección y nos da como resultado su

contenido.

OPERACIONES CON PUNTEROS

Operación de asignación =

A un puntero se le puede asignar una dirección de memoria concreta, la dirección de una variable o el contenido de otro puntero.

Page 4: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

3

Una dirección de memoria concreta: int *ptr; ... ptr = 0x1F3CE00A; ... La dirección de una variable del tipo al que apunta el puntero: char c; char *ptr; ... ptr = &c; Otro puntero del mismo tipo: char c; char *ptr1; char *ptr2; … ptr1 = &c; ptr2 = ptr1; El código siguiente explica el comportamiento de los punteros en memoria:

Suponer que la variable “y” está en la localidad de memoria 1001, “z” en 1002, “nptr”

en 1003, y “mptr” en 1007, las variables “y” y “z” son declaradas de tipo entero e inicializadas a 5 y 3 respectivamente, “nptr” y “mptr” son declarados como punteros a enteros.

Page 5: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

4

A “nptr” se le asigna la dirección de “y” por lo que “nptr” se carga con la dirección 1001 como se muestra en la figura.

“z” obtiene el contenido de “nptr”. En el ejemplo “nptr” apunta a la localidad de memoria 1001 (localidad de y). Por lo tanto, “z” obtiene el valor de “y”.

Se asigna el valor entero 7 al contenido del puntero “nptr”, por lo cual se hace una copia en la variable “y”, ya que éste puntero contiene la dirección de memoria de “y”.

La dirección del puntero “nptr” es asignada a “mptr”, por lo que éste puntero tendrá la misma dirección que tiene “y”, esto es igual a la siguiente instrucción “mptr” = &y.

Page 6: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

5

Ejemplo de uso de punteros

#include <stdio.h> void main() { int a = 1, b = 2; int *ip; /* ip es un puntero a entero */ printf("\n\n\t PRUEBA DE PUNTEROS.\n"); printf("\nValores iniciales: a = %d, b = %d \n", a, b); printf("\nDirecciones de memoria de a = %X y b = %X\n", &a, &b); printf("\ndireccion de memoria inicial en el puntero ip = %X \n", ip); printf("\nbasura en *ip = %d \n", *ip); printf("\nEl puntero ip apunta a \'a\'\n"); ip = &a; /* ip apunta a x; *ip da el valor de x */ printf("\nip = &a"); printf("\n\nip = %X, a = %d, *ip = %d\n\n", ip, a, *ip); b = *ip; /* y es ahora 1 */ *ip = 0; /* x es ahora 0 */ printf("\n\t Asignaciones \n\nb = *ip, *ip = 0\n"); printf("\nb = %d; a = %d\n\n", b, a); }

Page 7: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

6

Ejemplo 2

Programa que suma un valor a una variable a través de un puntero #include <stdio.h> void main() { int a, *p; a=5; printf("\n\nEl valor inicial de a = %d y su direccion de memoria es : %X\n", a, &a); p=&a; printf("\np = &a\n\np = %X y *p = %d", p, *p); *p+=7; printf("\n\nEl contenido de *p se suma con el valor 7\n\n"); printf("\nEl valor final de la variable a = %d y el contenido de *p = %d\n\n", a,*p); }

OPERACIONES ARITMETICAS

A un puntero se le puede sumar o restar un entero.

Ejemplo: int *p; // declara p como un puntero a un entero p++; // hace que p apunte al siguiente entero p--; // hace que p apunte al entero anterior p = p + 3; // avanzar tres enteros p = p – 3; // retroceder tres enteros

Page 8: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

7

COMPARACION DE PUNTEROS

Es posible comparar dos punteros en una expresión de relación. Esta operación tiene

sentido si ambos punteros apuntan a elementos del mismo array.

Ejemplo de punteros con operaciones aritméticas

#include <stdio.h> void main() { int a = 2, b = 5, c[] = {1,10,30,44}, i, *pa, *pb, *pc; printf("\nValores iniciales\n\n”); printf(“a = %d &a = %X b = %d &b = %X c = {1,10,30,44}\n", a, &a, b, &b); for (i = 0; i < 4; i++) printf("c[%d] = %d direccion de memoria : %X\n", i, c[i], &c[i]); printf("\n pa apunta a la direccion de la variable a\n\npa = &a\n"); pa = &a; // pa apunta a la direccion de a printf("pa = %X, *pa = %d\n\n",pa, *pa); printf("\nSe suma 1 al valor apuntado por pa y luego se asigna a b\n"); b = *pa + 1; // se le está sumando 1 al valor apuntado por pa y luego se asigna a b printf("b = %d\n\n",b); pc = c; //pc apunta al arreglo c printf("pc apunta al arreglo c\n pc = c\n\n pc = %X\n\n", pc); printf("el puntero pc se desplaza una posicion de memoria y asigna ese contenido a \'b\' \n "); b = *(pc + 1); // pc se desplaza una posicion de memoria y asigna ese contenido a b printf(" b = %d\n\n", b); printf("pb = &b\n"); pb = &b; printf("pb = %X , direccion de b = %X, b = %d\n\n",pb,&b,b); printf(" *pb = 0\n"); *pb = 0; // el contenido de pb es puesto a cero printf("La variable b indirectamente se incrementa en 2 unidades\n\n"); *pb += 2; // la variable b indirectamente se incrementa en dos unidades printf("*pb = %d , b = %d\n\n",*pb,b); printf("La variable b indirectamente se decrementa en 1 unidad\n\n"); (*pb) --; // La variable b indirectamente se decrementa en una unidad printf("*pb = %d , b = %d\n\n",*pb,b); }

Page 9: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

8

PUNTERO NULO

Un puntero se puede inicializar como cualquier otra variable, aunque los únicos valores

significativos son NULL o la dirección de un objeto previamente definido.

NULL es una constante definida en el fichero stdio.h, cuando un puntero apunta a

NULL significa que apunta a la dirección 0 del sistema, y está a la espera de que se le

asigne una dirección válida. La siguiente sentencia no se debe realizar:

int *px = 103825;

Ya que el sistema es el encargado de asignar las direcciones y por lo tanto el usuario

no sabe acerca de la dirección 103825.

Errores comunes sobre punteros

Asignar punteros de distinto tipo int a = 10; int *ptri = NULL; double x = 5.0; double *ptrf = NULL; ptri = &a; ptrf = &x;

Page 10: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

9

ptrf = ptri; // ERROR

Utilizar punteros no inicializados char *ptr;

*ptr = ‘a’; // ERROR

Asignar valores a un puntero y no a la variable a la que apunta int n; int *ptr = &n; ptr = 9; // ERROR

Intentar asignarle un valor al dato apuntado por un puntero cuando éste es NULL int *ptr = NULL;

*ptr = 9; // ERROR

PUNTEROS Y ARRAYS

En C existe, entre punteros y arrays, una relación tal que, cualquier operación que se

pueda realizar mediante la indexación de un array, se puede realizar también con

punteros.

Cuando declaramos un vector

tipo identificador [dim]

En realidad

1. Reservamos memoria para almacenar dim elementos de tipo tipo.

2. Creamos un puntero identificador que apunta a la primera posición de la

memoria reservada para almacenar los componentes del array.

Por tanto, el identificador del array es un puntero.

Page 11: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

10

Utilizando la aritmética de punteros nos desplazamos de unas posiciones de memoria

a otras. Pero ¿cómo acceder a los contenidos de esas posiciones utilizando notación de

punteros?

Empleando el operador *, indirección que nos da el contenido de la dirección de

memoria apuntada.

Ejemplo:

Analice el siguiente programa, escrito primeramente con matrices y a continuación

con punteros.

// versión utilizando una matriz unidimensional

#include <stdio.h>

void main()

{

int lista[ ] = {24,30,15,45,34};

int indice;

for(indice = 0; indice < 5; indice ++)

printf(“\t%d”,lista[indice]);

printf(“\n\n”);

}

Page 12: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

11

En este ejemplo se ha utilizado la indexación, expresión lista[indice], para acceder a

los elementos de la matriz lista. Cuando se interpreta ésta expresión se sabe que a partir

de la dirección de comienzo de la matriz, esto es, a partir de lista, tiene que avanzar

indice elementos para acceder al contenido del elemento especificado por ese índice.

//versión con punteros

#include <stdio.h>

void main()

{

int lista[ ] = {24,30,15,45,34};

int indice;

for(indice = 0; indice < 5; indice ++)

printf(“\t%d”,*(lista + indice));

}

Esta versión es idéntica a la anterior, excepto que la expresión para acceder a los

elementos del array es: *(lista + indice). Esto deja constancia de que lista es la dirección

de comienzo del array. Si a esta dirección le sumamos 1, dicho de otra manera si indice

vale 1, nos situamos en el siguiente entero de lista; esto es *(lista + 1) y lista[1]

representan el mismo valor.

Punteros a cadena de caracteres

Puesto que una cadena de caracteres es un array de caracteres, la forma de definir un

puntero a una cadena de caracteres es:

char *cadena;

Page 13: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

12

El identificador del array es la dirección de comienzo del array. Para saber dónde

termina la cadena, el compilador añade el carácter ‘\0’ (ASCII 0, NULL):

char *nombre = “PEPE PEREZ”;

Si se quiere recorrer la cadena con notación de punteros se hace lo siguiente:

#include <stdio.h> void main () { char *nombre = "PEPE PEREZ"; int i = 0; do { printf("%c", *(nombre+i)); i++; }while (*(nombre+i)); printf("\n"); }

Muchas funciones de C que trabajan con cadenas de caracteres, utilizan punteros y

devuelven como resultado un puntero. Por ejemplo, la función de C strchr() para localizar

un carácter en una cadena, devuelve un puntero al carácter buscado o un puntero nulo si el

carácter no se encuentra.

Ejemplo: #include <stdio.h> #include <string.h> int main() { const char *cadena = "FERROCARRIL"; char caracter1 = 'A'; char caracter2 = 'z';

Page 14: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

13

if ( strchr( cadena, caracter1 ) != NULL ) printf( "\n\'%c\' se encuentra en %s\n\n", caracter1, cadena ); else printf( "\n\'%c\' no se encontro en %s\n\n", caracter1, cadena ); if ( strchr( cadena, caracter2 ) != NULL ) printf( "\n\'%c\' se encontro en %s\n\n", caracter2, cadena ); else printf( "\n\'%c\' no se encontro en %s\n\n", caracter2, cadena ); return 0; } El siguiente ejemplo copia una cadena de caracteres en otra, utilizando punteros.

#include <stdio.h>

void copia_cadena(char *p, char *q);

void main()

{

char cadena1[50], cadena2[50];

printf("Introducir cadena: ");

gets(cadena1);

copia_cadena(cadena2,cadena1); // copia la cadena1 en la cadena2

printf("\n\tLa cadena copiada es: %s\n\n",cadena2);

}

void copia_cadena(char *p, char *q) // copia q en p

{

while ((*p = *q) != '\0')

{

p ++;

q ++;

}

}

Page 15: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

14

El bucle formado por la sentencia while, realiza las siguientes operaciones:

1. Toma el carácter contenido en la dirección dada por q y lo copia en la dirección dada

por p.

2. Ve si el contenido de p es el carácter nulo.

3. p pasa apuntar a la siguiente dirección, y lo mismo sucede con q. Si no se dio la

condición de terminación, el proceso se repite desde el inicio.

Matrices de punteros

Son matrices que contienen elementos de tipo puntero, es decir, cada elemento de la

matriz contiene una dirección en lugar de un dato de tipo primitivo.

Ejemplo:

#include <stdio.h>

void main()

{

int *p[5]; //matriz de 5 elementos (int *)

int b = 30; // variable de tipo int

p[0] = &b; // p[0] apunta al entero b

printf (“\n\tEl contenido de *p[0] = %d\n\n”,*p[0]);

}

Page 16: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

15

Un array de dos dimensiones y un array de punteros se pueden usar de forma

parecida, pero no son lo mismo. Ejemplo:

int a[5][5]; //array bidimensional

int *p[5]; //array de punteros

En el ejemplo anterior, el compilador reserva memoria para un array a de 25

elementos de tipo entero y para un array p de 5 elementos declarados como punteros a

objetos de tipo entero.

Si cada uno de los objetos apuntados por los elementos del array p es a su vez un

array de 5 elementos de tipo entero, la ocupación de memoria será la de los 5 elementos

de p más la de los 25 elementos de los 5 array de enteros.

El acceso a los elementos de la matriz p puede hacerse utilizando la notación de

punteros o utilizando la indexación igual que lo haríamos con a.

Por ejemplo para asignar valores a los elementos referenciados por la matriz p y

después visualizarlos sería de la siguiente forma:

#include <stdio.h> #define F 5 #define C 5 void main() { int a[F][C] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25}; int *p[F], i, j; //A cada posición del arreglo de punteros se le está asignando la dirección de memoria de cada posición del arreglo bidimensional. for (i = 0; i < F; i++) p[i] = a[i]; printf("\n\n");

Page 17: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

16

//Impresión de los elementos almacenados en el arreglo bidimensional a través del //arreglo de punteros. for (i = 0; i < F; i++) { for (j = 0; j < C; j++) printf("%5d ", p[i][j]); printf("\n\n"); } }

¿Cómo se aplica la notación de punteros o aritmética de punteros para desplazarse en

un array bidimensional?

Existe por tanto una equivalencia:

Con subíndices Con punteros valor

p[0][0] *(*(p+0)+0) 1

p[0][1] *(*(p+0)+1) 2

p[0][2] *(*(p+0)+2) 3

p[0][3] *(*(p+0)+3) 4

.

.

.

p[4][4] *(*(p+4)+4) 25

*p representa un puntero a la primera fila, con *(p+1)+j para las direcciones y

*(*p+1)+j) para los contenidos. El segundo subíndice actúa sobre la columna.

Si en x[10][20] se quiere acceder al elemento de la fila 3 y la columna 6, se hace

escribiendo x[2][5]. Con notación de punteros, es equivalente a *(*(x+2)+5), ya que x+2

Page 18: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

17

es un puntero a la fila 3. Por tanto. El contenido de dicho puntero, *(x+2), es la fila 3. Si

se desplaza 5 posiciones en esa fila se llega a la posición *(x+2)+5, cuyo contenido es

*(*(x+2)+5). Ver dibujo:

PUNTEROS A PUNTEROS

Para especificar que una variable es un puntero a un puntero, la sintaxis utilizada es la

siguiente:

Tipo **varpp;

Donde Tipo especifica el tipo del objeto apuntado después de una doble indirección

(puede ser cualquier tipo incluyendo tipos derivados) y varpp es el identificador de la

variable puntero a puntero.

Por ejemplo: int a, *p, **pp; a = 10; //dato p = &a; // puntero que apunta al dato pp = &p; // puntero que apunta al puntero que a la vez apunta al

// dato

Page 19: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

18

Se dice que p es una variable con un nivel de indirección, esto es, a través de p no se

accede directamente al dato, sino a la dirección que indica dónde está el dato. Haciendo

un razonamiento similar se dice que pp es una variable con dos niveles de indirección.

Ejemplo:

#include <stdio.h> void main() { int a[3][3], *p[3], **q, i,j; for (i = 0; i < 3; i++) p[i] = a[i]; q =p; for (i = 0; i < 3; i++)

{ for (j = 0; j < 3; j++) { printf("q[%d][%d] = ",i,j); scanf("%d", &q[i][j]); } } printf("\n\n"); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) printf("%5d ",q[i][j]); printf("\n"); } }

El nombre de un array de dos dimensiones no puede considerarse como un puntero a

puntero. La siguiente asignación daría un error.

int a[5][5];

int **p = a; //diferentes niveles de indirección

Page 20: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

19

ASIGNACIÓN DINÁMICA DE MEMORIA

La asignación dinámica de memoria es una característica de C. Le permite al usuario

crear tipos de datos y estructuras de cualquier tamaño de acuerdo a las necesidades que

se tengan en el programa.

Dos de las aplicaciones más comunes son:

� Arreglos Dinámicos

� Estructuras dinámicas de datos

La asignación dinámica de memoria consiste en asignar la cantidad de memoria

necesaria para almacenar un objeto durante la ejecución del programa, en vez de hacerlo

en la fase de compilación del mismo. Cuando se asigna memoria para un objeto de tipo

cualquiera, se devuelve un puntero a la zona de memoria asignada. Según esto, lo que tiene

que hacer el compilador es asignar una cantidad fija de memoria para almacenar la

dirección del objeto asignado dinámicamente, en vez de hacer una asignación para el

objeto en sí. Esto implica declarar un puntero a un tipo de datos igual al tipo del objeto

que se quiere asignar dinámicamente. Por ejemplo, si queremos asignar memoria

dinámicamente para una matriz de enteros, implica declarar un puntero a un entero:

int *p;

Page 21: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

20

Funciones para asignación dinámica de memoria.

La función malloc es empleada comúnmente para intentar “tomar” una porción contigua

de memoria, es decir, asignar un bloque de memoria de size bytes consecutivos para

almacenar uno o más objetos de un tipo cualquiera.

La función malloc se encuentra en el archivo cabecera stdlib.h yEstá definida como:

void *malloc (size_t size);

Lo anterior indica que regresará un puntero del tipo void *, el cual es el inicio en

memoria de la porción reservada de tamaño size. Si no puede reservar esa cantidad de

memoria, la función regresa un puntero nulo o NULL.

Dado que void * es regresado, C asume que el puntero puede ser convertido a

cualquier tipo. El tipo de argumento size_t está definido en la cabecera stddef.h y es un

tipo entero sin signo.

Por lo tanto:

char *cp;

cp = (char *) malloc(100);

Intenta obtener 100 bytes y asignarlos a la dirección de inicio de cp.

Lo más usual es usar la función sizeof () para indicar el número de bytes y no el tipo

de argumento size_t, por ejemplo:

int *p;

p = (int *) malloc(100 * sizeof(int));

Page 22: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

21

El compilador de C requiere hacer una conversión de tipo. La forma de lograr la

conversión cast es usando (char *) e (int *), que permite convertir un puntero void a un

puntero tipo char e int respectivamente.

El operador sizeof se usa para encontrar el tamaño de cualquier tipo de dato, variable

o estructura.

Ejemplo usando la función malloc ()

#include <stdio.h>

#include <stdlib.h>

void main()

{

int *p = NULL;

int nbytes = 100;

p = (int *) malloc(nbytes);

if (p == NULL)

printf("\n\tInsuficiente espacio de memoria\n\n");

else

printf("Se han asignado %d bytes de memoria\n\n",nbytes);

}

En el siguiente ejemplo se reserva memoria para la variable ip, en donde se emplea la

relación que existe entre punteros y array (arreglos), para manejar la memoria reservada

como un array. Por ejemplo:

Page 23: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

22

#include <stdio.h>

#include <stdlib.h>

void main()

{

int *ip = NULL, i;

ip = (int *) malloc(5 * sizeof(int));

ip[0] = 1000;

for (i = 1; i < 5; i++)

scanf("%d",&ip[i]);

printf("\n\n");

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

printf("%5d",ip[i]);

printf("\n\n");

}

Cuando se ha terminado de usar una porción de memoria siempre se deberá liberar

usando la función free(). Esta función permite que la memoria liberada esté disponible

nuevamente quizás para otra llamada de la función malloc().

La función free() toma un puntero como un argumento y libera la memoria a la cual el

puntero hace referencia, pero no pone el puntero a NULL. Si el puntero que referencia el

bloque de memoria que deseamos liberar es nulo, la función free no hace nada. Su sintaxis

es:

void free (void *vpuntero);

Ésta función se encuentra en el archivo cabecera stdlib.h

Si la memoria liberada por free no ha sido previamente asignada por malloc, calloc, o

realloc, se pueden producir errores durante la ejecución del programa.

Page 24: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

23

Ejemplo:

#include <stdio.h>

#include <stdlib.h>

void main()

{

int *p = NULL;

int nbytes = 100;

p = (int *) malloc(nbytes);

if (p != NULL)

printf("\nSe ha asignado memoria correctamente\n\n");

else

printf("\n\nNo se ha podido asignar menmoria\n");

free(p); //Libera memoria para el puntero p

}

Existen dos funciones para reservar memoria, calloc() y realloc().

Los prototipos de estas funciones son las siguientes:

void *calloc (size_t nmemb, size_t size);

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

Estas funciones se encuentran en el archivo cabecera stdlib.h

Cuando se usa la función malloc(), la memoria no es inicializada (a cero) o borrada. Si

se quiere inicializar la memoria entonces se puede utilizar la función calloc(). Se debe

observar la diferencia de sintaxis entre calloc y malloc, ya que calloc toma el número de

elementos deseados (nmemb) y el tamaño del elemento (size), como dos argumentos

individuales.

Page 25: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

24

Por lo tanto para asignar 100 elementos enteros que estén inicializados a cero se

puede hacer:

int *ip;

ip = (int *) calloc(100, sizeof(int));

¿Qué hace exactamente realloc? Depende de si se pide más o menos memoria de la

que ya se tiene reservada: Si se pide más memoria, intenta primero ampliar la zona de memoria asignada. Si las

posiciones de memoria que siguen a las que ocupa a en ese instante están libres, se las asigna a la variable puntero. En caso contrario, solicita una nueva zona de memoria, copia el contenido de la vieja zona de memoria en la nueva, libera la vieja zona de memoria y nos devuelve el puntero a la nueva (zona de memoria). Si no puede reasignarse una nueva memoria la función realloc devuelve NULL.

Si se pide menos memoria, libera la que sobra en el bloque reservado.

Si para el ejemplo anterior, se quiere reasignar la memoria a 50 enteros en vez de 100

apuntados por ip, se hará:

ip = (int *) realloc (ip, 50 * sizeof(int));

Uso de la función realloc

#include <stdio.h>

#include <stdlib.h>

void main()

{

int *p = NULL, *q = NULL;

int nbytes = 100;

Page 26: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

25

//asigna memoria nbytes al puntero p

p = (int *) malloc(nbytes);

if (p == NULL)

printf("\n\tInsuficiente espacio de memoria\n");

printf("\n\nSe han asignado %d bytes de memoria\n",nbytes);

//reasigna el bloque para contener datos

if (nbytes == 0)

{

free (p);

printf("\nEl bloque ha sido liberado\n");

}

q = (int *) realloc (p, nbytes*2);

if (q == NULL)

{

puts("La reasignacion no ha sido posible");

puts("Se conserva el bloque original");

}

else

{

p = q;

puts("Bloque reasignado");

printf("\nNuevo tamaño %d bytes\n", nbytes*2);

}

Page 27: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

26

free(p);

puts("Bloque de memoria liberado");

}

Matrices Dinámicas

Las matrices dinámicas son matrices que se crean durante la ejecución del programa.

Sus elementos pueden ser de cualquier tipo, al igual que las matrices estáticas.

Utilizando la técnica de asignación de memoria dinámicamente, podemos decidir

durante la ejecución cuantos elementos queremos que tenga nuestro array.

Para asignar memoria dinámicamente para una matriz se utiliza la función malloc o

calloc de la biblioteca de C.

Matrices dinámicas numéricas (Enteros o Reales)

Para crear una matriz en tiempo de ejecución, es necesario crear un puntero que

apunte a objetos del tipo de los elementos del array.

Ejemplo:

#include <stdio.h>

#include <stdlib.h>

Page 28: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

27

void main()

{

int *p = NULL;

int nbytes = 0, nElementos = 0, i = 0;

do

{

printf("Numero de elementos de la matriz: ");

scanf("%d",&nElementos);

fflush(stdin);

}while (nElementos < 1);

nbytes = nElementos * sizeof(int); //Aqui se determina el tamaño del bloque de memoria

if ((p = (int *) malloc (nbytes)) == NULL)

printf("\n\nInsuficiente espacio de memoria");

printf("\n\nSe han asignado %d bytes de memoria\n\n",nbytes);

//Iniciar los elementos de la matriz a cero

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

{

p[i] = 0;

printf(“%5d”,p[i]);

}

printf("Se está liberando memoria\n\n");

//Se libera memoria para el puntero p

free(p);

system("pause");

printf("\n\n");

}

Page 29: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

28

Para asignar memoria a una matriz de dos dimensiones, el proceso se divide en dos

partes:

� Asignar memoria para una matriz de punteros, cuyos elementos referenciarán

cada una de las filas de la matriz de dos dimensiones que desea crear.

� Asignar memoria para cada una de las filas. El número de elementos de cada fila

puede ser variable.

Para crear la matriz de punteros, primero tenemos que crear un puntero a un puntero,

puesto que sus elementos van a ser punteros a objetos de un determinado tipo.

int **m; // puntero que referencia la matriz de puntero

El paso siguiente es asignar memoria para la matriz de punteros:

m = (int **) malloc (nfilas * sizeof (int *));

Esto implica que la matriz de punteros debe tener nfilas elementos y que cada

elemento será un puntero a un entero (el primer entero de cada fila).

Para asignar memoria a cada una de las filas, suponiendo que tienen ncolumnas

elementos de tipo int:

for (f = 0; f < ncolumnas; f ++)

m[f] = (int *) malloc (ncolumnas * sizeof (int));

Ejemplo de matriz bidimensional dinámica

#include <stdio.h>

#include <stdlib.h>

void main()

Page 30: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

29

{

int **ppa = NULL;

int nFilas = 0, nCols = 0,f = 0, c = 0;

do

{

printf("Numero de Filas de la matriz: ");

scanf("%d",&nFilas);

fflush(stdin);

}while (nFilas < 1);

do

{

printf("Numero de Columnas de la matriz: ");

scanf("%d",&nCols);

fflush(stdin);

}while (nCols < 1);

//Asignar memoria para el array de punteros

if ((ppa = (int **) malloc (nFilas * sizeof(int *))) == NULL)

{

printf("\n\nInsuficiente espacio de memoria");

exit(0);

}

//Asignar memoria para cada fila

for (f = 0; f < nFilas; f ++)

{

if ((ppa[f] = (int *) malloc (nCols * sizeof(int))) == NULL)

{ printf("\n\nInsuficiente espacio de memoria");

exit(0);

}

Page 31: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

30

}

//Iniciar los elementos de la matriz a cero

for (f = 0; f < nFilas; f ++)

for (c = 0; c < nCols; c++)

*(*(ppa+f)+c) = 0;

//Impresion de datos de la matriz

for (f = 0; f < nFilas; f ++)

{

for (c = 0; c < nCols; c++)

printf("%d",*(*(ppa+f)+c));

printf("\n");

}

printf("Se está liberando memoria\n\n");

//Liberar la memoria asignada a cada fila

for (f = 0; f < nFilas; f ++)

free (ppa+f);

//Liberar la memoria asignada al array de punteros

free (ppa);

system("pause");

printf("\n\n");

}

Page 32: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

31

Para liberar la memoria ocupada por el array, primero liberamos la memoria

asignada a cada una de las filas y después la asignada al array de punteros.

Matrices dinámicas de cadenas de caracteres

Una matriz dinámica de cadena de caracteres es una matriz de dos dimensiones cuyos

elementos son de tipo char. Por lo tanto su construcción es idéntica a las matrices de dos

dimensiones vistas anteriormente.

Una matriz de cadena de caracteres es un caso típico donde las filas tienen un número

de elementos variables, dependiendo esto del número de caracteres que se almacene en

cada fila.

Ejemplo # 1:

Se trata de realizar un programa que lea una frase y, conservando el orden de las

palabras que ha leído, escriba cada una de estas palabras al revés. Por ejemplo:

“Hace mucho calor en el verano”

Se transformaría en:

“ecaH ohcum rolac ne le onarev”

#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXFRA 10 void main(void) { char c, temp[20]; char **frase; int j=0, i, npal=0, n; /* reservar espacio para el vector de punteros a las palabras */ frase = malloc(MAXFRA*sizeof(char*));

Page 33: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

32

printf("Introduzca una frase, y pulse \"Intro\" para finalizar.\n"); /* Lectura de las palabras */ do { c = getchar(); if (c != ' ' && c != '\n') temp[j++]=c; else { temp[j++] = '\0'; frase[npal] = malloc(j*sizeof(char)); strcpy(frase[npal++], temp); j=0; } } while (c != '\n'); printf("\n\nLas palabras de la frase son:\n"); for (j=0; j<npal; j++) printf("\t%s ", frase[j]); printf("\n\n"); printf("\n\nLas palabras al revés son:\n"); for (i=0; i<npal; i++) { printf("\t"); for (j=strlen(frase[i])-1; j>=0; j--) printf("%c", frase[i][j]); printf(" "); } printf("\n\n"); }

Page 34: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

33

Ejemplo #2:

/*Matriz dinámica de cadena de caracteres*/ #include <stdio.h> #include <stdlib.h> int LeerCadenas(char **nombre, int nFilas); void VisualizarCadenas(char **nombre, int nFilas); void main() { char **nombre = NULL; int nFilas = 0; int correcto = 0, filas = 0, f = 0; do { printf("\n\tNumero de filas de la matriz: "); correcto = scanf("%d",&nFilas); fflush(stdin); }while (!correcto || nFilas < 1); //Asignar memoria para la matriz de punteros if ((nombre = (char **)malloc(nFilas * sizeof(char *))) == NULL) { printf("\n\nInsuficiente espacio de memoria\n"); exit(0); } filas = LeerCadenas(nombre, nFilas); if (filas == -1) exit(0); VisualizarCadenas(nombre, filas); //Liberar la memoria asignada a cada una de las filas for (f = 0; f < filas; f++) free (nombre[f]); //Liberar la memoria asignada a la matriz de punteros free(nombre); } int LeerCadenas(char **nombre, int nFilas) { int f = 0, longitud = 0;

Page 35: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

34

char cadena[81]; printf("\n\tIntroducir cadenas de caracteres\n\n"); printf("para finalizar introduzca una cadena nula.\n"); printf("Esto es, pulse solo Enter.\n\n"); while(f < nFilas && (longitud = strlen(gets(cadena))) > 0) { //Asignar espacio para una cadena de caracteres if((nombre[f] = (char *)malloc(longitud + 1)) == NULL) { printf("Insuficiente espacio de memoria disponible\n"); return -1; } //copiar la cadena en el espacio de memoria asignada strcpy(nombre[f], cadena); f++; } return (f); } void VisualizarCadenas(char **nombre, int filas) { int f = 0; printf("\n\tVisualizacion de datos\n\n"); for(f = 0; f < filas; f++) printf("%s\n", nombre[f]); printf("\n\n"); }

Punteros a estructuras

Los punteros a estructuras se declaran igual que los punteros a otros tipos de datos.

Para referirse a un miembro de una estructura apuntada por un puntero hay que utilizar el

operador ‘->’.

El hecho de declarar un puntero a una estructura no significa que dispongamos de la

estructura; es necesario asignar al puntero un bloque de memoria del tamaño de la

estructura donde se almacenaran los datos de la misma.

Page 36: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

35

Ejemplo:

#include <stdio.h>

#include <string.h>

struct estudiante

{

char nombre[30];

char carnet[11];

int nota[5];

};

void main()

{

struct estudiante est, *pest;

int n, sum = 0;

float prom;

pest = &est;

printf("Nombre Estudiante: ");

gets(pest->nombre);

printf("No. Carnet: ");

fflush(stdin);

gets(pest->carnet);

printf("***Calificaciones del estudiante***\n");

for(n = 0; n < 5; n++)

{

printf("Nota[%d]: ", n+1);

scanf("%d",&pest->nota[n]);

sum += pest->nota[n];

}

prom = sum / 5;

Page 37: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

36

printf("\n****DATOS DEL ESTUDIANTE****\n");

printf("Nombre: %s\n",pest->nombre);

printf("No. Carnet: %s\n", pest->carnet);

printf("Promedio: %.f\n", prom);

}

Punteros a arrays de estructura

También se pueden usar punteros con arrays de estructuras. La forma de trabajar es

la misma, lo único que se tiene que hacer es asegurarse que el puntero inicialmente apunte

al primer elemento, luego saltar al siguiente hasta llegar al último.

Ejemplo:

#include <stdio.h> #define ELEMENTOS 3 struct estructura_amigo { char nombre[30]; char apellido[40]; char telefono[10]; int edad; }; struct estructura_amigo amigo[] = { "Juanjo", "Lopez", "504-4342", 30, "Marcos", "Gamindez", "405-4823", 42, "Ana", "Martinez", "533-5694", 20 };

Page 38: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

37

struct estructura_amigo *p_amigo; int main() { int num_amigo; p_amigo = amigo; /* apuntamos al primer elemento del array */ /* Ahora imprimimos sus datos */ for( num_amigo=0; num_amigo<ELEMENTOS; num_amigo++ ) { printf( "El amigo %s ", p_amigo->nombre ); printf( "%s tiene ", p_amigo->apellido ); printf( "%d años ", p_amigo->edad ); printf( "y su teléfono es el %s.\n" , p_amigo->telefono ); /* y ahora saltamos al siguiente elemento */ p_amigo++; } } En vez de p_amigo = amigo; se podía usar la forma p_amigo = &amigo[0]; es decir que

apunte al primer elemento (elemento 0) del array. La primera forma es la más usada pero la segunda quizás indica más claramente lo que se pretende.

Ahora se verá como introducir datos en un array de estructuras mediante punteros: #include <stdio.h> #define ELEMENTOS 3 struct estructura_amigo { char nombre[30]; char apellido[40]; int edad; }; struct estructura_amigo amigo[ELEMENTOS], *p_amigo;

Page 39: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

38

int main() { int num_amigo; /* apuntamos al primer elemento */ p_amigo = amigo; /* Introducimos los datos mediante punteros */ for ( num_amigo=0; num_amigo<ELEMENTOS; num_amigo++ ) { printf("Datos amigo %i\n",num_amigo); printf("Nombre: ");fflush(stdin); gets(p_amigo->nombre); printf("Apellido: ");fflush(stdin); gets(p_amigo->apellido); printf("Edad: ");fflush(stdin); scanf( "%d", &p_amigo->edad ); /* saltamos al siguiente elemento */ p_amigo++; } /* Ahora imprimimos sus datos */ p_amigo = amigo; for( num_amigo=0; num_amigo<ELEMENTOS; num_amigo++ ) { printf( "El amigo %s ", p_amigo->nombre ); printf( "%s tiene ", p_amigo->apellido ); printf( "%d años.\n", p_amigo->edad ); p_amigo++; } }

Page 40: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

39

EJERCICIOS PROPUESTOS

1. Calcule la longitud de una cantidad de caracteres ingresada por el teclado y visualice las

letras que contiene.

2. Escriba un programa en C que cuente el número de veces que aparece un carácter en

una cadena de N caracteres. Utilice asignación dinámica de memoria y recuerde liberar

dicha memoria.

3. Realice un programa que pida por teclado el tamaño de un vector y que almacene en él

números enteros aleatorios. Para recorrer el vector se pide utilizar punteros en lugar

de índices.

• El vector se crea en tiempo de ejecución, una vez que el usuario ha elegido el

tamaño.

• La función int rand(void) devuelve un número entero seudoaleatorio. Su prototipo

se encuentra en el fichero de cabecera stdlib.h

La función rand() genera una secuencia de números seudoaleatorios. Cada vez que se

invoca a esta función, devuelve un entero comprendido entre 0 y la macro

RAND_MAX definida en stdlib.h.

Se dice que rand() devuelve números seudoaleatorios porque siempre da los mismos

valores en el mismo orden. Para evitar que la secuencia aleatoria comience siempre

por la misma posición se puede utilizar la función srand() cuyo prototipo se

encuentra en stdlib.h y tiene la forma:

Page 41: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

40

void srand(unsigned semilla), esta función define un punto de inicio para la

secuencia generada por rand(); este punto de inicio viene dado por el parámetro

semilla.

Puede consultar la bibliografía de C para ver ejemplos sobre su funcionamiento.

4. Se pide crear un programa que pida una serie de números al usuario y halle el máximo, el

mínimo y el promedio de todos los datos. Para ello se debe crear una variable puntero

tipo float, pedir al usuario que introduzca el número de datos, y después los datos a

calcular. Se debe reservar memoria de forma dinámica para almacenar el vector de

dato.

5. Sea notas una matriz de 3 x 10 que almacene las calificaciones de los 10 alumnos de una

clase en cada una de las 3 asignaturas que cursan. Se pide diseñar una función que

reciba por parámetro las calificaciones obtenidas por los alumnos en una determinada

asignatura y que devuelva la calificación promedio. Hacer un programa que inicialice la

matriz con valores dados y que invoque a la función para calcular la nota promedio de

cada una de las asignaturas, imprimiendo el resultado por pantalla.

���� Utilice el siguiente prototipo de la función que calcula la nota promedio; recibe por parámetro la fila de la matriz que corresponde a la asignatura cuya nota promedio se va a calcular, double calculoPromedio (double * );

6. Cree una matriz bidimensional dinámicamente con N filas y M columnas e ingrese tanto

en la diagonal principal como en la secundaria unos y en las demás posiciones ceros.

Recuerde que las filas y columnas deben ser iguales, luego, imprima la matriz

resultante.

La impresión debe ser algo así:

Page 42: PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA · PDF filePUNTEROS Y ASIGNACION DINAMICA DE MEMORIA 1 PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA Un puntero es una variable que representa

PUNTEROS Y ASIGNACION DINAMICA DE MEMORIA

41

Matriz de 4 x 4

1 0 0 1

0 1 1 0

0 1 1 0

1 0 0 1

7. Hacer un programa que llene una matriz de nxm dinámicamente y almacene en su

diagonal principal el número correspondiente a la fila y además pida un carácter que

rellenará el resto de la matriz, ejemplo:

Filas: 3

Columnas: 3

Carácter de relleno: *

Matriz 3x3

0 * *

* 1 *

* * 2

8. Crear un programa en C que contenga una estructura denominada “Alumno”, en la que

deben considerarse como sus campos el nombre del alumno, el sexo (f o m) y la edad. El

programa debe permitir el ingreso de una cantidad finita de alumnos, calcular la

cantidad de varones y mujeres que hay en el grupo, y la edad mayor del alumno, luego

deberá visualizar la cantidad de mujeres y varones así como la información del alumno

cuya edad es mayor.