Funciones en C — práctica con 3 programas de la guagua: búsquedas con dos resultados, vectores que se transforman y las estadísticas de la línea (con scanf)
Hay un momento en IC2 en que el profesor escribe en la pizarra dos funciones casi idénticas y pregunta cuál modifica el vector original. Una recibe int v[] y la otra int *v. Casi toda la clase señala la segunda, convencida de que el asterisco marca la diferencia. Las dos lo modifican: un vector en C siempre viaja como una dirección, lo declares como lo declares. Esta práctica va de convertir esa idea, y la de pasar variables por referencia, en herramientas para resolver problemas de verdad.
Es la parte práctica de la teoría de funciones en C. Son tres programas completos de nivel medio, todos con la línea 201 de la guagua y con el estilo de los laboratorios de IC2 (prototipos arriba, main en medio y definiciones al final): funciones de búsqueda sobre los retrasos de los viajes, funciones que transforman vectores en su sitio y una calculadora de estadísticas que lee los viajeros de cada parada con scanf. Los datos tienen lo que tienen los de verdad: repetidos, negativos y huecos. Todas las salidas son de una ejecución real con gcc 14.
Tabla de Contenidos
Antes de empezar
Conviene tener claro:
- Cómo se escriben un prototipo, una definición y una llamada, y qué significa
void. - La diferencia entre pasar
x(una copia) y pasar&x(la dirección) a un parámetroint *. - Que un vector llega a la función como la dirección de su primera casilla, y que su tamaño hay que pasarlo aparte.
- Qué es
returny que solo puede devolver un valor.
Si alguno te suena dudoso, repasa la teoría (y la de punteros en C) antes de seguir.
Compila cada programa con gcc -Wall -std=c11 programa.c -o programa. Con -Wall gcc te avisa de casi todos los errores de este tema: llamadas sin prototipo, caminos sin return y sizeof sobre un parámetro vector. Puedes probarlos también en el entorno de C de la web; el tercero lee del teclado, así que escribe los datos en la pestaña Entrada.
Programa 1: funciones de búsqueda en vectores
Tenemos los retrasos, en minutos, de los 10 viajes de la línea 201 de un día. Queremos varias consultas: en qué viaje hubo un retraso concreto, cuál fue el peor y el mejor (y en qué viaje), cuántas veces se repite un retraso y si los datos están ordenados. Cada consulta será una función.
La idea
Una búsqueda tiene que devolver dos cosas: si ha encontrado el dato y dónde. Hay dos patrones, y en IC2 salen los dos:
- Patrón 1: devolver la posición con
returny usar-1como señal de «no está», porque nunca es una posición válida. - Patrón 2: devolver 1 o 0 con
returny dejar la posición en una variable demaina través de un puntero (int *pos).
El máximo y el mínimo usan el segundo patrón al revés: el valor sale por return y la posición, por el puntero.
Antes de programar, escribe la firma de cada función y señala qué parámetros son de entrada (el vector, n, el valor buscado) y cuáles de salida (int *pos). Las de salida llevarán & en la llamada.
El código
#include <stdio.h>
/* Prototipos: arriba, para que main pueda usarlas */
int buscar(int v[], int n, int buscado);
int buscar_pos(int v[], int n, int buscado, int *pos);
int maximo_con_pos(int v[], int n, int *pos);
int minimo_con_pos(int v[], int n, int *pos);
int contar(int v[], int n, int valor);
int esta_ordenado(int v[], int n);
void mostrar(int v[], int n);
int main(void) {
int retrasos[10] = {42, 7, 19, 7, 85, 26, 7, 54, 13, 7}; /* minutos, 10 viajes */
int ordenados[5] = {1, 3, 5, 7, 9};
int n = 10, pos, r;
printf("Retrasos: ");
mostrar(retrasos, n);
r = buscar(retrasos, n, 85); /* patrón 1: return con -1 */
if (r != -1) printf("85 min: viaje %d\n", r);
r = buscar(retrasos, n, 99);
if (r == -1) printf("99 min: ningún viaje\n");
if (buscar_pos(retrasos, n, 26, &pos)) /* patrón 2: 1/0 y posición por puntero */
printf("26 min: viaje %d\n", pos);
int max = maximo_con_pos(retrasos, n, &pos);
printf("\nPeor retraso: %d min (viaje %d)\n", max, pos);
int min = minimo_con_pos(retrasos, n, &pos);
printf("Mejor retraso: %d min (viaje %d)\n", min, pos);
printf("Viajes con 7 min: %d\n", contar(retrasos, n, 7));
printf("\n¿Retrasos ordenados? %s\n", esta_ordenado(retrasos, n) ? "Sí" : "No");
printf("¿{1,3,5,7,9} ordenado? %s\n", esta_ordenado(ordenados, 5) ? "Sí" : "No");
return 0;
}
/* Posición de la primera aparición, o -1 (un índice imposible) */
int buscar(int v[], int n, int buscado) {
for (int i = 0; i < n; i++)
if (v[i] == buscado)
return i; /* la primera y me voy */
return -1;
}
/* Devuelve 1/0 y deja la posición en *pos: dos resultados */
int buscar_pos(int v[], int n, int buscado, int *pos) {
for (int i = 0; i < n; i++)
if (v[i] == buscado) {
*pos = i; /* escribo en la variable de main */
return 1;
}
return 0; /* *pos no se toca */
}
/* El valor por return; la posición, por puntero */
int maximo_con_pos(int v[], int n, int *pos) {
int p = 0;
for (int i = 1; i < n; i++)
if (v[i] > v[p]) p = i;
*pos = p;
return v[p];
}
int minimo_con_pos(int v[], int n, int *pos) {
int p = 0;
for (int i = 1; i < n; i++)
if (v[i] < v[p]) p = i; /* < y no <=: me quedo con el primero */
*pos = p;
return v[p];
}
int contar(int v[], int n, int valor) {
int c = 0;
for (int i = 0; i < n; i++)
if (v[i] == valor) c++;
return c;
}
/* 1 si cada elemento es <= que el siguiente */
int esta_ordenado(int v[], int n) {
for (int i = 0; i < n - 1; i++) /* n - 1: comparo con v[i + 1] */
if (v[i] > v[i + 1])
return 0;
return 1;
}
void mostrar(int v[], int n) {
for (int i = 0; i < n; i++)
printf("%d ", v[i]);
printf("\n");
}
Salida
Retrasos: 42 7 19 7 85 26 7 54 13 7
85 min: viaje 4
99 min: ningún viaje
26 min: viaje 5
Peor retraso: 85 min (viaje 4)
Mejor retraso: 7 min (viaje 1)
Viajes con 7 min: 4
¿Retrasos ordenados? No
¿{1,3,5,7,9} ordenado? Sí
Compruébalo con los datos {42, 7, 19, 7, 85, 26, 7, 54, 13, 7}: el 85 está en la casilla 4 y el 26 en la 5; el 99 no está y buscar devuelve -1. El peor retraso es 85 (viaje 4); el mejor, 7, aparece en los viajes 1, 3, 6 y 9, y la función se queda con el primero porque compara con < y no con <=. El 7 sale 4 veces. Los retrasos no están ordenados (42 > 7 en la primera comparación) y {1, 3, 5, 7, 9} sí.
Traza de maximo_con_pos, que guarda la posición del mejor visto hasta ahora (p), no su valor:
i | v[i] | v[p] antes | ¿v[i] > v[p]? | p después |
|---|---|---|---|---|
| 1 | 7 | 42 | No | 0 |
| 2 | 19 | 42 | No | 0 |
| 3 | 7 | 42 | No | 0 |
| 4 | 85 | 42 | Sí | 4 |
| 5…9 | 26, 7, 54, 13, 7 | 85 | No | 4 |
Al final, *pos = 4 escribe en la pos de main y return v[4] devuelve 85.
Preguntas que te puedes hacer
¿Por qué -1 y no 0 para «no encontrado»? Porque 0 es una posición válida: el primer viaje. Si buscar devolviera 0 cuando no encuentra nada, no sabrías si el dato está en la casilla 0 o no está.
¿Por qué en buscar_pos no se toca *pos si no lo encuentra? Porque la función promete solo una cosa cuando devuelve 0: que no está. main no debe leer pos en ese caso, y por eso lo usa dentro del if. Tocar *pos con un valor inventado solo serviría para disimular errores.
¿Por qué esta_ordenado recorre hasta n - 1? Porque compara cada casilla con la siguiente, v[i + 1]. Si i llegara a n - 1, v[i + 1] sería la casilla n, que no existe.
¿Puede una función llamar a mostrar si está definida después? Sí, porque su prototipo está arriba. El orden de las definiciones da igual mientras todos los prototipos vayan antes de la primera llamada.
Llamar a buscar_pos(retrasos, n, 26, pos) sin &. pos es un int sin valor y la función lo usaría como dirección. gcc 14 lo convierte en un error de compilación (int donde se espera int *).
Pruébalo tú
- Escribe
int buscar_ultimo(int v[], int n, int x), que devuelva la última aparición recorriendo el vector de atrás hacia delante. - Haz que
minimo_con_posse quede con la última aparición del mínimo. ¿Qué único carácter tienes que cambiar?
Programa 2: funciones que transforman vectores
Ahora las funciones no consultan: cambian el vector. Damos la vuelta a las salidas del día, las rotamos (el primer turno pasa al final, o el último al principio), filtramos los cambios positivos de viajeros en un vector nuevo y quitamos los números de línea repetidos de una lista.
La idea
Como el vector llega como dirección, cualquier v[i] = … dentro de la función cambia el de main: no hace falta return. Lo delicado son dos funciones que además cambian un tamaño:
filtrar_positivoscrea un vector nuevo y tiene que decirle amaincuántos elementos ha metido: recibeint *m.quitar_repetidoshace encoger el propio vector: recibeint *ny lo decrementa cada vez que tapa un hueco.
Y rotar_k reutiliza rotar_derecha: una función llamando a otra en lugar de repetir código.
Antes de programar, dibuja las casillas y decide la dirección de cada recorrido. Si vas a correr los elementos a la derecha, recorre de atrás hacia delante; si los corres a la izquierda, de delante hacia atrás. En la dirección equivocada, el primer valor se copia en todas las casillas.
El código
#include <stdio.h>
void intercambiar(int *a, int *b);
void invertir(int v[], int n);
void rotar_derecha(int v[], int n);
void rotar_izquierda(int v[], int n);
void rotar_k(int v[], int n, int k);
void filtrar_positivos(int v[], int n, int res[], int *m);
void quitar_repetidos(int v[], int *n);
void mostrar(const char *titulo, int v[], int n);
int main(void) {
int salidas[8] = {10, 20, 30, 40, 50, 60, 70, 80}; /* minutos tras las 9:00 */
mostrar("Salidas: ", salidas, 8);
invertir(salidas, 8);
mostrar("Invertidas: ", salidas, 8);
invertir(salidas, 8); /* otra vez: como estaban */
rotar_derecha(salidas, 8);
mostrar("Rotar derecha: ", salidas, 8);
rotar_izquierda(salidas, 8);
rotar_izquierda(salidas, 8);
mostrar("Rotar izq. x2: ", salidas, 8);
int zonas[5] = {1, 2, 3, 4, 5};
rotar_k(zonas, 5, 2);
mostrar("Zonas, rotar 2: ", zonas, 5);
int cambio[8] = {-3, 7, -1, 15, -8, 4, 0, 12}; /* suben menos bajan */
int positivos[8], m;
filtrar_positivos(cambio, 8, positivos, &m); /* &m: la función lo rellena */
printf("Positivos (%d): ", m);
mostrar("", positivos, m);
int lineas[9] = {201, 202, 201, 301, 202, 201, 303, 301, 210};
int n = 9;
quitar_repetidos(lineas, &n); /* &n: el tamaño cambia */
printf("Líneas (%d): ", n);
mostrar("", lineas, n);
return 0;
}
void intercambiar(int *a, int *b) {
int t = *a; *a = *b; *b = t;
}
/* Solo hasta la mitad: n / 2 intercambios */
void invertir(int v[], int n) {
for (int i = 0; i < n / 2; i++)
intercambiar(&v[i], &v[n - 1 - i]);
}
/* [1,2,3,4] -> [4,1,2,3] */
void rotar_derecha(int v[], int n) {
int ultimo = v[n - 1];
for (int i = n - 1; i > 0; i--) /* de atrás hacia delante */
v[i] = v[i - 1];
v[0] = ultimo;
}
/* [1,2,3,4] -> [2,3,4,1] */
void rotar_izquierda(int v[], int n) {
int primero = v[0];
for (int i = 0; i < n - 1; i++) /* de delante hacia atrás */
v[i] = v[i + 1];
v[n - 1] = primero;
}
/* Reutiliza otra función: k rotaciones de una casilla */
void rotar_k(int v[], int n, int k) {
for (int i = 0; i < k % n; i++)
rotar_derecha(v, n);
}
/* Copia los positivos a res y deja en *m cuántos hay */
void filtrar_positivos(int v[], int n, int res[], int *m) {
*m = 0;
for (int i = 0; i < n; i++)
if (v[i] > 0) {
res[*m] = v[i];
(*m)++; /* paréntesis: el valor, no el puntero */
}
}
/* Deja cada número una vez, en el orden en que aparece */
void quitar_repetidos(int v[], int *n) {
int i = 0;
while (i < *n) {
int j = i + 1;
while (j < *n) {
if (v[j] == v[i]) {
for (int k = j; k < *n - 1; k++) /* tapo el hueco */
v[k] = v[k + 1];
(*n)--; /* el vector encoge */
} else {
j++;
}
}
i++;
}
}
void mostrar(const char *titulo, int v[], int n) {
printf("%s", titulo);
for (int i = 0; i < n; i++)
printf("%d ", v[i]);
printf("\n");
}
Salida
Salidas: 10 20 30 40 50 60 70 80 Invertidas: 80 70 60 50 40 30 20 10 Rotar derecha: 80 10 20 30 40 50 60 70 Rotar izq. x2: 20 30 40 50 60 70 80 10 Zonas, rotar 2: 4 5 1 2 3 Positivos (4): 7 15 4 12 Líneas (5): 201 202 301 303 210
- Invertir hace 8 / 2 = 4 intercambios (10↔80, 20↔70, 30↔60, 40↔50). Invertir dos veces deja el vector como estaba.
- Rotar a la derecha una vez: el 80 pasa delante. Rotar a la izquierda dos veces sobre eso: el 80 vuelve al final y el 10 se va detrás de él. Resultado: 20 … 80 10.
- Rotar 2 las zonas {1, 2, 3, 4, 5}: dos rotaciones a la derecha, 4 5 1 2 3. El
k % nhace que rotar 7 sea lo mismo que rotar 2. - Filtrar: de {-3, 7, -1, 15, -8, 4, 0, 12} pasan 7, 15, 4 y 12 (el 0 no es positivo) y
mvale 4. - Quitar repetidos: de nueve números de línea quedan cinco, en el orden en que aparecieron.
Traza de quitar_repetidos sobre {201, 202, 201, 301, 202, 201, 303, 301, 210}:
i | v[i] | Repetidos que tapa | Vector después | *n |
|---|---|---|---|---|
| 0 | 201 | casillas 2 y 5 | 201 202 301 202 303 301 210 | 7 |
| 1 | 202 | casilla 3 | 201 202 301 303 301 210 | 6 |
| 2 | 301 | casilla 4 | 201 202 301 303 210 | 5 |
| 3 | 303 | ninguno | igual | 5 |
| 4 | 210 | ninguno | igual | 5 |
Fíjate en que, cuando tapa un hueco, j no avanza: en la casilla j acaba de entrar el siguiente número y hay que comprobarlo también.
Preguntas que te puedes hacer
¿Por qué (*m)++ y no *m++? Porque ++ va antes que *: *m++ avanzaría el puntero m (la copia local de la dirección) y el contador de main se quedaría en 0. Con los paréntesis se incrementa el valor apuntado.
¿Por qué res[*m] = v[i]? Porque *m es a la vez el contador y la primera casilla libre del vector de resultado: con 0 positivos se escribe en la casilla 0, con 1 en la 1…
¿Por qué filtrar_positivos necesita un vector de 8 si solo salen 4? Porque la función no sabe de antemano cuántos va a encontrar: en el peor caso todos son positivos. El vector de destino tiene que tener sitio para todos.
¿Por qué rotar_k hace k % n rotaciones? Rotar n veces un vector de n casillas lo deja igual. Con el resto, rotar 12 veces un vector de 5 es rotarlo 2, y te ahorras 10 vueltas inútiles.
Pasar n por valor a quitar_repetidos. La función encogería su copia, main seguiría creyendo que hay 9 números y mostraría los restos que quedan al final del vector.
Pruébalo tú
- Escribe
void escalar(int v[], int n, int factor), que multiplique cada casilla, y úsala para pasar los minutos a segundos. - Cambia
quitar_repetidospara que devuelva conreturncuántos números ha quitado, además de actualizar*n.
Programa 3: calculadora de estadísticas de la línea
El último programa junta todo: lee del teclado cuántas paradas hay y cuántos viajeros subieron en cada una, y calcula la media, la mediana, la moda (con cuántas veces se repite) y la varianza. Cada estadística es una función, y una de ellas llama a otra.
La idea
leer_datos rellena el vector de main con scanf y devuelve cuántos datos ha leído (0 si algo falla, para que main pare). Las estadísticas son funciones que devuelven un double. Dos decisiones importantes:
- La mediana necesita ordenar, pero si ordenara el vector de
mainlo dejaría cambiado para las demás funciones. Trabaja sobre una copia local. - La moda devuelve dos cosas: el valor (por
return) y cuántas veces aparece (por el punteroint *frecuencia).
Antes de programar, decide qué funciones pueden cambiar el vector y cuáles no. Solo leer_datos debería escribir en él; para las demás, puedes declarar el parámetro const int v[] y gcc te protegerá.
El código
#include <stdio.h>
#define MAX 100
int leer_datos(int v[], int max);
double media(int v[], int n);
double mediana(int v[], int n);
int moda(int v[], int n, int *frecuencia);
double varianza(int v[], int n);
void ordenar(int v[], int n);
int main(void) {
int viajeros[MAX];
int n = leer_datos(viajeros, MAX);
if (n == 0) return 1; /* sin datos no hay estadística */
int veces;
int m = moda(viajeros, n, &veces); /* valor por return, veces por puntero */
printf("\n=== ESTADÍSTICAS DE LA LÍNEA 201 ===\n");
printf("Paradas: %d\n", n);
printf("Media: %.2f\n", media(viajeros, n));
printf("Mediana: %.1f\n", mediana(viajeros, n));
printf("Moda: %d (%d veces)\n", m, veces);
printf("Varianza: %.2f\n", varianza(viajeros, n));
printf("Datos sin tocar: ");
for (int i = 0; i < n; i++) printf("%d ", viajeros[i]);
printf("\n");
return 0;
}
/* Lee cuántos datos hay y los datos; devuelve n (0 si algo falla) */
int leer_datos(int v[], int max) {
int n;
printf("¿Cuántas paradas? (1-%d): ", max);
if (scanf("%d", &n) != 1 || n < 1 || n > max) {
printf("Número de paradas no válido\n");
return 0;
}
for (int i = 0; i < n; i++) {
printf(" Viajeros en la parada %d: ", i + 1);
if (scanf("%d", &v[i]) != 1) return 0; /* &v[i]: dirección de esa casilla */
}
return n;
}
double media(int v[], int n) {
int suma = 0;
for (int i = 0; i < n; i++) suma += v[i];
return (double)suma / n; /* el cast, ANTES de dividir */
}
/* Ordena una COPIA: el vector de main no se toca */
double mediana(int v[], int n) {
int copia[MAX];
for (int i = 0; i < n; i++) copia[i] = v[i];
ordenar(copia, n);
if (n % 2 == 1) return copia[n / 2];
return (copia[n / 2 - 1] + copia[n / 2]) / 2.0; /* par: media de los dos centrales */
}
int moda(int v[], int n, int *frecuencia) {
int mejor = v[0];
*frecuencia = 0;
for (int i = 0; i < n; i++) {
int c = 0;
for (int j = 0; j < n; j++)
if (v[j] == v[i]) c++;
if (c > *frecuencia) { /* > y no >=: gana el primero que aparece */
*frecuencia = c;
mejor = v[i];
}
}
return mejor;
}
/* Llama a otra función: media */
double varianza(int v[], int n) {
double m = media(v, n), s = 0;
for (int i = 0; i < n; i++)
s += (v[i] - m) * (v[i] - m);
return s / n;
}
void ordenar(int v[], int n) {
for (int i = 0; i < n - 1; i++)
for (int j = 0; j < n - 1 - i; j++)
if (v[j] > v[j + 1]) {
int t = v[j]; v[j] = v[j + 1]; v[j + 1] = t;
}
}
Salida
Con los viajeros de 8 paradas (15, 8, 42, 8, 27, 19, 8 y 35):
¿Cuántas paradas? (1-100): 8 Viajeros en la parada 1: 15 Viajeros en la parada 2: 8 Viajeros en la parada 3: 42 Viajeros en la parada 4: 8 Viajeros en la parada 5: 27 Viajeros en la parada 6: 19 Viajeros en la parada 7: 8 Viajeros en la parada 8: 35 === ESTADÍSTICAS DE LA LÍNEA 201 === Paradas: 8 Media: 20.25 Mediana: 17.0 Moda: 8 (3 veces) Varianza: 151.94 Datos sin tocar: 15 8 42 8 27 19 8 35
Comprobación a mano:
- Media: 15 + 8 + 42 + 8 + 27 + 19 + 8 + 35 = 162, y 162 / 8 = 20,25.
- Mediana: ordenados quedan 8 8 8 15 19 27 35 42. Con 8 datos (par) es la media de los dos centrales, (15 + 19) / 2 = 17,0.
- Moda: el 8 aparece 3 veces; ningún otro se repite.
- Varianza: la media de los cuadrados de las distancias a 20,25. Por ejemplo, el 42 aporta (42 − 20,25)² = 473,06; sumando las ocho y dividiendo entre 8 sale 151,94.
- Datos sin tocar: el vector de
mainsigue en el orden en que se tecleó, porque la mediana ordenó su copia.
Traza de moda (solo las vueltas en las que cambia algo):
i | v[i] | Veces que aparece (c) | ¿c > *frecuencia? | mejor / *frecuencia |
|---|---|---|---|---|
| 0 | 15 | 1 | Sí (1 > 0) | 15 / 1 |
| 1 | 8 | 3 | Sí (3 > 1) | 8 / 3 |
| 2…7 | 42, 8, 27, 19, 8, 35 | 1 o 3 | No | 8 / 3 |
Preguntas que te puedes hacer
¿Por qué &v[i] en el scanf? scanf necesita la dirección donde dejar el número. v[i] es el entero de la casilla i; &v[i] es su dirección. También valdría v + i.
¿Por qué leer_datos devuelve n en lugar de recibir int *n? Las dos formas funcionan. Devolverlo deja una llamada más limpia (int n = leer_datos(...)) y usa el 0 como señal de error. Lo importante es que el tamaño llegue a main por algún camino.
¿Por qué / 2.0 en la mediana? Con dos int, (15 + 18) / 2 daría 16 en lugar de 16,5. El 2.0 fuerza la división decimal.
¿Por qué varianza llama a media en lugar de calcularla otra vez? Para no repetir código: si un día cambias cómo se calcula la media, solo lo cambias en un sitio. Una función puede llamar a otra siempre que su prototipo esté arriba.
¿Qué pasa si escribo letras en vez de un número? scanf devuelve 0, leer_datos devuelve 0 y main termina con return 1 sin calcular nada. Mejor que dividir entre un n que no tiene valor.
Ordenar el vector original dentro de mediana. Las estadísticas saldrían bien, pero «Datos sin tocar» saldría ordenado y cualquier función que se llamara después vería los datos en otro orden. Si una función solo tiene que consultar, no debe dejar huella.
Pruébalo tú
- Añade
int paradas_sobre_media(const int v[], int n)y muestra cuántas paradas superan la media. - Haz que
leer_datosvuelva a preguntar si el número de paradas no es válido, en lugar de terminar.
Errores típicos en esta práctica
- Olvidar el
&al llamar a una función con parámetros de salida:buscar_pos(v, n, x, pos). *m++en lugar de(*m)++para incrementar un contador recibido por puntero.- Pasar el tamaño por valor a una función que lo cambia (
quitar_repetidos). - Usar 0 como «no encontrado» cuando 0 es una posición válida.
- Ordenar el vector original en una función que solo debería consultar.
- Recorrer en la dirección equivocada al desplazar elementos, copiando el mismo valor en todas las casillas.
Míralo paso a paso en Python Tutor
En Python Tutor, eligiendo C, se ve muy bien una función que devuelve un valor por return y otro por puntero. Pega este programa:
#include <stdio.h>
int maximo_con_pos(int v[], int n, int *pos) {
int p = 0;
for (int i = 1; i < n; i++) {
if (v[i] > v[p]) {
p = i;
}
}
*pos = p;
return v[p];
}
int main(void) {
int retrasos[5] = {42, 7, 85, 26, 13};
int pos;
int max = maximo_con_pos(retrasos, 5, &pos);
printf("%d en el viaje %d\n", max, pos);
return 0;
}
Qué observar paso a paso:
- Antes de la llamada,
posexiste en el marco demainpero sin valor. - Al entrar en
maximo_con_pos,vyposson dos flechas: una al vector demainy otra a su variablepos. - Durante el
for, solo cambia la variable localp: 0, y luego 2 cuando aparece el 85. - En
*pos = p;se rellena la cajaposdemain, al otro lado de la flecha. - Al volver, el
return v[p]llega amaxy el marco de la función desaparece. Debe imprimir85 en el viaje 2.
Resumen
- Un vector llega a la función como dirección:
int v[]eint *vson lo mismo y las dos permiten modificar el original. - Para «devolver» varias cosas, una sale por
returny las demás por punteros; en la llamada, las de salida llevan&. - Para «no encontrado», un valor que nunca sea válido (-1 para una posición) o un
returnde 1/0 con la posición por puntero. - Si una función cambia el tamaño de un vector, recibe
int *ny usa(*n)--o(*n)++. - Una función que solo consulta trabaja sobre una copia (o recibe
const int v[]) para no dejar huella. - Una función puede reutilizar otra (
rotar_k,varianza) si su prototipo está arriba.
Checklist: ¿lo has practicado?
- ¿Has ejecutado los tres programas y comprobado las salidas?
- ¿Sabes cuándo usar el patrón
-1y cuándo el de 1/0 con la posición por puntero? - ¿Sabes por qué
(*m)++necesita los paréntesis? - ¿Puedes explicar por qué la mediana trabaja sobre una copia?
- ¿Has comprobado a mano la media y la mediana?
- ¿Has intentado los «Pruébalo tú» sin mirar la teoría?
Si has respondido que sí a casi todo, estás listo para los ejercicios de funciones en C, donde ya no te doy el código hecho. ¡Nos vemos allí!
Siguiente paso: ejerciciosFunciones en C — ejercicios resueltos con la guagua: segundo peor retraso, paradas que se cierran y abren y horarios que se fusionan (más el chuletario para el examen)¿Te ha servido este artículo? Así puedes apoyar SergioLearns →




Qué es un sistema operativo — teoría con tu portátil en una tarde de estudio, una llamada a write() y la CPU que nunca descansa (y los tres programas que no se ejecutaban a la vez)