Final de práctica — Introducción a la Computación

Temas: todo el curso, con énfasis en las semanas 9 a 15 · Duración: 2 horas

Este es un examen de práctica con el formato del final. Sirve para medir cuánto tiempo les toma cada tipo de pregunta: resuélvanlo en papel, con el reloj corriendo y sin computadora, y recién después comprueben sus respuestas en el entorno del curso. El formato general está en exams/README.md. Dos horas no alcanzan para todos los temas: el examen real puede preguntar los que aquí no aparecen, como hardware y sistema operativo, o double.

Indicaciones

  • Los errores menores de sintaxis no importan si la idea es correcta.
  • En las preguntas de “qué escribe”, justifiquen con una tabla de variables o una explicación: la salida sola no basta.
  • Todo el código compila sin advertencias con gcc -Wall -Wextra -std=c17, salvo la línea de la pregunta 5c y el programa de la pregunta 10, que tienen errores a propósito.
  • Supongan el entorno del curso: un int ocupa 4 bytes, un double ocupa 8 bytes, el texto está en UTF-8, y EOF vale -1. Las direcciones de memoria son un ejemplo: en una corrida real cambian.
  • El pseudocódigo va en el formato del curso: ←, mientras, si, div, mod, NULO.
  • Si les piden una función, no hace falta escribir los #include. Pueden usar string.h.
  • Python solo se lee: nadie les va a pedir que escriban un programa en Python.
Parte Preguntas
A. Repaso de las semanas 1 a 7 1–2
B. Seguir programas a mano 3–8
C. Encontrar el bug 9–10
D. Pseudocódigo y C 11–13
E. Eficiencia 14–15
F. Internet, Python e IA 16–18

Parte A — Repaso de las semanas 1 a 7

Pregunta 1 — Representación

a) Escriban el número hexadecimal E7 en binario de 8 bits. ¿Qué número es sin signo? ¿Y en complemento a dos?

b) Sumen 01101100 + 00100101, con 8 bits en complemento a dos. ¿Cuánto da la suma en decimal, y cómo se lee el resultado de 8 bits? ¿Qué nombre tiene lo que pasó? Si eso le pasa a un int en C, ¿qué dice el lenguaje?

Pregunta 2 — Ciclos y funciones

#include <stdio.h>

int collapse(int n) {
    int steps = 0;
    while (n > 9) {
        int sum = 0;
        while (n > 0) {
            sum += n % 10;
            n /= 10;
        }
        n = sum;
        steps++;
    }
    return steps * 100 + n;
}

int main(void) {
    int n = 9875;
    int r = collapse(n);
    printf("%d %d\n", n, r);
    return 0;
}

a) ¿Qué escribe? Hagan una tabla con los valores de n, sum y steps al terminar cada vuelta del ciclo exterior.

b) ¿Por qué el n de main no cambió, aunque collapse lo divide hasta dejarlo en un dígito?

Parte B — Seguir programas a mano

Pregunta 3 — Arreglos

int a[6] = {5, 8, 1, 9, 2, 7};
int i = 0;
int j = 5;
while (i < j) {
    if (a[i] > a[j]) {
        int saved = a[i];
        a[i] = a[j];
        a[j] = saved;
    }
    i++;
    j--;
}
for (int k = 1; k < 6; k++) {
    a[k] = a[k] + a[k - 1];
}

a) ¿Qué tiene a justo antes del último for? ¿Y al final?

b) Si a empieza en la dirección 2000, ¿dónde está a[4]? ¿Qué elemento está en la dirección 2012? ¿Cuánto vale sizeof(a)? Si se escribe a[6] = 0;, ¿qué se puede decir de lo que pasa?

Pregunta 4 — Arreglos y funciones

¿Qué escribe? Expliquen por qué cada variable de main cambia o no cambia.

#include <stdio.h>

int update(int x, int v[], int n) {
    x = x + 1;
    for (int i = 0; i < n; i++) {
        v[i] = v[i] + x;
    }
    n = 0;
    return x * 2 + n;
}

int main(void) {
    int x = 1;
    int v[3] = {10, 20, 30};
    int n = 3;
    int r = update(x, v, n);
    printf("%d %d %d\n", x, r, n);
    printf("%d %d %d\n", v[0], v[1], v[2]);
    return 0;
}

Pregunta 5 — Cadenas

#include <stdio.h>
#include <string.h>

int main(void) {
    char a[8] = "sol";
    char b[8];
    strncpy(b, "solar", 7);
    b[7] = '\0';

    printf("%zu %zu\n", strlen(a), sizeof(a));
    a[1] = '\0';
    printf("%s %zu %zu\n", a, strlen(a), sizeof(a));
    printf("%d %d\n", strcmp(b, "sola") > 0, strcmp("Sol", "sol") < 0);
    printf("%s\n", strstr(b, "la"));
    printf("%d\n", strchr(b, 'z') == NULL);
    return 0;
}

a) ¿Qué escribe? Consideren que 'S' vale 83 y 's' vale 115.

b) Dibujen en memoria char t[6] = "uña";, con el índice y el byte en hexadecimal de cada casilla (u es 75, a es 61, y la ñ es c3 b1). ¿Cuánto valen strlen(t) y sizeof(t)?

c) Con char d[5];, se hace strncpy(d, "cielo", 5);. ¿d es una cadena? ¿Qué pasa si después se escribe con %s? ¿Cómo se copia bien?

Pregunta 6 — Matrices

#include <stdio.h>

#define ROWS 3
#define COLS 4

int mystery(int m[][COLS], int rows, int col) {
    int best = 0;
    for (int i = 1; i < rows; i++) {
        if (m[i][col] > m[best][col]) {
            best = i;
        }
    }
    return best;
}

int main(void) {
    int m[ROWS][COLS] = {
        {14, 9, 17, 11},
        {8, 20, 13, 5},
        {12, 6, 16, 19},
    };
    for (int j = 0; j < COLS; j++) {
        printf("%d ", mystery(m, ROWS, j));
    }
    printf("\n");
    return 0;
}

a) ¿Qué escribe?

b) Una matriz double t[4][5] empieza en la dirección 5000. ¿Cuántos bytes ocupa? ¿Dónde está t[2][3]? ¿Por qué, al pasar una matriz a una función, hay que indicar las columnas y no las filas?

Pregunta 7 — struct

#include <stdio.h>

struct item {
    char name[12];
    int stock[2];
};

struct item restock(struct item it, int amount) {
    it.stock[0] = it.stock[0] + amount;
    return it;
}

void clear_copy(struct item it) {
    it.stock[1] = 0;
    printf("%d\n", it.stock[1]);
}

void clear_array(int stock[]) {
    stock[1] = 0;
}

int main(void) {
    struct item a = {"arroz", {5, 7}};
    struct item b = a;

    b.name[0] = 'A';
    restock(a, 10);
    printf("%s %d %d\n", a.name, a.stock[0], a.stock[1]);

    b = restock(b, 10);
    clear_copy(a);
    printf("%s %d %d\n", a.name, a.stock[0], a.stock[1]);
    printf("%s %d %d\n", b.name, b.stock[0], b.stock[1]);

    clear_array(b.stock);
    printf("%d\n", b.stock[1]);
    return 0;
}

a) ¿Qué escribe?

b) clear_copy y clear_array hacen lo mismo con stock[1], pero solo una cambia el original. ¿Por qué?

Pregunta 8 — Archivos

El archivo notas.txt tiene estas 6 líneas, y la quinta está vacía:

Ana 14 16
Luis 9
Rosa 12 x
Eva 20 11 3

Juan 11 12
#include <stdio.h>

#define LINE_SIZE 64

int main(void) {
    FILE *file = fopen("notas.txt", "r");
    if (file == NULL) {
        perror("notas.txt");
        return 1;
    }

    char line[LINE_SIZE];
    int number = 0;
    int good = 0;
    while (fgets(line, LINE_SIZE, file) != NULL) {
        char name[20];
        char extra[2];
        int a = 0;
        int b = 0;
        number++;
        int fields = sscanf(line, "%19s %d %d %1s", name, &a, &b, extra);
        if (fields == 3) {
            printf("%s %.1f\n", name, (a + b) / 2.0);
            good++;
        } else {
            printf("Línea %d: %d campos\n", number, fields);
        }
    }
    fclose(file);
    printf("Buenas: %d de %d\n", good, number);
    return 0;
}

¿Qué escribe?

Parte C — Encontrar el bug

Pregunta 9 — Una búsqueda que casi funciona

Esta función debe devolver el índice de value en el arreglo ordenado a, o -1.

int find(const int a[], int n, int value) {
    int low = 0;
    int high = n - 1;
    while (low < high) {
        int mid = low + (high - low) / 2;
        if (a[mid] == value) {
            return mid;
        } else if (a[mid] < value) {
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }
    return -1;
}

Se usa con int codes[8] = {3, 7, 11, 19, 24, 31, 40, 52};.

a) Sigan find(codes, 8, 52) en una tabla con low, high y mid. ¿Qué devuelve? ¿Qué debería devolver?

b) Corrijan la función, y expliquen qué caso se estaba perdiendo.

c) Un compañero la probó solo con el 19 y con el 31, y las dos pruebas pasaron. ¿Qué le dirían? ¿Qué casos debió probar?

Pregunta 10 — Un programa con cuatro errores

Este programa debe escribir Encontrado si el archivo codigos.txt, con un código por línea, tiene una línea igual a A-001.

#include <stdio.h>
#include <string.h>

#define CODE_SIZE 6
#define LINE_SIZE 40

int main(void) {
    char code[CODE_SIZE];
    char line[LINE_SIZE];
    FILE *file = fopen("codigos.txt", "r");

    while (!feof(file)) {
        fgets(line, LINE_SIZE, file);
        strcpy(code, line);
        if (code == "A-001") {
            printf("Encontrado\n");
        }
    }
    fclose(file);
    return 0;
}

a) Encuentren cuatro errores. Para cada uno, expliquen qué puede pasar. Una pista: piensen también en una línea correcta, A-001, con su salto de línea.

b) Escriban solo las líneas que cambian.

Parte D — Pseudocódigo y C

Pregunta 11 — Eliminar de un vector

Un vector tiene n elementos en uso. Queremos eliminar todas las apariciones de un valor, sin cambiar el orden de los demás y sin usar otro arreglo. Por ejemplo, si v tiene 3, 7, 3, 3 y 9, al eliminar el 3 queda con 7 y 9.

a) Escriban el algoritmo eliminar_valor(v, n, valor) en pseudocódigo.

b) Tradúzcanlo a la función int remove_value(int v[], int n, int value).

c) ¿Qué devuelve la función? ¿Por qué tiene que devolverlo, si el arreglo ya se cambió?

Pregunta 12 — struct y cadenas

Una bodega guarda de cada producto su nombre, de hasta 19 bytes, su precio en céntimos y cuántas unidades tiene.

a) Definan struct product.

b) Escriban int find_product(const struct product list[], int n, const char name[]), que devuelve el índice del producto con ese nombre, o -1 si no está.

Pregunta 13 — Validar un código

Un código es válido si tiene exactamente esta forma: una letra mayúscula de A a Z, un guion, y tres dígitos. Por ejemplo, A-123.

Escriban int is_valid_code(const char s[]), que devuelve 1 si es válido y 0 si no. Debe funcionar también con cadenas cortas, como "" o "A-", sin leer fuera de la cadena.

Parte E — Eficiencia

Pregunta 14 — Búsqueda binaria

Índice 0 1 2 3 4 5 6 7 8 9 10 11
Valor 4 9 13 18 22 27 31 36 42 50 63 77

a) Sigan la búsqueda binaria del 47, en una tabla con low, high, mid y a[mid]. ¿Qué devuelve? ¿A cuántos elementos miró? ¿A cuántos miraría la búsqueda lineal?

b) Partiendo a la mitad, sin decimales, hasta llegar a 0, ¿a cuántos elementos mira como máximo la búsqueda binaria en un arreglo de 5000? ¿Y la lineal?

Pregunta 15 — Ordenar y comparar

a) Sigan el ordenamiento por selección de 6, 4, 9, 1, 7 y 3, con una fila por pasada: i, dónde estaba el menor, y cómo queda el arreglo. ¿Cuántas comparaciones hizo? ¿Cuántas haría si el arreglo ya estuviera ordenado? ¿Por qué?

b) Un programa tarda 4 segundos con N = 10 000. ¿Cuánto esperan con N = 30 000, si su trabajo crece como N? ¿Y si crece como N²?

c) En una lista desordenada de 1000 elementos, un equipo hará 400 búsquedas de valores que no están, y otro hará 600. Pueden buscar con la búsqueda lineal sin preparar nada, u ordenar una vez por selección y usar la binaria. Contando solo comparaciones, ¿qué le conviene a cada equipo?

Parte F — Internet, Python e IA

Respondan en dos o tres líneas por ítem.

Pregunta 16 — Internet

a) Al abrir una página con HTTPS ocurren estas cuatro cosas, aquí desordenadas: (i) se revisa el certificado y se acuerda una clave; (ii) se pide la ruta y llega un código de estado; (iii) un nombre se traduce a un número; (iv) se abre una conexión al puerto 443. Ordénenlas, digan qué protocolo hace cada una, y expliquen por qué (i) no puede ir antes de (iv).

b) Un compañero dice: “Como la página usa HTTPS, nadie en este wifi público puede saber qué hago”. ¿Tiene razón? Den dos cosas que quien administra la red sí puede ver, y dos que no.

Pregunta 17 — Leer Python

values = [3, 8, 5, 10]
total = 0
for v in values:
    if v % 2 == 0:
        total = total + v // 2
print(total)
print(values[-1])
print(values[2] / 2)
for i in range(1, 3):
    print(values[i])

a) ¿Qué escribe?

b) ¿Qué pasa en Python con print(values[7])? ¿Y en C, con un arreglo de 4 elementos y printf("%d", a[7])? ¿Qué implica esa diferencia para quien programa?

Pregunta 18 — Inteligencia artificial y ética

a) Para cada problema, ¿escribirían reglas o entrenarían un modelo? ¿Por qué? (i) Saber si un DNI tiene exactamente 8 dígitos. (ii) Reconocer si una foto muestra un perro.

b) Dos modelos se entrenan con 100 ejemplos y se evalúan con otros 40.

Modelo Errores en entrenamiento Errores en prueba
A 0 de 100 14 de 40
B 9 de 100 5 de 40

¿Cuál usarían? ¿Cómo se llama lo que le pasa al otro? ¿Por qué los datos de prueba se separan antes de entrenar?

c) Un LLM responde con una cita completa, con autor, tema y año, de un artículo que no existe. ¿Cómo puede pasar, si lo que hace es predecir el siguiente token? ¿Por qué el tono seguro de la respuesta no ayuda a decidir? ¿Cómo la comprobarían?

d) Una financiera entrena un modelo con sus decisiones pasadas de crédito. Le quita la columna “sexo”, y deja el distrito y el trabajo. ¿Con eso ya no hay sesgo? ¿Por qué?

Lista para repasar: resultados de aprendizaje

Después de corregir el examen, marquen cada fila que ya pueden hacer sin mirar los apuntes. Cada una es un resultado de aprendizaje del programa del curso, con las semanas donde se ve y las preguntas de este examen que lo practican. Si una fila les costó, vuelvan a esas semanas.

Puedo… Semanas Preguntas
Describir un problema como un algoritmo, en pseudocódigo, y seguirlo a mano 1, 4, 5 y 13 3 a 8 (seguir programas), 11a, 14a y 15a
Explicar cómo se guardan números y texto en bits, y prever el overflow y la imprecisión de los decimales 3 y 10 1, 5b y 6b
Escribir en C programas con decisiones, ciclos, funciones, arreglos, cadenas, matrices, struct y archivos 2, 4 a 7 y 9 a 12 2 a 8, 11b, 12 y 13
Probar y depurar mis programas, leyendo los mensajes del compilador y de los sanitizers 1, 7 y 10 9 y 10
Usar la terminal y lo básico de Git 1 y 3 Ninguna: practíquenlo en los laboratorios de esas semanas
Explicar a grandes rasgos cómo funcionan el hardware, el sistema operativo e internet 9 y 14 3b y 6b (direcciones de memoria) y 16
Comparar algoritmos de búsqueda y ordenamiento según su eficiencia, con mediciones reales 13 9, 14 y 15
Explicar qué hace un modelo de machine learning, y reconocer los límites y efectos éticos de la IA 15 18

La pregunta 17 (leer Python) es de la semana 14. No corresponde a un resultado propio del programa, pero ayuda a comparar C con otro lenguaje.