funciones en C práctica arrays búsqueda transformación estadísticas

Funciones en C — 3 programas reales que consolidan el paso por referencia

Las funciones en C práctica real es lo que toca ahora. En el artículo anterior vimos la teoría, cómo declarar funciones, qué es void, por qué existe el prototipo y la diferencia entre paso por valor y paso por referencia. Ahora construimos tres programas donde cada función tiene una responsabilidad clara y el paso por referencia no es un concepto abstracto sino la herramienta natural para el problema.

Todos los programas siguen la misma estructura: prototipos arriba, main en el medio, definiciones al final, el estilo que verás en IC2.

Funciones en C práctica — Programa 1: Funciones de búsqueda en arrays

La búsqueda en arrays es donde el paso por referencia brilla de forma más clara. Cuando necesitas devolver no solo si el elemento existe sino también su posición, tienes dos opciones: devolver la posición con return (y usar -1 para «no encontrado») o usar un puntero para devolver la posición y el return para el resultado booleano. Los dos patrones aparecen en IC2, aquí los vemos los dos.

#include <stdio.h>

/* Prototipos */
int buscar_elemento(int vec[], int n, int buscado);
int buscar_con_posicion(int vec[], int n, int buscado, int *posicion);
int buscar_maximo(int vec[], int n, int *posicion);
int buscar_minimo(int vec[], int n, int *posicion);
int contar_ocurrencias(int vec[], int n, int buscado);
int esta_ordenado(int vec[], int n);
void mostrar_array(int vec[], int n);

int main(void) {
    int numeros[10] = {42, 7, 19, 7, 85, 26, 7, 54, 13, 7};
    int n = 10;
    int posicion, encontrado;

    printf("Array: ");
    mostrar_array(numeros, n);
    printf("\n");

    /* Buscar elemento — devuelve posición o -1 */
    posicion = buscar_elemento(numeros, n, 85);
    if (posicion != -1)
        printf("85 encontrado en posición %d\n", posicion);
    else
        printf("85 no encontrado\n");

    posicion = buscar_elemento(numeros, n, 99);
    if (posicion != -1)
        printf("99 encontrado en posición %d\n", posicion);
    else
        printf("99 no encontrado\n");

    printf("\n");

    /* Buscar con posición por referencia */
    encontrado = buscar_con_posicion(numeros, n, 26, &posicion);
    if (encontrado)
        printf("26 encontrado en posición %d\n", posicion);
    else
        printf("26 no encontrado\n");

    printf("\n");

    /* Máximo y mínimo con posición */
    buscar_maximo(numeros, n, &posicion);
    printf("Máximo: %d en posición %d\n",
           numeros[posicion], posicion);

    buscar_minimo(numeros, n, &posicion);
    printf("Mínimo: %d en posición %d\n",
           numeros[posicion], posicion);

    printf("\n");

    /* Contar ocurrencias */
    printf("El 7 aparece %d veces\n",
           contar_ocurrencias(numeros, n, 7));

    printf("\n");

    /* ¿Está ordenado? */
    printf("¿Array ordenado? %s\n",
           esta_ordenado(numeros, n) ? "Sí" : "No");

    int ordenado[5] = {1, 3, 5, 7, 9};
    printf("¿[1,3,5,7,9] ordenado? %s\n",
           esta_ordenado(ordenado, 5) ? "Sí" : "No");

    return 0;
}

/* Busca buscado en vec — devuelve posición o -1 si no existe */
int buscar_elemento(int vec[], int n, int buscado) {
    int i;
    for (i = 0; i < n; i++) {
        if (vec[i] == buscado)
            return i;    /* primera ocurrencia */
    }
    return -1;           /* no encontrado */
}

/* Busca buscado — devuelve 1/0 y guarda posición en *posicion */
int buscar_con_posicion(int vec[], int n, int buscado, int *posicion) {
    int i;
    for (i = 0; i < n; i++) {
        if (vec[i] == buscado) {
            *posicion = i;    /* guarda la posición por referencia */
            return 1;         /* encontrado */
        }
    }
    return 0;                 /* no encontrado */
}

/* Devuelve el máximo y guarda su posición en *posicion */
int buscar_maximo(int vec[], int n, int *posicion) {
    int i, pos_max = 0;
    for (i = 1; i < n; i++) {
        if (vec[i] > vec[pos_max])
            pos_max = i;
    }
    *posicion = pos_max;    /* guarda posición por referencia */
    return vec[pos_max];    /* devuelve el valor máximo */
}

/* Devuelve el mínimo y guarda su posición en *posicion */
int buscar_minimo(int vec[], int n, int *posicion) {
    int i, pos_min = 0;
    for (i = 1; i < n; i++) {
        if (vec[i] < vec[pos_min])
            pos_min = i;
    }
    *posicion = pos_min;
    return vec[pos_min];
}

/* Cuenta cuántas veces aparece buscado en vec */
int contar_ocurrencias(int vec[], int n, int buscado) {
    int i, contador = 0;
    for (i = 0; i < n; i++) {
        if (vec[i] == buscado)
            contador++;
    }
    return contador;
}

/* Devuelve 1 si vec está ordenado ascendentemente, 0 si no */
int esta_ordenado(int vec[], int n) {
    int i;
    for (i = 0; i < n - 1; i++) {
        if (vec[i] > vec[i + 1])
            return 0;    /* encontramos un par desordenado */
    }
    return 1;
}

void mostrar_array(int vec[], int n) {
    int i;
    for (i = 0; i < n; i++)
        printf("%d ", vec[i]);
    printf("\n");
}
Array: 42 7 19 7 85 26 7 54 13 7

85 encontrado en posición 4
99 no encontrado

26 encontrado en posición 5

Máximo: 85 en posición 4
Mínimo: 7 en posición 1

El 7 aparece 4 veces

¿Array ordenado? No
¿[1,3,5,7,9] ordenado? Sí

Fíjate en el patrón que se repite en buscar_maximo y buscar_minimo: la función devuelve el valor con return y guarda la posición con un puntero. Eso es exactamente para lo que sirve el paso por referencia, cuando necesitas que una función «devuelva» más de una cosa. En C solo puedes usar return una vez; el resto de resultados van por referencia.

Funciones en C práctica — Programa 2: Funciones de transformación que modifican arrays

Las transformaciones sobre arrays son el caso más natural del paso por referencia, el array ya llega como puntero, así que cualquier modificación dentro de la función afecta al original directamente.

#include <stdio.h>

/* Prototipos */
void invertir(int vec[], int n);
void rotar_derecha(int vec[], int n);
void rotar_izquierda(int vec[], int n);
void rotar_n_posiciones(int vec[], int n, int k);
void filtrar_positivos(int vec[], int n, int resultado[], int *m);
void eliminar_duplicados(int vec[], int *n);
void intercambiar(int *a, int *b);
void mostrar_array(int vec[], int n);

int main(void) {
    int vec[8] = {10, 20, 30, 40, 50, 60, 70, 80};
    int n = 8;
    int i;

    printf("Array original: ");
    mostrar_array(vec, n);

    /* Invertir */
    invertir(vec, n);
    printf("Invertido:      ");
    mostrar_array(vec, n);

    invertir(vec, n);    /* volver al original */
    printf("Restaurado:     ");
    mostrar_array(vec, n);
    printf("\n");

    /* Rotar derecha */
    rotar_derecha(vec, n);
    printf("Rotar derecha:  ");
    mostrar_array(vec, n);

    rotar_derecha(vec, n);
    printf("Rotar derecha:  ");
    mostrar_array(vec, n);
    printf("\n");

    /* Restaurar y rotar izquierda */
    int vec2[8] = {10, 20, 30, 40, 50, 60, 70, 80};
    rotar_izquierda(vec2, n);
    printf("Rotar izquierda: ");
    mostrar_array(vec2, n);
    printf("\n");

    /* Rotar N posiciones */
    int vec3[5] = {1, 2, 3, 4, 5};
    printf("Original [1-5]: ");
    mostrar_array(vec3, 5);

    rotar_n_posiciones(vec3, 5, 2);
    printf("Rotar 2 pos:    ");
    mostrar_array(vec3, 5);
    printf("\n");

    /* Filtrar positivos */
    int mixto[8] = {-3, 7, -1, 15, -8, 4, 0, 12};
    int positivos[8];
    int m;

    printf("Array mixto: ");
    mostrar_array(mixto, 8);

    filtrar_positivos(mixto, 8, positivos, &m);
    printf("Solo positivos (%d): ", m);
    mostrar_array(positivos, m);
    printf("\n");

    /* Eliminar duplicados */
    int con_dupl[10] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
    int nd = 10;

    printf("Con duplicados:    ");
    mostrar_array(con_dupl, nd);

    eliminar_duplicados(con_dupl, &nd);
    printf("Sin duplicados:    ");
    mostrar_array(con_dupl, nd);

    return 0;
}

void intercambiar(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

/* Invierte el array en su propio espacio */
void invertir(int vec[], int n) {
    int i;
    for (i = 0; i < n / 2; i++) {
        intercambiar(&vec[i], &vec[n - 1 - i]);
    }
}

/* Rota un puesto a la derecha: [1,2,3,4] → [4,1,2,3] */
void rotar_derecha(int vec[], int n) {
    int ultimo = vec[n - 1];
    int i;
    for (i = n - 1; i > 0; i--) {
        vec[i] = vec[i - 1];    /* desplaza hacia la derecha */
    }
    vec[0] = ultimo;
}

/* Rota un puesto a la izquierda: [1,2,3,4] → [2,3,4,1] */
void rotar_izquierda(int vec[], int n) {
    int primero = vec[0];
    int i;
    for (i = 0; i < n - 1; i++) {
        vec[i] = vec[i + 1];    /* desplaza hacia la izquierda */
    }
    vec[n - 1] = primero;
}

/* Rota k posiciones a la derecha */
void rotar_n_posiciones(int vec[], int n, int k) {
    int i;
    k = k % n;    /* si k >= n, dar vueltas completas no cambia nada */
    for (i = 0; i < k; i++) {
        rotar_derecha(vec, n);
    }
}

/* Copia en resultado[] los elementos > 0 de vec — guarda el tamaño en *m */
void filtrar_positivos(int vec[], int n, int resultado[], int *m) {
    int i;
    *m = 0;
    for (i = 0; i < n; i++) {
        if (vec[i] > 0) {
            resultado[*m] = vec[i];
            (*m)++;    /* incrementa el contador por referencia */
        }
    }
}

/* Elimina duplicados de vec en su propio espacio — actualiza *n */
void eliminar_duplicados(int vec[], int *n) {
    int i, j, k;
    for (i = 0; i < *n; i++) {
        for (j = i + 1; j < *n; ) {
            if (vec[j] == vec[i]) {
                /* eliminar vec[j] desplazando el resto */
                for (k = j; k < *n - 1; k++) {
                    vec[k] = vec[k + 1];
                }
                (*n)--;    /* el array tiene un elemento menos */
            } else {
                j++;
            }
        }
    }
}

void mostrar_array(int vec[], int n) {
    int i;
    for (i = 0; i < n; i++)
        printf("%d ", vec[i]);
    printf("\n");
}
Array original:  10 20 30 40 50 60 70 80
Invertido:       80 70 60 50 40 30 20 10
Restaurado:      10 20 30 40 50 60 70 80

Rotar derecha:   80 10 20 30 40 50 60 70
Rotar derecha:   70 80 10 20 30 40 50 60

Rotar izquierda: 20 30 40 50 60 70 80 10

Original [1-5]:  1 2 3 4 5
Rotar 2 pos:     4 5 1 2 3

Array mixto:     -3 7 -1 15 -8 4 0 12
Solo positivos (3): 7 15 4

Con duplicados:  3 1 4 1 5 9 2 6 5 3
Sin duplicados:  3 1 4 5 9 2 6

Hay dos detalles importantes en este programa que vale la pena interiorizar.

El primero está en filtrar_positivos, la función recibe int *m para poder actualizar el tamaño del array resultado. Dentro usas (*m)++ con paréntesis, sin ellos, *m++ incrementaría el puntero en vez del valor, que es un error clásico en C.

El segundo está en eliminar_duplicados, el tamaño n se pasa como int *n porque la función lo modifica. Cuando eliminas un elemento el array encoge y *n decrece. Si pasaras n por valor la función no podría comunicar el nuevo tamaño al exterior.

Funciones en C práctica — Programa 3: Calculadora de estadísticas completa

Este programa combina todo, búsqueda, transformación y cálculo, en una calculadora de estadísticas que el usuario alimenta con sus propios datos. Cada estadística es una función independiente.

#include <stdio.h>

#define MAX 100

/* Prototipos */
int leer_datos(int vec[], int max);
int maximo(int vec[], int n);
int minimo(int vec[], int n);
float media(int vec[], int n);
float varianza(int vec[], int n);
float desviacion_tipica(int vec[], int n);
int mediana(int vec[], int n);
int moda(int vec[], int n, int *frecuencia);
void ordenar(int vec[], int n);
void intercambiar(int *a, int *b);
void copiar_array(int origen[], int destino[], int n);
void mostrar_estadisticas(int vec[], int n);
void mostrar_array(int vec[], int n);

int main(void) {
    int datos[MAX];
    int n;

    printf("=== CALCULADORA DE ESTADÍSTICAS ===\n\n");
    printf("¿Cuántos números quieres analizar? (máx %d): ", MAX);
    scanf("%d", &n);

    if (n <= 0 || n > MAX) {
        printf("Número de elementos no válido\n");
        return 1;
    }

    n = leer_datos(datos, n);

    printf("\nDatos introducidos: ");
    mostrar_array(datos, n);
    printf("\n");

    mostrar_estadisticas(datos, n);

    return 0;
}

/* Lee n números del usuario — devuelve cuántos se leyeron */
int leer_datos(int vec[], int n) {
    int i;
    printf("Introduce %d números enteros:\n", n);
    for (i = 0; i < n; i++) {
        printf("  Número %d: ", i + 1);
        scanf("%d", &vec[i]);
    }
    return n;
}

/* Devuelve el valor máximo */
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;
}

/* Devuelve el valor mínimo */
int minimo(int vec[], int n) {
    int i, min = vec[0];
    for (i = 1; i < n; i++)
        if (vec[i] < min) min = vec[i];
    return min;
}

/* Devuelve la media aritmética */
float media(int vec[], int n) {
    int i, suma = 0;
    for (i = 0; i < n; i++)
        suma += vec[i];
    return (float)suma / n;
}

/* Devuelve la varianza */
float varianza(int vec[], int n) {
    int i;
    float m = media(vec, n);
    float suma_cuadrados = 0.0;
    for (i = 0; i < n; i++) {
        float diferencia = vec[i] - m;
        suma_cuadrados += diferencia * diferencia;
    }
    return suma_cuadrados / n;
}

/* Devuelve la desviación típica */
float desviacion_tipica(int vec[], int n) {
    /* sqrt está en math.h — simplificamos con aproximación */
    float v = varianza(vec, n);
    float raiz = v;
    float mejora;
    int i;
    /* método de Newton para la raíz cuadrada */
    for (i = 0; i < 20; i++) {
        if (raiz == 0) break;
        mejora = (raiz + v / raiz) / 2.0;
        if (mejora == raiz) break;
        raiz = mejora;
    }
    return raiz;
}

void intercambiar(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

void copiar_array(int origen[], int destino[], int n) {
    int i;
    for (i = 0; i < n; i++)
        destino[i] = origen[i];
}

/* Ordena vec ascendentemente — burbuja */
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]);
}

/* Devuelve la mediana — trabaja sobre una copia para no alterar el original */
int mediana(int vec[], int n) {
    int copia[MAX];
    copiar_array(vec, copia, n);
    ordenar(copia, n);
    if (n % 2 == 1)
        return copia[n / 2];
    else
        return (copia[n / 2 - 1] + copia[n / 2]) / 2;
}

/* Devuelve la moda y guarda su frecuencia en *frecuencia */
int moda(int vec[], int n, int *frecuencia) {
    int i, j, max_freq = 0, valor_moda = vec[0];
    int freq_actual;

    for (i = 0; i < n; i++) {
        freq_actual = 0;
        for (j = 0; j < n; j++) {
            if (vec[j] == vec[i])
                freq_actual++;
        }
        if (freq_actual > max_freq) {
            max_freq = freq_actual;
            valor_moda = vec[i];
        }
    }
    *frecuencia = max_freq;    /* frecuencia por referencia */
    return valor_moda;
}

/* Muestra todas las estadísticas */
void mostrar_estadisticas(int vec[], int n) {
    int frecuencia;
    int valor_moda;
    int copia[MAX];

    printf("=== ESTADÍSTICAS ===\n");
    printf("Elementos:         %d\n", n);
    printf("Máximo:            %d\n", maximo(vec, n));
    printf("Mínimo:            %d\n", minimo(vec, n));
    printf("Rango:             %d\n", maximo(vec, n) - minimo(vec, n));
    printf("Media:             %.2f\n", media(vec, n));
    printf("Varianza:          %.2f\n", varianza(vec, n));
    printf("Desv. típica:      %.2f\n", desviacion_tipica(vec, n));
    printf("Mediana:           %d\n", mediana(vec, n));

    valor_moda = moda(vec, n, &frecuencia);
    printf("Moda:              %d (aparece %d veces)\n",
           valor_moda, frecuencia);

    /* Mostrar array ordenado sin modificar el original */
    copiar_array(vec, copia, n);
    ordenar(copia, n);
    printf("Ordenado:          ");
    mostrar_array(copia, n);
}

void mostrar_array(int vec[], int n) {
    int i;
    for (i = 0; i < n; i++)
        printf("%d ", vec[i]);
    printf("\n");
}

Ejemplo de ejecución con los datos {15, 8, 42, 8, 27, 19, 8, 35}:

=== CALCULADORA DE ESTADÍSTICAS ===

¿Cuántos números quieres analizar? (máx 100): 8
Introduce 8 números enteros:
  Número 1: 15
  Número 2: 8
  ...
  Número 8: 35

Datos introducidos: 15 8 42 8 27 19 8 35

=== ESTADÍSTICAS ===
Elementos:         8
Máximo:            42
Mínimo:            8
Rango:             34
Media:             20.25
Varianza:          131.69
Desv. típica:      11.47
Mediana:           17
Moda:              8 (aparece 3 veces)
Ordenado:          8 8 8 15 19 27 35 42

Hay tres decisiones de diseño en este programa que vale la pena identificar. La función mediana trabaja sobre una copia del array, si ordenara el original, mostrar_estadisticas mostraría los datos ya alterados al final. La función moda usa int *frecuencia para devolver dos resultados: el valor de la moda con return y su frecuencia con el puntero. Y desviacion_tipica llama a varianza, una función puede llamar a otra, igual que en Python.

Visualízalo con Python Tutor

Python Tutor también visualiza C, y es donde más brilla para entender el paso por referencia. Ve a pythontutor.com, selecciona C en el desplegable de lenguaje y pega este código:

#include <stdio.h>

void doblar_valor(int n) {
    n = n * 2;
}

void doblar_referencia(int *n) {
    *n = *n * 2;
}

void intercambiar(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main(void) {
    int x = 5;
    int y = 10;

    doblar_valor(x);
    doblar_referencia(&x);
    intercambiar(&x, &y);

    return 0;
}

Ejecuta paso a paso y observa cuatro cosas. Cuando llamas a doblar_valor(x) aparece un nuevo marco de función con su propia variable n, una copia de x. Cuando la función termina ese marco desaparece y x no ha cambiado. Cuando llamas a doblar_referencia(&x) el parámetro n es un puntero, Python Tutor dibuja una flecha desde n hacia x. Cuando haces *n = *n * 2 la flecha te muestra exactamente qué variable estás modificando. En intercambiar verás las dos flechas apuntando a x e y al mismo tiempo, y cómo temp guarda el valor antes de que se sobreescriba.

Esa flecha del puntero hacia la variable original es la imagen mental que necesitas tener clara antes de los ejercicios.

El patrón que debes llevarte

/* PATRÓN 1 — función que devuelve un resultado */
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;
}

/* PATRÓN 2 — función que devuelve resultado Y posición */
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 */
}

/* PATRÓN 3 — función que modifica array y su tamaño */
void filtrar(int vec[], int *n, int limite) {
    int i, j = 0;
    for (i = 0; i < *n; i++)
        if (vec[i] > limite)
            vec[j++] = vec[i];
    *n = j;    /* nuevo tamaño por referencia */
}

/* PATRÓN 4 — trabajar sobre copia para no alterar el original */
void operacion_no_destructiva(int vec[], int n) {
    int copia[MAX];
    copiar_array(vec, copia, n);
    /* trabajar sobre copia, no sobre vec */
    ordenar(copia, n);
}

En el siguiente artículo encontrarás ejercicios propuestos con solución para practicar por tu cuenta.

Publicaciones Similares

2 comentarios

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *