Академический Документы
Профессиональный Документы
Культура Документы
Apuntadores en C
Temas
Distribucin de memoria en un programa. Introduccin al concepto de apuntador. Declaracin de apuntadores. Desreferencias. Aritmtica de apuntadores. Apuntadores y arreglos. Paso de parmetros a funciones por referencia.
Objetivo
General:
Aplicar el concepto de apuntador dentro del lenguaje de programacin ANSI C.
Especficos:
Introducir el concepto de apuntador. Aplicar aritmtica de apuntadores para acceder valores en arreglos.
Punteros o Apuntadores
Un apuntador o puntero es una variable que contiene una direccin de memoria. Por ejemplo, la direccin de otra variable .
Apuntadores
Apuntadores
Son poderosos pero difciles de manejar Se utilizan para manejar valores por referencia Tienen una relacin directa con los arreglos y con las cadenas (arreglos de caracteres) Necesarios para el manejo de memoria dinmica.
Declaracin de apuntadores
Las variables puntero se declaran de la siguiente forma: tipo *nombre; Siendo nombre el identificador de la variable puntero, y tipo el tipo de variable a la que apunta. Por ejemplo:
char *m; int *n; float *p; // apuntador a char // apuntador a entero // apuntador a flotante
En estas declaraciones, las variables m, n y p son punteros que apuntan, respectivamente, a datos de tipo char, int y float.
6
Declaracin e Inicializacin
Para declarar mltiples apuntadores se requieren mltiples asteriscos:
int *myPtr1, *myPtr2;
Ejemplo
int y = 9; int *yPtr; yPtr = &y; // yPtr almacena la direccin de y
yPtr apunta a y
y 9 yPtr 500000 600000 600000 y 9
yPtr
Ejemplo:
*yPtr = 20; // asigna 20 a y Porque yPtr apunta a y
Mas ejemplos
Dadas las declaraciones
float x; float *p, *q;
Ahora p y q almacenan la misma direccin de memoria: la de la variable x. El mismo efecto se consigue con la asignacin directa entre punteros:
p = &x; q = p;
11
Ejemplo 1
#include <stdio.h> int main() { int x; /* variable entera */ int y; /* variable entera */ int *px; /* variable puntero a entero */ x = 5; px = &x; /* asigna a px la direccion de x */ y = *px; /* asigna a y el contenido de la direccion almacenada en px */ printf("x = %d\n", x); printf("y = %d\n", y); printf("*px = %d\n", *px); getch(); return 0; }
12
Ejemplo 2
#include <stdio.h> int main() { int a; // a es un entero int *ptrA; // ptrA es un apuntador a un entero a = 7; ptrA = &a; // a ptrA se le asigna la direccin de a printf("La direccin de a es %d \nEl valor de ptrA es %d", &a, ptrA); printf("\n\nEl valor de a es %d \nEl valor de *ptrA es %d", a, *ptrA);
printf("\n\nMuestra de que * y & son inverso uno de otro\n"); printf("\n *&ptrA = &*ptrA \n%d=%d",*&ptrA ,&*ptrA);
getch(); return 0; } // fin de main
13
Ejercicio
Dado el siguiente fragmento de cdigo:
float n1; float n2; float *p1; float *p2; n1 = 4.0; p1 = &n1; p2 = p1; n2 = *p2; n1 = *p1 + *p2;
15
v[0]
v[1]
v[2]
v[3]
v[4]
16
Incremento / Decremento
Los operadores ++ y -- actan de modo diferente segn el tipo apuntado por el puntero. Si p es un puntero a caracteres (char *p) la operacin p++ incrementa el valor de p en 1. Si embargo, si p es un puntero a enteros (int *p), la misma operacin p++ incrementa el valor de p en 2 para que apunte al siguiente elemento, pues el tipo int ocupa dos bytes. Del mismo modo, para el tipo float la operacin p++ incrementa el valor de p en 4. Lo dicho para el operador ++ se cumple exactamente igual, pero decrementando, para el operador --.
17
Asignacin de apuntadores
Se pueden asignar (copiar el contenido), slo si son del mismo tipo ambos apuntadores Si no son del mismo tipo, se requiere el uso de casting
Es un apuntador genrico, representa cualquier tipo No se requiere casting para convertir un apuntador a un apuntador void El apuntador void no puede ser desreferenciado
18
Comparacin
Pueden compararse punteros del mismo modo que cualquier otra variable, teniendo siempre presente que se comparan direcciones y NO contenidos.
int *p, *q; if (p == q) puts ("p y q apuntan a la misma posicin de memoria");
19
Puntero NULL
Cuando se asigna 0 a un puntero, este no apunta a ningn objeto o funcin. La constante simblica NULL definida en stdio.h tiene el valor 0 y representa el puntero nulo. Es una buena tcnica de programacin asegurarse de que todos los punteros toman el valor NULL cuando no apuntan a ningn objeto o funcin. int *p = NULL; Para ver si un puntero no apunta a ningn objeto o funcin:
if (p == NULL) printf("El puntero es nulo\n"); else printf("El contenido de *p es\n", *p);
20
La direccin de
&b[ 3 ] es lo misma que bPtr + 3
21
Punteros y vectores
El nombre del vector representa la direccin del primer elemento del vector:
float vector[MAX_TAM]; vector == &vector[0]
Es decir, &x[i] y (x+i) representan la direccin del i-esimo elemento del vector x => x[i] y *(x+i) representan el contenido del i-esimo elemento del vector x.
22
Ejemplo 1/2
// Uso de subndices y notacin de apuntadores con arreglos. #include <stdio.h>
int main() { int i, j, offset1, offset2; int b[] = { 10, 20, 30, 40 }; int *bPtr = b; // inicializa bPtr para apuntar al arreglo b
// salida del array b usando subndices (notacin arreglo subndice) printf("Array b se imprime como:\n\n"); printf("Notacion Arreglo Subindices\n"); for ( i = 0; i < 4; i++ ) printf("b[%d] = %d \n", i, b[ i ] );
// Salida de arreglo b usando notacin apuntador desplazamiento printf("Notacion apuntador/ desplazamiento\n"); printf("el apuntador es el nombre del arreglo\n"); for ( offset1 = 0; offset1 < 4; offset1++ ) printf("* (b + %d )= %d \n", offset1, *( b + offset1 ) );
23
Ejemplo 2/2
// salida del array b usando subndices sobre bPtr printf("\nNotacion apuntador subindice\n"); for ( j = 0; j < 4; j++ ) printf("bPtr[%d] = %d \n", j, bPtr[ j ] ); printf("\nNotacion apuntador / desplazamiento\n"); // salida del array b usando notacin apuntador/desplazamiento sobre bPtr for ( offset2 = 0; offset2 < 4; offset2++ ) printf("* (bPtr + %d )= %d \n", offset2, *( bPtr + offset2 ) ); getch(); return 0; } // fin main
Salida: Con el arreglo y sus subndices b[0] = 10 b[1] = 20 b[2] = 30 b[3] = 40 Con notacin apuntador/desplazamiento *(b + 0) = 10 *(b + 1) = 20 *(b + 2) = 30 *(b + 3) = 40
24
Ejercicio
Hacer un programa que realice operaciones sobre un array utilizando un apuntador llamado aPtr y notacin apuntador desplazamiento. Los valores del arreglo a son: 2.2, 4.4, 6.6, 8.8, 10.
1. 2. 3. 4. 5. 6. 7. 8. 9. Imprimir el tamao de cada uno de los elementos del arreglo en bytes. Asignar al primer elemento el valor 3. Multiplicar el tercer elemento por 2. Restar del cuarto elemento, la suma del primero y el segundo. Imprimir todos los valores del arreglo. Obtener el menor de los nmeros en el arreglo y la direccin de memoria en donde est almacenado. Mover el apuntador al ltimo elemento y modificar su contenido a 0. Obtener el tamao o nmero de elementos del arreglo. Regresa el apuntador a la posicin inicial del arreglo.
Hacer una funcin que imprima todos los valores del arreglo utilizando como parmetro un apuntador a un arreglo y el nmero de elementos del mismo.
Probarla con el ejemplo anterior.
25
Apuntadores a caracteres
// Imprime de la a a la z utilizando un apuntador
#include <stdio.h> int main() { char var1 ; /*una variable del tipo caracter */ char *pchar; /* un apuntador a una variable del tipo caracter */ pchar = &var1 ; /*asignamos al apuntador la direccion de la variable */ for (var1 = 'a'; var1 <= 'z'; var1++) printf("%c", *pchar) ; /* imprimimos el valor de la variable apuntada */ getch(); return 0 ; }
26
Arreglos de apuntadores
Un arreglo puede contener apuntadores
Normalmente se usan para almacenar arreglos de cadenas:
char *suit[ 4 ] = {"Hearts", "Diamonds", "Clubs", "Spades" };
H D C S
e i l p
a a u a
r m b d
t o s e
s n \0 s
\0 d s \0
\0
El arreglo suit tiene un tamao fijo, pero los strings pueden ser de cualquier tamao.
28
Ejercicio
1. Hacer un programa que inicialice el arreglo suit del ejemplo anterior y que despus imprima su contenido. 2. Hacer una funcin que reciba un apuntador a cadena y regrese la longitud de la misma.
Prototipo de la funcin: int mystrlen(char *s);
29
argc: Entero que indica el nmero de parmetros tecleados (incluye el nombre del programa). argv[ ]: Matriz de cadenas de caracteres. Cada uno de los elementos argv[i] es una cadena que almacena un argumento.
30
Para que los argumentos sean tratados como diferentes tienen que ir separados por uno o varios espacios blancos
31
Ejemplo
Programa que lista los parmetros, si los hay, de la lnea de rdenes. #include <stdio.h> int main (int argc, char *argv[ ]) { register int i; printf ("\nNombre del programa: %s", argv[0]); if (argc == 1) printf ("\nNo se han introducido parmetros"); else { printf ("\nParmetros en la lnea de rdenes: "); for (i = 1; i < argc; i++) printf ("\n%d: %s", i, argv[i]); } return 0; }
32
Ejercicio
Hacer un programa que reciba como argumentos de la funcin main() dos valores y que imprima el resultado de la suma de ambos. Si no recibe el nmero correcto de parmetros que imprima un mensaje de error.
33
Memoria dinmica
Cuando un vector se define como un puntero no se le pueden asignar valores ya que un puntero no reserva espacio en memoria.
float x[10] define un vector compuesto por 10 nmeros reales en este caso SI se reserva espacio para los elementos. float *x declara un puntero a float. No se reserva memoria.
Si se quiere que float x se comporte como un vector habr que reservar memoria para los 10 elementos: x = (float *) malloc(10 * sizeof(float));
debemos indicar el tipo de apuntador que deseamos utilizar (float*)
malloc(nb) (stdlib.h) reserva un bloque de memoria de nb bytes. Para liberar la memoria asignada se utiliza free() (stdlib.h) free(x); El uso de punteros permite definir vectores de forma dinmica.
34
Ejemplo
#include <stdio.h> #include <stdlib.h> #include <string.h> char *p , palabra[20] ; p = (char *)malloc(sizeof(char)*128) ; printf("Escriba su nombre : ") ; scanf("%s" , p ) ; strcpy(palabra , " Como le va " ) ; printf("%s%s" , palabra , p ) ; }
35
Ejemplo (1/2)
Programa que calcula la media de un vector de tamao especificado de forma dinmica. #include <stdio.h> #include <stdlib.h> void leer_vector(int vector[], int dim); int media_vector(int vector[], int dim); main() { int *v_numeros; int dimension; int media; printf("Dimension del vector: "); scanf("%d", &dimension); v_numeros = (int *) malloc(dimension*sizeof(int)); leer_vector(v_numeros, dimension); media = media_vector(v_numeros, dimension); printf("La media es %d\n", media); free(v_numeros); }
37
Ejemplo (2/2)
Programa que calcula la media de un vector de tamao especificado de forma dinmica. void leer_vector(int vector[], int dim) { int j; for(j=0; j<dim; j++) { printf("Elemento %d: ", j); scanf("%d", &vector[j]); } return; } int media_vector(int vector[], int dim) { int j; int media = 0; for(j=0; j<dim; j++) media = media + vector[j]; return(media/dim); }
38
El retorno de las mismas puede inicializar apuntadores del mismo tipo al devuelto , distinto , por medio del uso del casting . Algunas funciones, tales como malloc() y calloc() definen su retorno como apuntadores a void : void *malloc( int tamano ) ; de esta forma al invocarlas, debemos indicar el tipo de apuntador que deseamos utilizar: p = (double *) malloc( 64 ) ;
39
Recursos
Ejemplos y ejercicios resueltos sobre apuntadores:
http://wiki.lidsol.net/wiki/index.php?title=Apuntadores_3# asignacion_de_memoria_dinamica_para_estructuras
40