Pedir el nombre de un fichero al usuario y de ahí leer una matriz. El número de filas y columnas estará en la primera línea. Este programa sólo trabaja con matrices cuadradas, así que si no lo es, se detendrá ahí. En el resto de filas del fichero estará la matriz, colocada de la forma intuitiva. El programa escribirá en pantalla el determinante de la matriz.
Vamos a organizar el programa en funciones que vayan haciendo cada bloque o paso de la resolución. El primer bloque consiste en leer del fichero que diga el usuario la matriz. Es un caso típico de lectura de matriz, análogo a los que ya hemos visto, con la única diferencia de que hay que chequear que la matriz sea cuadrada; para terminar el programa en caso contrario podemos usar exit. Este bloque se hará en una función qué podemos llamar, por ejemplo, leer. Sus argumentos serán, por este orden, el tamaño de la matriz (un solo valor, puesto que es cuadrada) y luego la propia matriz, a la que vamos a suponer que hemos predimensionado a tamaño 100. Vamos a echar un vistazo a cómo son las cabeceras de las funciones que tienen algún argumento tabla o matriz.
Plantilla a poner
void nombrefuncion ( ...tipo nombrematriz[filas][columnas]...)
Lo primero el tipo de los elementos de la matriz (float, Metros, Punto, ...)
Luego el nombre. En ningún caso lleva * Las tablas o matrices son siempre, automáticamente, de entrada y salida.
Luego un par de corchetes y entre ellos el número de filas de la matriz. Reglamentariamente no es obligatorio y se podría dejar el par de corchetes vacío. Para evitar confusiones con otras situaciones en las que no se pueden dejar vacíos, suele ser recomendable acostumbrarse a ponerlo siempre.
Luego otro par de corchetes y entre ellos el número de columnas de la matriz. Es obligatorio: no se puede en ningún caso dejar el par de corchetes vacío.
Por ejemplo, si queremos la cabecera de la función escribir cuyos argumentos fuesen en primer lugar la cantidad de filas de una matriz, en segundo lugar la cantidad de columnas, y en tercer lugar la propia matriz, que ha sido dimensionada a esas filas y esas columnas, todos ellos de entrada, sería: void escribir(int filas, int colums, float matriz[filas][colums])

Está perfecta. También podríamos haber omitido filas en el primer par de corchetes.

Si queremos la cabecera de la función generar cuyos argumentos, todos de salida, son una matriz, predimensionada a 50 filas y columnas, y la cantidad real de filas y columnas usadas, sería: void generar(float matriz[][colums], int *filas, int *colums)

Tiene un fallo: la cantidad de columnas que se pone en los corchetes es la de dimensión, no la que realmente uses.

Si queremos la cabecera de la función trasponer cuyos argumentos sean, por este orden, una matriz, predimensionada a 100 filas y columnas (entrada), la cantidad real de filas y columnas usadas (ambos de entrada) y otra matriz para la traspuesta de la anterior (salida), dimensionada a su tamaño estrictamente necesario, sería: void trasponer(float matriz[][], filas, colums, *traspuesta[][])

Tiene varios fallos: una matriz nunca lleva * la cantidad de columnas es obligatorio ponerla y faltan tipos.

Por ejemplo, para la función escala que recibe como argumentos de entrada dos matrices del mismo tamaño, un valor numérico aparte y el tamaño de esas matrices:
void escala(float matrizor[nfilas][ncols],float matrizesc[nfilas][ncols], float escala, int nfilas, int ncols)
Regular: No le falta ni le sobra, pero el orden no es bueno, porque se encuentra que necesita el valor de nfilas y ncols, antes de verlos en la lista de argumentos.
Por ejemplo, la función seleccionar recibe unos argumentos de entrada que son: la cantidad de filas y de columnas utilizadas en una matriz, un indicador de fila y columna de cierto elemento, y la propia matriz qué son números sin decimales y que ha sido predimensionada a 100 filas y 100 columnas:
void seleccionar(int nfilas, int ncols, int cualf, int cualc, int tabla[100][100])
Bien: Fíjate que se emplea el valor de dimensión, no el de uso
Por ejemplo, la función totales tiene un argumento de entrada que es una matriz, cuyas filas son una cantidad de años y cuyas columnas son unos ciertos meses, y un argumento de salida que es una lista del tamaño la cantidad de meses:
void totales(ventas[años][], *totales[meses])
Mal: ¿Dónde están los tipos? El número de columnas no puede faltar. No puede haber nombres con ñ y esa variable tendrá que ir declarada previamente. Las listas y tablas nunca llevan *
Volviendo a nuestro programa, la función leer va a tener como argumentos, ambos de salida, el tamaño real usado y la propia matriz, a la que supondremos predimensionada a tamaño 100. ¿Cómo es su cabecera (sin incluir la llave de inicio)?
void leer(int *tamreal, float matrizgrande[100][100])
Exacto. El orden de argumentos se puede invertir, si se invierte también en la llamada. La cantidad de filas es opcional.
void leer(int *tamreal, float *matrizgrande[][100])
Las matrices nunca llevan * Siempre son automáticamente de entrada y salida.
void leer(int *tamreal, float matrizgrande[100][])
No, lo que podrías dejar vacío son las filas, nunca las columnas

Vamos a resolver el determinante por el método de los adjuntos. Cada adjunto lo resolveremos por el mismo método, así que necesitamos homogeneizar el tratamiento. Vamos a optar porque las sucesivas matrices sean de tamaño ajustado. Entonces la original hay que copiarla a otra ajustada, lo cual podemos hacer en main o en una función. Otra opción es leer primero el tamaño y esperar ahí para dimensionar la matriz. Toma la decisión que quieras y prepáralo. Pienso que para eso no necesites pistas.

Sigamos. Puesto que vamos a usar el método de los adjuntos, vamos a preparar una función para sacar la matriz adjunta de un elemento.

Si la función se va a llamar adjunta y va a tener como argumentos, por este orden, todos de entrada menos el último: el tamaño y la matriz original, la fila y columna del elemento cuya adjunta queremos, y la matriz adjunta, ¿cómo es su cabecera?
void adjunta(int tam, float mator[tam][tam], int fel, int cel, float matad[tam-1][tam-1])
Sí. El tamaño se usa en la declaración de la matriz, así que tiene que ir primero. La cantidad de filas es opcional.
void adjunta(int tam, float mator[][tam], int fel, int cel, tam--, float *matad[][tam])
Las matrices no llevan * y tam-- es una instrucción; no puede meterse en una lista de argumentos
void leer(int *tamreal, float matrizgrande[100][])
No, lo que podrías dejar vacío son las filas, nunca las columnas

Preparemos esa función. Rellenaremos la matriz adjunta copiando desde la matriz original. Para recorrerla tendremos el típico doble ciclo de filas y columnas. Vamos con el de filas.

Realmente tenemos que recorrer ambas matrices, pero no son iguales (la adjunta es más pequeña), así que inicializaremos también su índice de filas, pero el incremento, como no va a ser siempre (la fila del elemento cuya adjunta estamos creando no cuenta), lo llevaremos dentro del ciclo.

¿Cómo es la cabecera de este for (sin incluir la llave de inicio)?
for(filor=0,filad=0;filor<tam; filor++)
Sí. filor sería el índice de filas de la matriz original.
for(filor=filad=0;filor<tam-1; filor+1)
Hay que llegar hasta tam, no hasta tam-1; y filor+1 no cambia el valor de filor, sólo hace un cálculo.
for(filor=0,filad=0;filad<tam; filor=filor+1)
Si es filor el que va subiendo, será el que hay que comparar con tam
for(filor=filad=0;filor<tam; filor+=1)
Sí. filor sería el índice de filas de la matriz original.

Dentro de este ciclo de filas, lo primero que vamos a mirar es si esta fila hay que copiarla. La del elemento cuya adjunta estamos sacando, no hay que copiarla; el resto sí.

Vamos a poner un if que mire si hay que saltarse esta fila ¿Cómo es la cabecera (sin incluir la llave de inicio)?
if(filor==fel)
if(fel=filor)
¿Cuántos, cuántos iguales se ponen para comparar?
if(filor==fel-1)
Aquí los índices los va sacando el programa, no los mete el usuario.

Si se cumple el if hay que pasar a la siguiente: puedes usar la instrucción continue. Si no, pasamos al ciclo de columnas, que es análogo al de filas, también con un if al principio para ver si hay que saltarse esa columna. Si no, copiamos el elemento de la original a la adjunta.

¿Recuerdas cómo se maneja un elemento de una matriz o tabla?

Plantilla a poner
...,nombrematriz[fila][columna]...
Se pone el nombre de la matriz
Luego un par de corchetes y entre ellos el número de la fila del elemento que interesa de la matriz. Recuerda que están numeradas desde 0
Luego otro par de corchetes y entre ellos el número de columna.
Entonces ¿cómo es la instrucción para copiar el elemento correspondiente a la adjunta?
matad[filad][colad]=mator[filor][color];
matad[filor][color]=mator[filor][color];
Recuerda que los índices de las matrices no coinciden
mator[filor][color]=matad[filad][colad];
¿De dónde estás cogiendo y dónde estás poniendo?

Después de copiar el elemento sube la columna de la adjunta (recuerda que lo habíamos dejado para incrementarlo dentro del ciclo) Después del ciclo de columnas pon el incremento de la fila de la adjunta. Termina la función adjunta comprobando las llaves.

En el programa principal habrá una llamada a la función determinante. Esa función irá calculando los adjuntos, llamando a la propia función determinante ¿Qué argumentos tendrá la función? El tamaño y la propia matriz cuyo determinante interesa como entrada, y el determinante como salida. De esa forma podemos construir la cabecera.

¿Cómo será la llamada? ¿Cómo son las llamadas a funciones cuando algún argumento es una matriz?

Plantilla a poner
nombrefunción(...nombrematriz...);
Se pone el nombre de la matriz, sólo, sin corchetes,, siempre que queramos pasar la matriz completa (si pones corchetes pasaría sólo un elemento)
Si la función se va a llamar determinante ¿cómo es su llamada desde main? (Recuerda que le pasamos la matriz de tamaño ajustado)
determinante(tamreal, matriz, &det);
determinante(tamreal, matriz[tamreal][tamreal], &det);
Así pasaría sólo el elemento de la fila tamreal, columna tamreal
determinante(tamreal, matriz[][], &det);
No se ponen corchetes en la llamada cuando pasa toda la metriz

Vamos a construir la función determinante.

Esta función va a necesitar llamarse a sí misma, para calcular los adjuntos. Toda función que haga eso tiene que tener separado un caso simple que se resuelve directamente.

Vamos a elegir el tamaño 2 para resolución directa, así que pon un if que compruebe si el tamaño es 2

Si se cumple el if ¿cómo calculamos el determinante? (En este caso es el producto de una diagonal menos el de la otra)
*det=matriz[0][0]*matriz[1][1]-matriz[0][1]*matriz[1][0];
*det=matriz[1][1]*matriz[2][2]-matriz[1][2]*matriz[2][1];
det=matriz[1][1]*matriz[0][0]-matriz[1][0]*matriz[0][1];

En otro caso (else) vamos a usar los adjuntos de la primera fila. Antes pon el determinante a 0, porque lo iremos sumando.

En el ciclo de la primera fila vamos a mover dos variables: la columna y el signo, que va cambiando.

¿Cómo será la cabecera de ciclo? (pongamos que operamos primero la columna y luego el signo)
for(col=0,signo=1; col<tam; col++,signo=-signo)
for(col=0,signo=+; col<=tam; ++col,-signo)
Lo de =+ no tiene sentido No hay columna tam, la última es tam-1 y - signo opera, pero no guarda el resultado

Dentro del ciclo lo primero sacar la matriz adjunta del elemento correspondiente, para lo cual usaremos la función que hicimos antes.

¿Cómo será la llamada que hay que poner aquí?
adjunta(tam, matriz, 0, col, matadj);
adjunta(tam,matriz,fil,col,adjunta);
fil no la tenemos, y una variable no puede llamarse igual que una función.
adjunta(tam-1,matriz,fil,col,&matadjunta);
El primer argumento es el tamaño de la matriz original, o sea, tam, fil no la tenemos, y las matrices nunca pasan con &

Ahora calcularemos el determinante de la matriz adjunta usando la propia función determinante.

¿Cómo será la llamada?
determinante(tam-1, matadj, &detadj);
determinante(tam, matriz, &*det);;
Si tam es el tamaño de la matriz completa, el de la adjunta será uno menos, la matriz que hay que pasar es la adjunta, y no podemos usar det para el determinante de la adjunta porque ése es el que usamos para la completa, y nos lo machacaría; necesitamos otra variable
determinante(tam, matadj, det);
Si tam es el tamaño de la matriz completa, el de la adjunta será uno menos, y no podemos usar det para el determinante de la adjunta porque ése es el que usamos para la completa, y nos lo machacaría; necesitamos otra variable

Una vez calculado el determinante de la matriz adjunta, le multiplicamos por el elemento correspondiente y, con su signo, le acumulamos al determinante total.

O sea, en C...(cogiendo primero el elemento, luego el signo y luego el determinante adjunto)
*det+=matriz[0][col]*signo*detadj;
*det = *det+matriz[fil][col]*(signo)detadj;
La fila es fijo la 0, porque lo estamos haciendo así, y lo de (signo)detadj no tiene sentido; signo es una variable que vale 1 ó -1 y lo vamos multiplicando
*det = *det (signo)matadj[0][col]*det;
Lo de (signo)matadj no tiene sentido; signo es una variable que vale 1 ó -1 y lo vamos multiplicando. El elemento le cogemos de la matriz completa. Y el determinante adjunto lo habíamos puesto en otra variable.

Cierra los ciclos,cierra el else y declara todas las variables. Comprueba que en todas las funciones estén declaradas todas las variables.

Pruébalo con una matriz cuyo determinante conozcas. Si te atascas con algo, consulta al profesor.