Funciones en C — ejercicios para dominar el paso por referencia
Las funciones en C ejercicios con solución cierran este bloque. Ya viste la teoría y practicaste con programas reales. Ahora toca resolver por tu cuenta en gedit y compilar con gcc en Fedora. Tres ejercicios en tres niveles con especial atención a los dos errores que más destrozan una implementación de funciones en C: olvidar & al pasar una variable que se va a modificar, y olvidar pasar el tamaño n junto con el array.
Como siempre: intenta resolverlo, usa la pista si llevas más de 10 minutos atascado, compara con la solución comentada al final y copia el código en pythontutor.com para la ver la ejecución de manera más detallada.
Tabla de Contenidos
Funciones en C ejercicios — Nivel Básico
Ejercicio 1 — Función que busca el segundo máximo
Escribe un programa con estas tres funciones:
int maximo(int vec[], int n)— devuelve el valor máximo del arrayint segundo_maximo(int vec[], int n)— devuelve el segundo valor más grande (distinto del máximo)void mostrar_array(int vec[], int n)— muestra el array en pantalla
La salida debe ser:
Array: 42 7 19 85 26 85 54 13 Máximo: 85 Segundo máximo: 54 Array: 10 10 10 10 Máximo: 10 Segundo máximo: no existe (todos los elementos son iguales) Array: 5 3 Máximo: 5 Segundo máximo: 3
Requisitos importantes:
- Si todos los elementos son iguales no hay segundo máximo — muestra el mensaje correspondiente
- El segundo máximo debe ser un valor distinto del máximo — si el máximo aparece varias veces no cuenta como segundo máximo
- El array puede tener elementos repetidos
💡 Pista — el error de olvidar &:
/* MAL — intentar devolver el segundo máximo por referencia sin & */ int segundo; buscar_segundo_maximo(vec, n, segundo); /* segundo no cambia */ /* BIEN — si usas puntero, pasa la dirección */ int segundo; buscar_segundo_maximo(vec, n, &segundo); /* segundo sí cambia */
En este ejercicio no necesitas paso por referencia para el segundo máximo — puedes devolver -1 como señal de «no existe» y usar return. Pero si quisieras devolver también la posición del segundo máximo, necesitarías int *posicion y &posicion al llamar.
Para encontrar el segundo máximo sin ordenar el array: recorre una vez para encontrar el máximo, luego recorre otra vez buscando el mayor valor que sea estrictamente menor que el máximo.
Funciones en C ejercicios — Nivel Intermedio
Ejercicio 2 — Función que elimina un elemento en una posición dada
Escribe un programa con estas funciones:
int eliminar_posicion(int vec[], int *n, int posicion)— elimina el elemento enposicion, desplaza el resto hacia la izquierda y actualiza*n. Devuelve el valor eliminado. Si la posición no es válida devuelve -1 y no modifica nada.void insertar_posicion(int vec[], int *n, int posicion, int valor)— insertavalorenposicion, desplaza el resto hacia la derecha y actualiza*n. Si la posición no es válida no hace nada.void mostrar_array(int vec[], int n)— muestra el array
La salida debe ser:
Array inicial: 10 20 30 40 50 Longitud: 5 Eliminando posición 2 (valor 30): Array: 10 20 40 50 Longitud: 4 Eliminando posición 0 (valor 10): Array: 20 40 50 Longitud: 3 Insertando 99 en posición 1: Array: 20 99 40 50 Longitud: 4 Eliminando posición inválida (5): Posición 5 fuera de rango — array no modificado Array: 20 99 40 50 Longitud: 4
💡 Pistas — los dos errores:
/* ERROR 1 — olvidar & al pasar n para que la función lo modifique */
int n = 5;
eliminar_posicion(vec, n, 2); /* MAL — n no cambia fuera */
eliminar_posicion(vec, &n, 2); /* BIEN — n se actualiza */
/* ERROR 2 — olvidar validar la posición antes de acceder */
/* Si posicion >= *n o posicion < 0 → acceso fuera del array */
if (posicion < 0 || posicion >= *n) {
printf("Posición %d fuera de rango\n", posicion);
return -1; /* salir sin modificar nada */
}
Para eliminar un elemento en la posición p: desplaza todos los elementos desde p+1 hasta n-1 una posición hacia la izquierda, luego decrementa *n. Para insertar: desplaza todos los elementos desde n-1 hasta p una posición hacia la derecha, luego coloca el valor en p e incrementa *n. El orden del desplazamiento importa — si empiezas por el lado equivocado sobrescribes datos.
Funciones en C ejercicios — Desafío Final
Ejercicio 3 — Fusionar dos arrays ordenados en uno ordenado
Escribe un programa con estas funciones:
void fusionar(int a[], int na, int b[], int nb, int resultado[], int *nr)— fusiona los arraysayb(ambos ya ordenados ascendentemente) enresultado[], que también queda ordenado. Guarda el tamaño del resultado en*nr.void ordenar(int vec[], int n)— ordena un array ascendentemente (puedes usar burbuja)void mostrar_array(int vec[], int n)— muestra el array
La salida debe ser:
Array A (ordenado): 3 7 11 15 22 Array B (ordenado): 1 5 9 12 18 25 30 Fusionados: 1 3 5 7 9 11 12 15 18 22 25 30 Longitud resultado: 12 Caso con repetidos: Array A: 2 4 6 8 Array B: 3 4 7 8 9 Fusionados: 2 3 4 4 6 7 8 8 9 Longitud resultado: 9 Caso vacío: Array A: 1 3 5 Array B: (vacío) Fusionados: 1 3 5 Longitud resultado: 3
💡 Pistas:
La fusión eficiente de dos arrays ordenados no necesita ordenar el resultado al final — puedes construirlo ordenado directamente usando dos índices:
/* Idea del algoritmo */
int i = 0, j = 0, k = 0;
while (i < na && j < nb) {
if (a[i] <= b[j]) {
resultado[k++] = a[i++]; /* toma de A */
} else {
resultado[k++] = b[j++]; /* toma de B */
}
}
/* cuando uno se agota, copia el resto del otro */
El error de olvidar & aparece con *nr, si llamas a fusionar sin &nr el tamaño del resultado nunca llega al exterior. El error de olvidar el tamaño aparece si intentas hacer la fusión sin pasar na y nb, la función no tiene forma de saber hasta dónde llegan los arrays.
Los casos especiales que tienes que probar: un array vacío (na=0 o nb=0), arrays con elementos repetidos entre sí, y arrays de distinto tamaño.
Soluciones Comentadas
Solución Ejercicio 1:
#include <stdio.h>
/* Prototipos */
int maximo(int vec[], int n);
int segundo_maximo(int vec[], int n);
void mostrar_array(int vec[], int n);
int main(void) {
int a[8] = {42, 7, 19, 85, 26, 85, 54, 13};
int b[4] = {10, 10, 10, 10};
int c[2] = {5, 3};
int segundo;
/* Array A */
printf("Array: "); mostrar_array(a, 8);
printf("Máximo: %d\n", maximo(a, 8));
segundo = segundo_maximo(a, 8);
if (segundo == -1)
printf("Segundo máximo: no existe\n\n");
else
printf("Segundo máximo: %d\n\n", segundo);
/* Array B — todos iguales */
printf("Array: "); mostrar_array(b, 4);
printf("Máximo: %d\n", maximo(b, 4));
segundo = segundo_maximo(b, 4);
if (segundo == -1)
printf("Segundo máximo: no existe (todos los elementos son iguales)\n\n");
else
printf("Segundo máximo: %d\n\n", segundo);
/* Array C — dos elementos */
printf("Array: "); mostrar_array(c, 2);
printf("Máximo: %d\n", maximo(c, 2));
segundo = segundo_maximo(c, 2);
if (segundo == -1)
printf("Segundo máximo: no existe\n\n");
else
printf("Segundo máximo: %d\n\n", segundo);
return 0;
}
int maximo(int vec[], int n) {
int i, max = vec[0];
for (i = 1; i < n; i++)
if (vec[i] > max) max = vec[i];
return max;
}
int segundo_maximo(int vec[], int n) {
int i;
int max = maximo(vec, n); /* primero encontramos el máximo */
int segundo = -1; /* -1 = no encontrado todavía */
/* buscamos el mayor valor estrictamente menor que max */
for (i = 0; i < n; i++) {
if (vec[i] < max) { /* solo valores distintos del máximo */
if (segundo == -1 || vec[i] > segundo)
segundo = vec[i];
}
}
return segundo; /* -1 si no existe segundo máximo */
}
void mostrar_array(int vec[], int n) {
int i;
for (i = 0; i < n; i++) printf("%d ", vec[i]);
printf("\n");
}
Solución Ejercicio 2:
#include <stdio.h>
#define MAX 100
/* Prototipos */
int eliminar_posicion(int vec[], int *n, int posicion);
void insertar_posicion(int vec[], int *n, int posicion, int valor);
void mostrar_estado(int vec[], int n);
void mostrar_array(int vec[], int n);
int main(void) {
int vec[MAX] = {10, 20, 30, 40, 50};
int n = 5;
int eliminado;
printf("Array inicial: "); mostrar_array(vec, n);
printf("Longitud: %d\n\n", n);
/* Eliminar posición 2 */
eliminado = eliminar_posicion(vec, &n, 2);
printf("Eliminando posición 2 (valor %d):\n", eliminado);
mostrar_estado(vec, n);
/* Eliminar posición 0 */
eliminado = eliminar_posicion(vec, &n, 0);
printf("Eliminando posición 0 (valor %d):\n", eliminado);
mostrar_estado(vec, n);
/* Insertar 99 en posición 1 */
insertar_posicion(vec, &n, 1, 99);
printf("Insertando 99 en posición 1:\n");
mostrar_estado(vec, n);
/* Posición inválida */
printf("Eliminando posición inválida (5):\n");
eliminado = eliminar_posicion(vec, &n, 5);
if (eliminado == -1)
printf("Posición 5 fuera de rango — array no modificado\n");
mostrar_estado(vec, n);
return 0;
}
int eliminar_posicion(int vec[], int *n, int posicion) {
int i, valor;
/* Validar posición */
if (posicion < 0 || posicion >= *n)
return -1; /* posición inválida — no modifica nada */
valor = vec[posicion]; /* guardar el valor antes de eliminarlo */
/* Desplazar hacia la izquierda desde posicion+1 */
for (i = posicion; i < *n - 1; i++)
vec[i] = vec[i + 1];
(*n)--; /* el array tiene un elemento menos */
return valor;
}
void insertar_posicion(int vec[], int *n, int posicion, int valor) {
int i;
/* Validar posición — puede insertar al final (posicion == *n) */
if (posicion < 0 || posicion > *n)
return;
/* Desplazar hacia la derecha desde el final hasta posicion */
/* IMPORTANTE: empezar desde el final para no sobrescribir */
for (i = *n; i > posicion; i--)
vec[i] = vec[i - 1];
vec[posicion] = valor; /* colocar el nuevo elemento */
(*n)++; /* el array tiene un elemento más */
}
void mostrar_estado(int vec[], int n) {
printf("Array: "); mostrar_array(vec, n);
printf("Longitud: %d\n\n", n);
}
void mostrar_array(int vec[], int n) {
int i;
for (i = 0; i < n; i++) printf("%d ", vec[i]);
printf("\n");
}
Solución Ejercicio 3:
#include <stdio.h>
#define MAX 200
/* Prototipos */
void fusionar(int a[], int na, int b[], int nb,
int resultado[], int *nr);
void ordenar(int vec[], int n);
void intercambiar(int *a, int *b);
void mostrar_array(int vec[], int n);
int main(void) {
int a[5] = {3, 7, 11, 15, 22};
int b[7] = {1, 5, 9, 12, 18, 25, 30};
int resultado[MAX];
int nr;
/* Caso normal */
printf("Array A (ordenado): "); mostrar_array(a, 5);
printf("Array B (ordenado): "); mostrar_array(b, 7);
fusionar(a, 5, b, 7, resultado, &nr);
printf("Fusionados: "); mostrar_array(resultado, nr);
printf("Longitud resultado: %d\n\n", nr);
/* Caso con repetidos */
int c[4] = {2, 4, 6, 8};
int d[5] = {3, 4, 7, 8, 9};
printf("Caso con repetidos:\n");
printf("Array A: "); mostrar_array(c, 4);
printf("Array B: "); mostrar_array(d, 5);
fusionar(c, 4, d, 5, resultado, &nr);
printf("Fusionados: "); mostrar_array(resultado, nr);
printf("Longitud resultado: %d\n\n", nr);
/* Caso vacío */
int e[3] = {1, 3, 5};
int f[1] = {0}; /* array vacío — na=0 */
printf("Caso vacío:\n");
printf("Array A: "); mostrar_array(e, 3);
printf("Array B: (vacío)\n");
fusionar(e, 3, f, 0, resultado, &nr);
printf("Fusionados: "); mostrar_array(resultado, nr);
printf("Longitud resultado: %d\n", nr);
return 0;
}
void fusionar(int a[], int na, int b[], int nb,
int resultado[], int *nr) {
int i = 0, j = 0, k = 0;
/* Mientras ambos arrays tengan elementos */
while (i < na && j < nb) {
if (a[i] <= b[j]) {
resultado[k++] = a[i++]; /* toma de A */
} else {
resultado[k++] = b[j++]; /* toma de B */
}
}
/* Copiar el resto de A si queda algo */
while (i < na)
resultado[k++] = a[i++];
/* Copiar el resto de B si queda algo */
while (j < nb)
resultado[k++] = b[j++];
*nr = k; /* tamaño del resultado por referencia */
}
void intercambiar(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
void ordenar(int vec[], int n) {
int i, j;
for (i = 0; i < n - 1; i++)
for (j = 0; j < n - i - 1; j++)
if (vec[j] > vec[j + 1])
intercambiar(&vec[j], &vec[j + 1]);
}
void mostrar_array(int vec[], int n) {
int i;
for (i = 0; i < n; i++) printf("%d ", vec[i]);
printf("\n");
}
Chuletario — Funciones en C
/* ============================================
CHULETARIO — Funciones en C
Sergio Learns · sergiolearns.com
============================================ */
/* ESTRUCTURA BÁSICA */
tipo_retorno nombre(tipo param1, tipo param2) {
/* cuerpo */
return valor; /* si no es void */
}
/* PROTOTIPO — antes de main si la definición va después */
int sumar(int a, int b); /* con nombres (opcional) */
int sumar(int, int); /* sin nombres (también válido) */
/* VOID — sin retorno */
void imprimir(int n) {
printf("%d\n", n);
/* return; opcional para salir antes */
}
/* VOID — sin parámetros */
int leer(void) {
int n;
scanf("%d", &n);
return n;
}
/* PASO POR VALOR — recibe copia, no modifica original */
void doblar_valor(int n) {
n = n * 2; /* solo modifica la copia local */
}
int x = 5;
doblar_valor(x); /* x sigue siendo 5 */
/* PASO POR REFERENCIA — recibe dirección, modifica original */
void doblar_ref(int *n) {
*n = *n * 2; /* modifica el valor en esa dirección */
}
int x = 5;
doblar_ref(&x); /* x ahora vale 10 — pasamos la dirección */
/* CUÁNDO USAR CADA UNO */
/* ¿La función necesita MODIFICAR la variable? → referencia (*) */
/* ¿La función solo necesita LEER la variable? → valor */
/* ¿Es un array? → siempre pasa su dirección automáticamente */
/* PASO DE ARRAYS — automáticamente por referencia */
void modificar(int vec[], int n) {
vec[0] = 99; /* modifica el array original */
}
int nums[5] = {1, 2, 3, 4, 5};
modificar(nums, 5); /* sin & — los arrays ya pasan su dirección */
/* int vec[] e int *vec son equivalentes como parámetros */
void f1(int vec[], int n) { ... }
void f2(int *vec, int n) { ... } /* equivalente */
/* DEVOLVER MÁS DE UN RESULTADO */
/* Usa return para el resultado principal */
/* Usa punteros para los resultados adicionales */
int buscar_maximo(int vec[], int n, int *posicion) {
int i, pos = 0;
for (i = 1; i < n; i++)
if (vec[i] > vec[pos]) pos = i;
*posicion = pos; /* posición por referencia */
return vec[pos]; /* valor con return */
}
int pos;
int max = buscar_maximo(nums, 5, &pos); /* & obligatorio */
/* MODIFICAR TAMAÑO DE ARRAY */
void eliminar(int vec[], int *n, int pos) {
int i;
for (i = pos; i < *n - 1; i++)
vec[i] = vec[i + 1];
(*n)--; /* paréntesis obligatorios — (*n)++ no *n++ */
}
int n = 5;
eliminar(nums, &n, 2); /* & obligatorio — n cambia */
/* FUNCIÓN QUE LLAMA A OTRA */
float desviacion(int vec[], int n) {
float v = varianza(vec, n); /* puede llamar a otra función */
return raiz_cuadrada(v);
}
/* COPIA PARA NO ALTERAR ORIGINAL */
#define MAX 100
void no_destructivo(int vec[], int n) {
int copia[MAX];
int i;
for (i = 0; i < n; i++) copia[i] = vec[i];
ordenar(copia, n); /* trabajar sobre copia */
}
/* PATRÓN INTERCAMBIAR — base de muchos algoritmos */
void intercambiar(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
intercambiar(&vec[i], &vec[j]); /* & sobre elementos de array */
/* RETORNAR -1 COMO SEÑAL DE ERROR O "NO ENCONTRADO" */
int buscar(int vec[], int n, int buscado) {
int i;
for (i = 0; i < n; i++)
if (vec[i] == buscado) return i;
return -1; /* convenio: -1 = no encontrado */
}
/* ERRORES TÍPICOS */
/* 1. Olvidar & al pasar variable que se modifica */
int n = 5;
eliminar(vec, n, 2); /* MAL — n no cambia fuera */
eliminar(vec, &n, 2); /* BIEN */
/* 2. Olvidar pasar el tamaño n junto con el array */
void f(int vec[]) { ... } /* MAL — no sabe cuántos hay */
void f(int vec[], int n) { ... } /* BIEN */
/* 3. (*n)++ sin paréntesis */
*n++; /* MAL — incrementa el puntero, no el valor */
(*n)++; /* BIEN — incrementa el valor apuntado */
/* 4. Olvidar el prototipo */
int main(void) {
sumar(3, 4); /* error si sumar va después y no hay prototipo */
}
int sumar(int a, int b) { return a + b; }
/* SOLUCIÓN: añadir int sumar(int a, int b); antes de main */
/* 5. Devolver valor en función void */
void imprimir(int n) {
printf("%d\n", n);
return 5; /* error de compilación */
}
/* 6. Modificar array pensando que es copia */
void f(int vec[], int n) {
vec[0] = 99; /* modifica el original — NO es una copia */
}
/* SOLUCIÓN: copiar el array dentro de la función si no quieres modificarlo */
/* 7. Desplazamiento en orden incorrecto al insertar */
/* Al insertar en posición p, desplazar de DERECHA a IZQUIERDA */
for (i = *n; i > p; i--)
vec[i] = vec[i - 1]; /* bien — no sobrescribe */
/* Al eliminar en posición p, desplazar de IZQUIERDA a DERECHA */
for (i = p; i < *n - 1; i++)
vec[i] = vec[i + 1]; /* bien — no sobrescribe */

Un comentario