|
|
|
||
|
|
|||
|
|
|||
|
Lenguaje c |
|||
|
8) Punteros |
|||
|
|
Los
punteros en el Lenguaje C , son variables que poseen la dirección de las
ubicaciones en memoria de otras variables, y por medio de ellos se tendra un
poderoso método de acceso a todas ellas . Quizás esta parte sea la mas conflictiva del lenguaje , ya que muchos programadores en C , lo ven como un método extraño ó al menos desacostrumbrado. Sin embargo , y en la medida que uno se va familiarizando con ellos , se convierten en la herramienta más cómoda y directa para el manejo de variables complejas , argumentos , parámetros , etc , y se empieza a preguntar como es que hizo para programar hasta aquí , sin ellos . Veamos primero , como se declara un puntero : |
||
|
tipo de variable apuntada *nombre_del_puntero ;
int *pint ;
double *pfloat ;
char *letra , *codigo , *caracter ;
En estas
declaraciones sólo decimos al compilador que reserve una posición de memoria
para albergar la dirección de una variable , del tipo indicado , la cual
será referenciada con el nombre que hayamos dado al puntero . int var ; /* declaro ( y se crea en memoria ) una variable entera ) */
int *pint ; /* un puntero que contendrá la dirección de una variable entera */
pint = &var ; /* escribo en la dirección de memoria donde está el
puntero la dirección de la variable entera */ Lo que hemos hecho se puede simbolizar de la siguiente manera : donde dentro del recuadro está el contenido de cada variable . Pint xxxxxx valor contenido por var Dirección de var yyyyyy (posición de memoria xxxxxx (posición de memoria ocupada por el puntero ) ocupada por la variable)
. y = var ; y = *pint ; printf("%d" , var ) ; printf("%d" , *pint) ; En estos casos , la expresión " *nombre_del_puntero " , implica " contenido de la variable apuntada por el mismo " Veamos un corto ejemplo de ello :
#include main()
return
0; PUNTEROS Y ARRAYS
El
nombre de un array , para el compilador C , es un PUNTERO inicializado con
la dirección del primer elemento del array . Sin embargo hay una importante
diferencia entre ambos.
ASIGNACION
Es
perfectamente válido asignar a un puntero el valor de otro , el resultado de
ésta operación es cargar en el puntero punt la dirección del elemento [0]
del array conjunto , y posteriormente en la variable var el valor del mismo
(8.0) y para luego cambiar el valor de dicho primer elemento a 25.1 .
PUNTEROS Y VARIABLES DINAMICAS
double *p ; notemos que ésta declaración no crea lugar para la variable , sino que asigna un lugar en la memoria para que posteriormente se guarde ahí la dirección de aquella Para reservar una cantidad dada de bytes en el Heap , se efectua una llamada a alguna de las funciones de Librería , dedicadas al manejo del mismo . La más tradicional es malloc() ( su nombre deriva de memory allocation ) , a esta función se le dá como argumento la cantidad de bytes que se quiere reservar , y nos devuelve un pointer apuntando a la primer posición de la "pila" reservada . En caso que la función falle en su cometido ( el Heap está lleno ) devolvera un puntero inicializado con NULL . p = malloc(8) ;
acá
hemos pedido 8 bytes y hemos asignado a p el retorno de la función , es
decir la dirección en el Heap de la memoria reservada. p = malloc( sizeof(double) ); En caso de haber hecho previamente un uso intensivo del Heap , se debería averiguar si la reserva de lugar fué exitosa: if( p == NULL ) rutina_de_error(); si no lo fué estas sentencias me derivan a la ejecución de una rutina de error que tomará cuenta de este caso . Por supuesto podría combinar ambas operaciones en una sola , if( ( p = malloc( sizeof(double) ) ) == NULL ) { printf("no hay mas lugar en el Heap ..... " ); exit(1) ; }
se ha
reemplazado aquí la rutina de error , por un mensaje y la terminación del
programa , por medio de exit() retornando un código de error . *p = a * ( b + 37 ); y para recuperarlo , y asignarselo a otra variable bastaría con escribir : var = *p; PUNTEROS A STRINGS
p = "Esto es un string constante " ; esta operación no implica haber copiado el texto , sino sólo que a p se le ha asignado la dirección de memoria donde reside la "E" del texto . #include
#define TEXT1 "¿ Hola , como " #define TEXT2 "estas ? "
main()
{
char pal[20] , *p ; int i ; p = TEXT1 ;
for( i = 0 ; ( pal[i] = *p++ ) != '\0' ; i++ ) ;
p = TEXT2 ; printf("%s" , pal ) ;
printf("%s" , p ) ;
return 0 ;
}
while( *pal++ = *p++ ) ; ARRAYS DE PUNTEROS
char *flecha; definía a un puntero a un caracter , la definición char *carcaj[5]; implica un array de 5 punteros a caracteres .
INICIALIZACION DE ARRAYS DE PUNTEROS
char *vocales[] = { "letra no válida" , "a" , "e" , "i" , "o" , "u" , } Igual que antes, no es necesario en este caso indicar la cantidad de elementos , ya que el compilador los calcula por la cantidad de términos dados en la inicialización. Asi el elemento vocales[0] será un puntero con la dirección del primer string, vocales[1], la del segundo, etc. PUNTEROS A ESTRUCTURAS
struct conjunto {
int a ;
double b ;
char c[5] ;
} stconj ; stconj.a = 10 ;
stconj.b = 1.15 ;
stconj.c[0] = 'A' ; La forma de realizar lo mismo , mediante el uso de un puntero, sería la siguiente : struct conjunto {
int a ;
double b ;
char c[5] ;
} *ptrconj ;
ptrconj = (struct conjunto *)malloc( sizeof( struct conjunto )) ;
ptrconj->a = 10 ;
ptrconj->b = 1.15 ;
ptrconj->c[0] = 'A' ; En este caso vemos que antes de inicializar un elemento de la estructura es necesario alojarla en la memoria mediante malloc(), observe atentamente la instrucción: primero se indica que el puntero que devuelve la función sea del tipo de apuntador a conjunto (ésto es sólo formal), y luego con sizeof se le da como argumento las dimensiones en bytes de la estructura. PUNTEROS COMO PARAMETROS DE FUNCIONES
struct
conjunto { int a ; double b ; char c[5] ; } datos ;
Hicimos
notar, en su momento, que en este caso la estructura se copiaba en el stack
y así era pasada a la función, con el peligro que esto implicaba, si ella
era muy masiva, de agotarlo.
struct
conjunto { int a ; double b ; char c[5] ; } *pdatos ;
Con lo
que sólo ocupo lugar en el stack para pasarle la dirección de la misma.
Luego en la función, como todos los miembros de la estructuras son
accesibles por medio del puntero, tengo pleno control de la misma.
char *funcion1( char * var1 ) ;
double *funcion2(int i , double j , char *k ) ;
struct item *funcion3( struct stock *puntst ) ;
El retorno de las mismas puede inicializar punteros del mismo tipo al devuelto , ó distinto , por medio del uso del casting . Algunas funciones , tales como malloc() y calloc() definen su retorno como punteros a void : void *malloc( int tamano ) ; de esta forma al invocarlas , debemos indicar el tipo de puntero de deseamos p = (double *)malloc( 64 ) ;
|
|||
|
Descargar gratis los programas y compiladores necesarios para aprender a programar |
|||
|
¿Buscas algo? |
|||
|
|
|||
|
|
|||
|
|
|||