UNIVERSIDAD DE EL SALVADOR FACULTAD DE INGENIERIA Y ARQUITECTURA ESCUELA DE INGENIERIA DE SISTEMAS INFORMATICOS ESTRUCTURAS DE DATOS GUIA DE LABORATORIO PUNTEROS Introducción: Un puntero es una variable que contiene la dirección de un objeto ya sea otra variable, un vector, estructura, etc . Cuando se declara un puntero éste contiene una dirección arbitraria, si leemos a dónde apunta nos dará un valor indefinido y si se escribe en tal dirección estamos variando el contenido de una posición de memoria. Los punteros son útiles para: modificar los argumentos en las funciones, asignación dinámica de memoria y la optimización de uso de la misma. La presente guía pretende ejemplificar el uso de los punteros en diferentes situaciones para una mejor comprensión de su uso. Objetivo: Que el estudiante conozca y practique el uso de los punteros en C. Ejemplo 1 Objetivo del programa: Mostrar el uso de los operadores básicos en la declaración de punteros Empleando el direccionamiento y el operador de indirección. #include <stdio.h> #include <conio.h> void main(void) { int a; int *punt; //declaración de puntero. a=57; //inicialización de variable punt=&a; //asignación de dirección al puntero. clrscr(); printf("a = %d", a); //imprimo valor de variable printf("\n&a = %x", &a); //imprimo dirección variable apuntada (en hexadecimal) printf("\npunt = %x ", punt); //imprimo la dirección guardada (la de la variable apuntada) printf("\n*punt = %d", *punt); //imprimo el contenido de la dirección apuntada. printf("\ntama¤o puntero %d", sizeof(punt)); getch(); } Ejemplo 2 Objetivo del programa: Manipular el contenido de variables de diferentes tipos de datos a través de la aplicación de punteros. #include <stdio.h> #include <conio.h> void main() { char carac='A', *r; int a=12,b=45, c; ESTRUCTURAS DE DATOS CICLO II 1 int *p, *q; clrscr(); printf("Dirección de a=%p\n", &a); printf("Dirección de b=%p\n", &b); printf("a = %d b = %d\n", a, b); printf("Dirección de caract = %p\n", &carac); printf("carac = %c\n", carac); printf("Valor ASCII de carac = %d\n", carac); printf("Dirección de p = %p\n", &p); printf("Dirección de q = %p\n", &q); printf("Dirección de r = %p\n", &r); p = &a; q = &b; r = &carac; printf("El puntero p apunta a la dirección: %p\n", p); printf("Y su contenido es: %d\n", *p); printf("El puntero q apunta a la dirección: %p\n", q); printf("Y su contenido es: %d\n", *q); printf("El puntero r apunta a la dirección: %p\n", r); printf("Y el contenido de *r es: %d\n", *r); printf("Como caracter ASCII *r contiene: %c\n", *r); getch(); } Ejemplo 3 Objetivo del programa: Aplicar la notación de punteros para manipular un arreglo. Note que el arreglo tiene una limitante relacionada a la cantidad de memoria reservada. #include <stdio.h> #include <stdlib.h> #include<conio.h> #define MAXCOL 30 void main() { int nfila, ncol, f, c,(*a)[MAXCOL]; clrscr(); puts("Intro n§ de filas:"); scanf("%d", &f); puts("Introducir numero de columnas:"); scanf("%d", &c); puts("Llenamos el array:"); for(nfila=0; nfila<f; nfila++) for(ncol=0; ncol<c; ncol++) { printf("(*(a+%d)+%d) = ", nfila, ncol); scanf("%d", *(a+nfila)+ncol); } puts("Imprimimos el array:"); for(nfila=0; nfila<f; nfila++) { for(ncol=0; ncol<c; ncol++) printf(" %d",*(*(a+nfila)+ncol)); puts(""); ESTRUCTURAS DE DATOS CICLO II 2 } getch(); } Ejemplo 4 Objetivo del programa: Referenciar a un arreglo como un puntero a un grupo de arreglos contiguos. #include <stdio.h> #include <conio.h> void main() { int x[2][3], fil, col; clrscr(); puts("Llenamos el array"); for(fil=0; fil<2; fil++) for(col=0; col<3; col++) { printf("x[%d][%d] = ", fil, col); scanf("%d", &x[fil][col]); } printf("\nImprimimos usando un puntero a un grupo de arrays:\n"); printf("\nPRIMERA FILA:\n"); for(col=0; col<3; col++) printf(" %d", (*x)[col]); printf("\nSEGUNDA FILA:\n"); for(col=0; col<3; col++) printf(" %d", (*(x+1))[col]); getch(); } Ejemplo 5 Objetivo del programa: Mostrar el acceso al contenido de un arreglo a través de la declaración de un puntero hacia esa estructura. #include <conio.h> #include <stdio.h> void main() { int mat[] = {1,2,3,4}, *pmat, i; clrscr(); printf("\Empleamos notación decimal\n"); printf("Hacemos que el puntero señale al primer elemento del array: pmat = mat"); pmat = mat; //pmat=&mat[0]; //ES LO MISMO QUE pmat =mat printf("\nComprobamos los valores: "); printf("\nDirección de inicio del array: mat = %u", &mat[0]); getch(); printf("\nDirección de pmat: &pmat = %u", &pmat); ESTRUCTURAS DE DATOS CICLO II 3 getch(); printf("\n Imprimimos las direcciones de memoria:\n"); for(i=0; i<4; i++) { printf("\n&mat[%u] = %u (pmat+%u) = %u ", i, &mat[i], i, (pmat+i)); printf(" mat[%u] = %u *(pmat+%u) = %u" , i, mat[i], i, *(pmat+i)); } getch(); } Ejemplo 6 Objetivo del programa: Declarar un puntero a una cadena de caracteres e imprimirlo carácter a carácter hasta que detecta, en el bucle do...while el carácter nulo de final de cadena ('\0') #include <stdio.h> #include <conio.h> void main() { char *nombre = "PEPE PEREZ"; int i=0; clrscr(); do printf("%c", *(nombre+i)); while(*(nombre+i++)); //postincremento de i, para cambiar VCB puts(" "); //imprime blanco ,m s salto de l¡nea. puts(nombre); getch(); } Ejemplo 7 Objetivo del programa: Manipular estructuras de memoria estáticas, empleando subíndices y aritmética de punteros. #include <stdio.h> #include <conio.h> void main() { float mat[2][4] = { {1.45, -2.35, -14.08, 17.3}, //primera fila {20, 2.95, 0.082, 6.023} //segunda fila }; int i, j; clrscr(); puts("Imprimimos las direcciones de memoria y valores contenidos:"); puts("\nDireccción de memoria &mat[i][j] \t\tContenido mat[i][j]"); for(i=0;i<2; i++) ESTRUCTURAS DE DATOS CICLO II 4 for(j=0; j<4; j++) printf("\n\t&mat[%d][%d] = %p \t\t\t mat[%d][%d] = %g", i\ ,j,&mat[i][j], i,j, mat[i][j]); getch(); printf("\n\nRepetimos los resultados empleando notación de punteros:\n"); getch(); puts("\nDireccción de memoria *(mat+i)+j \t\tContenido *(*(mat+i)+j)"); for(i=0;i<2; i++) for(j=0; j<4;j++) printf("\n\t(mat+%d)+%d = %p \t\t\t *(*(mat+%d)+%d) = %g", i,j, *(mat+i)+j, i,j, *(*(mat+i)+j)); getch(); printf("\n\nVeamos algunos valores (sin escribir i cuando vale cero: "); printf("\n*(*(mat)) = %g",*(*(mat))); printf("\n*(*(mat)+1) = %g",*(*(mat)+1)); printf("\n*(*(mat+1)+1) = %g",*(*(mat+1)+1)); getch(); } Ejemplo 8 Objetivo del programa: acceder a los datos de un arreglo bidimensional, empleando subíndices y aritmética de punteros. /* Imprime los valores de una matriz con punteros*/ #include "stdio.h" #include "conio.h" #define FILAS 3 #define COLUMNAS 2 void main() { int i; char mat[FILAS][COLUMNAS]= {{1,2},{3,4},{5,6}}; clrscr(); puts("Imprimimos como array:"); for(i=0; i<FILAS*COLUMNAS; i++) printf("%d\n", (*mat)[i]); puts("\nImprimimos utilizando punteros:"); for(i=0; i<FILAS*COLUMNAS; i++) printf("%d\n", (**mat+i)); //------getch(); } Ejemplo 9 Objetivo del programa: Emplear notación de punteros para manipular un arreglo unidimensional de punteros ESTRUCTURAS DE DATOS CICLO II 5 // con notación de punteros tanto en la entrada como //salida de datos. #include "stdio.h" #include "conio.h" void main() { int i,j; int *p[4]; //array de punteros// int **px=p; //px es un puntero a un puntero// clrscr(); printf("Introduzca 16 valores enteros\n"); for (i=0; i<4; i++) for (j=0; j<4; j++) scanf ("%d", *(px+i)+j); for (i=0; i<4; i++) { for (j=0; j<4; j++) printf("%7d", *(*(px+i)+j)); printf("\n"); } getch(); } Ojo es vector y se maneja como matriz corregir en 9 y 10 ver si se deja con un ciclo o 2. Ejemplo 10 Objetivo del programa: Presentar un arreglo unidimensional de punteros y un puntero a puntero, introducirle valores e imprimirlo. #include <stdio.h> #include <conio.h> void main() { int i,j; int *p[4]; //array de punteros// int **px=p; //px es un puntero a un puntero// clrscr(); printf ("Introduzca 16 valores enteros:\n"); for (i=0; i<4; i++) for (j=0; j<4; j++) scanf ("%d", &px[i][j]); for (i=0; i<4; i++) { for (j=0; j<4; j++) printf("%7d",px[i][j]); //Imprime como array "%7d" deja 7 blancos ESTRUCTURAS DE DATOS CICLO II 6 //printf("%7d", *(*(px+i)+j)); //Imprime como puntero printf("\n"); } getch(); } Ejemplo 11 Objetivo del programa: Mostrar las direcciones de memoria y los contenidos de la misma, al emplear arreglos unidimensionales y aritmética de punteros #include <stdio.h> #include <conio.h> void main() { int mat[] = {2, 16, -4, 29, 234, 12, 0, 3}, i =0; system(cls); puts("Imprimimos las direcciones de memoria y valores contenidos:"); puts("\nDireccción de memoria &mat[i] \t\tContenido mat[i]"); for ( ; i<8 ; i++) printf("\n\t&mat[%d] = %p \t\t mat[%d] = %d", i,&mat[i], i, mat[i]); getch(); printf("\n\nRepetimos los resultados empleando notación de punteros:\n"); getch(); puts("\nDireccción de memoria mat + i \t\tContenido *(mat+i)"); for( i=0 ; i<8 ; i++) printf("\n\tmat+%d = %p \t\t\t *(mat+%d) = %d", i, mat+i, i, *(mat+i)); getch(); } EJERCICIOS 1. Un programa C contiene la siguiente declaración: static char *color[6] = {“red”, “green”, “blue”, “white”, “black”, “yellow”}; a) ¿Cuál es el significado de color? __________________________________________________________________ b) ¿Cuál es el significado de (color+2)? __________________________________________________________________ c) ¿Cuál es el valor de *color? __________________________________________________________________ d) ¿Cuál es el valor de *(color + 2)? __________________________________________________________________ e) ¿Cuál es la diferencia de color[5] y *(color+5)? 2. Escriba el propósito de cada una de las siguientes declaraciones en C: a) float ( *x ) ( int *a ); ____________________________________________________________________ ____________________________________________________________________ ESTRUCTURAS DE DATOS CICLO II 7 b) float ( *x ( int *a ) ) [20]; ____________________________________________________________________ ____________________________________________________________________ c) float x ( int ( *a ) [] ); ____________________________________________________________________ ____________________________________________________________________ d) float x ( int *a[] ); ____________________________________________________________________ ____________________________________________________________________ e) float *x ( int a[] ); ____________________________________________________________________ ____________________________________________________________________ 3. Escriba un programa completo en C, usando notación de punteros en lugar de notación de arreglos que lea una línea de texto, la guarde en un arreglo, y luego la escriba en forma inversa. Permita que el tamaño de la línea sea terminada por un retorno de carro pero que no exceda 80 caracteres. 4. Escriba un programa en C, usando notación de punteros en lugar de notación de arreglos que lea un arreglo unidimensional de números enteros y aplicando un método de ordenamiento de vectores los ordene en forma Ascendente. ESTRUCTURAS DE DATOS CICLO II 8