Ejercicio obligatorio 3
Fecha de entrega: Domingo 7 de mayo
Nota
Nunca es buena idea empezar por un ejercicio integrador antes de tener practicados los temas que el trabajo integra.
Se sugiere antes de desarrollar este trabajo resolver, al menos, los siguientes ejercicios de la guía de Memoria dinámica:
Ejercicio 12 (combinar vectores).
Ejercicio 14.a (matriz identidad).
Ejercicio 16 con el 1.b y 1.c de la guía de estructuras (dirección y persona).
Introducción
Queremos modelar una matriz, para ello definimos la estructura:
typedef struct {
double **m;
size_t filas, columnas;
} matriz_t;
que permite almacenar en memoria una matriz según el siguiente esquema:
Trabajo
Creación y destrucción
Se pide implementar la función auxiliar
matriz_t *_matriz_crear(size_t n, size_t m);
que genere la memoria necesaria para almacenar una matriz de n
x m
valores.
Los valores no deben ser inicializados. La función debe devolver la matriz
creada o NULL
en caso de falla.
Se pide implementar la función void matriz_destruir(matriz_t *matriz);
que libere la memoria asociada a la matriz
previamente creada.
Acceso a los datos
Se pide implementar una función
size_t matriz_filas(const matriz_t *matriz);
que devuelve el número de
filas de la matriz
.
Se pide implementar una función
size_t matriz_columnas(const matriz_t *matriz);
que devuelve el número
de columnas de la matriz
.
Se pide implementar una función
void matriz_dimensiones(const matriz_t *matriz, size_t *filas, size_t *columnas);
que devuelva la cantidad de filas
y columnas
de la matriz
.
Se pide implementar una función
double matriz_obtener(const matriz_t *matriz, size_t fila, size_t columna);
que devuelva el valor almacenado en la posición fila
, columna
de la
matriz
.
Generación de matrices
Implementar una función
matriz_t *matriz_crear(size_t n, size_t m, double a[n][m]);
que cree
una matriz a partir del arreglo bidimensional a
. La función debe retornar la
matriz creada o NULL
en caso de falla.
Implementar una función
matriz_t *matriz_clonar(const matriz_t *matriz);
que devuelva una copia
de matriz
en memoria nueva o NULL
en caso de falla.
Implementar una función
matriz_t *matriz_identidad(size_t n);
que devuelva la matriz identidad
de \(\mathbb R^{n\times n}\) o NULL
en caso de falla.
Alguna operación suelta del EJ2
Implementar una función
matriz_t *matriz_multiplicar(const matriz_t *a, const matriz_t *b);
que
devuelva \(A \times B\). En caso de falla o de no ser compatibles las
matrices recibidas debe devolver NULL
.
Aplicación y validación
Se provee el código fuente de la función main()
que realiza llamadas a cada
una de estas funciones. Dicha función debe ser la que se entregue como parte
del trabajo sin efectuarle modificaciones de ningún tipo
#include <stddef.h>
#include <assert.h>
typedef struct {
double **m;
size_t filas, columnas;
} matriz_t;
int main(void) {
double k[3][2] = {{21, -11},
{-11, 23},
{0, -12}};
matriz_t *m1 = matriz_identidad(3);
assert(m1 != NULL);
assert(matriz_filas(m1) == 3 && matriz_columnas(m1) == 3);
assert(matriz_obtener(m1, 0, 0) == 1);
assert(matriz_obtener(m1, 1, 0) == 0);
assert(matriz_obtener(m1, 2, 2) == 1);
assert(matriz_obtener(m1, 2, 0) == 0);
matriz_t *m2 = matriz_crear(3, 2, k);
assert(m2 != NULL);
assert(matriz_filas(m2) == 3 && matriz_columnas(m2) == 2);
size_t f, c;
matriz_dimensiones(m2, &f, &c);
assert(f == 3 && c == 2);
assert(matriz_obtener(m2, 0, 0) == 21);
assert(matriz_obtener(m2, 1, 0) == -11);
assert(matriz_obtener(m2, 2, 1) == -12);
assert(matriz_multiplicar(m2, m1) == NULL);
matriz_t *m3 = matriz_multiplicar(m1, m2);
assert(m3 != NULL);
matriz_destruir(m1);
assert(matriz_filas(m3) == 3 && matriz_columnas(m3) == 2);
matriz_t *m4 = matriz_clonar(m3);
assert(m4 != NULL);
matriz_destruir(m3);
assert(matriz_filas(m4) == 3 && matriz_columnas(m4) == 2);
assert(matriz_obtener(m2, 0, 0) == matriz_obtener(m4, 0, 0));
assert(matriz_obtener(m2, 1, 0) == matriz_obtener(m4, 1, 0));
assert(matriz_obtener(m2, 0, 1) == matriz_obtener(m4, 0, 1));
assert(matriz_obtener(m2, 2, 1) == matriz_obtener(m4, 2, 1));
matriz_destruir(m2);
matriz_destruir(m4);
assert(_matriz_crear(1000, 1UL << 59) == NULL);
assert(_matriz_crear(1UL << 59, 1000) == NULL);
return 0;
}
El programa al ser invocado deberá pasar los asserts dados.
Entrega
Deberá entregarse el código fuente del programa desarrollado.
El programa debe:
Compilar correctamente con los flags:
-Wall -Werror -std=c99 -pedantic
pasar Valgrind correctamente,
validar los asserts.
La entrega se realiza a través del sistema de entregas.
El ejercicio es de entrega individual.