1 Cambios

1.1 De 1.0.0 a 1.0.1

  • El prototipo de mfree es: void mfree(Matrix& m). Fíjate que el parámetro m se pasa por referencia.
  • Descarga los archivos de partida con el nuevo prototipo de la función.

1.2 Versión 1.0.0

  • Enunciado original.

2 Objetivos

  • Adquirir práctica y destreza con las características de C++ que lo hacen un mejor C.
  • Profundizar en los conocimientos aprendidos en Programación I.
  • Hacer uso de las herramientas estudiadas en la práctica 0.

3 Enunciado

Esta práctica consta de 2 ejercicios. En ambos emplearemos los siguientes tipos de datos y constantes que se encuentran en p1.h:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
/// Tipo de cada elemento de la matriz ~> typedef int32_t etype_t;
using etype_t  = int32_t;
/// El tipo de la fila de la matriz de bajo nivel
using row_t    = etype_t*;
//! El tipo matriz de bajo nivel.
using matrix_t = row_t*;

/** Tipo matriz.
 * Cada dato de este tipo conoce sus dimensiones.
 */
struct Matrix {
  matrix_t data;
  uint32_t rows;
  uint32_t cols;
};

/// Tipo puntero a función: etype_t f(etype_t)
using fp_t = etype_t(*)(etype_t);

// Matriz nula o matriz vacia
const Matrix null_matrix = {nullptr, 0, 0};

3.1 Código común a ambos ejercicios.

Para poder realizar la implementación de las funciones pedidas en los dos ejercicios siguientes debemos implementar primero estas funciones que nos permiten trabajar con el tipo Matrix:

1
2
3
4
5
6
/// Muestra la matriz por pantalla
void mshow(const Matrix m);
/// Reserva la memoria para la matriz y la inicializa al valor v
Matrix  mreserve(uint32_t r, uint32_t c, etype_t v = 0);
/// Libera la memoria de la matriz
void mfree(Matrix& m);

Veamos lo que hacen estas funciones:

  1. void mshow(const Matrix m) :
    • Muestra la matriz m por pantalla al estilo de como tienes en los ejemplos.
  2. Matrix mreserve(uint32_t r, uint32_t c, etype_t v = 0) :
    • Crea (y devuelve) en memoria dinámica una matriz de r filas y c columnas, inicializando cada una de sus componentes al valor v (que por defecto vale 0).
    • Si el numero de filas o columnas pedido es 0 entonces devuelve null_matrix.
  3. void mfree(Matrix& m) :
    • Libera la memoria de la matriz m pasando m a ser null_matrix.

3.2 Ejercicio 1. Modificación de los elementos de una matriz.

Se nos pide implementar una función que reciba como argumentos un dato de tipo Matrix y otro de tipo fp_t (puntero a función).

Su prototipo es el siguiente:

void map_elements(Matrix m, fp_t f);

Y su funcionamiento es:

  1. void map_elements(Matrix m, fp_t f); :
    • Recorrer por filas y columnas los elementos de m y aplicarle a cada uno de ellos la función f de manera que el resultado devuelto reemplaza el valor original del elemento de m pasado a f.
    • Veamos un ejemplo (tienes más en mainp1.cc):
//  f = etype_t power2(etype_t e) { return e * e; }
Original m:
[ 5 3 ]
[ 2 1 ]

map_elements(m, power2);

Mapped (power2) m:
[ 25 9 ]
[ 4 1 ]

3.3 Ejercicio 2. Operaciones con matrices.

Se nos pide implementar dos funciones que nos permitan hacer crecer y/o encogerse a una matriz m por una cantidad de unidades u. El prototipo de estas dos funciones es:

1
2
3
4
5
/// Crea una nueva matriz con 'u' unidades mas que la original en la
/// que las nuevas celdas se inicializan al valor 'v'.
Matrix matrix_grow(const Matrix m, uint32_t u, etype_t v = 0);
/// Crea una nueva matriz con 'u' unidades menos que la original.
Matrix matrix_shrink(const Matrix m, uint32_t u)

Veamos lo que deben hacer ambas funciones:

  1. Matrix matrix_grow(const Matrix m, uint32_t u, etype_t v = 0) :
    • Creará y devolverá una nueva matriz que tendrá dos filas y dos columnas más que la matriz original ‘m’ por cada unidad ‘u’ pedida. Si ‘u’ es 0 devolverá una matriz null_matrix.
    • Estas nuevas filas y columnas rodearán a las filas y columnas de la matriz original que mantendrán sus valores originales mientras que los elementos de las nuevas celdas se inicializarán al valor ‘v’.
    • Si la matriz ‘m’ no está creada (null_matrix) devolverá una matriz null_matrix.
    • Veamos un ejemplo:
m:
[ 5 3 ]
[ 2 1 ]

nm = matrix_grow(m, 2, 1);

nm:
[ 1 1 1 1 1 1 ]
[ 1 1 1 1 1 1 ]
[ 1 1 5 3 1 1 ]
[ 1 1 2 1 1 1 ]
[ 1 1 1 1 1 1 ]
[ 1 1 1 1 1 1 ]
  1. Matrix matrix_shrink(const Matrix m, uint32_t u) :
    • Creará y devolverá una nueva matriz que tendrá dos filas y dos columnas menos que la matriz original ‘m’ por cada unidad ‘u’ pedida. Si ‘u’ es 0 devolverá una matriz null_matrix.
    • Estas nuevas filas y columnas se eliminarán por el principio y el final de la matriz.
    • Devolverá una matriz null_matrix en el caso de que no se pueda reducir (la matriz resultado tendría filas o columnas \(<= 0\))
    • Veamos un ejemplo:
m:
[ 1 1 1 1 1 1 ]
[ 1 1 1 1 1 1 ]
[ 1 1 5 3 1 1 ]
[ 1 1 2 1 1 1 ]
[ 1 1 1 1 1 1 ]
[ 1 1 1 1 1 1 ]

nm = matrix_shrink(m, 2);

nm:
[ 5 3 ]
[ 2 1 ]

Tienes un programa de ejemplo en mainp1.cc y su salida es:

Ejercicio 1
===========

Test1
Original m:
[ 5 3 ]
[ 2 1 ]

Mapped (power2) m:
[ 25 9 ]
[ 4 1 ]

--------------------------

Test2
Original m:
[ 1 2 3 ]
[ 4 5 6 ]
[ 7 8 9 ]

Mapped (sum10) m:
[ 11 12 13 ]
[ 14 15 16 ]
[ 17 18 19 ]

--------------------------

Test3
Original m:
[ 1 2 3 8 ]
[ 4 5 6 2 ]
[ 1 7 8 9 ]
[ 3 4 18 29 ]

Mapped (triple) m:
[ 3 6 9 24 ]
[ 12 15 18 6 ]
[ 3 21 24 27 ]
[ 9 12 54 87 ]

--------------------------

Ejercicio 2
===========

Test4
original is r: 2 , c: 2
[ 5 3 ]
[ 2 1 ]

Grow 2u:
new is r: 6 , c: 6
[ 1 1 1 1 1 1 ]
[ 1 1 1 1 1 1 ]
[ 1 1 5 3 1 1 ]
[ 1 1 2 1 1 1 ]
[ 1 1 1 1 1 1 ]
[ 1 1 1 1 1 1 ]

--------------------------

Test5
Original m:
[ 1 2 3 8 ]
[ 4 5 6 2 ]
[ 1 7 8 9 ]
[ 3 4 18 29 ]
Couldn't shrink by 2 units.

--------------------------

Test6
Original m:
[ 1 2 3 8 ]
[ 4 5 6 2 ]
[ 1 7 8 9 ]
[ 3 4 18 29 ]

Shrink 1u:
new is r: 2 , c: 2
[ 5 6 ]
[ 7 8 ]

--------------------------

Test7
Original m:
[ 1 2 3 ]
[ 4 5 6 ]
[ 1 7 8 ]
[ 3 4 18 ]
Couldn't shrink by 2 units.

Shrink 1u:
new is r: 2 , c: 1
[ 5 ]
[ 7 ]

--------------------------

4 División del código fuente en archivos

  • Tendremos un único archivo de cabecera ( p1.h ) con los prototipos de las funciones además de los #include necesarios para que no de errores de compilación.

  • Este archivo hará uso de la guarda para protegerlo de su inclusión más de una vez que hemos visto en el tema-1.

  • Tendremos un único archivo de implementación ( p1.cc, trabajamos en C++) con la implementación de todas las funciones además de los #include necesarios para que no de errores de compilación (también incluirá a p1.h). Este archivo no contendrá ningún programa principal (main) pero sí podrá contener las funciones auxiliares que necesites.

  • Para poder probar tus funciones puedes crearte la función main que quieras en otro archivo, p.e. mainp1.cc (el cual incluirá a p1.h) y compilarlo y enlazarlo con el anterior así: g++ -g -Wall --std=c++17 mainp1.cc p1.cc -o p1. No es necesario entregarlo, si se hace no pasa nada.

  • También puedes emplear el archivo Makefile para compilar y enlazar. Recuerda que lo tienes en la carpeta de la práctica.

  • Todos los archivos `.h' y `.cc' se encontrarán dentro de una carpeta llamada irp2-p1.

5 Entrega. Requisitos técnicos

  • Requisitos que tiene que cumplir este trabajo práctico para considerarse válido y ser evaluado (si no se cumple alguno de los requisitos la calificación será cero):

  • El archivo entregado se llama irp2-p1.tgz (todo en minúsculas), no es necesario entregar ningún programa principal, sólo son necesarios tus archivos `.h' y `.cc' en una carpeta llamada irp2-p1. A su vez, esta carpeta estará comprimida en el fichero llamado irp2-p1.tgz. Este archivo lo puedes crear así en el terminal:

    tar cfz irp2-p1.tgz irp2-p1

  • También puedes emplear el archivo Makefile que tienes en la carpeta de la práctica para generar el fichero de la entrega tal y como hemos visto en clase de prácticas: make tgz.

  • Al descomprimir el archivo irp2-p1.tgz se crea un directorio de nombre irp2-p1 (todo en minúsculas).

  • Dentro del directorio irp2-p1 estará al menos el archivo p1.cc (todo en minúsculas).

    Recuerda que el fichero ‘p1.hno se debe modificar, de lo contrario tus ficheros ‘.cc’ no compilarán con el corrector. No es necesario entregarlo, si se hace no pasa nada.

  • Las clases, métodos y funciones implementados se llaman como se indica en el enunciado (respetando en todo caso el uso de mayúsculas y minúsculas). También es imprescindible respetar estrictamente los textos y los formatos de salida que se indican en este enunciado.

  • Al principio de todos los ficheros fuente (`.h’ y `.cc’) entregados y escritos por ti se debe incluir un comentario con el nombre y el NIF (o equivalente) de la persona que entrega la práctica, como en el siguiente ejemplo:

    // NIF: 12345678-Z
    // NOMBRE: GARCIA PEREZ, LAURA
    
  • Un error de compilación/enlace implicará un cero en esa parte de la práctica.

  • Lugar y fecha de entrega : Recuerda que las entregas se realizan siempre en (y sólo en) https://pracdlsi.dlsi.ua.es en las fechas y condiciones allí publicadas. Puedes entregar la práctica tantas veces como quieras, sólo se corregirá la última entrega (las anteriores no se borran). El usuario y contraseña para entregar prácticas es el mismo que se utiliza en UACloud.

6 Detección de plagios/copias

  • IMPORTANTE:
    • Cada práctica debe ser un trabajo original de la persona que la entrega.

    • En caso de detectarse indicios de copia de una o más prácticas se tomarán las medidas disciplinarias correspondientes, informando a las direcciones de Departamento y de la EPS por si hubiera lugar a otras medidas disciplinarias adicionales.