República Bolivariana de Venezuela
Ministerio del Poder Popular Para La Defensa
Universidad Nacional Experimental Politécn...
Punteros Y Direccionamiento De Memoria

Un puntero

es una variable que contiene una dirección de memoria.

Normalmente, e...
Asignación de punteros

Como en el caso de cualquier otra variable, un puntero puede utilizarse a la
derecha de una declar...
Punteros Y Arrays

Existe una estrecha relación entre los punteros y los arrays. Considérese el
siguiente fragmento:
char ...
Indirección Múltiple

Se puede hacer que un puntero apunte a otro puntero que apunte a un valor de
destino. Esta situación...
char *p;
p = (char *) malloc(1000);

Después de la asignación, p apunta al primero de los 1000 bytes de la memoria
libre. ...


Puntero constante: es aquel que se declara como tal y, por tanto, siempre apunta a
la misma posición

tipodato *const n...
main()

{

char palabra[20] , *p ;

int i ;

p = TEXTO1 ;

for( i = 0 ; ( palabra[i] = *p++ ) != '0' ; i++ ) ;

p = TEXTO2...
Vemos que aquí se ha agregado muy poco a lo ya sabido , sin embargo hay un
tipo de error muy frecuente , que podemos anali...
#include

char *p , palabra[20] ;

p = (char *)malloc(sizeof(char)128) ;

printf("Escriba su nombre : ") ;

scanf("%s" , p...
scanf("%s" , p ) ;

palabra = "¿ Como le va " ;

printf("%s%s" , palabra , p ) ; }

Obsérvese , que es idéntico al primero...
} datos

;

void una_funcion( struct conjunto datos );

Hicimos notar, en su momento, que en este caso la estructura se co...
p_control = "valor : %d " ;

printf( p_control , var ) ;

PUNTEROS COMO RESULTADO DE UNA FUNCION

Las funciones que retorn...
Ejercicio 1:

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct agenda_telefon...
scanf("%i",&opcion);
system("clear");

switch(opcion)
{
case 1:

printf("nnnnnttt! NUEVO REGISTRO
!nn");
printf("tNombre :...
else
{

printf("nnttEl registro no
fue guardado");
getchar();
system("clear");

}
break;
case 2:
printf("nnnntt ***** A G ...
{
primer == malloc(sizeof(tipo_agenda));

if(primer != NULL)
{
strcpy(primer->_numero,r_numero);

strcpy(primer->_nombre,r...
while (anterior>siguiente_registro

&& strcmp(anterior->siguie nte_registro-

>_nombre,ultimo->_nombre)<0)
anterior = ante...
anterior = NULL;
while(nodo && strcmp(nodo->_nombre,r_nombre)<0)

{
anterior = nodo;
nodo = nodo->siguiente_registro;
}

i...
Ejercicio 2:

#include <conio.h>
#include <stdio.h>
#define N_VENDEDORES 18
#define N_PRODUCTOS 10

/* Función que muestra...
case 2:
printf("Numero de vendedor: ");scanf("%d",&nvend);

printf("Ventas total del vendedor %d=%.2lfn",

nvend,totalVend...
}
double totalVendedor(double v[][N_PRODUCTOS], int nVendedor){

double resp=0;
int i;
for(i=0;i<N_PRODUCTOS;i++){
resp+=v...
Upcoming SlideShare
Loading in...5
×

Luis hernandez 22310621

184

Published on

Programacion I- Apuntadores

Published in: Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
184
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
7
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Luis hernandez 22310621

  1. 1. República Bolivariana de Venezuela Ministerio del Poder Popular Para La Defensa Universidad Nacional Experimental Politécnica De Las Fuerzas Armadas UNEFA –Yaracuy Extensión Nirgua Profesor: Luis Sequera Integrante: Luis Hernández Programación I Apuntadores Y Direcciones De Memoria
  2. 2. Punteros Y Direccionamiento De Memoria Un puntero es una variable que contiene una dirección de memoria. Normalmente, esa dirección es la posición de otra variable de memoria. Si una variable contiene la dirección de otra variable, entonces se dice que la primera variable apunta a la segunda. Si una variable va a contener un puntero, entonces tiene que declararse como tal. Una declaración de un puntero consiste en un tipo base, un * y el nombre de la variable. La forma general es: tipo *nombre; Donde tipo es cualquier tipo válido y nombre es el nombre de la variable puntero. El tipo base del puntero define el tipo de variables a las que puede apuntar. Técnicamente, cualquier tipo de puntero puede apuntar a cualquier dirección de la memoria, sin embargo, toda la aritmética de punteros esta hecha en relación a sus tipos base, por lo que es importante declarar correctamente el puntero. Existen dos operadores especiales de punteros: & y *. El operador de dirección (&) devuelve la dirección de memoria de su operando. El operador de indirección (*) devuelve el contenido de la dirección apuntada por el operando. Después de declarar un puntero, pero antes de asignarle un valor, éste contiene un valor desconocido; si en ese instante lo intenta utilizar, probablemente se estrellará, no sólo el programa sino también el sistema operativo. Por convenio, se debe asignar el valor nulo a un puntero que no este apuntando a ningún sitio, aunque ésto tampoco es seguro. Apuntadores Y Direcciones De Memoria
  3. 3. Asignación de punteros Como en el caso de cualquier otra variable, un puntero puede utilizarse a la derecha de una declaración de asignación para asignar su valor a otro puntero. Por Ejemplo: int x; int *p1,*p2; p1=&x; p2=p1; Tanto p1 como p2 apuntan a x. Aritmética de Punteros Existen sólo dos operaciones aritméticas que se puedan usar con punteros: la suma y la resta. Cada vez que se incrementa un puntero, apunta a la posición de memoria del siguiente elemento de su tipo base. Cada vez que se decrementa, apunta a la posición del elemento anterior. Con punteros a caracteres parece una aritmética normal, sin embargo,el resto de los punteros aumentan o decrecen la longitud del tipo de datos a los que apuntan. Por ejemplo, si asumimos que los enteros son de dos bytes de longitud y p1 es un puntero a entero con valor actual 2000. Entonces, después de la expresión p1++; p1 contiene el valor 2002, no 2001. No pueden realizarse otras operaciones aritméticas sobre los punteros más allá de la suma y resta de un puntero y un entero. En particular, no se pueden multiplicar o dividir punteros y no se puede sumar o restar el tipo float o el tipo double a los punteros. Apuntadores Y Direcciones De Memoria
  4. 4. Punteros Y Arrays Existe una estrecha relación entre los punteros y los arrays. Considérese el siguiente fragmento: char cad[80], *p1; p1=cad; Aquí, p1 ha sido asignado a la dirección del primer elemento del array cad. Para acceder al quinto elemento de cad se escribe cad[4] o *(p1+4). Un nombre de array sin índice devuelve la dirección de comienzo del array, que es el primer elemento. El compilador traduce la notación de arrays en notación de punteros. Es decir, al crear un array se genera un puntero (en realidad una constante de puntero) con el mismo nombre que apunta a la dirección del primer elemento del array. Arrays de Punteros Los punteros pueden estructurarse en arrays como cualquier otro tipo de datos. La declaración, por ejemplo, para un array de punteros a enteros de tamaño 10 es: int *x[10]; Para asignar la dirección de una variable entera llamada var al tercer elemento del array de punteros se escribe:x[2]=&var; Se puede encontrar el valor de var de la forma: var de la forma: *x[2];Si se quiere pasar un array de punteros a una función, se puede utilizar el mismo método que se utiliza para otros arrays: llamar simplemente a la función con el nombre del array sin índices. Así se pasa el puntero que apunta al array. No se pasa un puntero a enteros, sino un puntero a un array de punteros a enteros. Apuntadores Y Direcciones De Memoria
  5. 5. Indirección Múltiple Se puede hacer que un puntero apunte a otro puntero que apunte a un valor de destino. Esta situación se denomina indirección múltiple o punteros a punteros. Una variable que es puntero a puntero tiene que declararse como tal. Esto se hace colocando un * adicional en frente del nombre de la variable. Por ejemplo, la siguiente declaración inicial indica al compilador que ptr es un puntero a puntero de tipo float:float **ptr; Funciones de Asignación Dinámica Los punteros proporcionan el soporte necesario para el potente sistema de asignación dinámica de memoria de C. La asignación dinámica es la forma en la que un programa puede obtener memoria mientras se está ejecutando. Como ya se ha visto, a las variables globales se les asigna memoria en tiempo de compilación y las locales usan la pila. Sin embargo, durante la ejecución no se pueden añadir variables globales o locales, pero existen ocasiones en las que un programa necesita usar cantidades de memoria variables. El centro del sistema de asignación dinámica está compuesto por las funciones (existentes en la biblioteca stdlib.h) malloc(), que asigna memoria; y free() que la devuelve. El prototipo de la función malloc() es: stdlib.h) malloc(), que asigna memoria; y free() que la devuelve.void *malloc(size_t número de bytes); Tras una llamada fructífera, malloc() devuelve un puntero, el primer byte de memoria dispuesta. Si no hay suficiente memoria libre para satisfacer la petición de malloc(), se da un fallo de asignación y devuelve un nulo. El fragmento de código que sigue asigna 1000 bytes de memoria: Apuntadores Y Direcciones De Memoria
  6. 6. char *p; p = (char *) malloc(1000); Después de la asignación, p apunta al primero de los 1000 bytes de la memoria libre. El siguiente ejemplo dispone espacio para 50 enteros. Obsérvese el uso de sizeof para asegurar la portabilidad: p apunta al primero de los 1000 bytes de la memoria libre. El siguiente ejemplo dispone espacio para 50 enteros. Obsérvese el uso de sizeof para asegurar la portabilidad: int *p; p= (int *) malloc(50*sizeof(int)); La función free() es la opuesta de malloc() porque devuelve al sistema la memoria previamente asignada. Una vez que la memoria ha sido liberada, puede ser reutilizada en una posterior llamada a malloc(). El prototipo de la función free() es: void free (void *p); free(p); Tipo De Punteros  Puntero genérico: es aquel que no apunta a ningún tipo de dato void *nombrepuntero; Se declaran así para que posteriormente se les pueda hacer apuntar a cualquier tipo de dato.  Puntero nulo: es aquel que no apunta a ningún dato tipodato *nombrepuntero = NULL; NULL es una constante definida en stdio.h. Se utiliza para indicar situaciones de error Apuntadores Y Direcciones De Memoria
  7. 7.  Puntero constante: es aquel que se declara como tal y, por tanto, siempre apunta a la misma posición tipodato *const nombrepuntero; El contenido, el dato apuntado, si puede cambiar. Si es el dato lo que se declara como constante se escribe const tipodato *nombrepuntero; Si el puntero y el dato al que apunta se declaran constantes const tipodato *const nombrepuntero PUNTEROS A STRINGS No hay gran diferencia entre el trato de punteros a arrays , y a strings , ya que estos dos últimos son entidades de la misma clase . Sin embargo analicemos algunas particularidades . Así como inicializamos un string con un grupo de caracteres terminados en '0' , podemos asignar al mismo un puntero : 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 . A partir de ello podemos manejar a p como lo hemos hecho hasta ahora . Veamos un ejemplo #include #define TEXTO1 "¿ Hola , como " #define TEXTO2 "le va a Ud. ? " Apuntadores Y Direcciones De Memoria
  8. 8. main() { char palabra[20] , *p ; int i ; p = TEXTO1 ; for( i = 0 ; ( palabra[i] = *p++ ) != '0' ; i++ ) ; p = TEXTO2 ; printf("%s" , palabra ) ; printf("%s" , p ) ; return 0 ; } Definimos primero dos strings constantes TEXTO1 y TEXTO2 , luego asignamos al puntero p la dirección del primero , y seguidamente en el FOR copiamos el contenido de éste en el array palabra , observe que dicha operación termina cuando el contenido de lo apuntado por p es el terminador del string , luego asignamos a p la dirección de TEXTO2 y finalmente imprimimos ambos strings , obteniendo una salida del tipo : " ¿ Hola , como le va a UD. ? " ( espero que bien ) . Reconozcamos que esto se podría haber escrito más compacto, si hubieramos recordado que palabra tambien es un puntero y NULL es cero , así podemos poner en vez del FOR while( *palabra++ = *p++ ) ; Apuntadores Y Direcciones De Memoria
  9. 9. Vemos que aquí se ha agregado muy poco a lo ya sabido , sin embargo hay un tipo de error muy frecuente , que podemos analizar , fíjese en el EJEMPLO siguiente , ¿ ve algun problema ? . ( CON ERRORES ) #include char *p , palabra[20] ; printf("Escriba su nombre : ") ; scanf("%s" , p ) ; palabra = "¿ Como le va " ; printf("%s%s" , palabra , p ) ; } Pues hay dos errores , a falta de uno , el primero ya fue analizado antes , la expresión scanf("%s" , p ) es correcta pero , el error implícito es no haber inicializado al puntero p , el cual sólo fué definido , pero aun no apunta a ningun lado válido . El segundo error está dado por la expresión : palabra = " ¿ Como le va " ; ( también visto anteriormente ) ya que el nombre del array es una constante y no puede ser asignado a otro valor . ¿Como lo escribiríamos para que funcione correctamente ? (CORRECTO) #include #include Apuntadores Y Direcciones De Memoria
  10. 10. #include char *p , palabra[20] ; p = (char *)malloc(sizeof(char)128) ; printf("Escriba su nombre : ") ; scanf("%s" , p ) ; strcpy(palabra , "¿ Como le va " ) ; printf("%s%s" , palabra , p ) ; } Observe que antes de scanf() se ha inicializado a p, mediante el retorno de malloc() y a al array palabra se le copiado el string mediante la función vista anteriormente. Debemos aclarar también que, la secuencia de control %s en el printf() impone enviar a la pantalla un string, estando éste apuntado por el argumento siguiente al control, éste puede ser tanto el nombre de un array, como un puntero, ya que ambos explicitan direcciones. Una forma alternativa de resolverlo , sería: #include main() { char p[20] , *palabra ; printf("Escriba su nombre : ") ; Apuntadores Y Direcciones De Memoria
  11. 11. scanf("%s" , p ) ; palabra = "¿ Como le va " ; printf("%s%s" , palabra , p ) ; } Obsérvese , que es idéntico al primero , con la salvedad que se ha invertido las declaraciones de las variables , ahora el puntero es palabra y el array es p . Ambas soluciones son equivalentes y dependerá del resto del programa , cual es la mejor elección . PUNTEROS Y FUNCIONES La relación entre los punteros y las funciones , puede verse en tres casos distintos , podemos pasarle a una función un puntero como argumento (por supuesto si su parámetro es un puntero del mismo tipo ) , pueden devolver un puntero de cualquier tipo , como ya hemos visto con malloc() y calloc() , y es posible también apuntar a la dirección de la función , en otras palabras , al código en vez de a un dato. PUNTEROS COMO PARAMETROS DE FUNCIONES . Supongamos que hemos declarado una estructura , se puede pasar a una función de la siguiente manera: struct conjunto { int a ; double b ; char c[5] ; Apuntadores Y Direcciones De Memoria
  12. 12. } datos ; void una_funcion( struct conjunto 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. Otra forma equivalente es utilizar un puntero a la estructura : struct conjunto { int a ; double b ; char c[5] ; } *pdatos ; void una_funcion( struct conjunto *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. Un ejemplo de funciones ya usadas que poseen como parámetros a punteros son: scanf(puntero_a_string_de_control , punteros_a_variables) printf(puntero_a_string_de_control , variables ) En ambas vemos que los strings de control son , como no podría ser de otro modo , punteros , es decir que los podríamos definir fuera de la función y luego pasarselos a ellas : Apuntadores Y Direcciones De Memoria
  13. 13. p_control = "valor : %d " ; printf( p_control , var ) ; PUNTEROS COMO RESULTADO DE UNA FUNCION Las funciones que retornan punteros son por lo general aquellas que modifican un argumento, que les ha sido pasado por dirección ( por medio de un puntero ) , devolviendo un puntero a dicho argumento modificado , ó las que reservan lugar en el Heap para las variables dinámicas , retornando un puntero a dicho bloque de memoria . Así podremos declarar funciónes del tipo de: 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 ) ; Apuntadores Y Direcciones De Memoria
  14. 14. Ejercicio 1: #include <conio.h> #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct agenda_telefonica { char _nombre[25]; char _apellido[25]; char _numero[12]; struct agenda_telefonica *siguiente_registro; }tipo_agenda; typedef tipo_agenda *tipo_nodo,*tipo_lista; int opcion,posicion,resp,i; char nombre[25],apellido[25],numero[12]; void insertar(tipo_lista *r_lista,char r_nombre[],char r_apellido[],char r_numero[]); void borrar(tipo_lista *r_lista,char r_nombre[]); void mostrar(tipo_lista *lista); int main() {clrscr(); tipo_lista lista = NULL; do { printf("nnnnnttt! M E N U !nn"); printf("tt1) Nuevo Registronn"); printf("tt2) Mostrar Agenda Telefonicann"); printf("tt3) Borrar Registronn"); printf("tt4) Cerrar el programann"); printf("tt----> OPCION [1-4]: "); Apuntadores Y Direcciones De Memoria
  15. 15. scanf("%i",&opcion); system("clear"); switch(opcion) { case 1: printf("nnnnnttt! NUEVO REGISTRO !nn"); printf("tNombre : "); scanf("%s",nombre); printf("nntApellido : "); scanf("%s",apellido); printf("nntNumero movil :"); scanf("%s",numero); system("clear"); printf("nnnnnttt! NUEVO REGISTRO !nn"); printf("tNombrettApellidottNumeronnt%stt%stt%sn",nombre, apellido,nume ro); printf("t-----------------------------------------------"); printf("nntttDesea Guardar este registro?nttt1) Sinttt2) NontttOPCION: "); scanf("%i",&resp);getchar(); if (resp==1) { insertar(&lista,nombre,apellido,numero); printf("nnttSu Registro ha sido guardado exitosamenten"); getchar(); system("clear"); } Apuntadores Y Direcciones De Memoria
  16. 16. else { printf("nnttEl registro no fue guardado"); getchar(); system("clear"); } break; case 2: printf("nnnntt ***** A G E N D A *****n"); mostrar(&lista);getchar(); getchar(); system("clear"); break; case 3: mostrar(&lista); printf("nnttIntroduzca el nombre a BUSCAR : "); scanf("%s",nombre); borrar(&lista,nombre); } }while(opcion<4); printf("ttCreado por : !Luis Hernandez!nn"); getchar(); return 0; } void insertar(tipo_lista *r_lista,char r_nombre[],char r_apellido[],char r_numero[]) { tipo_nodo primer,ultimo,anterior; primer = *r_lista; if (primer == NULL) Apuntadores Y Direcciones De Memoria
  17. 17. { primer == malloc(sizeof(tipo_agenda)); if(primer != NULL) { strcpy(primer->_numero,r_numero); strcpy(primer->_nombre,r_nombre); strcpy(primer->_apellido,r_apellido); primer->siguiente_registro = NULL; *r_lista = primer; } } else { ultimo == malloc(sizeof(tipo_agenda)); if (ultimo != NULL) { strcpy(ultimo->_numero,r_numero); strcpy(ultimo->_nombre,r_nombre); strcpy(ultimo->_apellido,r_apellido); if(strcmp((*r_lista)->_nombre,ultimo>_nombre)>0) { ultimo->siguiente_registro = *r_lista; *r_lista = ultimo; } else { anterior = *r_lista; Apuntadores Y Direcciones De Memoria
  18. 18. while (anterior>siguiente_registro && strcmp(anterior->siguie nte_registro- >_nombre,ultimo->_nombre)<0) anterior = anterior>siguiente_registro; ultimo->siguiente_registro = anterior->siguiente_registro; anterior->siguiente_registro = ultimo; } } } } void mostrar(tipo_lista *lista) { tipo_nodo nodo_muestra=*lista; printf("tt__________________________________n"); while(nodo_muestra != NULL) { printf("tt|Nombre : | %sntt|Apellido : | %sntt|Numero | %sn",nodo_muestra->_nombre,nodo_muestra->_apellido,nodo_muestra>_numero); printf("tt|________________________________n"); nodo_muestra = nodo_muestra->siguiente_registro; } } void borrar(tipo_lista *r_lista,char r_nombre[]) { tipo_nodo nodo,anterior; nodo= *r_lista; Apuntadores Y Direcciones De Memoria :
  19. 19. anterior = NULL; while(nodo && strcmp(nodo->_nombre,r_nombre)<0) { anterior = nodo; nodo = nodo->siguiente_registro; } if(!nodo || strcmp(nodo->_nombre,r_nombre)!=0) { printf("nntt"%s" no se encuentra en la listann",r_nombre);getchar(); getchar(); system("clear"); return; } else {getchar(); /* Borrar el nodo */ if(!anterior) /* Primer elemento */ *r_lista = nodo->siguiente_registro; else /* un elemento cualquiera */ anterior->siguiente_registro = nodo>siguiente_registro; free(nodo); printf("ntt"%s" ha sido eliminado de la lista",r_nombre); getchar(); system("clear"); } } Apuntadores Y Direcciones De Memoria
  20. 20. Ejercicio 2: #include <conio.h> #include <stdio.h> #define N_VENDEDORES 18 #define N_PRODUCTOS 10 /* Función que muestra el menú del programa y retorna el número de menú elegido por el usuario */ int mostrarMenu(); /* Función que calcula el total de todas las ventas*/ double mostrarTotal(double v[][N_PRODUCTOS]); /* Función que calcula el total de ventas de un vendedor*/ double totalVendedor(double v[][N_PRODUCTOS], int nVendedor); int main(){ clrscr(); double ventas[N_VENDEDORES][N_PRODUCTOS]={0}; int resp=mostrarMenu(); int nvend, nprod; double cantidad; while(resp!=4){ switch(resp){ case 1: printf("Numero de vendedor: ");scanf("%d",&nvend); printf("Numero de producto: ");scanf("%d",&nprod); printf("Cantidad ventida: ");scanf("%lf",&cantidad); ventas[nvend][nprod]=cantidad; break; Apuntadores Y Direcciones De Memoria
  21. 21. case 2: printf("Numero de vendedor: ");scanf("%d",&nvend); printf("Ventas total del vendedor %d=%.2lfn", nvend,totalVendedor(ventas,nvend)); break; case 3: printf("Total de ventas=%.2lfn", mostrarTotal(ventas)); break; } resp=mostrarMenu(); } getch(); } int mostrarMenu(){ int resp; printf("nn"); printf("1) A¤adir datosn"); printf("2) Mostrar total de vendedorn"); printf("3) Mostrar total de ventasn"); printf("4) Salirn"); scanf("%d",&resp); return resp; } double mostrarTotal(double v[][N_PRODUCTOS]){ double resp=0; int i,j; for(i=0;i<N_VENDEDORES;i++){ for(j=0;j<N_PRODUCTOS;j++){ resp+=v[i][j]; } } return resp; Apuntadores Y Direcciones De Memoria
  22. 22. } double totalVendedor(double v[][N_PRODUCTOS], int nVendedor){ double resp=0; int i; for(i=0;i<N_PRODUCTOS;i++){ resp+=v[nVendedor][i]; } return resp; } Apuntadores Y Direcciones De Memoria

×