punteros
Diferencias
Muestra las diferencias entre dos versiones de la página.
| Ambos lados, revisión anteriorRevisión previaPróxima revisión | Revisión previa | ||
| punteros [2012/08/03 22:02] – [Big endian vs. Little endian] lmateu | punteros [2021/09/22 20:07] (actual) – [Big endian vs. Little endian] lmateu | ||
|---|---|---|---|
| Línea 1: | Línea 1: | ||
| - | ===== Punteros ===== | + | ====== Punteros |
| Además del identificador de las variables globales o automáticas, | Además del identificador de las variables globales o automáticas, | ||
| Línea 16: | Línea 16: | ||
| Para no entrar a usar valores numéricos de la direcciones en memoria graficaremos una dirección simplemente como una flecha hacia la variable de destino. | Para no entrar a usar valores numéricos de la direcciones en memoria graficaremos una dirección simplemente como una flecha hacia la variable de destino. | ||
| - | ==== Desreferencia ==== | + | ===== Desreferencia |
| El operador unario de prefijo ' | El operador unario de prefijo ' | ||
| Línea 44: | Línea 44: | ||
| {{ : | {{ : | ||
| - | ==== Declaración de punteros con valor inicial ==== | + | ===== Declaración de punteros con valor inicial |
| Al igual que con cualquier variable, al declarar un puntero es posible darle un valor inicial. | Al igual que con cualquier variable, al declarar un puntero es posible darle un valor inicial. | ||
| Línea 59: | Línea 59: | ||
| Por otra parte, en la asignación //*p= 2//, el asterisco sí es el operador de desreferencia y por lo tanto se está cambiando //a//, no //p//. | Por otra parte, en la asignación //*p= 2//, el asterisco sí es el operador de desreferencia y por lo tanto se está cambiando //a//, no //p//. | ||
| - | ==== Ejemplo: función que intercambia los valores de 2 variables ==== | + | ===== Ejemplo: función que intercambia los valores de 2 variables |
| Al igual que en los métodos de Java, los parámetros de las funciones de C se pasan por valor. | Al igual que en los métodos de Java, los parámetros de las funciones de C se pasan por valor. | ||
| Línea 103: | Línea 103: | ||
| Escriba la función swap_double que intercambia valores de variables de tipo double. | Escriba la función swap_double que intercambia valores de variables de tipo double. | ||
| - | === Función que intercambia las direcciones de 2 punteros === | + | ===== Función que intercambia las direcciones de 2 punteros |
| Suponga que ahora tiene este código: | Suponga que ahora tiene este código: | ||
| Línea 110: | Línea 110: | ||
| int main() { | int main() { | ||
| int a= 1, b= 2; | int a= 1, b= 2; | ||
| - | int *px= &a, *py= &b; | + | int *pa= &a, *pb= &b; |
| swap_ptr(& | swap_ptr(& | ||
| } | } | ||
| </ | </ | ||
| - | Ahora se busca que después de invocar swap_ptr, //px// apunte a //b// y //py// apunte a // | + | Ahora se busca que después de invocar swap_ptr, //pa// apunte a //b// y //pb// apunte a // |
| < | < | ||
| Línea 132: | Línea 132: | ||
| Por lo tanto al asignar //*p= *q// se está cambiando el valor de px en el llamador (main). | Por lo tanto al asignar //*p= *q// se está cambiando el valor de px en el llamador (main). | ||
| - | === Como entender la declaración de punteros === | + | ===== Como entender la declaración de punteros |
| Hay que confesar que la declaración de un puntero simple //int *p// o uno doble //int %%**%%q// no suena natural. | Hay que confesar que la declaración de un puntero simple //int *p// o uno doble //int %%**%%q// no suena natural. | ||
| Línea 149: | Línea 149: | ||
| * Escriba la función swap_ptr_ptr que intercambia 2 variables de tipo // | * Escriba la función swap_ptr_ptr que intercambia 2 variables de tipo // | ||
| - | ==== Comparación de punteros ==== | + | ===== Comparación de punteros |
| Se puede determinar si 2 punteros apuntan a la misma variable comparando ambos punteros con los operadores binarios == y !=. Vea este ejemplo: | Se puede determinar si 2 punteros apuntan a la misma variable comparando ambos punteros con los operadores binarios == y !=. Vea este ejemplo: | ||
| Línea 183: | Línea 183: | ||
| Aun cuando p!=r, sí se cumple que *p == *r porque en el segundo caso se comparan los valores almacenados en las variables. | Aun cuando p!=r, sí se cumple que *p == *r porque en el segundo caso se comparan los valores almacenados en las variables. | ||
| - | ==== El puntero nulo ==== | + | ===== El puntero nulo ===== |
| Al declarar variables automáticas sin inicialización, | Al declarar variables automáticas sin inicialización, | ||
| Línea 199: | Línea 199: | ||
| } | } | ||
| ... más código ... | ... más código ... | ||
| - | if (p == NULL) { | + | if (p != NULL) { |
| *p= 50; | *p= 50; | ||
| } | } | ||
| Línea 207: | Línea 207: | ||
| No es válido acceder a la dirección NULL en un proceso y por lo tanto si se desreferencia un puntero nulo se produce el error // | No es válido acceder a la dirección NULL en un proceso y por lo tanto si se desreferencia un puntero nulo se produce el error // | ||
| - | + | ===== Punteros locos ===== | |
| - | ==== Punteros locos ==== | + | |
| El tipo del valor retornado por la siguiente función es un puntero. | El tipo del valor retornado por la siguiente función es un puntero. | ||
| Línea 231: | Línea 230: | ||
| * La memoria que ocupó alguna vez x sí fue reasignada y se le dió un nuevo valor distinto de 1. Al desreferenciar p se obtiene un valor incorrecto. | * La memoria que ocupó alguna vez x sí fue reasignada y se le dió un nuevo valor distinto de 1. Al desreferenciar p se obtiene un valor incorrecto. | ||
| - | ==== Variables dinámicas ==== | + | **Ejercicio** |
| + | ¿Qué despliega el siguiente programa? | ||
| + | |||
| + | < | ||
| + | #include < | ||
| + | |||
| + | int *getvar(int x) { | ||
| + | return &x; /* Incorrecto: no haga esto! */ | ||
| + | } | ||
| + | |||
| + | int main() { | ||
| + | int *p= getvar(1); | ||
| + | int *q= getvar(2); | ||
| + | printf(" | ||
| + | } | ||
| + | </ | ||
| + | ===== Variables dinámicas: malloc/free ===== | ||
| Una variable dinámica se crea explícitamente llamando a la función malloc. | Una variable dinámica se crea explícitamente llamando a la función malloc. | ||
| Línea 239: | Línea 254: | ||
| < | < | ||
| int *getvar() { | int *getvar() { | ||
| - | int *q= (int*)malloc(sizeof(int)); | + | int *q= malloc(sizeof(int)); |
| *q= 1; | *q= 1; | ||
| return q; | return q; | ||
| Línea 248: | Línea 263: | ||
| printf(" | printf(" | ||
| free(p); | free(p); | ||
| + | return 0; | ||
| } | } | ||
| </ | </ | ||
| - | Al invocar malloc se debe especificar el tamaño de la memoria requerida. | + | Al invocar malloc se debe especificar el tamaño de la memoria requerida. |
| Note que al retornar getvar, se destruyen todas sus variables locales (automáticas). | Note que al retornar getvar, se destruyen todas sus variables locales (automáticas). | ||
| Línea 259: | Línea 275: | ||
| Las variables dinámicas se crean en una zona especial de la memoria de un proceso denominada el // | Las variables dinámicas se crean en una zona especial de la memoria de un proceso denominada el // | ||
| - | === No hay recolector de basuras === | + | ==== No hay recolector de basuras ==== |
| En Java no es necesario liberar la memoria porque posee un recolector de basuras que recicla automáticamente los objetos que ya no son accesibles por el programa. | En Java no es necesario liberar la memoria porque posee un recolector de basuras que recicla automáticamente los objetos que ya no son accesibles por el programa. | ||
| - | ==== Aritmética de punteros ==== | + | ===== Aritmética de punteros |
| La característica más importante de C es su flexibilidad con el manejo de memoria, la que se ve reflejada en la // | La característica más importante de C es su flexibilidad con el manejo de memoria, la que se ve reflejada en la // | ||
| Línea 268: | Línea 284: | ||
| Ningún otro lenguaje de programación ampliamente usado ofrece aritmética de punteros. | Ningún otro lenguaje de programación ampliamente usado ofrece aritmética de punteros. | ||
| - | Para enteder | + | Para entender |
| < | < | ||
| - | int *p= (int*)malloc(10*sizeof(int)); | + | int *p= malloc(10*sizeof(int)); |
| </ | </ | ||
| - | ¿De que sirve pedir espacio para 10 enteros consecutivos en la memoria? | + | ¿De qué sirve pedir espacio para 10 enteros consecutivos en la memoria? |
| {{ : | {{ : | ||
| Línea 289: | Línea 305: | ||
| </ | </ | ||
| - | === Azucar sintáctico === | + | ==== Azucar sintáctico |
| El problema es que escribir *(p+i) es pesado sintácticamente, | El problema es que escribir *(p+i) es pesado sintácticamente, | ||
| Línea 298: | Línea 314: | ||
| < | < | ||
| - | int *p= (int*)malloc(10*sizeof(int)); | + | int *p= malloc(10*sizeof(int)); |
| int s= 0; | int s= 0; | ||
| int i; | int i; | ||
| Línea 312: | Línea 328: | ||
| < | < | ||
| - | int *p= (int*)malloc(10*sizeof(int)); | + | int *p= malloc(10*sizeof(int)); |
| int s= 0; | int s= 0; | ||
| int i; | int i; | ||
| Línea 325: | Línea 341: | ||
| < | < | ||
| int *p, *r, x; /* x no es puntero */ | int *p, *r, x; /* x no es puntero */ | ||
| - | p= (int*)malloc(...); | + | p= malloc(...); |
| ... | ... | ||
| r=p; | r=p; | ||
| + | ... | ||
| free(p); | free(p); | ||
| + | ... | ||
| x= *r; /* r es dangling reference */ | x= *r; /* r es dangling reference */ | ||
| </ | </ | ||
| - | Aquí r y p apuntan a la misma dirección de memoria. | + | Aquí r y p apuntan a la misma dirección de memoria. |
| - | + | ||
| - | === Ejercicio === | + | |
| - | + | ||
| - | El siguiente programa es absolutamente legal en C. | + | |
| - | + | ||
| - | < | + | |
| - | int *p= ( (int*)malloc(10*sizeof(int)) ) + 5; /* Ojo con el + 5 al final */ | + | |
| - | int i; | + | |
| - | for (i= -5; i<5; i++) | + | |
| - | p[i]= 0; | + | |
| - | </code> | + | |
| - | + | ||
| - | Por supuesto, acá no se está fomentando este estilo de programación, | + | |
| - | === Restricciones === | + | ==== Restricciones |
| - | Solo está permitido sumar o restar un entero a un puntero. | + | Solo está permitido sumar o restar un entero a un puntero. |
| < | < | ||
| Línea 369: | Línea 374: | ||
| En el caso de la resta de punteros, se cumple esta propiedad: %%(p + i) - p ≡ i%% | En el caso de la resta de punteros, se cumple esta propiedad: %%(p + i) - p ≡ i%% | ||
| - | === Arreglos de C vs. arreglos en Java === | + | ==== Arreglos de C vs. arreglos en Java ==== |
| Dado que en Java los arreglos corresponden a un objeto bien definido con índices que parten en 0 y terminan en el tamaño del arreglo menos 1, Java puede validar cada acceso y arrojar una excepción cuando el índice está fuera del rango permitido. | Dado que en Java los arreglos corresponden a un objeto bien definido con índices que parten en 0 y terminan en el tamaño del arreglo menos 1, Java puede validar cada acceso y arrojar una excepción cuando el índice está fuera del rango permitido. | ||
| Línea 377: | Línea 382: | ||
| Gracias a la aritmética de punteros es posible programar en C sistemas operativos, malloc/free o el recolector de basuras de Java. En contrapartida esta aritmética conduce a todo tipo de errores que son muy difíciles de diagnosticar. | Gracias a la aritmética de punteros es posible programar en C sistemas operativos, malloc/free o el recolector de basuras de Java. En contrapartida esta aritmética conduce a todo tipo de errores que son muy difíciles de diagnosticar. | ||
| - | ==== Cast de punteros ==== | + | ===== Cast de punteros |
| El significado de un cast de un dato primitivo es distinto del de un cast de un puntero. | El significado de un cast de un dato primitivo es distinto del de un cast de un puntero. | ||
| Línea 397: | Línea 402: | ||
| Es importante destacar que en la mayoría de los casos asignar un puntero a otro puntero de distinto tipo conduce a un error de programación. | Es importante destacar que en la mayoría de los casos asignar un puntero a otro puntero de distinto tipo conduce a un error de programación. | ||
| - | ==== Big endian vs. Little endian ==== | + | === Ejercicio === |
| + | |||
| + | El siguiente programa es absolutamente legal en C. ¿Qué hace? | ||
| + | |||
| + | < | ||
| + | int *p= ( (int*)malloc(10*sizeof(int)) ) + 5; /* Ojo con el + 5 al final */ | ||
| + | int i; | ||
| + | for (i= -5; i<5; i++) | ||
| + | p[i]= 0; | ||
| + | </ | ||
| + | |||
| + | Por supuesto, acá no se está fomentando este estilo de programación, | ||
| + | |||
| + | |||
| + | ===== Big endian vs. Little endian | ||
| ¿Qué valor retorna la siguiente función? | ¿Qué valor retorna la siguiente función? | ||
| Línea 413: | Línea 432: | ||
| {{ : | {{ : | ||
| - | El valor retornado por esta función depende de una propiedad del hardware. | + | El valor retornado por esta función depende de una propiedad del hardware. |
| Los únicos casos en donde esta distinción arquitectural es importante es cuando se graban archivos binarios o se transmiten datos binarios por la red. Es decir en vez de escribir los enteros en formato ascii en notación decimal, se escriben directamente los 4 bytes del entero. | Los únicos casos en donde esta distinción arquitectural es importante es cuando se graban archivos binarios o se transmiten datos binarios por la red. Es decir en vez de escribir los enteros en formato ascii en notación decimal, se escriben directamente los 4 bytes del entero. | ||
| Línea 422: | Línea 441: | ||
| Programe la función int '' | Programe la función int '' | ||
| - | ==== Resumen ==== | + | ===== Resumen |
| La siguiente tabla resume las operaciones con punteros: | La siguiente tabla resume las operaciones con punteros: | ||
| Línea 434: | Línea 453: | ||
| |puntero nulo | '' | |puntero nulo | '' | ||
| |aritmética de punteros | '' | |aritmética de punteros | '' | ||
| - | |||
punteros.1344031335.txt.gz · Última modificación: por lmateu
