Sunteți pe pagina 1din 5

El uso de punteros en C supone, por su proximidad a las

direcciones del lenguaje máquina, una fuente de potencia y


flexibilidad. Pero precisamente por su proximidad al lenguaje
máquina los punteros suelen ser difíciles de entender en un
primer momento, y ciertamente son la fuente de numerosos
errores. Por tanto, conviene meditar (no hay otra expresión)
sobre los conceptos asociados a estas estructuras del
lenguaje.

Un puntero es una variable que contiene la dirección de una


posición de memoria. Esa posición de memoria es la
dirección de comienzo de una variable; la variable puede
serdinámica .

Esta es la esencia del concepto: una dirección de memoria,


esto es, la dirección de un determinado byte. Esto puede
suponer una cierta dificultad conceptual cuando encontramos
declaraciones de puntero como las siguientes:
int * p;
float * q;
double * r;
¿Qué tiene que ver un int , o un float , o un double , con
un puntero? Todas las direcciones de memoria son iguales,
luego puede parecer sobrante asociar un tipo al puntero p .
Sin embargo, tiene sentido. Dada una dirección de memoria,
¿cómo se pude saber la extensión de la variable que comienza
en ella? ¿Cómo saber el tipo de esa variable?
Verdaderamente, es imprescindible asociar un tipo a los
punteros: sólo así podremos interpretar correctamente la
variable cuya dirección contienen.

Declaración de punteros .
En general, dado un Tipo atómico, los punteros de ese tipo
se declaran en la forma
Tipo * puntero_de_tipo;
esto es: basta intercalar un asterisco entre el nombre del tipo
y el nombre de la variable para hacer que la variable
declarada sea un puntero de algun objeto del tipo Tipo .

Punteros no iniciados .
En el momento de su declaración, el puntero contiene un
valor que no está definido, y no es otro que la trama de bits
que haya en memoria en la zona reservada para el puntero
por el compilador. Esta trama es ciertamente aleatoria e
imprevisible, y puede muy bien ser la dirección de una zona
de memoria perteneciente a la aplicación, o más
probablemente se tratará de una zona de memoria no
perteneciente a aplicación. Si interpretamos la (¡inexistente¡)
variable señalada por el puntero, el valor obtenido es
impredecible, y lo más probable es que su codificación no se
ajuste al tipo de variable asociado al puntero. Si intentamos
escribir y la "variable" señalada no reside en el espacio de
memoria de nuestra aplicación, el programa se detendrá de
inmediato, por haber intentado acceder a una posición que no
le pertenece. Si la "variable" señalada reside en la zona de
memoria de nuestra aplicación, podremos ciertamente
escribir... y muy posiblemente destruiremos información de
una variable realmente existente. Esta destrucción de
información se notará tarde o temprano, sin que sea posible
determinar fácilmente por qué se ha producido.
Consiguientemente:

Antes de emplear un puntero para obtener el valor de una


variable o para dar valor a la variable señalada por el
puntero, es imprescindible almacenar en el puntero la
dirección de la zona de memoria deseada.

¿Cómo se le da valor a un puntero? Mediante una operación


de asignación. Para obtener la dirección de la zona de
memoria que debe señalar el puntero se puede emplear el
operador ampersand (&) o bien cualquier función que
proporcione un puntero de tipo compatible con el nuestro. En
este sentido, hay que tener en cuenta que C aplica a los
punteros las mismas reglas de comprobación estricta de tipos
que se aplican a todas las demás variables.

La constante NULL .
Como medida preventiva, el lenguaje C ofrece una constante
que denota el puntero nulo, esto es, una dirección tal que
todo intento de acceder a la variable que comienza en esta
dirección (tanto para leer como para escribir) se detecta y
supone la parada inmediata del programa. Esta constante se
denomina NULL . Es buena práctica de programación asignar
el valor NULL a los punteros recién declarados. De esta
manera, el intento de utilizar esos punteros sin darles antes
un valor válido será detectado y se producirá un error. Esto se
haría mediante una declaración de la forma
Tipo * puntero = NULL;

Operador & . El operador & proporciona la dirección de su


operando, esto es, del objeto que se le proporciona como
argumento. En general, su aplicación tendrá la forma
siguiente:
Tipo variable;
Tipo * puntero;
puntero = &variable;
Obsérvese la necesidad de respetar los tipos en las
asignaciones de punteros, ya mencionada. Sin embargo,
internamente, todas las direcciones ocupan cuatro bytes. Por
tanto es posible refundir punteros de distintos tipos, y los
resultados son correctos si el usuario conoce realmente la
estructura señalada. Véase el Ejercicio 9 .

Operador * y acceso a variables señaladas por punteros


El operador *, antepuesto a una variable de tipo puntero,
denota el objeto señalado por ese puntero. A este proceso se
denomina "deshacer una indirección". De este modo se
consigue una expresión totalmente equivalente al nombre de
una variable, que podrá empleare exactamente igual que el
nombre de la variable, si existiera. La utilización del operador
* será en general de la forma
Tipo variable, valor;
Tipo * puntero;
puntero = &variable;
*puntero = valor; /* Equivale a variable = valor; */
La importancia de poder utilizar
indistintamente *puntero y variable se hará patente en el
tema dedicado a variables dinámicas . En pocas palabras,
existe un mecanismo que permite crear y destruir variables
bajo el control directo del programador. Las variables así
creadas no poseen nombre, y el acceso a las mismas se
efectúa a través de punteros, empleando el operador * para
acceder directamente a ellas si son atómicas, o bien otros
operadores ( [] , -> ) sin son estructuradas.

Alias .
Las expresiones variable y *puntero de la sección anterior
son equivalentes. Se dice entonces que p es un alias de
variable. Nada impide crear múltiples alias de una variable,
que podrían utilizarse desde distintos lugares de un
programa:
float valor;
float *alias_1, *alias_2, *alias_3;
alias_1 = alias_2 = alias_3 = &valor;
El uso de alias es potencialmente peligroso, pues permite
modificar el valor de una variable empleando cualquiera de
esos alias.

Punteros de tipos estructurados. Baste decir que todos los


tipos de variables de C poseen el correspondiente tipo de
puntero. De hecho, ¡incluso las funciones tienen sus punteros!
En particular, las variables estructurada disponen también de
sus tipos de punteros, lo cual hace posible, como se
mencionaba más arriba, crear variables estructuradas
dinámicamente, para después acceder a ellas de forma
análoga al sus equivalentes estáticos o automáticos. El
objetivo del uso de punteros en C es, por tanto, doble:
 Por una parte, se pretende aproximar en lo posible los
programas en C a programas en lenguaje máquina; esto
mejora la eficiencia y la flexibilidad, y lleva a programas
muy compactos.
 Por otra, se consigue optimizar el consumo de memoria.
En efecto, dado que se pueden crear y destruir variables
bajo control del programador, nunca será preciso
mantener en el programa una estructura de datos que ya
no se precise, y será posible adaptar el programa a la
situación concreta en que se está ejecutando (número de
elementos de una lista, dimensiones de un archivo de
disco, etc.).

El uso de punteros en C puede resultar complejo en un


principio, pero hace que el lenguaje resulte ideal para su
destino inicial, que era y es la programación de sistemas.

S-ar putea să vă placă și