Diseño de algoritmos “Punteros” Claudio Gutiérrez-Soto.
Punteros Un puntero es una variable que hace referencia a una dirección de memoria Sintaxis: Tipo_Dato *nombre_variable_puntero; Ejemplo: int *p; Asignación de Dirección nombre_puntero=&variable;
Punteros El carácter & delante de una variable indica que lo se está accediendo es a la dirección de memoria de dicha variable. Ejemplo: int *p; p=0; /* p posee la dirección NULL ó 0*/ p=NULL; /* p posee la dirección NULL ó 0*/ p=&i; /*p apunta hacia i ó conteniendo la dirección de i */ p=(int )1501; /*dirección absoluta de memoria */
Punteros " Si p es un puntero, entonces *p es el valor de la variable a la que apunta .“ Ejemplo: double x,y,*p; p=&x; y=*p; Lo anterior es equivalente a : y=*&x; y=x;
Punteros Inicialización Sintaxis: tipo_dato *nombre_puntero=&variable; Ejemplo: int i=7,*p=&i;
Punteros Construcciones a las que no se debe apuntar. *No apuntar a constantes. &3 /* ilicito*/ *No apuntar a arreglos, el nombre de un arreglo es una constante int a[77]; &a; *No apuntar a expresiones ordinarias &(k+99)
Punteros *No apuntar a variables de tipo register. register v; &v; *Si a es un arreglo, expresiones como: &a[0] y a[i+j+3] adquieren sentido
Punteros int i=3, j=5, k,*p=&i, q=&5,r; double x=11.5;
Punteros
Punteros Llamada por valor Máx(a,b) Int a,b; { return((a>b)?a:b); } Llamado por referencia Máx(a,b,m_ptr) Int a, b,*m_ptr; *m_ptr=(a>b)?a:b;
Punteros Relación entre punteros y arreglos. Un puntero es una variable cuyos valores son direcciones. El nombre de un arreglo es una dirección o puntero fijo. Cuando se declara un arreglo, el compilador debe asignar una dirección base y la cantidad de almacenamiento suficiente como para alojar a todos los elementos del arreglo.
Punteros #define TAM 100 int a[TAM], *p; y el sistema hece que los bytes numerados 300, 304, 309,......696 sean las direcciones de a[0], a[1], a[2],...,a[99]. p=a; = p=&a[0];
Punteros Aritmética de punteros La aritmética de puntero proporciona una opción para la indización de arreglos, las proposiciones p=a+1; = p=&a[1]; Sumar un arreglo: suma=0; for(p=a; p<&a[TAM];++p) suma+=*p;
Punteros suma=0; for(i=0;i<TAM;++i) suma+=*(a+i); Debido a que a es un puntero constante, las expresiones como: a=p; ++a; a+=2; Son ilícitas, no se puede cambiar la dirección de a. Expresiones apuntadoras como p+1, ++p y p+=i son válidas. Double a[ ]; = double*a;
Punteros Cadenas Las cadenas son arreglos unidimensionales de tipo char, Por convención, una cadena en C se termina con centinela de fin de cadena ó carácter nulo \0. char s[ ]="ABC" char *p="a es por anon o pastel alfabeto" void main() { char *q="del cual todos tienen parte"; printf("\n%s,%s\n %s",s,p,q); ABC: a es por anon o pastel alfabeto del cual todos tienen parte. For(p=q;*q!='\0';++q) *q+=1 printf("\n %s\n\n",p); }
Punteros Arreglos multidimensionales Expresiones equivalentes ab[i][i] *(b[i]+j) (*(b+i))[j] *((*(b+i))+J) (&b[0][0]+5i+j) Al definir la función, en el encabezamiento, la declaración: Int (*v)[5]; = int v[ ][5]; Int c[7][9][2]; C[i][j][k] = (&c[0][0][0]+9*2+i+2*j+k)
Asignación dinámica de memoria Cuando definimos un arreglo con un tamaño definido, podemos tener dos posibles casos, uno es un desaprovechamiento de la memoria y otro es la falta de espacio, lo cual en general no sucede.
Asignación dinámica de memoria Por ende, podría ser posible definir: int *x; En lugar de int x[10]; No obstante, si no conocemos el tamaño de manera predeterminada, es posible asignar espacio de manera dinámica.
Asignación dinámica de memoria Así para asignar memoria de manera dinámica podemos utilizar la función malloc, como sigue: x= (int *)malloc(10*sizeof(int)); Esta función reserva un bloque de memoria cuyo tamaño (en bytes) es equivalente a 10 cantidades enteras.
Asignación dinámica de memoria En general el <<cast>> de tipo que procede a malloc debe ser consistente con el tipo de datos de la variable puntero. Así si quisiéramos pedir en tiempo de ejecución para una variable tipo double sería: y=(double *)malloc(10*sizeof(double));
Asignación dinámica de memoria int i,n,*x; …. printf(“Cuántos números serán ingresados\”); scanf(“%d”,&n); /* reserva de memoria para n */ x=(int *)malloc(n*sizeof(int)); for(i=0;i<n;i++){ printf( “i=%d x=“, i+1); scanf(“%d”,x+i); }
Uso de typedef en estructuras Recordemos que la palabra reservada typedef nos permite redefinir un tipo de dato, por ejemplo: typedef int entero; Es posible definir tipos de datos con la nueva definición entero a,b,c;
Uso de typedef en estructuras Por ello, en términos generales se puede definir. typedef struct{ miembro 1; miembro 2; miembro 3; …. }nuevo-tipo;
Uso de typedef en estructuras typedef struct{ int mes; int dia; int anho; }fecha; fecha Aux;
Estructuras y punteros Podemos acceder a la dirección de una variable estructura de la misma manera que cualquier otra dirección, mediante el uso del operador (&). Así podemos escribir: tipo *ptvar;
Estructuras y punteros Ejemplo: typedef struct{ int no_cuenta; char tipo_cuenta; char nombre[80]; float saldo; }cuenta; cuenta cliente, *pc;
Estructuras y punteros En este ejemplo cliente es una variable estructura de tipo cuenta y pc un puntero que apunta a una variable de tipo cuenta. Por ende pc=&cliente; Así podemos acceder a un miembro individual de una estructura en términos de su correspondiente variable puntero escribiendo Ptvar->miembro Lo que es equivalente a escribir variable.miembro
Estructuras y punteros El operador -> puede combinarse con el operador punto para acceder a un submiembro dentro de una estructura. Por lo tanto, un submiembro puede ser accedido escribiendo ptvar->miembro.submiembro
Estructuras y punteros typedef struct{ int mes; int dia; int anio; }fecha; struct Cuenta{ int no_cuenta; char tipo_cuenta; char nombre[80]; float saldo; fecha ultimopago; }cliente,*pc=&cliente; cliente.no_cuenta, pc->no_cuenta, (*pc).no_cuenta
Estructuras y punteros typedef struct{ int mes; int dia; int anio; }fecha; struct Cuenta{ int no_cuenta; char tipo_cuenta; char nombre[80]; float saldo; fecha ultimopago; }cliente,*pc=&cliente; cliente.ultimopago.mes, pc->ultimopago.mes, (*pc).ultimopago.mes
Estructuras y punteros struct Cuenta{ int no_cuenta; char tipo_cuenta; char nombre[80]; float saldo; fecha ultimopago; }cliente,*pc=&cliente; typedef struct{ int mes; int dia; int anio; }fecha; Para acceder al tercer carácter del nombre, este puede ser accedido de la siguiente manera: cliente.nombre[2] pc->nombre[2] (*pc).nombre[2]
Ejemplo main(){ int n=3333; char t=‘A’; float b=99.99; typedef struct{ int mes; int dia; int anio; }fecha; struct Cuenta{ int *no_cuenta; char *tipo_cuenta; char *nombre; float *saldo; fecha ultimopago; }cliente,*pc=&cliente; cliente.no_cuenta=&n; cliente.tipo_cuenta=&t; cliente.nombre=“Lázaro”; cliente.saldo=&b; printf(“%d %c %s %.2f”,*cliente.no_cuenta,*cliente.tipo_cuenta, cliente.nombre,*cliente.saldo); printf(“%d %c %s %.2f \n”,*pc->no_cuenta,*pc->tipo_cuenta, pc->nombre,*pc->saldo); } 3333 A Lázaro 99.99
¿Preguntas?