Título: Problemas para rellenar la matriz Publicado por: 4PR3ND1Z en 28 Febrero 2019, 09:42 am Buenos días. El problema me surge a la hora de rellenar la matriz puesto que me pide dos veces que ingrese los datos. Os adjunto el ejercicio entero por si alguien quisiera echarle una ojeada.
Citar /* 15. Desarrollar una función que determine si una matriz es simétrica o no. Una matriz es simétrica: A = A^t - La matriz debe ser cuadrada. - Aij = Aji |2 5 9| |2 5 9| |5 8 -1| -> |5 8 -1| |9 -1 10| |9 -1 10| */ #include <iostream> #include <stdlib.h> using namespace std; void pedirDatos(); void matrizCuadrada(int, int); void rellenarMatriz(int m[][10], int, int); void mostrarMatriz(int m[][10], int, int); void matrizSimetrica(int m[][10], int, int); int m[10][10], nFil, nCol; int main(){ pedirDatos(); matrizCuadrada(nFil, nCol); cout<<"\n"; rellenarMatriz(m, nFil, nCol); mostrarMatriz(m, nFil, nCol); matrizSimetrica(m, nFil, nCol); cout<<"\n\n"; system("pause"); return 0; } void pedirDatos(){ cout<<"Introduce el numero de filas de la matriz: "; cin>>nFil; cout<<"\nIntroduce el numero de columnas de la matriz: "; cin>>nCol; } void matrizCuadrada(int nFil, int nCol){ if(nFil != nCol){ cout<<"\nLa matriz debe ser cuadrada (ej. 4x4)"; cout<<"\n\n"; pedirDatos(); } else rellenarMatriz(m, nFil, nCol); } void rellenarMatriz(int m[][10], int nFil, int nCol){ for(int i=0; i<nFil; i++){ for(int j=0; j<nCol; j++){ cout<<"Introduce un numero para |"<<i<<"| |"<<j<<"|: "; cin>>m[j]; } } } void mostrarMatriz(int m[][10], int nFil, int nCol){ cout<<"\n\nLa matriz queda compuesta de la siguiente manera: "; for(int i=0; i<nFil; i++){ cout<<"\n"; for(int j=0; j<nCol; j++){ cout<<"|"<<m[j]<<"|"; } } } void matrizSimetrica(int m[][10], int nFil, int nCol){ int cont = 0; for(int i=0; i<nFil; i++){ for(int j=0; j<nCol; j++){ if(m[j] == m[j]){ cont++; } } } if(cont == (nFil * nCol)){ cout<<"\nLa matriz es simetrica."; } else{ cout<<"\nLa matriz no es simetrica."; } } Gracias por tu tiempo. Título: Re: Problemas para rellenar la matriz Publicado por: K-YreX en 28 Febrero 2019, 12:41 pm Te recomiendo que no uses variables globales ya que no es muy recomendado para casos como este... Además de que estás usando la mayoría de funciones con parámetros (excepto <pedirDatos()>) así que con cambiar esa por:
Código
Además hay un problema en <matrizCuadrada()>. Imagina que introduces <nFil> != <nCol>... Te dirá que la matriz debe ser cuadrada y te volverá a pedir los datos pero no la construirá. La forma más común de resolver esto es usar un filtro. Te dejo un ejemplo para que tú lo adaptes a tu código. Código
Ahora imagina el otro caso, a la primera introduces unas dimensiones iguales (<nFil> == <nCol>)... Primero se llamará a la función <rellenarMatriz()> que está en el <else> de la función <matrizCuadrada()> y después a la función <rellenarMatriz()> que está en el <main>. Por eso te pide los valores dos veces. Unas recomendaciones de diseño, no de funcionalidad:
Si ya de paso cambias las etiquetas de código por las de C++ mejor. Ya que las <i> entre corchetes [] no aparecen ya que se confunden con la etiqueta de letra cursiva y el código se hace más complicado de interpretar... :-X Título: Re: Problemas para rellenar la matriz Publicado por: 4PR3ND1Z en 28 Febrero 2019, 19:52 pm Unos consejos geniales. Tomaré nota.
¿A qué te refieres con cambiar la función void pedirDatos() por void pedirDatos(int &nFil, int &nCol)? Imagino que te refieres al paso de parámetros por referencia para así poder incluir las variables dentro del main. Bien detectado el fallo de control típico de un novato (más aún si cabe :xD) en la función matrizCuadrada. Cómo no se iba a repetir si efectivamente tenía llamadas a la función en el main y en la propia función... :-\ Perdona si he cometido errores en la publicación, aún tengo que familiarizarme. :-\ Título: Re: Problemas para rellenar la matriz Publicado por: 4PR3ND1Z en 28 Febrero 2019, 20:40 pm Este sería el resultado tras aplicar los cambios. Muchas gracias.
Código: /* 15. Desarrollar una función que determine si una matriz es simétrica o no. Una matriz es simétrica: A = A^t - La matriz debe ser cuadrada. - Aij = Aji |2 5 9| |2 5 9| |5 8 -1| -> |5 8 -1| |9 -1 10| |9 -1 10| */ #include <iostream> #include <cstdlib> using namespace std; void pedirDatos(int&, int&); void matrizCuadrada(int m[][10], int&, int&); void rellenarMatriz(int m[][10], int&, int&); void mostrarMatriz(int m[][10], int&, int&); void matrizSimetrica(int m[][10], int&, int&); int main(){ int m[10][10], nFil, nCol; pedirDatos(nFil, nCol); matrizCuadrada(m, nFil, nCol); cout<<"\n"; mostrarMatriz(m, nFil, nCol); matrizSimetrica(m, nFil, nCol); cout<<"\n\n"; cin.get(); //system("pause"); return 0; } void pedirDatos(int& nFil, int& nCol){ cout<<"Introduce el numero de filas de la matriz: "; cin>>nFil; cout<<"\nIntroduce el numero de columnas de la matriz: "; cin>>nCol; } void matrizCuadrada(int m[][10], int& nFil, int& nCol){ do{ cout<<"\nLa matriz debe ser cuadrada (ej. 4x4)"; cout<<"\n\n"; pedirDatos(nFil, nCol); }while(nFil != nCol); rellenarMatriz(m, nFil, nCol); } void rellenarMatriz(int m[][10], int& nFil, int& nCol){ for(int i=0; i<nFil; i++){ for(int j=0; j<nCol; j++){ cout<<"Introduce un numero para |"<<i<<"| |"<<j<<"|: "; cin>>m[i][j]; } } } void mostrarMatriz(int m[][10], int& nFil, int& nCol){ cout<<"\n\nLa matriz queda compuesta de la siguiente manera: "; for(int i=0; i<nFil; i++){ cout<<"\n"; for(int j=0; j<nCol; j++){ cout<<"|"<<m[i][j]<<"|"; } } } void matrizSimetrica(int m[][10], int& nFil, int& nCol){ int cont = 0; for(int i=0; i<nFil; i++){ for(int j=0; j<nCol; j++){ if(m[i][j] == m[j][i]){ cont++; } } } if(cont == (nFil * nCol)){ cout<<"\nLa matriz es simetrica."; } else{ cout<<"\nLa matriz no es simetrica."; } } Título: Re: Problemas para rellenar la matriz Publicado por: K-YreX en 28 Febrero 2019, 21:46 pm Ahora ya funciona pero si te has dado cuenta, pides los datos dos veces seguidas. Una vez en el <main> y otra vez en la función <matrizCuadrada()>...
Te comento las diferencias entre el filtro <do while> y el <while> ya que esto se puede hacer de ambas formas. Un bloque de código dentro de un <do while> siempre se ejecuta al menos una vez aunque la condición sea falsa ya que primero está el <do> y luego el <while>. Es como "primero haces y luego compruebas". En cambio un <while> es justo lo contrario; "primero compruebas y luego ya si eso, haces". Aquí te muestro un bloque infinito. ¿Por qué si la condición de primeras no se cumple? Pues porque primero mostramos el 0, luego lo incrementamos <iteracion = 1> y luego comprobamos si es mayor que 0. Y como sí que lo es pues ya se ejecuta de forma infinita. Código
Lo mismo con un <while>. La parte interna del bucle nunca se ejecuta. Al principio iteracion vale 0, comprobamos si es mayor que 0 y como no lo es, se acabó. Código
Entonces ahora te muestro las opciones que tienes:
Código
Código
Código Con esta última opción ya no tienes que usar siempre el paso por referencia y así evitar errores mayores. Es más, yo dejaría el esquema general del programa en algo así :-X: Código En el caso de <esSimetrica()>. Cuando se usa una función para comprobar algo es mejor que devuelva <true/false> y luego tú ya verás lo que haces con ello. Imagina un programa muy grande donde tienes que comprobar si 100 matrices son simétricas y vas mostrando por pantalla el resultado de cada una, cuando no es necesario. Entonces es mejor hacer que devuelva un <bool> de si es simétrica o no y ya en el <main> haces lo que quieras. Algo así: Código
Título: Re: Problemas para rellenar la matriz Publicado por: 4PR3ND1Z en 1 Marzo 2019, 17:47 pm Excelente explicación. Poco más y me haces un programa nuevo. :laugh:
Claro yo tenía entendido que si introducía las variables dentro del main, en caso de mandarlas a las funciones debía hacerlo siempre por referencia. Otra cosa que me acabas de enseñar es a usar más el const int una vez tengo definidos los valores para los enteros. Lo que no termino de entender es TAM. Entiendo que C++ pide al menos un tamaño máximo de columnas y también he visto como se pueden predefinir pero en este caso que no van predefinidas no le encuentro el sentido. Me imagino que habrás definido int TAM = 10; int m[][TAM]; Por cierto, no sé como organizarme ahora que empiezo a ver temas un poco más complejos. Me gustaría guardar tanta información como sea posible y no sé por donde empezar ¿Qué métodos usas? Estoy siguiendo un videotutorial de YT para que te hagas una idea. :-\ Gracias de nuevo por tu tiempo y por tan extensas explicaciones de calidad. De mayor quiero expresarme como tú. ;-) Título: Re: Problemas para rellenar la matriz Publicado por: K-YreX en 1 Marzo 2019, 19:49 pm Primero: lo de usar <TAM> es para evitar "números mágicos" (magic numbers) que son números que aparecen por el código literalmente y que es difícil ver a qué están haciendo referencia. Siempre es mejor guardar esos valores en constantes y así en el caso de querer modificar el tamaño/alcance del programa, sólo tendrás que modificar el valor de la constante.
Te muestro un código muy sencillo donde guardamos un array y luego lo mostramos. Imagina el caso que queremos que el programa en vez de almacenar 10 valores, ahora queremos que almacene un máximo de 20... En el primer código tendríamos que cambiar cada 10 por 20; mientras que en el segundo bastaría con cambiar el valor de <TAM> Código Otra buena utilidad es cuando todavía no sabemos usar memoria dinámica, es decir; que si queremos que el usuario introduzca n datos pero no sabemos cuánto va a valer n hasta el tiempo de ejecución, podemos crear un máximo para declarar el array y luego controlar la cantidad de valores que va a usar el usuario con otra variable. Se desperdicia memoria pero es la forma de hacerlo con memoria estática. Te dejo aquí un ejemplo: Código
Respecto al tema del aprendizaje, al final lo importante es que vayas practicando todo lo que vas viendo, si te limitas a ver códigos hechos nunca sabrás tratar con los errores que te van a surgir cuando seas tú quien los escriba. Siempre habrá temas más importantes que vas a usar en prácticamente todos los programas que hagas y otras cosas que no usarás casi nunca. Para empezar a programar tampoco necesitas haber memorizado TODO antes. Es suficiente con que sepas qué cosas se pueden hacer y cuando necesites usar algo poco común siempre podrás buscar por internet o en libros cómo se usaba eso que quieres implementar. Normalmente los tutoriales que van por "capítulos" suelen ir bien estructurados para que la curva de aprendizaje no sea muy grande y te van metiendo conceptos poco a poco. Simplemente seguir aprendiendo e ir probando todo lo que vas viendo. Suerte :-X |