6. a – Matrices Genéricas
Una matriz genérica en el contexto de programación en C se refiere a una estructura de datos bidimensional que puede contener elementos de cualquier tipo, en contraste con una matriz específica que está limitada a un tipo de datos particular. En C, no existe un tipo de datos nativo que permita crear matrices completamente genéricas, pero se pueden simular utilizando punteros y asignación dinámica de memoria.
Para llegar a cabo esto, debemos entender que vamos a tener que asignar memoria dinámicamente para la matriz y todos sus elementos. Esto se hace mediante el uso de funciones como malloc()
.
Además, debemos entender que al ser una matriz genérica el acceso a los elementos de la misma se va a realizar a través de punteros a void
. Estos punteros deben ser convertidos al tipo de dato deseado antes de poder operar con ellos.
Finalmente, después de haber terminado de usar la matriz genérica, es importante liberar la memoria asignada utilizando funciones como free()
.
En resumen, una matriz genérica en C es una estructura de datos flexible que permite almacenar elementos de diferentes tipos en una matriz bidimensional, utilizando punteros a void
y asignación dinámica de memoria. Esto puede ser útil en situaciones donde se necesita trabajar con datos heterogéneos o cuando el tipo de datos no está determinado de antemano.
- Cuando se tiene doble asterisco es la cantidad de des-referencias que tengo que hacer para llegar a la variable del elemento.
- Los punteros a void no se pueden desreferenciar.
- Desde void ** no puedo acceder pero si puedo acceder desde int **.
- Cuando creo tipo de dato void, en realidad estoy reservando memoria en bytes y luego puedo guardar lo que yo quiera. Puede ser una estructura, un entero, un flotante, etc.
- Desde un doble puntero a void puedo hacer aritmética de puntero porque apunta a un puntero a void. Pero desde un puntero a void no puedo hacer aritmética de puntero porque no se a que tipo de dato apunta.
Lo primero que hago es crear la matriz con malloc y hago la cantidad de filas por el sizeof del tipo de dato.
![](http://programacionunlam.com.ar/wp-content/uploads/2023/09/image-6.png)
Esto lo hago:
void ** mat = malloc ( cantFilas * sizeof(void*)); // reservo memoria para todas los punteros a void de filas. if(!mat) { return NULL; }
Y luego hago para cada vector en un ciclo for. Este ciclo for lo tengo que recorrer desde i hasta ult. Estos los debo calcular. i va a ser el inicio ( mat ) y ult va a ser desde mat+cantFilas -1.
![](http://programacionunlam.com.ar/wp-content/uploads/2023/09/image-7.png)
#include <stdio.h> #include <stdlib.h> void ** crearMatriz ( size_t cantFilas, size_t cantColumnas, size_t tamElem); void destruirMatriz ( void** mat, size_t filas); int sumarDiagPrincipal ( int ** mat, size_t cols); void cargarMatriz (int ** mat, size_t filas, size_t columnas); void mostrarMatriz (int ** mat, size_t filas, size_t columnas); int main() { int filas = 4; int columnas =4; int ** matriz = (int**)crearMatriz(filas, columnas, sizeof(int)); if(!matriz) { puts("Sin Memoria"); return 0; } cargarMatriz(matriz,filas,columnas); mostrarMatriz(matriz,filas,columnas); int acum = sumarDiagPrincipal(matriz,columnas); printf("Suma diagonal: %d \n", acum); destruirMatriz((void**)matriz, filas); return 0; } void ** crearMatriz ( size_t cantFilas, size_t cantColumnas, size_t tamElem) { //tamElem esta en bytes void ** mat = malloc ( cantFilas * sizeof(void*)); // reservo memoria para todas los punteros a void de filas. if(!mat) { return NULL; } void **ult = mat + cantFilas -1; for (void ** i = mat; i<=ult; i++) { *i = malloc(cantColumnas * tamElem); if(!*i) { for(void** j=mat; j<i; j++) { free(*j); } free(mat); // si hago solo free de mat libera la primer columna y el resto no. return NULL; } } return mat; } void destruirMatriz ( void** mat, size_t filas) { void** ult = mat + (filas -1); for( void ** i = mat ; i<=ult; i++) free(*i); free(mat); } void cargarMatriz (int ** mat, size_t filas, size_t columnas) { for(int i = 0; i <filas; i++) for(int j=0; j<columnas; j++) mat[i][j]=i*4+j+1; } int sumarDiagPrincipal ( int ** mat, size_t cols) { int sum =0; for(int i =0; i<cols; i++) sum+= mat[i][i]; return sum; } void mostrarMatriz (int ** mat, size_t filas, size_t columnas) { for(int i = 0; i <filas; i++) { for(int j=0; j<columnas; j++) printf("%d \t", mat[i][j]); printf("\n"); } }
La idea de crear matrices genércias es podes cambiar los tipos de datos. Si ven: crearMatriz, destruirMatriz son genéricas y cargarMatriz y mostrarMatriz obviamente dependiendo el tipo es lo que voy a enviar.
#include <stdio.h>
#include <stdlib.h>
void ** crearMatriz ( size_t cantFilas, size_t cantColumnas, size_t tamElem);
void destruirMatriz ( void** mat, size_t filas);
void cargarMatriz (float ** mat, size_t filas, size_t columnas);
void mostrarMatriz (float ** mat, size_t filas, size_t columnas);
int main()
{
int filas = 2;
int columnas =4;
float ** matriz = (float**)crearMatriz(filas, columnas, sizeof(int));
if(!matriz)
{
puts("Sin Memoria");
return 0;
}
cargarMatriz(matriz,filas,columnas);
mostrarMatriz(matriz,filas,columnas);
destruirMatriz((void**)matriz, filas);
return 0;
}
void ** crearMatriz ( size_t cantFilas, size_t cantColumnas, size_t tamElem)
{
//tamElem esta en bytes
void ** mat = malloc ( cantFilas * sizeof(void*));
// reservo memoria para todas los punteros a void de filas.
if(!mat)
{
return NULL;
}
void **ult = mat + cantFilas -1;
for (void ** i = mat; i<=ult; i++)
{
*i = malloc(cantColumnas * tamElem);
if(!*i)
{
for(void** j=mat; j<i; j++)
{
free(*j);
}
free(mat); // si hago solo free de mat libera la primer columna y el resto no.
return NULL;
}
}
return mat;
}
void destruirMatriz ( void** mat, size_t filas)
{
void** ult = mat + (filas -1);
for( void ** i = mat ; i<=ult; i++)
free(*i);
free(mat);
}
void cargarMatriz (float ** mat, size_t filas, size_t columnas)
{
for(int i = 0; i <filas; i++)
for(int j=0; j<columnas; j++)
mat[i][j]=i*4.2+j+1.3;
}
void mostrarMatriz (float ** mat, size_t filas, size_t columnas)
{
for(int i = 0; i <filas; i++)
{
for(int j=0; j<columnas; j++)
printf("%f \t", mat[i][j]);
printf("\n");
}
}
Producto de Matrices
Para matrices no cuadradas, por ejemplo tengo una matriz de 2×4 y una 4×3. Las columnas de la primer matriz debe ser la misma cantidad de filas de la matriz 2.
![](http://programacionunlam.com.ar/wp-content/uploads/2023/09/image-8.png)
![](http://programacionunlam.com.ar/wp-content/uploads/2023/09/image-9.png)
#include <stdio.h>
#include <stdlib.h>
void ** crearMatriz ( size_t cantFilas, size_t cantColumnas, size_t tamElem);
void destruirMatriz ( void** mat, size_t filas);
void cargarMatriz (int ** mat, size_t filas, size_t columnas);
void cargarMatriz2 (int ** mat, size_t filas, size_t columnas);
void mostrarMatriz (int ** mat, size_t filas, size_t columnas);
int ** productoMatrices(int** m1, int** m2, int filM1, int colM1filM2, int colM2);
int main()
{
int filas = 2;
int filas2 = 4;
int columnas =4;
int columnas2 =3;
int ** matriz = (int**)crearMatriz(filas, columnas, sizeof(int));
int ** matriz2 = (int**)crearMatriz(filas2, columnas2, sizeof(int));
if(!matriz)
{
puts("Sin Memoria");
return 0;
}
if(!matriz2)
{
puts("Sin Memoria");
return 0;
}
cargarMatriz(matriz,filas,columnas);
cargarMatriz2(matriz2,filas2,columnas2);
mostrarMatriz(matriz,filas,columnas);
printf("\n");
mostrarMatriz(matriz2,filas2,columnas2);
int **matrizResult = productoMatrices(matriz,matriz2,filas,columnas,columnas2);
printf("\n");
mostrarMatriz(matrizResult,filas,columnas2);
destruirMatriz((void**)matriz, filas);
destruirMatriz((void**)matriz2, filas2);
destruirMatriz((void**)matrizResult,filas);
return 0;
}
void ** crearMatriz ( size_t cantFilas, size_t cantColumnas, size_t tamElem)
{
//tamElem esta en bytes
void ** mat = malloc ( cantFilas * sizeof(void*));
// reservo memoria para todas los punteros a void de filas.
if(!mat)
{
return NULL;
}
void **ult = mat + cantFilas -1;
for (void ** i = mat; i<=ult; i++)
{
*i = malloc(cantColumnas * tamElem);
if(!*i)
{
for(void** j=mat; j<i; j++)
{
free(*j);
}
free(mat); // si hago solo free de mat libera la primer columna y el resto no.
return NULL;
}
}
return mat;
}
void destruirMatriz ( void** mat, size_t filas)
{
void** ult = mat + (filas -1);
for( void ** i = mat ; i<=ult; i++)
free(*i);
free(mat);
}
void cargarMatriz (int ** mat, size_t filas, size_t columnas)
{
for(int i = 0; i <filas; i++)
for(int j=0; j<columnas; j++)
mat[i][j]=i*4+j+1;
}
void cargarMatriz2 (int ** mat2, size_t filas2, size_t columnas2)
{
for(int i = 0; i <filas2; i++)
for(int j=0; j<columnas2; j++)
mat2[i][j]=i*3+j+1;
}
void mostrarMatriz (int ** mat, size_t filas, size_t columnas)
{
for(int i = 0; i <filas; i++)
{
for(int j=0; j<columnas; j++)
printf("%d \t", mat[i][j]);
printf("\n");
}
}
int ** productoMatrices(int** m1, int** m2, int filM1, int colM1filM2, int colM2)
{
int** matrizResult = (int**)crearMatriz(filM1, colM2, sizeof(int));
if(!matrizResult)
return NULL;
for (int i= 0; i< filM1 ; i++)
{
for (int j= 0; j< colM2; j++)
{
matrizResult[i][j]=0;
for (int k=0; k< colM1filM2; k++)
matrizResult[i][j]+= m1[i][k]*m2[k][j];
}
}
return matrizResult;
}
![](http://programacionunlam.com.ar/wp-content/uploads/2023/09/image-10.png)