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 →