← C EspañolChapter 07 of 13

Punteros

## Objetivos de Aprendizaje - Comprender los conceptos básicos de punteros - Dominar operaciones con punteros - Trabajar con punteros y arreglos - Aprender aritmética de punteros ## ¿Qué es un Puntero? Un puntero es una variable que almacena la dirección de memoria de otra variable. ```c int x = 10; int *ptr = &x; // ptr contiene la dirección de x printf("%d\n", x); // Valor de x: 10 printf("%p\n", ptr); // Dirección de x printf("%d\n", *ptr); // Valor en la dirección: 10 ``` ## Declaración de Punteros ### Sintaxis ```c int *ptr; // Puntero a int char *cptr; // Puntero a char float *fptr; // Puntero a float double *dptr; // Puntero a double ``` ### Confusión Común ```c int *p1, p2; // p1 es puntero, p2 es int (¡no ambos!) int *p1, *p2; // Ambos son punteros ``` ## Operador de Dirección (&) ```c int x = 10; int *ptr = &x; // &x da la dirección de x printf("Address of x: %p\n", &x); printf("ptr contains: %p\n", ptr); ``` ## Operador de Desreferencia (*) ```c int x = 10; int *ptr = &x; printf("%d\n", *ptr); // 10 (valor en la dirección) *ptr = 20; // Modificar valor a través del puntero printf("%d\n", x); // 20 (x ahora es 20) ``` ## Puntero NULL ### Declaración ```c int *ptr = NULL; // Buena práctica - inicializar a NULL ``` ### Verificar Antes de Usar ```c int *ptr = NULL; if (ptr != NULL) { printf("%d\n", *ptr); } ``` ### Sin Inicializar vs NULL ```c int *p1; // Sin inicializar - valor basura int *p2 = NULL; // Puntero NULL - seguro de verificar ``` ## Punteros y Arreglos ### Nombre del Arreglo como Puntero ```c int arr[] = {1, 2, 3, 4, 5}; int *ptr = arr; // arr se convierte en puntero al primer elemento printf("%d\n", *ptr); // 1 (primer elemento) printf("%d\n", *(ptr + 1)); // 2 (segundo elemento) ``` ### Equivalencia ```c arr[i] == *(arr + i) &arr[i] == arr + i ``` ### Índice de Arreglo con Puntero ```c int arr[] = {10, 20, 30}; int *ptr = arr; printf("%d\n", ptr[0]); // 10 printf("%d\n", ptr[1]); // 20 ``` ## Aritmética de Punteros ### Incremento/Decremento ```c int arr[] = {10, 20, 30}; int *ptr = arr; ptr++; // Mover al siguiente int printf("%d\n", *ptr); // 20 ptr--; // Mover al int anterior printf("%d\n", *ptr); // 10 ``` ### Adición/Resta ```c int arr[] = {10, 20, 30, 40, 50}; int *ptr = arr; printf("%d\n", *(ptr + 2)); // 30 printf("%d\n", *(ptr + 4)); // 50 ptr = &arr[4]; printf("%d\n", *(ptr - 2)); // 30 ``` ### Diferencia Entre Punteros ```c int arr[] = {10, 20, 30, 40, 50}; int *p1 = &arr[0]; int *p2 = &arr[4]; ptrdiff_t diff = p2 - p1; // 4 ``` ## Punteros y Funciones ### Paso por Referencia ```c void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } int main(void) { int x = 10, y = 20; swap(&x, &y); printf("%d %d\n", x, y); // 20 10 return 0; } ``` ### Parámetro Arreglo ```c int sum(int *arr, int size) { int total = 0; for (int i = 0; i < size; i++) { total += arr[i]; // o *(arr + i) } return total; } int main(void) { int nums[] = {1, 2, 3, 4, 5}; printf("%d\n", sum(nums, 5)); // 15 return 0; } ``` ## const con Punteros ### Puntero a const ```c const int x = 10; const int *ptr = &x; // *ptr = 20; // ¡Error! No se puede modificar a través del puntero ``` ### Puntero const ```c int x = 10; int y = 20; int *const ptr = &x; *ptr = 30; // OK - puede modificar el valor // ptr = &y; // ¡Error! No puede cambiar adónde apunta ptr ``` ### Puntero const a const ```c const int x = 10; const int *const ptr = &x; // No puede modificar el valor ni cambiar la dirección ``` ## Puntero a Puntero ```c int x = 10; int *p1 = &x; int **p2 = &p1; // Puntero a puntero printf("%d\n", **p2); // 10 ``` ### Caso de Uso: Modificar puntero en función ```c void allocate(int **ptr) { *ptr = malloc(sizeof(int)); **ptr = 42; } int main(void) { int *p = NULL; allocate(&p); printf("%d\n", *p); // 42 free(p); return 0; } ``` ## Puntero Void ### Puntero Genérico ```c void *ptr; // Puede apuntar a cualquier tipo int x = 10; double y = 3.14; ptr = &x; // printf("%d\n", *ptr); // ¡Error! No se puede desreferenciar void* printf("%d\n", *(int*)ptr); // Cast a int* ptr = &y; printf("%f\n", *(double*)ptr); // Cast a double* ``` ### Usar con malloc ```c void *malloc(size_t size); void *memcpy(void *dest, const void *src, size_t n); ``` ## Memoria Dinámica (malloc/free) ```c #include int *ptr = (int*)malloc(sizeof(int)); if (ptr == NULL) { // Falló la asignación return 1; } *ptr = 42; printf("%d\n", *ptr); free(ptr); // Liberar memoria ptr = NULL; // Evitar puntero colgante ``` ## Punteros a Funciones ```c int add(int a, int b) { return a + b; } int subtract(int a, int b) { return a - b; } int main(void) { int (*operation)(int, int); operation = add; printf("%d\n", operation(5, 3)); // 8 operation = subtract; printf("%d\n", operation(5, 3)); // 2 return 0; } ``` ## Errores Comunes ### Puntero Colgante (Dangling Pointer) ```c int *ptr = malloc(sizeof(int)); free(ptr); // ptr todavía apunta a memoria liberada - ¡MAL! ptr = NULL; // Siempre establecer a NULL después de free ``` ### Doble Liberación ```c free(ptr); free(ptr); // ¡Comportamiento indefinido! ``` ### Fuga de Memoria ```c int *ptr = malloc(sizeof(int)); ptr = malloc(sizeof(int)); // Primera asignación con fuga free(ptr); ``` ### Puntero Sin Inicializar ```c int *ptr; // *ptr = 10; // ¡Indefinido! Apunta a basura ptr = malloc(sizeof(int)); // Inicializar primero *ptr = 10; free(ptr); ``` ## Resumen - Los punteros almacenan direcciones de memoria - `*` declara puntero y desreferencia - `&` obtiene la dirección de una variable - NULL es seguro; sin inicializar es peligroso - El nombre del arreglo se convierte en puntero - Aritmética de punteros: `ptr + n`, `ptr - n` - Usar `const` para prevenir modificación - `void*` puede apuntar a cualquier tipo - Siempre `free()` la memoria asignada dinámicamente - Establecer punteros a NULL después de liberar

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →