Les vencimos

1º Bachillerato · TIC I

Lección 27 · C · Programación

Vectores, arrays y funciones

1º Bachillerato · TIC I · Decreto 40/2022 CyL

Objetivos

  1. Crear un vector, leer una casilla y no salir del índice.
  2. Recorrer el vector con un para desde 0 hasta longitud - 1.
  3. Escribir una función con parámetros y un valor devuelto.
  4. Distinguir lo que la función recibe, lo que calcula y lo que deja fuera.
  5. Ver el mismo recorrido en un array de Arduino y en una lista de Python.

Explicación

Un vector (en JavaScript se dice array) guarda varios valores bajo un solo nombre, en orden. lecturas no es «la luz»: es la serie. Cada valor vive en un índice. El primero es 0, el segundo es 1, y el último es la longitud menos uno. Si hay cuatro lecturas, los índices son 0, 1, 2 y 3. Pedir la casilla 4 es un error, no un cero educado. El laboratorio se para y lo dice. En una placa, leer fuera del array es comportamiento indefinido: a veces basura, a veces un cuelgue. No es una casilla vacía con la que se pueda calcular una media.

Recorrer

El para encaja aquí porque las vueltas se saben: tantas como casillas. para i = 0 hasta v.longitud - 1 entra en todas y en ninguna de más. Escribir hasta v.longitud es el error de esta lección. La condición parece natural («hasta el número de elementos») y se come una casilla que no existe. Por eso la traza se hace con el índice escrito al lado del valor, no solo con la suma.

Dentro del vector todas las casillas de esta práctica son números, las lecturas. Mezclar en la misma serie un texto y un número complica la media: la suma dejaría de ser una suma en cuanto el + encuentre una cadena. Si necesitas el nombre del sensor, no va en la casilla 2: va en otro nombre, o en un objeto, que es la lección siguiente.

Funciones

Una función es un algoritmo con nombre. Se le pasan parámetros (los datos de entrada de ese subproblema) y devuelve un resultado, o hace un efecto que has decidido limitar. media(v) no debería encender el LED por su cuenta: debería devolver un número. Quien llama, let m = media(lecturas), decide qué hacer con m. Esa separación es la misma descomposición de la lección 23, ahora con una frontera que el lenguaje vigila.

Los parámetros son variables nuevas de la función, no copias mágicas del nombre de fuera. Si el parámetro se llama v, dentro se usa v, no lecturas, aunque al llamar hayas pasado lecturas. Cambiar un número parámetro no cambia la variable de fuera. En este laboratorio los vectores se pasan como el propio vector: si una función escribiera en una casilla, se vería fuera. Por eso una función de media no escribe en las casillas. Calcula y devuelve.

devolver

devolver termina la función y entrega el valor. Lo que escribas debajo, en la misma función, no se ejecuta. Sin devolver, la llamada no tiene un número que guardar: el resultado es nulo y la media «desaparece» aunque la suma se hubiera hecho. El error se ve en el entorno: m no es 480, es nulo. 480 es la media de 420, 510, 390 y 600, porque la suma es 1920 y hay cuatro casillas.
420 + 510 = 930
930 + 390 = 1320
1320 + 600 = 1920
1920 ÷ 4 = 480
Si te sale 640, has dividido entre tres: te comiste una casilla o contaste mal la longitud.
1920 ÷ 3 = 640

En la placa y en la Pi

En el sketch, int lecturas[4] reserva cuatro enteros, y una función int media(int v[], int n) recibe también la longitud, porque un array de C no la guarda solo. En Python, sum(lecturas)/len(lecturas) es la misma idea con la longitud incluida. En JavaScript, lecturas.length. Tres sintaxis, un cuidado: no uses un índice que no esté entre 0 y n-1. El LED sigue fuera de la función de la media. Encenderlo es otra función o el si de siempre, que compara la media, o la última lectura, con el umbral. No metas digitalWrite dentro de media «ya que estamos»: el día que quieras la media para un informe, encenderás un pin sin querer.

El canvas, si dejas el vector en lecturas, dibuja una barra por casilla. La altura no es el pin: es el dato. El pin sigue siendo la decisión posterior. Ejecutar tiene que mostrar m = 480 en el ejemplo. Si no sale, no arregles el 480 a mano en un escribe: arregla el recorrido.

Vector y función 0 1 2 3 lecturas[i] media(v) parámetro: v devuelve 480
Índices 0, 1, 2 y 3. La media no vive en una quinta casilla: la devuelve la función.

Glosas de esta lección

Vector. Serie ordenada bajo un nombre. En JavaScript, array.

Índice. Posición. Empieza en 0. Tiene que ser entero y caber.

longitud. Cuántas casillas hay. El último índice es longitud - 1.

Parámetro. Nombre de la entrada de la función, distinto del argumento con el que llamas.

Argumento. El valor que pasas en la llamada: media(lecturas).

devolver. Cierra la función y entrega un valor a quien llamó.

Efecto. Un cambio fuera de la función, como encender un pin. La media no debería tenerlo.

Fuera de rango. Índice negativo, fraccionario o mayor o igual que la longitud. Es un error.

Ejemplos resueltos

Ejemplo 1 — Índice 4

para i = 0 hasta lecturas.longitud intenta leer la casilla 4. No existe. El mensaje lo dice. Se cambia el hasta por longitud - 1 y la suma pasa a 1920.
420 + 510 = 930
930 + 390 = 1320
1320 + 600 = 1920

Ejemplo 2 — Media que enciende

Dentro de media alguien escribe el pin. Al pedir la media para el informe de las 18:00 el LED se enciende. Se saca el digitalWrite al algoritmo que llama.

Ejemplo 3 — Olvido del cero

El para empieza en 1. La media usa tres casillas y el 420 desaparece. 510+390+600 = 1500, entre 3 es 500, que casualmente es el umbral y parece «correcto».
510 + 390 = 900
900 + 600 = 1500
1500 ÷ 3 = 500 La traza con índices enseña que falta el 0.

Decisiones de aula

Cada caso es una entrega del avisador del patio del IES Duero (Aranda de Duero). Lee la situación antes de la decisión.

1. Cuatro variables sueltas

Situación. luz1, luz2, luz3, luz4 y una suma a mano.

No conviene. Porque todavía no hay muchos datos.

Decisión. Guardar el vector y recorrer. La función media no cambia cuando mañana hay ocho lecturas.

Por qué: luz1, luz2, luz3 y luz4 con una suma a mano sirven solo mientras sean cuatro. El algoritmo de la media no depende de cuántas casillas hay, solo de no salirse. El vector se recorre, y añadir una lectura no obliga a inventar luz5.

2. Empezar en 1

Situación. El grupo dice que la casilla cero es rara y la salta.

No conviene. Porque en clase se numera desde uno.

Decisión. Recorrer desde 0 y escribir el índice al lado en la tabla.

Por qué: Saltar la casilla cero porque «en clase se numera desde uno» borra una lectura. La media se sesga hacia las horas que quedan, no es un detalle de estilo. El recorrido empieza en 0 y llega hasta la última casilla que existe, sin hueco al principio.

3. Longitud de C

Situación. En el sketch, el array no lleva la longitud encima.

No conviene. Inventar un 4 escrito en tres sitios distintos.

Decisión. Pasar n a la función y usar un solo sitio para el 4, o calcular el tamaño con la fórmula del compilador de C que el IDE ya conoce (sizeof), sin reescribir el número a ciegas.

Por qué: En el sketch la longitud no viaja sola encima del array, y tres cuatros escritos en sitios distintos se desincronizan en cuanto añades una lectura. Se pasa n a la función o se calcula el tamaño en un solo sitio. El 4 repetido a mano no es el tamaño.

4. Devolver y escribir

Situación. La función devuelve la media y además hace un escribe de depuración que se queda en la entrega.

No conviene. Porque ayuda.

Decisión. Quitar el escribe de la función antes de darla por cerrada, o dejarlo solo en la llamada.

Por qué: Una función que devuelve la media y además escribe un mensaje de depuración mezcla el resultado con el ruido. En una placa, «hablar» a veces se confunde con tocar un pin. El escribe de prueba se quita de la entrega; la función solo devuelve el número.

El mismo avisador, en tres lenguajes

El problema no cambia: si la luz del patio del IES Duero baja de 500, hay que avisar. Cambia quién ejecuta. El pseudocódigo lo ejecuta el laboratorio de esta página. El sketch lo compilaría el IDE de Arduino hacia la UNO. El fragmento de Python lo ejecutaría una Raspberry Pi con gpiozero, si hubiera placa. Aquí no hay placa.

Media en el laboratorio

Con [420, 510, 390, 600] devuelve 480.
420 + 510 = 930
930 + 390 = 1320
1320 + 600 = 1920
1920 ÷ 4 = 480

funcion media(v)
  let s = 0
  para i = 0 hasta v.longitud - 1
    s = s + v[i]
  fin
  devolver s / v.longitud
fin

Array en la UNO

El for de C usa i < n, que es lo mismo que hasta n-1 en nuestro para, porque el hasta de aquí incluye el final. return es devolver. El LED no está en esta función.

int lecturas[4] = {420, 510, 390, 600};
int media(int v[], int n) {
  long s = 0;
  for (int i = 0; i < n; i++) s += v[i];
  return s / n;
}

Lista en la Pi

len es la longitud. sum recorre desde el índice 0. El GPIO 18 se decide después, comparando m o la última casilla con el umbral.

lecturas = [420, 510, 390, 600]
def media(v):
    return sum(v) / len(v)
m = media(lecturas)   # 480

Casillas de la serie

ÍndiceValorSuma acumulada¿Existe?
0420420sí
1510930sí
23901320sí
36001920sí
4——no

1920 / 4 = 480.
1920 ÷ 4 = 480
La fila del índice 4 está para que se vea el fallo, no para que se programe. Dividir 1920 entre 3 es el síntoma de haberse dejado una casilla.
1920 ÷ 3 = 640

Lectura guiada

Cambia el vector a [100, 100, 100, 100]. La media tiene que ser 100.
100 + 100 = 200
200 + 100 = 300
300 + 100 = 400
400 ÷ 4 = 100 Es una prueba tonta y por eso vale: si no sale 100, el recorrido está roto y con los datos del patio no se vería tan claro. Luego vuelve al ejemplo de 480.

Escribe una segunda función maximo(v) que devuelva la mayor lectura, con un si dentro del para. No enciendas el LED dentro. Quien llame puede comparar ese máximo con el umbral si el problema lo pide. El parámetro sigue siendo el vector entero, no una casilla suelta.

En C, el for (int i = 0; i < n; i++) no visita n. Visita 0, 1, …, n-1. Es el mismo conjunto que para i = 0 hasta n - 1 en este laboratorio, donde el hasta sí se incluye. Al traducir, se traduce la condición, no las palabras sueltas.

Errores que se repiten

Rúbrica de esta lección

CriterioAún noEn procesoConseguidoNotable
ÍndicesDesde 1 o hasta longitudA veces0 … longitud-1Tabla índice-valor
FunciónCopia de la sumaSin devolverParámetro y devolverNo toca el pin
ResultadoCualquier número480 escrito a mano480 por el recorridoSe prueba con otro vector
TiposTexto en una casillaSin mirarTodas las lecturas son númerosLa media se guarda en un número
PlacaNo se mencionaSolo el LEDArray de C y lista de Python, índice 0La longitud se pasa o se pide, no se duplica a ciegas

Mini cierre

El vector se recorre desde 0 hasta longitud-1. La función devuelve la media y no enciende nada. 480 es la prueba del ejemplo, no un número que se escriba a mano.

Comprueba

Abre cada pregunta, responde en el cuaderno y después mira la solución. El párrafo «Por qué» es la parte que se estudia.

1. ¿Por qué el último índice de cuatro casillas es 3 y no 4?

Respuesta. Porque se empieza en 0: 0, 1, 2 y 3 son cuatro posiciones. 4 sería la quinta.

Por qué: La longitud dice cuántas hay, no cuál es la última etiqueta. Confundirlas es el error más caro del tema, porque a veces no salta a la vista: solo desaparece una lectura o se lee memoria que no es tuya.

2. ¿Qué está mal en una función media que además hace digitalWrite?

Respuesta. Mezcla el cálculo con un efecto sobre el pin. Quien pide la media no puede evitar el LED.

Por qué: La descomposición exige que el subproblema no arrastre salidas que no son suyas. Si mañana la media va a un informe del bloque A, el pin no tiene nada que hacer ahí. Se compara fuera, en el si que ya conoces.

3. La suma es 1920 y alguien divide entre 3. ¿Qué síntoma ves, y qué no debes hacer?

Respuesta. La media sale 640 en vez de 480. No debes escribir escribe 480 para taparlo.

Por qué: 640 es el síntoma de un recorrido mal contado, a menudo por saltarse el índice 0 y dividir por la longitud entera, o al revés.
1920 ÷ 4 = 480
1920 ÷ 3 = 640 Tapar la salida no corrige el para. Hay que ver qué i se han visitado.

En la vida real

Castilla y León, sin servidor

  • La lista de notas de una evaluación es un vector: la media del grupo no se calcula dejando fuera al primero porque «el cero del índice da cosa».
  • En el cuaderno de campo de un patio de Soria, cuatro temperaturas son un vector aunque estén escritas en columna.
  • El casillero de secretaría que empieza en el número 1 es una interfaz humana. El programa puede enseñar «lectura 1» sumando uno al índice al escribir, sin guardar los datos desde uno.
  • Cuando el departamento presta una sola Pi, todas las medias se ensayan aquí con el mismo vector y se comparan los 480 antes de discutir el sensor.
Laboratorio · en esta página Abrir en pestaña →

Un vector se escribe [420, 510, 390, 600]. El primer índice es 0. longitud es la propiedad .longitud. Una funcion se declara con funcion nombre(params) y se cierra con fin; devolver sale con un valor.

GPIO 18

Simulación local · sin hardware

Raspberry Pi (BCM) · paralelo didáctico Arduino UNO D13 · pin GPIO 18

Estado del pin: LOW · LED apagado

OFF

Cada pulsación no mete sola un dato en el vector: el programa tiene que guardarlo. El interruptor sigue siendo la salida HIGH/LOW. HIGH enciende el LED (en la Pi, 3,3 V; en Arduino UNO el paralelo didáctico es digitalWrite HIGH en D13). No se envía nada fuera de esta página.

Pulsa Ejecutar. El resultado se queda en esta página.

Escribes y dibujas aquí mismo: no hay salto a otro módulo. La misma herramienta, a pantalla completa, está en l27-vectores-arrays-y-funciones.html y en el marco (útil si el navegador permite file:// en iframes).

Reto Profesor

Media sin tocar el pin

Deja en el editor el vector de cuatro lecturas y una función media que devuelva 480 al ejecutar. En el cuaderno, escribe la tabla índice y valor. Añade, si quieres, una función que devuelva la primera lectura, lecturas[0], y explica por qué no es lecturas[1]. El pin, si lo nombras, se decide fuera de la función. Una buena entrega sigue dando 100 si cambias todas las casillas a 100.

reto_id: bach1-tic-L27