Saltar al contenido
ES EN
Tema: automático

Ejercicio resuelto: matriz con órdenes de giro y desplazamiento en C

Ejercicio de examen en C: leer una matriz, aplicar desplazamientos circulares y giros de 90º, y mostrarla alineada con productos por fila y columna.

Actualizado el

Código de Examen C Fundamentos de programación Nivel examen Código probado

Código de Examen: Ejercicio resuelto: matriz con órdenes de giro y desplazamiento en C
Fundamentos de Programación · Examen finalEjercicio 3 · 2,5 puntos · 35 min

Un panel de luces se modela como una matriz de enteros de F filas y C columnas, con 1 ≤ F, C ≤ 10 y cada valor en el intervalo [-50, 50]. Escribe un programa en C que lea la matriz, le aplique una secuencia de órdenes y muestre el resultado final con formato tabular.

Entrada (por la entrada estándar). La primera línea contiene F y C. Le siguen F líneas con C enteros cada una. Después aparece un entero Q (0 ≤ Q ≤ 20) seguido de Q órdenes, una por línea, de dos tipos posibles.

D k: desplaza circularmente las columnas k posiciones a la derecha, con -1000 ≤ k ≤ 1000. Un valor negativo desplaza a la izquierda. El elemento que sale por un extremo de la fila entra por el otro.

G: gira la matriz 90 grados en sentido horario. Si la matriz era de F×C, pasa a ser de C×F.

Salida. Una primera línea Matriz FxC: con las dimensiones finales. Después, una línea por fila. Cada elemento se imprime alineado a la derecha con un ancho igual al número de caracteres del elemento más largo de toda la matriz, contando el signo menos. Los elementos se separan con un único espacio y no hay espacios al final de la línea.

A continuación, la línea Filas: seguida, para cada fila y en orden, de un espacio y el producto de sus elementos. Por último, la línea Columnas: con los productos de cada columna en el mismo formato.

Puedes suponer que la entrada respeta el formato. Si las dimensiones no están en el rango permitido o falta algún dato inicial, el programa imprimirá Entrada no valida. Organiza el código en funciones: una para leer, una por cada orden y una para imprimir.

Entrada de ejemplo

3 4
2 -1 3 4
5 0 -6 1
-3 7 2 10
3
D 1
G
D -1

Salida esperada

Matriz 4x3:
 1  4 10
 5  2 -3
 0 -1  7
-6  3  2
Filas: 40 -30 0 -36
Columnas: 0 -24 -420
Lectura de dimensiones, elementos y órdenes con comprobación del valor devuelto por scanf
0,5
Desplazamiento circular de columnas correcto para k negativo, nulo y mayor que el número de columnas
0,75
Giro horario de 90º con intercambio de dimensiones en matrices no cuadradas
0,5
Salida con ancho de columna calculado y productos por fila y columna sin desbordamiento
0,75

Pistas

Pista 1 · ¿Cómo guardo una matriz cuyas dimensiones cambian?

Reserva siempre un array de 10×10 y guarda aparte cuántas filas y columnas están en uso. Agrupar las tres cosas en un struct te permite pasar la matriz completa a cada función con un solo puntero, y tras un giro basta con intercambiar las dimensiones.

Pista 2 · ¿Qué hago con k = -998 o con k = 1000?

Desplazar C posiciones deja la fila igual, así que solo importa el resto de k entre C. En C, el operador % con un dividendo negativo devuelve un resto negativo. Busca una expresión que lleve cualquier k al rango [0, C-1] y escribe la fila desplazada en un vector auxiliar antes de copiarla de vuelta.

Pista 3 · ¿Adónde va el elemento (i, j) al girar?

En un giro horario, la columna j original se convierte en la fila j nueva, leída de abajo arriba. Deduce la fórmula del destino a partir de una matriz de 2×3 dibujada en papel y escribe el resultado en una matriz distinta de la original.

Solución

Solución explicada

La solución usa un tipo Matriz que agrupa las dimensiones en uso (f, c) y un array fijo v[10][10]. Todas las funciones reciben un puntero a ese struct. Así, las que modifican la matriz lo hacen sobre el original y no sobre una copia, como se explica en paso por valor y por referencia en C.

El programa tiene cuatro fases: leer, ejecutar órdenes, calcular el ancho de columna e imprimir con productos. Cada fase está en su propia función.

#include <stdio.h>

#define MAXD 10

typedef struct {
    int f;
    int c;
    int v[MAXD][MAXD];
} Matriz;

static int leer_matriz(Matriz *m)
{
    if (scanf("%d %d", &m->f, &m->c) != 2) return 0;
    if (m->f < 1 || m->f > MAXD || m->c < 1 || m->c > MAXD) return 0;
    for (int i = 0; i < m->f; i++)
        for (int j = 0; j < m->c; j++)
            if (scanf("%d", &m->v[i][j]) != 1) return 0;
    return 1;
}

/* Desplazamiento circular de columnas k posiciones a la derecha (k < 0: izquierda). */
static void desplazar(Matriz *m, int k)
{
    int d = ((k % m->c) + m->c) % m->c;
    if (d == 0) return;
    int fila[MAXD];
    for (int i = 0; i < m->f; i++) {
        for (int j = 0; j < m->c; j++)
            fila[(j + d) % m->c] = m->v[i][j];
        for (int j = 0; j < m->c; j++)
            m->v[i][j] = fila[j];
    }
}

/* Giro de 90 grados en sentido horario: (i, j) pasa a (j, f-1-i). */
static void girar(Matriz *m)
{
    Matriz r = {0};
    r.f = m->c;
    r.c = m->f;
    for (int i = 0; i < m->f; i++)
        for (int j = 0; j < m->c; j++)
            r.v[j][m->f - 1 - i] = m->v[i][j];
    *m = r;
}

static int ancho(int x)
{
    int n = (x <= 0) ? 1 : 0;
    while (x != 0) {
        n++;
        x /= 10;
    }
    return n;
}

static void imprimir(const Matriz *m)
{
    int w = 1;
    for (int i = 0; i < m->f; i++)
        for (int j = 0; j < m->c; j++) {
            int a = ancho(m->v[i][j]);
            if (a > w) w = a;
        }

    printf("Matriz %dx%d:\n", m->f, m->c);
    for (int i = 0; i < m->f; i++) {
        for (int j = 0; j < m->c; j++) {
            if (j > 0) putchar(' ');
            printf("%*d", w, m->v[i][j]);
        }
        putchar('\n');
    }

    printf("Filas:");
    for (int i = 0; i < m->f; i++) {
        long long p = 1;
        for (int j = 0; j < m->c; j++)
            p *= m->v[i][j];
        printf(" %lld", p);
    }
    putchar('\n');

    printf("Columnas:");
    for (int j = 0; j < m->c; j++) {
        long long p = 1;
        for (int i = 0; i < m->f; i++)
            p *= m->v[i][j];
        printf(" %lld", p);
    }
    putchar('\n');
}

int main(void)
{
    Matriz m = {0};
    int q;

    if (!leer_matriz(&m) || scanf("%d", &q) != 1 || q < 0) {
        printf("Entrada no valida\n");
        return 0;
    }

    for (int t = 0; t < q; t++) {
        char op;
        if (scanf(" %c", &op) != 1) break;
        if (op == 'D') {
            int k;
            if (scanf("%d", &k) != 1) break;
            desplazar(&m, k);
        } else if (op == 'G') {
            girar(&m);
        }
    }

    imprimir(&m);
    return 0;
}

Lectura. leer_matriz comprueba que scanf devuelve el número de datos esperado y que las dimensiones están en [1, 10]. Si algo falla devuelve 0, y main imprime el mensaje de error. Comprobar el valor de retorno de scanf no es un adorno: con las opciones de compilación habituales, ignorarlo puede producir avisos, y sin esa comprobación una entrada truncada dejaría casillas con basura.

Lectura de órdenes. En main, el formato " %c" lleva un espacio delante. Ese espacio consume el salto de línea anterior. Sin él, op recibiría '\n' y la orden se perdería, uno de los fallos más frecuentes en examen.

Desplazamiento. En desplazar, la expresión ((k % m->c) + m->c) % m->c normaliza cualquier k al rango [0, c-1]. Por ejemplo, con 3 columnas, -998 % 3 vale -2 en C, al sumar 3 queda 1 y el último módulo lo mantiene en 1. El elemento de la columna j va a la columna (j + d) % c de un vector auxiliar fila, que después se copia sobre la fila original. El auxiliar es necesario porque, al escribir directamente en la matriz, se pisarían valores que aún no se han movido.

El test desplazamientos grandes comprueba la normalización. D 1000 y D -998 equivalen cada uno a un desplazamiento de una posición a la derecha, así que la fila 1 2 3 termina como 2 3 1. El test tres por dos girada incluye D 3 sobre tres columnas: d vale 0 y la función sale sin hacer nada.

Giro. girar construye una matriz nueva r con las dimensiones intercambiadas y coloca cada v[i][j] en r.v[j][f-1-i]. La fórmula se comprueba con una matriz de 2×3 cuyas filas son 1 2 3 y 4 5 6: el 1, en (0,0), pasa a (0,1), y la nueva primera fila es 4 1. Al final, *m = r copia el struct completo, con array incluido, porque C sí permite asignar estructuras. El test cuatro giros verifica que cuatro giros devuelven la matriz original.

Salida formateada. ancho cuenta los caracteres de un entero: arranca en 1 si el valor es negativo (por el signo) o cero (por el dígito 0), y suma uno por cada división entre 10. imprimir obtiene el máximo w y usa %*d, que toma el ancho de un argumento. En el ejemplo, el elemento más largo ocupa dos caracteres (10, -3, -6), y por eso el 1 aparece precedido de un espacio. En el test cuatro giros el ancho es 3, por el -10.

Productos. Se acumulan en long long. Una fila de diez valores de módulo 50 da 5010, casi 1017, muy por encima de INT_MAX. El test límite de diez columnas produce exactamente 97656250000000000, y un int habría desbordado, lo que en C es comportamiento indefinido.

Casos de prueba

CasoEntradaSalida esperadaSalida realResultado
ejemplo del enunciado3 4 2 -1 3 4 5 0 -6 1 -3 7 2 10 3 D 1 G D -1Matriz 4x3: 1 4 10 5 2 -3 0 -1 7 -6 3 2 Filas: 40 -30 0 -36 Columnas: 0 -24 -420Matriz 4x3: 1 4 10 5 2 -3 0 -1 7 -6 3 2 Filas: 40 -30 0 -36 Columnas: 0 -24 -420OK
un solo elemento sin órdenes1 1 -7 0Matriz 1x1: -7 Filas: -7 Columnas: -7Matriz 1x1: -7 Filas: -7 Columnas: -7OK
desplazamientos grandes2 3 1 2 3 4 5 6 2 D 1000 D -998Matriz 2x3: 2 3 1 5 6 4 Filas: 6 120 Columnas: 10 18 4Matriz 2x3: 2 3 1 5 6 4 Filas: 6 120 Columnas: 10 18 4OK
cuatro giros2 3 -10 20 0 3 -4 5 4 G G G GMatriz 2x3: -10 20 0 3 -4 5 Filas: 0 -60 Columnas: -30 -80 0Matriz 2x3: -10 20 0 3 -4 5 Filas: 0 -60 Columnas: -30 -80 0OK
límite de diez columnas1 10 50 -50 50 50 -50 50 50 50 50 50 1 GMatriz 10x1: 50 -50 50 50 -50 50 50 50 50 50 Filas: 50 -50 50 50 -50 50 50 50 50 50 Columnas: 97656250000000000Matriz 10x1: 50 -50 50 50 -50 50 50 50 50 50 Filas: 50 -50 50 50 -50 50 50 50 50 50 Columnas: 97656250000000000OK
tres por dos girada3 2 1 2 3 4 5 6 2 G D 3Matriz 2x3: 5 3 1 6 4 2 Filas: 15 48 Columnas: 30 12 2Matriz 2x3: 5 3 1 6 4 2 Filas: 15 48 Columnas: 30 12 2OK

Salidas reales: código compilado con gcc 14.4.0 (C17) y ejecutado en un contenedor aislado el 26 de octubre de 2026.

Complejidad

Cada orden D recorre la matriz dos veces (escribir en el auxiliar y copiar de vuelta), y cada orden G la recorre una vez más la copia del struct. Ambas cuestan O(F·C). Con Q órdenes, el total es O(Q·F·C), al que se suma O(F·C) de la lectura, del cálculo del ancho y de los productos. Con los límites del enunciado son, como mucho, unas pocas miles de operaciones.

En memoria, el programa usa un array fijo de 100 enteros, una copia temporal del mismo tamaño en girar y un vector de 10 enteros en desplazar: espacio O(MAXD²), constante respecto a la entrada. No hace falta memoria dinámica, porque el tamaño máximo está acotado en el enunciado.

Errores típicos

  • Normalizar el desplazamiento con k % c sin más: para k negativo el resto es negativo y el índice (j + d) % c se sale del array.
  • Desplazar sobre la propia fila sin vector auxiliar. El primer valor escrito sobrescribe otro que todavía no se ha movido y la fila queda con elementos repetidos.
  • Girar en el mismo array o con un doble bucle de intercambios pensado para matrices cuadradas. Con F distinto de C, el destino (j, f-1-i) cae fuera de las dimensiones originales y se mezclan datos.
  • Olvidar intercambiar f y c tras el giro, de modo que los bucles posteriores recorren una forma equivocada.
  • Leer la orden con "%c" sin espacio previo, con lo que se lee el salto de línea en lugar de la letra.
  • Calcular los productos en int, o fijar el ancho con un número mágico como %4d en lugar de calcularlo a partir de los datos.

Variantes

Añadir la orden A: giro antihorario

Basta con otra función de la misma forma que girar, cambiando el destino a r.v[c-1-j][i] = v[i][j]. También vale llamar tres veces a girar. Es correcto pero triplica el coste, y conviene decirlo si el profesor pregunta por la eficiencia.

Desplazamiento vertical de filas

Una orden V k que mueve las filas hacia abajo se resuelve con la misma normalización, ahora módulo f. Como lo que se mueve son filas enteras, el auxiliar puede ser una matriz completa, o se puede copiar fila a fila con un bucle. Otra opción es girar, desplazar columnas y deshacer el giro, aunque eso exige pensar bien el sentido del desplazamiento.

Sin límite de tamaño

Si el enunciado no acotara F y C, el struct guardaría un puntero y la memoria se reservaría con malloc. El giro reservaría una matriz nueva y liberaría la antigua. Las operaciones básicas de recorrido están en matrices en C con sumas, traspuesta y traza.

En los temarios

Los arrays multidimensionales y su relación con los punteros forman parte de la Unidad III del programa de Algoritmos y Programación I (95.11) de la Universidad de Buenos Aires. Este ejercicio trabaja ese contenido: matrices de tamaño fijo con dimensiones lógicas variables, recorridos por índices y paso de estructuras mediante punteros.

En un nivel posterior, el programa de CC3301 Programación de Software de Sistemas de la Universidad de Chile se centra en la programación en C sobre la API de Linux. Para ese tipo de curso, dominar la lectura robusta con scanf y el manejo de arrays como el de este ejercicio es una base previa.

Historial de cambios

  1. Reescrito con la plantilla de Código de Examen: enunciado de examen, pistas, solución explicada, casos de prueba y código compilado y ejecutado; versión en inglés enlazada.
  2. Publicación original.

Artículo generado mediante AI.larebelion · Revisado por Kernel

Kernel

· Dirección de tecnología · España

«En este ejercicio el fallo caro no está en el bucle, sino en un módulo negativo o en un int que desborda sin avisar.»