Apunte Punteros y Aritmética de Punteros

Anuncio
Universidad Tecnológica Nacional
Facultad Regional Córdoba
Departamento Ingeniería en Electrónica
Catedra de Infomática 1
JTP Ing. Mascietti, Norma
PA Pereira, Mauro Alejandro
Punteros y aritmética de punteros
1. Introducción
Una de las características más poderosas del C, es el puntero o apuntador. Los punteros permiten simular las
llamadas por referencia y crear y manipular estructuras de datos dinámicas, que pueden crecer y encogerse en tiempos de
ejecución, como las pilas, árboles y listas. Nos introduciremos ahora en los conceptos básicos de los punteros.
2. Definición de punteros
Los punteros son variables cuyos valores son direcciones de memoria. Por lo general, una variable contiene un
valor específico, un entero, un flotante, un carácter, etc. En cambio, una variable puntero contiene la dirección en
memoria de una variable que contiene un valor específico. De esta manera, mediante el nombre o el identificador de
una variable, hacemos referencia directa a un valor. En cambio, mediante el nombre o identificador de un puntero,
hacemos referencia indirecta a un valor. Al proceso de referenciar a un valor a través de un puntero, se le llama
indirección.
Nombre
Valor
Direcciones
FB21
cont
5
FB22
FB23
ptrcont hace
referencia
indirecta a una
variable cuyo
valor es 5
ptrcont
FB22
FB24
FB25
FB26
ptrcont
FB22
FB27
cont
cont hace referencia
directa al valor 5
5
FB28
3. Operadores con punteros
& → Operador de Dirección
* → Operador de Indirección
( o de referencia)
( o de desreferencia )
devuelve la dirección donde
se almacena el operando
devuelve el valor del objeto
que apunta
Hay que tener siempre en cuenta que los punteros son variables cuyos valores son direcciones de memoria, y que
estos operadores nos permiten por un lado almacenar en un puntero la dirección de memoria de la variable y por otro
lado, recuperar el valor al que está apuntando.
En el siguiente ejemplo se puede apreciar esto:
Ejemplo:
#include <stdio.h>
int main(int argc, char **argv)
{
int cont=5;
//declaro una variable del tipo int y le asigno el valor 5
int *ptrcont;
//declaro una variable que apunta a una variable del tipo int
ptrcont = &cont;
//con & pido la dirección de memoria de la variable cont
//y dicha dirección queda guardada dentro de ptrcont
1
Universidad Tecnológica Nacional
Facultad Regional Córdoba
Departamento Ingeniería en Electrónica
Catedra de Infomática 1
JTP Ing. Mascietti, Norma
PA Pereira, Mauro Alejandro
printf("Valor de la variable cont: %d, dirección de memoria: %p\n", cont, &cont);
//referencia directa
printf("Valor de la variable cont: %d, dirección de memoria: %p\n", *ptrcont ,
ptrcont);
//referencia indirecta
return 0;
}
4. Llamada a funciones con paso de parámetros por puntero (por referencia)
Existen dos formas de pasar argumentos a una función, por valor o por referencia. Las ventajas de la segunda con
respecto a la primera son:
• Puedo trabajar sobre varias direcciones de variables en la función y modificarles sus valores “automáticamente”
en el main(), mientras que con una llamada por valor, sólo puedo retornar el valor de una variable, a través de
return().
• Si tengo un objeto de gran tamaño, puedo sobrecargar el sistema con una llamada por valor (recuerde que es hacer
una copia del objeto).
Ejemplo de sintaxis:
#include …
void función_por_referencia(int *,int *);
int main(int argc, char **argv)
{int var1=0,var2=0;
int *var3;
var3=&(var2);
…
…
función_por_referencia(&var1, var3);
…
…
return 0;
}
void función_por_referencia(int *a,*b){
…
…
…
}
//prototipo
//declaro una variable int
//declaro un apuntador a una var. int
//llamada a la función intercambio
//cuerpo de la función
Notese que en los argumentos del llamado de la función una de las variables tiene antepuesta el operador &
para obtener la dirección de memoria de dicha variable (var1) y la segunda variable var3 no lo tiene. Esto es debido
a que var1 es una variable común, y necesitamos pasarle la dirección de memoria de dicha variable a la función,
para que la función la pueda trabajar como puntero; mientras que var3 ya es un puntero, por lo que no es necesario
utilizar el operador & porque el valor de var3 es una dirección de memoria. ¿Confundido? Vea la siguiente imágen
y analice los ejercicios.
2
Universidad Tecnológica Nacional
Facultad Regional Córdoba
Departamento Ingeniería en Electrónica
Catedra de Infomática 1
JTP Ing. Mascietti, Norma
PA Pereira, Mauro Alejandro
Ejercicios:
Realice un programa que eleve al cubo un número utilizando punteros e imprima el valor
original y elevado en el main().
#include <stdio.h>
void cuboporpuntero ( int *ptrnro );
//prototipo
int main(int argc, char **argv)
{
int numero = 5;
printf("El valor original de numero es %d\n", numero);
cuboporpuntero ( &numero );
//llamada
printf("El nuevo valor de numero es %d\n", numero);
}
return 0;
void cuboporpuntero ( int *ptrnro )
{
*ptrnro = *ptrnro * *ptrnro * *ptrnro;
//cuerpo de la funcion
}
Escriba un programa en C que intercambie los valores de dos variables a través de una función,
pasándole los parámetros por referencia. Los valores iniciales e intercambiados deben imprimirse en
el main()
#include <stdio.h>
void swap ( int *, int * ) ;
//prototipo
int main(int argc, char **argv)
{
int var1 = 3;
int var2 = 5;
int *var3;
var3=&var2;
//el valor de var3 es igual a la dir. mem. de var2
printf("El valor original de la primera variable es : %d \n", var1);
printf("El valor original de la segunda variable es : %d \n", var2);
swap( &var1, var3 );
//llamada a la función intercambio
printf("Despues de llamar a intercambio, el valor de las variables son... \n\n" );
printf("El valor de la primera variable es : %d \n", var1);
printf("El valor de la segunda variable es : %d \n", var2);
}
return 0;
void swap ( int *x, int *y )
{
}
3
int tmp=0;
tmp = *x;
*x = *y;
*y = tmp;
//cuerpo de la función
//variable auxiliar
Universidad Tecnológica Nacional
Facultad Regional Córdoba
Departamento Ingeniería en Electrónica
Catedra de Infomática 1
JTP Ing. Mascietti, Norma
PA Pereira, Mauro Alejandro
5. Aritmética de punteros
Con los apuntadores se pueden realizar un conjunto limitado de operaciones aritméticas. Un apuntador puede ser
incrementado (++), decrementado (–), se puede añadir un entero a un apuntador (+ o +=), un entero puede ser restado de
un apuntador (- o -=), o un apuntador puede ser sustraído o restado de otro.
Nos enfocaremos en la adición. Suponga que cada variable int tiene 4 bytes, que ha sido declarado un arreglo int
v[10] y su primer elemento está en memoria en la posición 3000. El apuntador vPtr ha sido inicializado para apuntar al
primer elemento del vector, o sea v[0]. El valor de vPtr será 3000. En la aritmética convencional, la adición de 3000 + 2
nos daría 3002. Por lo regular, este no pasa en la aritmética de punteros. Cuando se añade o se resta un entero de un
apuntador, el apuntador no incrementa o decrementa sólo por el valor de dicho entero, sino por el entero
multiplicado por el tamaño del objeto al cual el apuntador se refiere. El número de bytes depende del tipo de datos
del objeto. Por ejemplo, si se realiza la siguiente instrucción:
vPtr +=2;
producirá que el apuntador se desplace a la posición 3008 (3000 + 2 * 4) de memoria, no a la 3002. vPtr ahora apunta a
v[2].
Pos final mem = Pos ini mem + ( incremento * tam del objeto)
Supongamos ahora que int vale 2 bytes, tenemos un arreglo de enteros llamado Vec2[5] y un apuntador int
Ptrvec2:
Nombre
Valor
Dirección
Si hacemos
Ptrvec2 = Vec2
Vec2[0]
Vec2[1]
Vec2[2]
Vec2[3]
Vec2[4]
10
20
30
40
15
FFE0
FFE2
FFE4
FFE6
FFE8
Ptrvec2
Vec2[0] hace
referencia directa al
valor 10
FFE0
*Ptrvec2 hace
referencia indirecta al
primer elemento del
vector de enteros
cuyo valor es 10
Si ahora incrementamos en 2 el puntero:
Ptrvec2 = Ptrvec2 + 2  FFE0 + 2*2
Vec2[0]
10
(2 es la cantidad de bytes que ocupa un entero)
Ptrvec2
Vec2[2]
FFE4
30
Ptrvec2 ahora vale FFE4 y apunta a 30
Otro ejemplo, es un arreglo de caracteres o string, en el cual cada carácter ocupa 1 byte:
Nombre
Vec1[0]
Vec1[1]
Vec1[2]
Vec1[3]
Vec1[4]
4
Valor
‘a’
‘b’
‘c’
‘d’
‘e’
Dirección
FF00
FF01
FF02
FF03
FF04
Ptrvec1
FF00
*Ptrvec1 hace referencia
indirecta al primer
elemento del vector de
caracteres cuyo valor es
‘a’
Vec1[0] hace referencia
directa al valor ‘a’
Vec1[0]
‘a’
Universidad Tecnológica Nacional
Facultad Regional Córdoba
Departamento Ingeniería en Electrónica
Si le sumamos 2 al puntero:
Ptrvec1 = Ptrvec1 + 2 
Catedra de Infomática 1
JTP Ing. Mascietti, Norma
PA Pereira, Mauro Alejandro
FF00 + 2*1
(1 es la cantidad de bytes que ocupa un caracter)
Ptrvec1 ahora vale FF02 y apunta a ‘c’
6.
Ptrvec1
Vec1[2]
FF02
‘c’
Uso del calificador const con apuntadores
El calificador const permite al programador informarle al compilador que el valor de una
variable particular no deberá ser modificado.
El buen eso de este calificador, permite programar en base al principio de mínimo privilegio.
Si un valor no se modifica (o no debería modificarse) en el cuerpo de una función al cual
es pasado, el valor deberá declararse como const, para asegurarse que no se modifica de forma
accidental.
Por ejemplo, considere una función a la que se le pasa por argumentos, un arreglo y su tamaño,
e imprime el arreglo completo. Esta función que se basa en el tamaño para imprimir hasta el último
valor nunca debería ser modificado, por lo que una buena práctica de programación sería que fuera
declarado como const.
5
Descargar