Punteros en C — 4 programas reales para perderles el miedo
Los punteros en C práctica real es lo que toca ahora. En el artículo anterior vimos la teoría. Ahora abre gedit en Fedora y escribe el código mientras lees. Cuatro programas progresivos, cada uno demuestra un uso real de los punteros que verás en IC2.
Recuerda el flujo:
gedit programa.c & gcc programa.c -o programa ./programa
Tabla de Contenidos
Nota — funciones en C
En estos programas usamos funciones para organizar el código. Las funciones en C las veremos en profundidad en el siguiente bloque, por ahora solo necesitas saber tres cosas:
/* Una función tiene esta estructura */
tipo_retorno nombre_funcion(parametros) {
/* cuerpo */
}
/* void significa que no devuelve nada */
void mi_funcion(int x) {
/* hace algo pero no devuelve valor */
}
/* int* significa que devuelve un puntero a int */
int* mi_funcion(int *vec, int n) {
return vec; /* devuelve una dirección */
}
Lo importante ahora es ver cómo se usan los punteros dentro de las funciones, no preocuparte por la estructura completa de las funciones. Si algo no queda claro, vuelve a este artículo cuando lleguemos al bloque de funciones en C.
Punteros en C práctica — Programa 1: Swap: intercambio de valores con punteros
El swap es el programa clásico para entender por qué los punteros existen. Primero la versión que no funciona para entender el problema:
gedit swap.c &
#include <stdio.h>
/* Versión SIN punteros — no funciona */
void swap_mal(int a, int b) {
int temp = a;
a = b;
b = temp;
/* a y b son copias locales — los originales no cambian */
}
/* Versión CON punteros — funciona */
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
printf("Antes del swap: x=%d, y=%d\n", x, y);
swap_mal(x, y);
printf("Después de swap_mal: x=%d, y=%d\n", x, y);
swap(&x, &y);
printf("Después de swap: x=%d, y=%d\n", x, y);
return 0;
}
Antes del swap: x=10, y=20 Después de swap_mal: x=10, y=20 Después de swap: x=20, y=10
swap_mal recibe copias de x e y, los intercambia dentro de la función pero los originales no cambian. swap recibe las direcciones de x e y, puede modificar los originales directamente a través de los punteros.
Este es el caso de uso fundamental de los punteros en C, cuando necesitas que una función modifique variables del exterior. En Python esto no existe porque las variables se pasan de forma diferente.
Punteros en C práctica — Programa 2: Recorrido de vectores con punteros
gedit vectores.c &
#include <stdio.h>
int main() {
int vec[6] = {15, 8, 42, 3, 27, 19};
int *ptr;
int n = 6;
/* Recorrido hacia adelante */
printf("Vector completo:\n");
for (ptr = vec; ptr < vec + n; ptr++) {
printf("%d ", *ptr);
}
printf("\n\n");
/* Recorrido hacia atrás */
printf("Vector al revés:\n");
for (ptr = vec + n - 1; ptr >= vec; ptr--) {
printf("%d ", *ptr);
}
printf("\n\n");
/* Solo elementos en posición par */
printf("Elementos en posición par (0,2,4):\n");
for (ptr = vec; ptr < vec + n; ptr += 2) {
printf("%d ", *ptr);
}
printf("\n\n");
/* Mostrar dirección y valor de cada elemento */
printf("Dirección y valor de cada elemento:\n");
for (ptr = vec; ptr < vec + n; ptr++) {
printf("Dirección: %p → Valor: %d\n", ptr, *ptr);
}
return 0;
}
Vector completo: 15 8 42 3 27 19 Vector al revés: 19 27 3 42 8 15 Elementos en posición par (0,2,4): 15 42 27 Dirección y valor de cada elemento: Dirección: 0x7ffd1234a0 → Valor: 15 Dirección: 0x7ffd1234a4 → Valor: 8 Dirección: 0x7ffd1234a8 → Valor: 42 Dirección: 0x7ffd1234ac → Valor: 3 Dirección: 0x7ffd1234b0 → Valor: 27 Dirección: 0x7ffd1234b4 → Valor: 19
Fíjate en las direcciones, cada int ocupa 4 bytes, por eso las direcciones aumentan de 4 en 4. Eso es la aritmética de punteros en acción, ptr++ avanza exactamente 4 bytes porque ptr es de tipo int*.
Punteros en C práctica — Programa 3: Función que modifica variables externas
Este programa es el más útil de todos, demuestra cómo usar punteros para que una función devuelva múltiples resultados. En C una función solo puede devolver un valor con return, con punteros puedes modificar tantas variables como necesites.
gedit estadisticas.c &
#include <stdio.h>
/* Función que calcula suma y media — devuelve dos resultados */
void calcular_suma_media(int *vec, int n, int *suma, float *media) {
int i;
*suma = 0;
for (i = 0; i < n; i++) {
*suma += vec[i];
}
*media = (float)(*suma) / n;
}
/* Función que encuentra máximo y mínimo */
void encontrar_max_min(int *vec, int n, int *maximo, int *minimo) {
int i;
*maximo = vec[0];
*minimo = vec[0];
for (i = 1; i < n; i++) {
if (vec[i] > *maximo) {
*maximo = vec[i];
}
if (vec[i] < *minimo) {
*minimo = vec[i];
}
}
}
/* Función que invierte el vector en su lugar */
void invertir_vector(int *vec, int n) {
int *inicio = vec;
int *fin = vec + n - 1;
int temp;
while (inicio < fin) {
temp = *inicio;
*inicio = *fin;
*fin = temp;
inicio++;
fin--;
}
}
int main() {
int vec[8] = {15, 8, 42, 3, 27, 19, 11, 35};
int n = 8;
int suma, maximo, minimo;
float media;
int i;
printf("=== ESTADÍSTICAS DEL VECTOR ===\n\n");
printf("Vector original: ");
for (i = 0; i < n; i++) {
printf("%d ", vec[i]);
}
printf("\n\n");
/* Llamadas con punteros */
calcular_suma_media(vec, n, &suma, &media);
encontrar_max_min(vec, n, &maximo, &minimo);
printf("Suma: %d\n", suma);
printf("Media: %.2f\n", media);
printf("Máximo: %d\n", maximo);
printf("Mínimo: %d\n", minimo);
printf("Rango: %d\n\n", maximo - minimo);
invertir_vector(vec, n);
printf("Vector invertido: ");
for (i = 0; i < n; i++) {
printf("%d ", vec[i]);
}
printf("\n");
return 0;
}
=== ESTADÍSTICAS DEL VECTOR === Vector original: 15 8 42 3 27 19 11 35 Suma: 160 Media: 20.00 Máximo: 42 Mínimo: 3 Rango: 39 Vector invertido: 35 11 19 27 3 42 8 15
Fíjate en cómo se llaman las funciones, calcular_suma_media(vec, n, &suma, &media). Los últimos dos argumentos llevan & porque son los que la función va a modificar. vec no lleva & porque un vector ya es un puntero.
La función invertir_vector usa dos punteros que se mueven desde los extremos hacia el centro intercambiando valores — es el patrón clásico de inversión in-place.
Punteros en C práctica — Programa 4: Búsqueda de máximo y mínimo con posición
gedit busqueda.c &
#include <stdio.h>
/* Devuelve puntero al máximo elemento */
int* encontrar_maximo(int *vec, int n) {
int *ptr;
int *ptr_max = vec;
for (ptr = vec + 1; ptr < vec + n; ptr++) {
if (*ptr > *ptr_max) {
ptr_max = ptr;
}
}
return ptr_max;
}
/* Devuelve puntero al mínimo elemento */
int* encontrar_minimo(int *vec, int n) {
int *ptr;
int *ptr_min = vec;
for (ptr = vec + 1; ptr < vec + n; ptr++) {
if (*ptr < *ptr_min) {
ptr_min = ptr;
}
}
return ptr_min;
}
/* Busca un valor y devuelve puntero a él o NULL si no existe */
int* buscar_valor(int *vec, int n, int valor) {
int *ptr;
for (ptr = vec; ptr < vec + n; ptr++) {
if (*ptr == valor) {
return ptr; /* devuelve puntero al elemento encontrado */
}
}
return NULL; /* no encontrado */
}
int main() {
int vec[8] = {15, 8, 42, 3, 27, 19, 11, 35};
int n = 8;
int *resultado;
int buscar;
printf("Vector: ");
int i;
for (i = 0; i < n; i++) {
printf("%d ", vec[i]);
}
printf("\n\n");
/* Máximo con su posición */
resultado = encontrar_maximo(vec, n);
printf("Máximo: %d en posición %d\n",
*resultado, (int)(resultado - vec));
/* Mínimo con su posición */
resultado = encontrar_minimo(vec, n);
printf("Mínimo: %d en posición %d\n",
*resultado, (int)(resultado - vec));
/* Búsqueda de valor */
printf("\n¿Qué valor buscas? ");
scanf("%d", &buscar);
resultado = buscar_valor(vec, n, buscar);
if (resultado != NULL) {
printf("Encontrado: %d en posición %d (dirección: %p)\n",
*resultado,
(int)(resultado - vec),
resultado);
} else {
printf("%d no está en el vector\n", buscar);
}
return 0;
}
Vector: 15 8 42 3 27 19 11 35 Máximo: 42 en posición 2 Mínimo: 3 en posición 3 ¿Qué valor buscas? 19 Encontrado: 19 en posición 5 (dirección: 0x7ffd1234b4)
Dos conceptos nuevos importantes en este programa:
Función que devuelve un puntero — int* encontrar_maximo(...) devuelve un puntero a un entero. Así puedes devolver no solo el valor sino también su posición en memoria.
NULL — es el puntero nulo, vale 0 y significa «ninguna dirección». Se usa como señal de «no encontrado» o «error». Siempre comprueba si un puntero es NULL antes de usarlo:
if (resultado != NULL) {
printf("%d\n", *resultado); /* seguro */
}
/* nunca hagas *resultado sin comprobar NULL primero */
La resta de punteros — resultado - vec da la posición del elemento en el vector. Si resultado apunta a la dirección 1008 y vec empieza en 1000, la diferencia es 8 bytes = 2 elementos de tipo int (8/4=2). Así calculas la posición sin necesitar una variable de índice.
Visualízalo con Python Tutor
Copia este código en pythontutor.com seleccionando C, el swap es el programa donde Python Tutor más claramente muestra por qué los punteros son necesarios:
#include <stdio.h>
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
swap(&x, &y);
printf("x=%d, y=%d\n", x, y);
return 0;
}
Observa cómo al llamar a swap se crean los punteros a y b que apuntan a x e y del main. Cuando modificas *a estás modificando x directamente.
Errores más comunes en estos programas
Error 1 — Olvidar & al llamar a funciones con punteros:
calcular_suma_media(vec, n, suma, media); /* MAL — pasa valores */ calcular_suma_media(vec, n, &suma, &media); /* BIEN — pasa direcciones */
Error 2 — Usar NULL sin comprobar:
int *ptr = buscar_valor(vec, n, 99);
printf("%d\n", *ptr); /* PELIGRO si ptr es NULL */
if (ptr != NULL) {
printf("%d\n", *ptr); /* SEGURO */
}
Error 3 — Salirse del vector con aritmética de punteros:
int *ptr = vec; ptr = ptr + n; /* apunta FUERA del vector */ *ptr = 5; /* comportamiento indefinido */
Resumen y siguiente paso
En este artículo practicaste punteros con cuatro programas reales. El swap demuestra por qué los punteros existen, el recorrido de vectores muestra la aritmética en acción, las funciones con punteros permiten devolver múltiples resultados y la búsqueda introduce el retorno de punteros y NULL.
En el siguiente artículo encontrarás ejercicios propuestos con solución para practicar por tu cuenta.
Pointers in C — 4 real programs to stop being afraid of them
Note — functions in C
These programs use functions to organise the code. We’ll cover C functions in depth in the next block — for now just three things to know:
/* A function has this structure */
return_type function_name(parameters) {
/* body */
}
/* void means it returns nothing */
void my_function(int x) {
/* does something but returns no value */
}
/* int* means it returns a pointer to int */
int* my_function(int *vec, int n) {
return vec; /* returns an address */
}
Focus on how pointers are used inside the functions, don’t worry about the full function structure yet. Come back to this article when we reach the C functions block.
Program 1 — Swap: value exchange with pointers
#include <stdio.h>
void swap_wrong(int a, int b) {
int temp = a;
a = b;
b = temp;
/* a and b are local copies — originals unchanged */
}
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
printf("Before: x=%d, y=%d\n", x, y);
swap_wrong(x, y);
printf("After swap_wrong: x=%d, y=%d\n", x, y);
swap(&x, &y);
printf("After swap: x=%d, y=%d\n", x, y);
return 0;
}
Before: x=10, y=20 After swap_wrong: x=10, y=20 After swap: x=20, y=10
swap_wrong receives copies, originals don’t change. swap receives addresses, modifies originals directly through pointers.
Program 2 — Array traversal with pointers
#include <stdio.h>
int main() {
int vec[6] = {15, 8, 42, 3, 27, 19};
int *ptr;
int n = 6;
printf("Forward:\n");
for (ptr = vec; ptr < vec + n; ptr++) {
printf("%d ", *ptr);
}
printf("\n\n");
printf("Backward:\n");
for (ptr = vec + n - 1; ptr >= vec; ptr--) {
printf("%d ", *ptr);
}
printf("\n\n");
printf("Even positions (0,2,4):\n");
for (ptr = vec; ptr < vec + n; ptr += 2) {
printf("%d ", *ptr);
}
printf("\n\n");
printf("Address and value:\n");
for (ptr = vec; ptr < vec + n; ptr++) {
printf("%p → %d\n", ptr, *ptr);
}
return 0;
}
Forward: 15 8 42 3 27 19 Backward: 19 27 3 42 8 15 Even positions (0,2,4): 15 42 27 Address and value: 0x7ffd1234a0 → 15 0x7ffd1234a4 → 8 0x7ffd1234a8 → 42 0x7ffd1234ac → 3 0x7ffd1234b0 → 27 0x7ffd1234b4 → 19
Each int occupies 4 bytes, addresses increase by 4. That’s pointer arithmetic in action.
Program 3 — Function that modifies external variables
#include <stdio.h>
void calculate_sum_average(int *vec, int n, int *sum, float *average) {
int i;
*sum = 0;
for (i = 0; i < n; i++) {
*sum += vec[i];
}
*average = (float)(*sum) / n;
}
void find_max_min(int *vec, int n, int *maximum, int *minimum) {
int i;
*maximum = vec[0];
*minimum = vec[0];
for (i = 1; i < n; i++) {
if (vec[i] > *maximum) *maximum = vec[i];
if (vec[i] < *minimum) *minimum = vec[i];
}
}
void reverse_array(int *vec, int n) {
int *start = vec;
int *end = vec + n - 1;
int temp;
while (start < end) {
temp = *start;
*start = *end;
*end = temp;
start++;
end--;
}
}
int main() {
int vec[8] = {15, 8, 42, 3, 27, 19, 11, 35};
int n = 8, sum, maximum, minimum, i;
float average;
printf("Original: ");
for (i = 0; i < n; i++) printf("%d ", vec[i]);
printf("\n\n");
calculate_sum_average(vec, n, &sum, &average);
find_max_min(vec, n, &maximum, &minimum);
printf("Sum: %d\n", sum);
printf("Average: %.2f\n", average);
printf("Max: %d\n", maximum);
printf("Min: %d\n", minimum);
reverse_array(vec, n);
printf("\nReversed: ");
for (i = 0; i < n; i++) printf("%d ", vec[i]);
printf("\n");
return 0;
}
Original: 15 8 42 3 27 19 11 35 Sum: 160 Average: 20.00 Max: 42 Min: 3 Reversed: 35 11 19 27 3 42 8 15
Program 4 — Max/min search with position
#include <stdio.h>
int* find_maximum(int *vec, int n) {
int *ptr, *ptr_max = vec;
for (ptr = vec + 1; ptr < vec + n; ptr++) {
if (*ptr > *ptr_max) ptr_max = ptr;
}
return ptr_max;
}
int* find_minimum(int *vec, int n) {
int *ptr, *ptr_min = vec;
for (ptr = vec + 1; ptr < vec + n; ptr++) {
if (*ptr < *ptr_min) ptr_min = ptr;
}
return ptr_min;
}
int* search_value(int *vec, int n, int value) {
int *ptr;
for (ptr = vec; ptr < vec + n; ptr++) {
if (*ptr == value) return ptr;
}
return NULL;
}
int main() {
int vec[8] = {15, 8, 42, 3, 27, 19, 11, 35};
int n = 8, search, i;
int *result;
printf("Array: ");
for (i = 0; i < n; i++) printf("%d ", vec[i]);
printf("\n\n");
result = find_maximum(vec, n);
printf("Max: %d at position %d\n", *result, (int)(result - vec));
result = find_minimum(vec, n);
printf("Min: %d at position %d\n", *result, (int)(result - vec));
printf("\nSearch for value: ");
scanf("%d", &search);
result = search_value(vec, n, search);
if (result != NULL) {
printf("Found: %d at position %d\n",
*result, (int)(result - vec));
} else {
printf("%d not in array\n", search);
}
return 0;
}
Array: 15 8 42 3 27 19 11 35 Max: 42 at position 2 Min: 3 at position 3 Search for value: 19 Found: 19 at position 5
NULL — the null pointer, value 0, means «no address». Used as «not found» signal. Always check before dereferencing:
if (result != NULL) {
printf("%d\n", *result); /* safe */
}
Pointer subtraction — result - vec gives the element’s position. If result points to address 1008 and vec starts at 1000, difference is 8 bytes = 2 int elements (8/4=2).
Common mistakes
/* Mistake 1 — missing & in function call */
calculate(vec, n, sum, average); /* WRONG */
calculate(vec, n, &sum, &average); /* RIGHT */
/* Mistake 2 — using NULL without checking */
int *ptr = search(vec, n, 99);
printf("%d\n", *ptr); /* DANGER if NULL */
if (ptr != NULL) { printf("%d\n", *ptr); } /* SAFE */
/* Mistake 3 — out of bounds */
ptr = vec + n;
*ptr = 5; /* undefined behaviour */

Un comentario