TEMA 6: PUNTEROS 1 PUNTEROS......................................................2

Anuncio
TEMA 6: PUNTEROS
1 PUNTEROS......................................................2
2 LOS OPERADORES DE PUNTEROS ............2
3 ASIGNACIÓN Y COMPARACIÓN DE
PUNTEROS ..............................................................3
4 INICIALIZACIÓN DE PUNTEROS...................4
5 PROBLEMAS CON LOS PUNTEROS ............5
5.1 EJEMPLO DE PUNTERO QUE NO APUNTA AL TIPO
CORRECTO.......................................................................................................................... 5
5.2 EJEMPLO DE PUNTERO NO INICIALIZADO .................................. 6
5.3 EJEMPLO DE PUNTERO USADO DE FORMA INCORRECTA . 6
Tema 6
Pág. 1
1 Punteros
Una variable puntero es una variable estática como cualquier
otra que, en vez de contener valores de datos, contiene valores
que representan direcciones de memoria. Estas direcciones
generalmente, representa la dirección de memoria donde se
encuentra otra variable. Cuando el puntero contiene la dirección
de otra variable decimos que el puntero apunta a dicha variable.
Para que pueda acceder correctamente a la variable a la que
apunta, el puntero debe conocer que tipo de datos almacena. Así
pues, el tipo del puntero debe coincidir con el de los datos que
apunta.
tipo *nombre puntero;
Por ejemplo:
int *p;
El asterisco le indica al compilador que p no va a guardar un
dato de tipo int, sino una dirección para apuntar a una variable int.
2 Los operadores de punteros
Existen dos operadores especiales que se usan con los
punteros: * y &.
El operador & (operador dirección), devuelve la dirección de
memoria de la variable a la que afecte. Así, por ejemplo
p = &x;
El operador * (operador indirección u operador contenido)
aplicado sobre una dirección de memoria, es decir, sobre una
variable de tipo puntero, permite acceder al valor de la variable
situada en esa dirección de memoria.
Nombre de la Dirección de memoria Variable en
variable
memoria
X
1002
1250
1004
1008
P
1010
1002
*p
1012
Tema 6
Pág. 2
Ejemplo:
#include <stdio.h>
int main()
{
int cuenta, q;
int *m;
cuenta = 100;/*a cuenta se le asigna 100 */
m = &cuenta;/*m =recibe direc. de cuenta*/
q = *m;/*q=cuenta a través de m */
printf(“%i”,q);/*muestra en pantalla 100 */
return 0;
}
3 Asignación y comparación de punteros
En general, los punteros se ajustan a las mismas reglas que
cualquier otra variable y expresión en C, pudiendo utilizarse a la
derecha de una declaración de asignación para asignar su valor a
otro puntero. De la misma forma, podemos comparar dos
punteros en una expresión relacional.
#include <stdio.h>
int main()
{
int i=100;
int *p1, *p2;
p1 = &i;
p2 = p1;
if (p1==p2) /*comparación de punteros */
printf(“p1 apunta a la misma dirección que p2”);
printf (“El valor de *p2 es %d\n”, *p2);
i--;
prinft(“El valor de i es %d\n”, i);
}
Tema 6
Pág. 3
4 Inicialización de punteros
Al igual que otras variables, C no inicializa los punteros
cuando se declaran y es preciso inicializarlos antes de su uso.
Si se trata de usar el puntero antes de asignar un valor (una
dirección), como la dirección a la que apunta es desconocida, al
usarla puede que estemos modificando una parte de la memoria
reservada al sistema operativo o al código máquina de nuestro
programa o de algún otro.
Nunca se debe manipular la zona de memoria apuntada
por un puntero si no tenemos la seguridad de que dicha
zona de memoria está correctamente reservada.
Debemos por tanto inicializar el puntero antes de utilizarlo o
hacer que explícitamente un puntero no apunte a ningún sitio. Por
convención se da a un puntero que apunta a ningún sitio el valor
nulo para significar que el puntero apunta a nada.
Así pues, para un puntero existen tres posibilidades:
1. Estar indefinido (lo más peligroso)
2. No apuntar a nada
3. Apuntar a una variable o dirección de memoria
determinada.
Hacer que un puntero no apunte a ningún sitio implica
asignarle un valor especial predefinido llamado NULL:
int * p;
P=NULL;
Se puede decir ahora que p no apunta a nada. Es una buena
idea asignar el valor NULL a todos los punteros tan pronto como
el programa empieza su ejecución. Utilizar un puntero con un
valor NULL es más seguro que utilizar un puntero indefinido. Sin
embargo, llegar a ser un puntero con un valor nulo no hace más
seguro su uso. Si se usa un puntero nulo en el lado izquierdo de
una sentencia de asignación, se correría todavía el riesgo de
estropear el programa o el sistema operativo.
Tema 6
Pág. 4
5 Problemas con los punteros
Desgraciadamente, el uso de punteros es fuente continua de
errores, tanto al compilar como, lo que es peor, a la hora de
ejecutar. donde tendremos muchas mas dificultades para localizar
los fallos. Los punteros ofrecen mucho poder y son necesarios
para muchos programas, pero nada dará más problemas que un
puntero incontrolado. Si un puntero contiene accidentalmente un
valor erróneo, puede ser el fallo más difícil de depurar, ya que en
tiempo de compilación no se detecta nada y durante la ejecución
del programa pueden producirse efectos colaterales que son
difíciles de detectar.
5.1 Ejemplo de puntero que no apunta al tipo correcto
#include <stdio.h>
int main()
{
float x = 55.4;
int *p;
/*p es un puntero a un entero*/
p = &x; /*ERROR! Hacemos que el puntero a entero p
apunte a una variable float*/
printf("El valor correcto es: %f\n", x);
printf("Valor apuntado (como float): %f\n", *p);
printf("Valor apuntado (como int) : %d\n", *p);
return 0;
}
El resultado por pantalla es algo asi:
El valor correcto es: 55.400000
Valor apuntado (como float): 508524232706.400024
Valor apuntado (como int) : -26214
El compilador no produce errores, y completa su tarea. Como
mucho nos muestra un warning, avisando de la operación
sospechosa ("Suspicious pointer conversion in function main"
(conversión de puntero sospechosa en la función main)).
Tema 6
Pág. 5
5.2 Ejemplo de puntero no inicializado
int main()
{
int i, *p;
i = 50;
*p = i; /* ¡ERROR! Usamos el puntero p sin inicializarlo.
¿A dónde apunta? */
printf(“El valor de i es %d\n”, i);
printf(“El valor de *p es %d\n”, *p);
return 0;
}
Este programa esta mal porque asigna el valor de i (50) a
alguna dirección de memoria desconocida.
Para evitar este tipo de problemas debemos siempre
asegurarnos que un puntero apunta a algo válido antes de usarlo.
La compilación no producen errores y como mucho, dependiendo
del compilador, se producirá un warning, avisando de la
operación sospechosa ("Possible use of pointer before definition"
(Posible uso de un puntero antes de definirlo)).
5.3 Ejemplo de puntero usado de forma incorrecta
Este error suele ocurrir cuando olvidamos poner el operador de
dirección (&). P.ej:
#include <stdio.h>
int main()
{
int i, *p;
i = 50;
p = i; /* ERROR, p=al valor de i en vez de su dirección */
printf(“El valor de i es %d\n”, i);
printf(“El valor de *p es %d\n”, *p);
return 0;
}
La última llamada a printf no imprimirá el valor de i sino un
valor desconocido. Al compilar, puede producir (depende del
compilador) un warning: "Suspicious pointer conversion" o
"Nonportable pointer conversion", dependiendo de los casos.
Tema 6
Pág. 6
Descargar