Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: 98Fran en 25 Agosto 2019, 16:47 pm



Título: Problema con los punteros C++
Publicado por: 98Fran en 25 Agosto 2019, 16:47 pm
Estoy empezando con C++ y hay algo que no entiendo por qué esta pasando, aquí esta mi codigo:

Código
  1. #include <iostream>
  2. #include <conio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5.  
  6. using namespace std;
  7.  
  8. int pedirNombre();
  9. void contarVocales(char*,int);
  10. void mostrarVocales();
  11.  
  12. int *p_a, *p_e, *p_i, *p_o, *p_u; // punteros de los contadores;
  13. char *nombre;
  14.  
  15. int main(){
  16.  
  17. contarVocales(nombre,pedirNombre());
  18. mostrarVocales();
  19.  
  20.  
  21.  
  22. getch();
  23. return 0;
  24. }
  25.  
  26. int pedirNombre(){
  27. int longitud;
  28. char usuario[30];
  29.  
  30. cout<<"Digite su nombre: ";
  31. cin.getline(usuario,30,'\n');
  32. longitud = strlen(usuario);
  33.  
  34. nombre = &usuario[0];
  35.  
  36. return longitud;
  37. }
  38.  
  39. void contarVocales(char* nombre,int n){
  40. int c_a, c_e, c_i, c_o, c_u; //contador vocales;
  41.  
  42. c_a = 0;
  43. c_e = 0;
  44. c_i = 0;
  45. c_o = 0;
  46. c_u = 0;
  47.  
  48. p_a = &c_a;
  49. p_e = &c_e;
  50. p_i = &c_i;
  51. p_o = &c_o;
  52. p_u = &c_u;
  53.  
  54. for(int i=0;i<n;i++){
  55. switch(*(nombre+i)){
  56. case 'a': c_a++; break;
  57. case 'e': c_e++; break;
  58. case 'i': c_i++; break;
  59. case 'o': c_o++; break;
  60. case 'u': c_u++; break;
  61. }
  62. }
  63. }
  64.  
  65. void mostrarVocales(){
  66. cout<<"num. de a: "<<*p_a<<endl;
  67. cout<<"num. de e: "<<*p_e<<endl;
  68. cout<<"num. de i: "<<*p_i<<endl;
  69. cout<<"num. de o: "<<*p_o<<endl;
  70. cout<<"num. de u: "<<*p_u<<endl;
  71. }

SALIDA:
---------------------------------------------------------------------------------------
Digite su nombre: aaaaaeeeeiiioou
num. de a: 1
num. de e: 4
num. de i: 3
num. de o: 2
num. de u: 1
---------------------------------------------------------------------------------------------

Si pongo un cout dentro de la funcion contarVocales() *p_a me da el valor correcto pero una vez sale de esa funcion y se meustra en la funcion mostrarVocales() me da el valor 1 todo el rato. El resto de vocales funcionan correctamente menos en la vocal a que es como si se borrase el valor al acabar la funcion y se sustituye por 1.

PD: he declarado los punteros de forma global por que no se otra forma de pasarlos a otra función y no se si puede pasar mas de un valor por el return (todos los ejemplos que he visto solo pasan 1 dato por el return).

PD2: por que cuando se usa una variable global como *nombre se declara dentro de el prototipo de función si en teoría si lo pasas sin referenciar también sive puesto que es un puntero global, es decir, en ves de usar:

Código
  1. void contarVocales(char*,int);

usar:

Código
  1. void contarVocales();

y escribir directamente la variable como en:

Código
  1. int pedirNombre();


Tengo un cacao con eso, debo o no debo poner las variables globales dentro del parentesis?¿ por lo que se si lo hago sin ser un puntero y no utiliza & pasaría una copia del valor (para asi no modificar el valor de la variable y usarlo en otra funciones si hace falta) pero en los punteros no veo la diferencia la verdad.

Se que es mucho pero la verdad agradecería a algún iluminado que me resuelva estas dudas que me están volviendo loco  ;D ;D. No quiero seguir más adelante con el curso ya que prefiero tener todo bien claro antes de profundizar más. Gracias!!!


Título: Re: Problema con los punteros C++
Publicado por: K-YreX en 25 Agosto 2019, 19:00 pm
Lo primero, para tu próxima consulta (o si quieres puedes modificar tu mensaje para añadirlo), coloca tu código entre etiquetas de código GeSHi. Esto hace el código más fácil de ver y evita algunos problemas de etiquetas.

Ahora vamos parte a parte... AVISO: Va a ser un mensaje extenso y con bastante contenido.
Empezando por las librerías: no uses la librería <conio.h>. Esta librería no es estándar por la que no siempre se puede compilar un programa que la incluye. Además sólo la usas para <getch()> (esto lo puedes sustituir por <cin.get()> que pertenece a la librería <iostream> y así ya no la necesitas y el programa sigue igual). Y aunque sea un tema menor, la convención del <.h> en las librerías es típico de C (para C++ empieza por <c> y no lleva <.h>) Ej: <stdlib.h> (C) -> <cstdlib> (C++)

Citar
Tengo un cacao con eso, debo o no debo poner las variables globales dentro del parentesis?¿ por lo que se si lo hago sin ser un puntero y no utiliza & pasaría una copia del valor (para asi no modificar el valor de la variable y usarlo en otra funciones si hace falta) pero en los punteros no veo la diferencia la verdad.
Lo siguiente que vamos a ver es el scope o alcance de una variable y su tiempo de vida. Una variable existe dentro de la función donde se declara y se "destruye" cuando acaba esa función (esto es así también para el <main> que no deja de ser una función) y para poder usarla en otra función debemos mandársela de alguna manera (uso de parámetros). Una variable global existe durante toda la ejecución del programa y es accesible en cualquier punto del programa, por lo que una variable global no es necesario mandarla como parámetro. Por esto último, una variable global se puede modificar desde cualquier lugar y hay que evitar su uso. Se pueden usar variables globales o más bien constantes para determinar valores predefinidos.

Citar
PD: he declarado los punteros de forma global por que no se otra forma de pasarlos a otra función y no se si puede pasar mas de un valor por el return (todos los ejemplos que he visto solo pasan 1 dato por el return).
Un <return> sólo devuelve un valor. Este puede ser un valor de tipo <int>/<char>/... o también puede ser un puntero. Por ejemplo para arrays/arreglos/vectores (las 3 son lo mismo). Existe la excepción de usar el tipo <pair> de la STL que es un par de datos. Por lo que podríamos devolver 2 o más si concatenamos un <pair> dentro de otro. Esto no es lo más habitual y no será necesario tirar de ello pero para que lo conozcas... Como regla general: el <return> devuelve un valor.

En C++ existe lo que es el paso por referencia (lo opuesto al paso por valor). Un parámetro pasado por valor, crea una copia dentro de la función por lo que su valor original no se ve alterado una vez estamos fuera de esa función. En cambio, un parámetro pasado por referencia manda la dirección de memoria original por lo que si su valor se altera dentro de la función, este también se verá alterado fuera. Los punteros guardan direcciones de memoria por lo que pasar un puntero como parámetro es como pasar la dirección de memoria del dato al que apunta (que es equivalente a pasar el dato por referencia).
Código
  1. int incrementar(int a){
  2.    return ++a;
  3. }
  4. int a = 2;
  5. int b = incrementar(a);
En este caso hemos pasado el parámetro por valor por lo que el original no cambia. (No voy a entrar en el tema de poner ++ antes o después del nombre ya que el resultado varía). La función hace una copia de <a>, la incrementa, se la asigna a <b> y al acabar la función la copia de <a> se "destruye" (porque su alcance sólo existe dentro de la función). Así que a == 2 y b == 3.

Código
  1. int incrementar(int &a){
  2.    return ++a;
  3. }
  4. int a = 2;
  5. int b = incrementar(a);
En este caso lo estamos pasando por referencia por lo que sí cambia. La función recibe la dirección de memoria de <a> por lo tanto no es ninguna copia. Incrementa <a>, se lo asigna a <b> y se acabó. No hay copia por lo que no se "destruye". Entonces a == 3 y b == 3.

Código
  1. int incrementar(int *p){
  2.    return ++(*p);
  3. }
  4. int a = 2:
  5. int *pa = &a;
  6. int b = incrementar(pa);
Aquí <pa> tiene como valor la dirección de memoria de <a>. La función recibe un puntero POR VALOR por lo que se hace una copia de su contenido (entonces se copia la dirección de <a> que es el contenido de <pa>). Si te das cuenta al final la función está trabajando con la dirección de memoria de <a> al igual que en el caso anterior por lo que esto es equivalente a hacer un paso por referencia de <a>. El valor entonces es a == 3 y b == 3.

También se puede pasar un puntero por referencia. Esto únicamente será necesario para trabajar sobre la dirección de memoria en la que está el puntero, NO A LA QUE APUNTA (nótese la diferencia, una variable está en una dirección de memoria y guarda un valor pero un puntero está en una dirección de memoria y guarda otra dirección de memoria). Y sólo se trabaja sobre la dirección de memoria del puntero para reservar memoria y liberarla (<new> y <delete>).

Y finalmente vamos a tu problema en concreto. Aunque en tu caso parece que sólo <*p_a> tiene un valor incorrecto, en realidad el fallo es bastante más grande. Entre el vector <usuario> que es local y se "destruye" al terminar la función y la mezcla de punteros globales con direcciones de memoria temporales como lo son las variables para contar las vocales, internamente hay un montón de errores de saltos que dependen de valores no inicializados, posiciones de escritura no válidas...

Creo que la mejor opción que tienes para no modificar mucho tu programa es:
1. Crear el array <nombre> en el <main>. Pasárselo a una función como parámetro y pedir un nombre al usuario. Devolver el tamaño de <nombre>.
2. Usar una función que reciba como parámetros el array <nombre>, la longitud, y una de estas dos opciones:
  • 5 variables por referencia declaradas en el <main> usadas como contadores.
  • Un array de <int> de tamaño 5 que equivale a juntar las 5 variables de la otra opción en un array.

Prueba los códigos que te he comentado antes y las cosas que no te hayan quedado muy claras y si tienes algún problema de nuevo, no dudes en preguntar pero por favor con el código entre etiquetas de código GeSHi... :-X :-X


Título: Re: Problema con los punteros C++
Publicado por: 98Fran en 25 Agosto 2019, 20:16 pm
Muchas gracias!!!, ahora surge otro problema xD:

Código
  1.  
  2. #include <iostream>
  3. #include <stdlib.h>
  4. #include <string.h>
  5.  
  6. using namespace std;
  7.  
  8. int pedirNombre(char&);
  9. void contarVocales(int);
  10. void mostrarVocales();
  11.  
  12. int *p_vocales; // punteros de los contadores;
  13. char *nombre;
  14.  
  15. int main(){
  16. int c_vocales[5] ={0,0,0,0,0}, longitud;  //0 == a, 1 == b ... 4 == u;
  17. char usuario[30];
  18.  
  19. nombre = &usuario[0];
  20. p_vocales = &c_vocales[0];
  21.  
  22. longitud = pedirNombre(usuario[30]);
  23. contarVocales(longitud);
  24. mostrarVocales();
  25.  
  26.  
  27.  
  28. cin.get();
  29. return 0;
  30. }
  31.  
  32. int pedirNombre(char& us){
  33. int longitud;
  34.  
  35. cout<<"Digite su nombre: ";
  36. cin.getline(us,30,'\n');
  37. longitud = strlen(us);
  38.  
  39. return longitud;
  40. }
  41.  
  42. void contarVocales(int n){
  43.  
  44. for(int i=0;i<n;i++){
  45. switch(*(nombre+i)){
  46. case 'a': *(p_vocales+i) = *(p_vocales+i) + 1; break;
  47. case 'e': *(p_vocales+i) = *(p_vocales+i) + 1;; break;
  48. case 'i': *(p_vocales+i) = *(p_vocales+i) + 1;; break;
  49. case 'o': *(p_vocales+i) = *(p_vocales+i) + 1; break;
  50. case 'u': *(p_vocales+i) = *(p_vocales+i) + 1; break;
  51. }
  52. }
  53.  
  54. }
  55.  
  56. void mostrarVocales(){
  57. cout<<"num. de a: "<<p_vocales[0]<<endl;
  58. cout<<"num. de e: "<<p_vocales[1]<<endl;
  59. cout<<"num. de i: "<<p_vocales[2]<<endl;
  60. cout<<"num. de o: "<<p_vocales[3]<<endl;
  61. cout<<"num. de u: "<<p_vocales[4]<<endl;
  62. }
  63.  

Me da error a la hora de usar cin.getline en la cadena de caractares que he pasado.


Título: Re: Problema con los punteros C++
Publicado por: 98Fran en 25 Agosto 2019, 20:42 pm
Al final he podido resolverlo (aun que dudo que sea de la manera mas adecuada xD):
Código
  1. #include <iostream>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. using namespace std;
  6.  
  7. int pedirNombre();
  8. void contarVocales(int);
  9. void mostrarVocales();
  10.  
  11. int *p_vocales; // punteros de los contadores;
  12. char *nombre;
  13.  
  14. int main(){
  15. int c_vocales[5] ={0,0,0,0,0}, longitud;  //0 == a, 1 == b ... 4 == u;
  16. p_vocales = &c_vocales[0];
  17.  
  18. longitud = pedirNombre();
  19. contarVocales(longitud);
  20. mostrarVocales();
  21.  
  22.  
  23. cout<<"\n"<<nombre<<endl;
  24.  
  25. cin.get();
  26. return 0;
  27. }
  28.  
  29. int pedirNombre(){
  30. int longitud;
  31.  
  32. cout<<"Digite su nombre: ";
  33. nombre = new char[30];
  34. cin.getline(nombre,30,'\n');
  35. longitud = strlen(nombre);
  36.  
  37. return longitud;
  38. }
  39.  
  40. void contarVocales(int n){
  41.  
  42. for(int i=0;i<n;i++){
  43. switch(nombre[i]){
  44. case 'a': *(p_vocales) = *(p_vocales) + 1; break;
  45. case 'e': *(p_vocales+1) = *(p_vocales+1) + 1; break;
  46. case 'i': *(p_vocales+2) = *(p_vocales+2) + 1; break;
  47. case 'o': *(p_vocales+3) = *(p_vocales+3) + 1; break;
  48. case 'u': *(p_vocales+4) = *(p_vocales+4) + 1; break;
  49. }
  50. }
  51. }
  52.  
  53. void mostrarVocales(){
  54. cout<<"num. de a: "<<p_vocales[0]<<endl;
  55. cout<<"num. de e: "<<p_vocales[1]<<endl;
  56. cout<<"num. de i: "<<p_vocales[2]<<endl;
  57. cout<<"num. de o: "<<p_vocales[3]<<endl;
  58. cout<<"num. de u: "<<p_vocales[4]<<endl;
  59. }

/*                             SALIDA:
---------------------------------------------------------------
Digite su nombre: aaaaeaeeieioiou
num. de a: 5
num. de e: 4
num. de i: 3
num. de o: 2
num. de u: 1

aaaaeaeeieioiou

---------------------------------------------------------------
PD: tenía mal lo del conteo que había puesto:
Código
  1. case 'a': *(p_vocales+i) = *(p_vocales+i) + 1; break;

Y no tenia que usar la i y otro error que me salto era que no podía usar ++ con los punteros:
Código
  1. case 'a': *(p_vocales) ++; break;

Aun que no se si usando esto serviría también:
Código
  1. case 'a': *(p_vocales) += 1; break;

Muchisimas gracias, ando un poco liado con la nomenglatura a la hora de pasar vectores por las funciones, pero al menos ya tengo esto resuelto  ;-) ;-). Si me resolvieses la duda de como pasar vectores ya sea int o cadenar char por referencia en funciones te lo agradecería muchimo tambien jajaja. Mil gracias ^^.


Título: Re: Problema con los punteros C++
Publicado por: K-YreX en 25 Agosto 2019, 21:00 pm
Respecto a tu primer mensaje (para no citarlo entero):
Bueno ya empieza a coger forma aunque hay que terminar de pulir ese código...
El primer error lo tienes en la función <pedirNombre()>. Aunque antes has visto que era equivalente pasar una variable por referencia que pasar un puntero ya que ambas son direcciones de memoria, no es exactamente lo mismo. Por lo que tienes que cambiar el parámetro de un <char> por referencia a un puntero de <char>. Es decir la función debe quedar así:
Código
  1. int pedirNombre(char*);
No olvides cambiarlo tanto en el prototipo de la función como abajo en la implementación.

Otro error lo tienes en la línea 22: Tenemos una función que debe recibir un puntero a <char> (porque cuando pasamos un array como parámetro lo que pasamos en realidad es un puntero de la primera posición del array) y tú le estás pasando <usuario[30]> que es la posición 30 del array <usuario>, es decir, le estás pasando un <char> (que además está fuera de los límites ya que si el tamaño es 30, las posiciones del array irían del 0 al 29 incluidos). En este caso solo se escribe el nombre del array tal que:
Código
  1. longitud = pedirNombre(usuario);

Hasta aquí los errores como tal. Una vez corregido eso, el programa ya funcionaría.

Y aquí un par de consejos o trucos:
  • Como antes te he comentado, hay que evitar las variables globales. Por tanto no deberíamos tener las líneas 12 y 13. El nombre de un array corresponde a un puntero que apunta a la primera posición del array. En tu caso:
Código
  1. // creamos un array de <int>
  2. int vocales[5] = {0}; // Con esto se inicializa la primera posicion al valor que indiques y el resto a 0 por lo tanto todo a 0
  3. int *puntero = &vocales[0]; // hacemos que <puntero> apunte al comienzo de <vocales>
  4. // Ahora tenemos dos punteros que apuntan a <vocales[0]>. Uno es <puntero> y el otro es <vocales> (<vocales> equivale a <&vocales[0]> por lo que podemos hacer:)
  5. int *puntero = vocales; // esto equivale a lo anterior
  6. // O directamente podemos usar <vocales> y nos ahorramos un puntero global que no nos traera nada bueno

  • La aritmética de puntero no es lo más cómodo digamos. Por lo tanto a no ser que te lo exijan o te guste, puedes usar la indexación:
Código
  1. vocales[i]
  2. *(vocales+i)
Estás dos sentencias son exactamente lo mismo. Siempre puedes pasar de una nomenglatura a la otra. Y sí se pueden incrementar punteros pero debes usar paréntesis:
Código
  1. int vocales[5] = {1,2,3,4,5};
  2. int *puntero = vocales;
  3. ++puntero; // ahora <puntero> apunta a la siguiente posicion
  4. ++(*puntero); // ahora incrementamos el valor al que apunta <puntero> que es <vocales[1]> entonces <vocales> = {1,3,3,4,5}
  5. ++(*(puntero+1)); // incrementamos el valor de la siguiente posicion a la que apunta <puntero>. Ahora <vocales> = {1,3,4,4,5}
Esto es igual para el -- y tanto si lo ponemos en prefijo como en sufijo.

Por lo tanto creo que lo mejor es:
  • Crear el array <char nombre[30]> en el <main>
  • Crear el array <int vocales[5]> en el <main>
  • Usar una función <int pedirNombre(char *nombre)> para pedir el nombre al usuario y obtener su longitud.
  • Usar una función <void contarVocales(char *nombre, int longitud, int *vocales)> para contar las vocales.
Así consigues resolver el programa sin variables globales, sin memoria dinámica y usando únicamente 2 variables (<nombre> y <vocales>) :-X


Respecto a tu segundo mensaje:
Te sugiero que modifiques lo que te comento más arriba en tu primer código para no meterte con memoria dinámica (<new>). Es mejor que primero aprendas bien a pasar los parámetros antes de nada.


Título: Re: Problema con los punteros C++
Publicado por: 98Fran en 25 Agosto 2019, 21:41 pm
Funciona perfecto tambien:
Código
  1. #include <iostream>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. using namespace std;
  6.  
  7. int pedirNombre(char*);
  8. void contarVocales(char*,int,int*);
  9. void mostrarVocales(int*);
  10.  
  11.  
  12. int main(){
  13. int c_vocales[5] ={0,0,0,0,0}, longitud;  //0 == a, 1 == b ... 4 == u;
  14. char nombre[30];
  15.  
  16. longitud = pedirNombre(nombre);
  17. contarVocales(nombre,longitud,c_vocales);
  18. mostrarVocales(c_vocales);
  19.  
  20.  
  21. cout<<"\n"<<nombre<<endl;
  22.  
  23. cin.get();
  24. return 0;
  25. }
  26.  
  27. int pedirNombre(char* nombre){
  28. int longitud;
  29.  
  30. cout<<"Digite su nombre: ";
  31.  
  32. cin.getline(nombre,30,'\n');
  33. longitud = strlen(nombre);
  34.  
  35. return longitud;
  36. }
  37.  
  38. void contarVocales(char*nombre,int n,int*p_vocales){
  39.  
  40. for(int i=0;i<n;i++){
  41. switch(nombre[i]){
  42. case 'a': *(p_vocales) = *(p_vocales) + 1; break;
  43. case 'e': *(p_vocales+1) = *(p_vocales+1) + 1; break;
  44. case 'i': *(p_vocales+2) = *(p_vocales+2) + 1; break;
  45. case 'o': *(p_vocales+3) = *(p_vocales+3) + 1; break;
  46. case 'u': *(p_vocales+4) = *(p_vocales+4) + 1; break;
  47. }
  48. }
  49. }
  50.  
  51. void mostrarVocales(int* vocales){
  52. cout<<"num. de a: "<<vocales[0]<<endl;
  53. cout<<"num. de e: "<<vocales[1]<<endl;
  54. cout<<"num. de i: "<<vocales[2]<<endl;
  55. cout<<"num. de o: "<<vocales[3]<<endl;
  56. cout<<"num. de u: "<<vocales[4]<<endl;
  57. }

No sabia que que cuando pasabas un vector a una función lo podías pasar como puntero con "*", hasta lo que he visto cuando se pasaba algo por referencia a una función se hacia con &, y si querías pasar un puntero tenias que crearlo del mismo tipo que el vector, luego vincularlo al primer espacio de la memoria y luego ya se pasaba con "*".

PD: Entonces lo que paso con: (char* nombre)
  • es la posición de memoria de la posición v[0] del vector?
o
  • es un puntero del vector que se llama nombre y esta en la posición v[0] del vector con su mismo nombre?.

Y  por qué no se usa (char& letra) como por ejemplo sí pasar un solo char como 'a'.
En el caso de (char& letra) que es un paso por referencia pasas la dirección de memoria también no? ya que puedes modificar la variable en otra funciones.

PD2: Lo explicas todo muy bien jajaja gracias por la paciencia que estas teniendo conmigo pero  incluso después de haber victo los pocos videos en youtube que hay de puntero y comprado 2 cursos en udemy de c++, nadie explica en profundidad como funciona la sintaxis y sus posibles variaciones si no que te obligan a aceptarlo todo como dogma y una vez hago mis propios problemas ya no se por donde tirar.


Título: Re: Problema con los punteros C++
Publicado por: K-YreX en 25 Agosto 2019, 23:07 pm
Citar
No sabia que que cuando pasabas un vector a una función lo podías pasar como puntero con "*", hasta lo que he visto cuando se pasaba algo por referencia a una función se hacia con &
Cuando se pasa algo por referencia se pasa con &, eso es cierto. Pero un puntero no siempre se pasa por referencia.
Código
  1. void funcion1(int a); // variable por valor
  2. void funcion2(int &a); // variable por referencia
  3. void funcion3(int *pa); // puntero por valor
  4. void funcion4(int *&pa); // puntero por referencia
Diría que esos son los tipos de parámetros que podemos usar más típicos. Luego claro está que podemos hacer conversiones de uno a otro. Por ejemplo es lo mismo pasar una variable por referencia que pasar un puntero a esa variable por valor. Todo depende de lo que nos guste más o lo que más nos convenga en cada momento: si estás trabajando todo el tiempo con variables y necesitas mandar una a una función y modificarla pero no puedes retornarla porque ya tienes un <return> (o cualquier otro motivo) pues la pasas por referencia (así ahorras crear un puntero y hacer que apunte a esa variable). En cambio si por un casual estás trabajando con punteros y quieres pasar el valor del puntero (es decir la variable a la que apunta) y modificarla pues para qué vas a crear otra variable y asignarle el valor del puntero para pasarla por referencia? En este caso te ahorras trabajo pasando el puntero directamente.

Como te he comentado antes el paso de un puntero por referencia es muy aislado. Hasta donde yo he visto y además si estás empezando sólo lo necesitarás para pasar un puntero a una función y dentro de la función reservar memoria con <new> o bien pasar un array (es decir, un puntero al que ya le has hecho <new>) y liberar esa memoria con <delete>. Quitando esos casos, no creo que necesites pasar un puntero por referencia. Por lo que puedes olvidarte un poco de él hasta que veas memoria dinámica.

Citar
y si querías pasar un puntero tenias que crearlo del mismo tipo que el vector, luego vincularlo al primer espacio de la memoria y luego ya se pasaba con "*". 
Esto no es necesario pero en algunas ocasiones se hace. Cuando tú creas un vector, el propio vector funciona como un puntero que apunta a la primera posición del vector.
Código
  1. int numeros[5] = {1,2,3,4,5};
  2. // aqui podemos usar <numeros> como si fuera un puntero que apunta a &numeros[0]
  3. // por lo tanto podemos hacer cosas como:
  4. cout << *numeros << endl; // imprime: 1
  5. for(size_t i = 0; i < 5; ++i)
  6.    cout << *(numeros+i) << " " << endl; // imprime: 1 2 3 4 5

¿Y para qué sirve crear otro puntero? Bueno, imagina que tienes una función para recorrer todo un vector. Esta la podemos hacer de varias formas, por ejemplo:
Código
  1. void recorrerVector1(int *numeros, int longitud){
  2.    for(int i = 0; i < longitud; ++i)
  3.        cout << *(numeros+i) << endl;
  4. }
  5.  
  6. void recorrerVector2(int *numeros, int longitud){
  7.    for(int i = 0; i < longitud; ++i){
  8.        cout << *numeros << endl;
  9.        ++numeros;
  10.    }
  11. }
Con ambas vas a obtener el mismo resultado pero tienen una diferencia. La primera le va diciendo a <numeros> "imprime el valor que está i posiciones por delante de ti" mientras que la segunda le dice a <numeros> "imprime el valor que hay en tu posición 0 y muévete". La primera no tiene ningún inconveniente, sin embargo, la segunda sí. Si a la segunda función le pasamos el nombre del vector para que haga de puntero y avanzamos el puntero, los valores que vaya dejando atrás los perderemos para siempre. Un vector se puede encontrar en memoria siempre que tengamos un puntero apuntando a él (al comienzo de él), si perdemos el puntero, perdemos el vector. Para ello se crea otro puntero nuevo que sea el que se vaya moviendo mientras el original siempre apunta al comienzo.
Código
  1. int numeros[5] = {1,2,3,4,5};
  2. int *puntero = numeros;
  3. recorrerVector2(puntero, 5); // aqui no hay problemas porque aunque <puntero> se mueva, <numeros> siempre apunta al comienzo del vector
  4. //en cambio si hacemos esto...
  5. recorrerVector2(numeros, 5); // ... adios al vector. Ya no hay forma de volver a usarlo ni de liberarlo si fuera memoria dinamica

Citar
PD: Entonces lo que paso con: (char* nombre)
es la posición de memoria de la posición v[0] del vector?
o
es un puntero del vector que se llama nombre y esta en la posición v[0] del vector con su mismo nombre?.
Lo que pasas es lo primero que dices, la posición de memoria de la posición 0 del vector.
Citar
En el caso de (char& letra) que es un paso por referencia pasas la dirección de memoria también no? ya que puedes modificar la variable en otra funciones.
Exacto. Cuando pasas una variable por referencia siempre pasas la dirección de memoria en la que está almacenada esa variable.

Citar
Y  por qué no se usa (char& letra) como por ejemplo sí pasar un solo char como 'a'.
Respecto a esto voy a extenderme un poco más para intentar explicarlo del todo...
Este ha sido tu planteamiento de antes:
Código
  1. int pedirNombre(char& us){
  2. int longitud;
  3.  
  4. cout<<"Digite su nombre: ";
  5. cin.getline(us,30,'\n');
  6. longitud = strlen(us);
  7.  
  8. return longitud;
  9. }
¿Se puede hacer? ¿No se puede hacer? La respuesta es que sí, se puede hacer pero como todo, hay que hacerlo bien. Pasamos primero a un ejemplo más simple:
Código
  1. void funcion1(int a){
  2.    cout << "La variable vale: " << a << " y su direccion de memoria es: " << &a << endl;
  3.    // Se muestra la direccion de memoria de la copia
  4.    // IMPORTANTE: el valor se obtiene con el nombre tal cual y la direccion con &
  5. }
  6.  
  7. void funcion2(int &a){
  8.    cout << "La variable vale: " << a << " y su direccion de memoria es: " << &a << endl;
  9.    // Se muestra la direccion de memoria de la original
  10.    // IMPORTANTE: el valor se obtiene con el nombre tal cual y la direccion con &
  11. }
  12.  
  13. void funcion3(int *pa){
  14.    cout << "La variable vale: " << *pa << " y su direccion de memoria es: " << pa << endl;
  15.    // Se muestra la direccion de memoria de la original pero no de <pa> sino a la que apunta <pa>
  16.    // IMPORTANTE: el valor se obtiene con * y la direccion con el nombre tal cual
  17. }
  18.  
  19. // USO DE LAS FUNCIONES
  20. int numero = 2;
  21. funcion1(numero); // se pasa un <int>
  22. funcion2(numero); // se pasa un <int> aunque el programa ya sabe que es por referencia
  23. funcion3(numero); // ERROR: El programa espera una direccion de memoria (puntero) y le estamos pasando un <int>
  24. funcion3(&numero); // Correcto: Le pasamos una direccion de memoria sin crear un puntero auxiliar (que tambien se podria hacer)
  25.  
Lo que quiero que veas con esto es que tanto en el paso por valor como por referencia lo que pasamos es el nombre de la variable y eso que en el primer caso estamos copiando el valor y en el segundo caso estamos usando su dirección de memoria pero nosotros siempre pasamos siempre el nombre de la variable tal cual y dentro de las funciones usamos también el nombre de la variable tal cual para mostrarla. En cambio, en la tercera función no pasamos el nombre de la variable tal cual sino que pasamos su dirección de memoria y dentro de la función no usamos el nombre tal cual para mostrarla <pa> sino que usamos el operador de desreferencia (el asterisco).

Entonces volviendo a tu función. La forma más simple es esta:
Código
  1. int pedirNombre(char *nombre){
  2.    cout << "Introduce nombre: ";
  3.    cin.getline(nombre, 30, '\n');
  4.    return strlen(nombre);
  5. }
  6.  
  7. // USO DE LA FUNCION
  8. int longitud = pedirNombre(nombre); // Como hemos visto antes tiene que recibir directamente la direccion de memoria, bien asi o bien asi:
  9. int longitud = pedirNombre(&nombre[0]); // que es exactamente lo mismo

¿Se puede hacer usando el paso por referencia? Claro que se puede pero necesitamos hacer algunos cambios:
Código
  1. int pedirNombre(char &nombre){
  2.    cout << "Introduce tu nombre: ";
  3.    cin.getline(&nombre, 30, '\n');
  4.    return strlen(&nombre);
  5. }
  6. // o bien:
  7. int pedirNombre(char &nombre){
  8.    char *puntero = &nombre;
  9.    cout << "Introduce nombre: ";
  10.    cin.getline(puntero, 30, '\n');
  11.    return strlen(puntero);
  12. }
  13.  
  14. // USO DE LA FUNCION
  15. int longitud = pedirNombre(nombre[0]); // como hemos visto antes se pasa la variable y ya el programa sabe que tiene que usar su direccion de memoria

Lo importante es saber cuando se usa la dirección de memoria y cuando no pero también hay que saber cuando es necesario que lo indiquemos nosotros y cuando no. ¿Cuál usar? Pues cada uno la que más le guste pero lo ideal sería usar la más legible en cada momento y para vectores siempre va a ser más legible el paso de punteros que el de referencias.


Título: Re: Problema con los punteros C++
Publicado por: 98Fran en 26 Agosto 2019, 00:04 am
Ahora sí que sí, más claro el agua. No sabía muy bien por donde tirar, o por punteros o por referencias, la nomenclatura cuando es por referencia en una cadena o vector, pero ahora ya lo tengo todo mucho mas claro.

Supongo que cuando avance más en el temario llegare a la sección de variables dinámicas, no había puesto lo del delete[] porque con todos los otros problemas que tenía se me había pasado. (De momento solo se crear variables dinámicas ya que hizo un pequeño inciso en el curso hablando de como ahorrar espacio en la memoria utilizando ese tipo de variables ya que supongo que si es de forma didáctica un par de vectores[100] no van a saturar la RAM pero si fuera algo más elaborado supongo que tiene que haber un limite).


Muchas gracias de verdad ^^. Ya fuera offtopic xD estoy haciendo un juego con unreal y al pasarlo a multijugador los blueprints(es codigo pero en viñetas unidas por nodos, la lógica básica pero no hace falta saber punteros o funciones) no sirven ya que ocurren Bugs cuando modificas ciertos valores y hay que usar C++. Lo que no se es si luego al usar visual studio la forma de programar va a ser distinta a como funciona Dev C++.

PD: Hice la carrera de electrónica y en el primer año di informática (muuuy básico) y llegamos hasta funciones, usábamos la librería <stdlib> para todo y usábamos printf o fprintf si era para una función y scanf, he visto que en algunos post hay gente que no usa <iostream> en C++ si se supone que es la estándar, por?

PD2: He visto que en C++ también se usa la programación orientada a objetos que se usa en unreal y que se parece a java. el C++ no es un lenguaje procedural? como puede ser orientado a objetos también?.


Título: Re: Problema con los punteros C++
Publicado por: K-YreX en 26 Agosto 2019, 00:41 am
Citar
Lo que no se es si luego al usar visual studio la forma de programar va a ser distinta a como funciona Dev C++
Visual Studio al igual que Dev C++ solo es un IDE como cualquier otro: Eclipse, NetBeans, CodeBlocks, etc. Pero al final C++ es C++, es decir, el lenguaje es el lenguaje y eso no cambia. Yo por ejemplo no uso ningún IDE, todos los proyectos los hago en un editor de texto (puedes usar desde un simple Bloc de Notas hasta un editor más especializado en programación como SublimeText o Atom que permiten tener muchas extensiones para facilitar el trabajo como si de un IDE se tratara) y los compilo desde la Terminal (en Linux) lo que equivaldría a hacerlo desde la Consola de Windows. Quiero decir que da igual dónde escribas tu código.

Citar
PD: Hice la carrera de electrónica y en el primer año di informática (muuuy básico) y llegamos hasta funciones, usábamos la librería <stdlib> para todo y usábamos printf o fprintf si era para una función y scanf, he visto que en algunos post hay gente que no usa <iostream> en C++ si se supone que es la estándar, por?
Normalmente cuando se trabaja a bajo nivel se usa mucho el lenguaje C que trabaja a más bajo nivel que C++. C se caracteriza por la librería <stdio.h> que contiene las funciones <printf()>, <scanf()>, <fprintf()>, etc mientras que C++ se caracteriza por <iostream> que engloba <cin>, <cout> entre otros.
C++ es como una expansión de C, por lo que todo lo que se podía hacer en C, se puede hacer en C++, pero en muchas ocasiones en C++ se crearon formas más sencillas de hacer las cosas al no ser de tan bajo nivel. Esto genera una gran confusión entre si estás aprendiendo C o C++. Un programa en C (fichero.c) lo puedes compilar como código fuente C (.c) o como código fuente C++ (.cpp), sin embargo, al revés, no. De ahí que muchas personas digan que programan en C++ y usen <stdio.h>, <stdlib.h>, etc. C++ también tiene sus propias versiones para estas librerías que tienen el mismo nombre quitando el <.h> del final y añadiendo una <c> al principio: <cstdio>, <cstdlib>, etc.

Citar
PD2: He visto que en C++ también se usa la programación orientada a objetos que se usa en unreal y que se parece a java. el C++ no es un lenguaje procedural? como puede ser orientado a objetos también?
El lenguaje C siempre ha sido uno de los más claros ejemplos de lenguaje procedural ya que permite dividir un problema en subproblemas que se resolverán mediante procedimientos (funciones). El lenguaje C++ se desarrolló a partir de C para hacer como una expansión de C que trabajase con el paradigma de programación orientada a objetos pero por ello no deja de ser un lenguaje procedural. Un lenguaje puede tener más de un paradigma de programación como es el caso.

PD: Te recomiendo una página que es cplusplus. Te dejo el enlace AQUÍ (http://cplsuplus.com) Ahí tienes un apartado a la izquierda de la página llamado <Reference> que contiene muchas librerías con su nombre en C y en C++. Además de otros archivos de cabecera como son los contenedores de la STL (muy útiles y cómodos de usar) y otros; y dentro de cada librería se encuentran sus funciones y constantes con explicaciones de uso y ejemplos. Está en inglés pero es muy fácil de entender y seguro que te saca de muchos apuros. Suerte. :-X


Título: Re: Problema con los punteros C++
Publicado por: 98Fran en 26 Agosto 2019, 18:15 pm
He hecho un pequeño programa con las tres formas de pasar vectores por funciones que me has comentando para interiorizarlo un poco y que no se me olviden xD, pero tengo un problema a la hora de imprimir la dirección de memoría en donde queda almacenada la cadena.

Código
  1. #include <iostream>
  2. #include <cstring>
  3.  
  4. using namespace std;
  5.  
  6. void pedirNombre1(char*);
  7. void pedirNombre2(char*);
  8. void pedirNombre3(char&);
  9. void contadorVocales1(char*);
  10. void contadorVocales2(char*);
  11. void contadorVocales3(char&);
  12.  
  13.  
  14. int main(){
  15. char nombre1[30], *p_nombre;
  16. char nombre2[30];
  17. char nombre3[30];
  18.  
  19. p_nombre = &nombre1[0];
  20.  
  21. pedirNombre1(p_nombre);
  22. pedirNombre2(nombre2);
  23. pedirNombre3(nombre3[0]);
  24. contadorVocales1(p_nombre);
  25. contadorVocales2(nombre2);
  26. contadorVocales3(nombre3[0]);
  27.  
  28.  
  29. cin.get();
  30. return 0;
  31. }
  32.  
  33. void pedirNombre1(char *p_nombre){
  34. cout<<"Ej.1 -- Digite una frase: ";
  35. cin.getline(p_nombre,30,'\n');
  36. }
  37.  
  38. void pedirNombre2(char *daigual2){
  39. cout<<"\nEj.2 -- Digite una frase: ";
  40. cin.getline(daigual2,30,'\n');
  41. }
  42.  
  43. void pedirNombre3(char &daigual3){
  44. cout<<"\nEj.3 -- Digite una frase: ";
  45. cin.getline(&daigual3,30,'\n');
  46. }
  47.  
  48. void contadorVocales1(char* p_daigual){
  49.  
  50. cout<<"\n------------------------------------------------------";
  51. cout<<"\nEj.1 -- La frase digitada es: "<<p_daigual<<". En la direccion: "<<*p_daigual;
  52.  
  53. }
  54.  
  55. void contadorVocales2(char* daigual){
  56.  
  57. cout<<"\n------------------------------------------------------";
  58. cout<<"\nEj.1 -- La frase digitada es: "<<daigual<<". En la direccion: "<<*daigual;
  59.  
  60. }
  61.  
  62. void contadorVocales3(char& daigual){
  63.  
  64. cout<<"\n------------------------------------------------------";
  65. cout<<"\nEj.1 -- La frase digitada es: "<<&daigual<<". En la direccion: "<<daigual;
  66.  
  67. }

Si uso con char me muestra toda la cadena:

Código
  1. char nombre[] = {'a','b','c'}, *p_nombre2;
  2. cout<<"Dir.1: "<<nombre[1]<<" | "<<p_nombre2<<endl;
  3.  
  4. //Salida: Dir.1: b | abc

Pero si lo uso con int me muestra la posición, por?

Código
  1. int nombre[] = {1,2,3}, *p_nombre2;
  2. cout<<"Dir.1: "<<nombre[1]<<" | "<<p_nombre2<<endl;
  3. //Salida: Dir.1: 2 | 0x6ffdf0

PD: pongo daigual para así acordarme que no hace falta poner el mismo nombre de la variable de main en la función, normalmente suelo acortar el nombre o alargarlo pero como era un ejemplo lo he dejado asi.


Título: Re: Problema con los punteros C++
Publicado por: K-YreX en 26 Agosto 2019, 18:50 pm
Citar
Pero si lo uso con int me muestra la posición, por?
Código
  1. int nombre[] = {1,2,3}, *p_nombre2;
  2. cout<<"Dir.1: "<<nombre[1]<<" | "<<p_nombre2<<endl;
  3. //Salida: Dir.1: 2 | 0x6ffdf0
En este caso creo que no hay dudas. <p_nombre2> sería un puntero que apunta al mismo sitio que <nombre> aunque no se vea ahí (es decir, imagino que has omitido el <p_nombre2 = nombre> o <p_nombre2 = &nombre[0]> que es equivalente). Entonces al mostrar <nombre[1]> estamos mostrando el valor almacenado en la posición 1 del array y al mostrar <p_nombre2> estamos mostrando la dirección de memoria a la que está apuntando.

Citar
Si uso con char me muestra toda la cadena:
Código
  1. char nombre[] = {'a','b','c'}, *p_nombre2;
  2. cout<<"Dir.1: "<<nombre[1]<<" | "<<p_nombre2<<endl;
  3. //Salida: Dir.1: b | abc
Aquí es donde la cosa cambia, los arrays de <char> que se conocen también como cadenas estilo C porque existían en C y fueron heredadas por C++. Cuando tienes un array de <int> por ejemplo, para mostrarlo hacemos lo siguiente:
Código
  1. for(int i = 0; i < size; ++i)
  2.    cout << arrayEnteros[i] << " ";
Pero imagina que tienes una cadena de <char> con un nombre y que quieres mostrar el nombre. Sería muy incómodo tener que hacer:
Código
  1. char nombre[] = "Pepe";
  2. cout << "Tu nombre es: ";
  3. for(int i = 0; i < 4; ++i)
  4.    cout << nombre[i];
Entonces como las cadenas de <char> no se suelen usar sólo para almacenar valores aislados sino también palabras o frases, para hacerlo más cómodo el lenguaje permite hacer:
Código
  1. char nombre[] = "Pepe";
  2. cout << "Tu nombre es: " << nombre << endl;
Y la máquina ya entiende que tiene que mostrar desde donde apunta <nombre> (&nombre[0]) hasta el caracter de fin de cadena '\0'. Cosa que con un array de enteros no podemos hacer. Entonces digamos que puedes entenderlo como que los arrays de <char> tienen sus excepciones respecto al resto.

Además en C++, al introducir la POO y con ello las clases y objetos, aparece la clase <string> que funciona como una cadena <char> pero sin necesidad de tener que reservar nosotros la memoria:
Código
  1. string nombre = "Pepe";
  2. cout << "La primera letra de " << nombre << " es: " << nombre[0] << endl;


Título: Re: Problema con los punteros C++
Publicado por: 98Fran en 26 Agosto 2019, 23:51 pm
Gracias!, es un poco lió que para cada cosa cambien la nomenclatura. Esto de los punteros en serio es un invento del diablo jajaja. Estaba siguiendo hace nada con el curso y ahora estaba viendo punteros con matrices, el otro programador usaba punteros y variables globales y yo lo intente en un principio con valores desde el main() y pasarlos a la función y me da problemas, luego intente hacerlo por variables globales y también se traba o al escribir la matriz o a la hora de mostrarla, te paso el codigo.
Código
  1. #include <iostream>
  2. #include <cstdlib>
  3. using namespace std;
  4.  
  5. void pedirDatos(int**,int&,int&);
  6. void imprimirDatos(int**,int,int);
  7.  
  8. int **p_m2;
  9.  
  10. int main(){
  11. int **p_m,fil,col;
  12.  
  13. pedirDatos(p_m,fil,col);
  14. //imprimirDatos(p_m,fil,col); No funciona, se para al mostrar la matriz
  15. cout<<*(*(p_m2+1)+1); //tampoco va, ahora se corta al insertar las variabes
  16.  
  17. //liberar memoria;
  18. for(int i=0;i<fil;i++){
  19. delete[] p_m[i];
  20. }
  21.  
  22. delete[] p_m;
  23.  
  24. cin.get();
  25. return 0;
  26. }
  27.  
  28. void pedirDatos(int** p_m,int &fil,int &col){
  29. cout<<"Digite numero de Filas: ";
  30. cin>>fil;
  31. cout<<"Digite numero de Columnas: ";
  32. cin>>col;
  33.  
  34. //Reservar memoria para matriz dinámica.
  35. p_m2 = new int*[fil]; //Reservando memoria para las filas.
  36. for(int i=0;i<fil;i++){
  37. p_m2[i] = new int[col]; //Reservando memoria para columnas
  38. }
  39.  
  40. cout<<"\nDigite elementos matriz: "<<endl;
  41. for(int i=0;i<col;i++){
  42. for(int j=0;j<fil;j++){
  43. cout<<"Digite un numero ["<<i<<"]["<<j<<"]: ";
  44. cin>>*(*(p_m+i)+j);
  45. }
  46. }
  47.  
  48. //Comprobar si lo ha grabado bien:
  49. for(int i=0;i<fil;i++){
  50. for(int j=0;j<col;j++){
  51. cout<<*(*(p_m+i)+j);
  52. }
  53. cout<<"\n";
  54. }//funciona, edit: despues de tocarlo todo 3000 veces ya no xD.
  55. }
  56.  
  57. void imprimirDatos(int** p_m,int f,int c){
  58. cout<<"\n------------------------------------\nLa matriz es: "<<f<<"x"<<c<<"\n\n";
  59. cout<<*(*(p_m+1)+1); //Tambien se traba a intentar imprimirlo
  60. /*for(int i=0;i<f;i++){
  61. for(int j=0;j<c;j++){
  62. cout<<*(*(p_m+i)+j);
  63. }
  64. cout<<"\n";
  65. }*/
  66. }

Lo que esta en /* es que me falla y para no borrarlo he intentarlo por variables globales e intentar imprimir un solo dato de la matriz lo deje así.

PD: ahora estoy intentando usar variables de columna y fila dentro de la función pero ni eso, se traba al intentar grabar la matriz.
Código
  1. void pedirDatos(int** p_m,int &fil,int &col){
  2. int f,c;
  3.  
  4. cout<<"Digite numero de Filas: ";
  5. cin>>f;
  6. cout<<"Digite numero de Columnas: ";
  7. cin>>c;
  8. cout<<f<<c<<endl; //Comprobar que guarde bien
  9. //Reservar memoria para matriz dinámica.
  10. p_m2 = new int*[f]; //Reservando memoria para las filas.
  11. for(int i=0;i<fil;i++){
  12. p_m2[i] = new int[c]; //Reservando memoria para columnas
  13. }
  14.  
  15. cout<<"\nDigite elementos matriz: "<<endl;
  16. for(int i=0;i<c;i++){
  17. for(int j=0;j<f;j++){
  18. cout<<"Digite un numero ["<<i<<"]["<<j<<"]: ";
  19. cin>>*(*(p_m+i)+j);
  20. }
  21. }

SALIDA: Digite numero de Filas: 3
Digite numero de Columnas: 2
32

Digite elementos matriz:
Digite un numero 0 0:
--------------------------------
Process exited after 3.64 seconds with return value 3221225477
Presione una tecla para continuar . . .


Título: Re: Problema con los punteros C++
Publicado por: K-YreX en 27 Agosto 2019, 00:25 am
Has hecho tantos cambios que estás mezclando <p_m> con <p_m2> en las funciones... :xD
Para evitar estas cosas es mejor usar nombres que se vean mejor y que se distingan mas facilmente. Y si te acostumbras a usar buenos nombres siempre al final los usarás hasta cuando estés haciendo programas de prueba.

Bueno el tema de matrices... Ibas bastante bien. Pero hay un detalle que te puse unos comentarios atrás... Voy a buscarlo:
Citar
Como te he comentado antes el paso de un puntero por referencia es muy aislado. Hasta donde yo he visto y además si estás empezando sólo lo necesitarás para pasar un puntero a una función y dentro de la función reservar memoria con <new> o bien pasar un array (es decir, un puntero al que ya le has hecho <new>) y liberar esa memoria con <delete>. Quitando esos casos, no creo que necesites pasar un puntero por referencia. Por lo que puedes olvidarte un poco de él hasta que veas memoria dinámica.

Entonces tienes dos opciones:
  • Opcion 1: Reservar memoria en el <main> y pasar el doble puntero por valor (como lo estás pasando ahora).
  • Opcion 2: Pasar el doble puntero por referencia y listo. Ya que has llegado hasta donde has llegado, te recomiendo esta segunda:
Código
  1. void pedirDatos(int**&, int&, int&);
Con ese cambio ya estaría listo. A la hora de llamar a la función solo tienes que pasarle el nombre como estás haciendo (es decir, que no debes cambiar la llamada a la función del <main>).

Y en el bucle para pedir la matriz de <pedirDatos()> tienes un pequeño error. Si trabajas siempre con: matriz[filas][columnas], entonces para mostrar la matriz el bucle externo maneja las filas y el interno las columnas (lo tienes al revés).
Si ves que se te complica la aritmética de punteros, puedes usar indexación que es más cómodo de ver y más fácil de trabajar y cuando ya tengas más experiencia usar la aritmética de punteros:
Código
  1. cout << *(*(matriz + i) + j) << endl; // aritmetica de punteros
  2. cout << matriz[i][j] << endl; // indexacion


Título: Re: Problema con los punteros C++
Publicado por: 98Fran en 27 Agosto 2019, 16:15 pm
Ahora sí jajaja, ayer estuve apunto de probar el método de pasar el puntero por referencia, pero como no sabía exactamente lo que hacía deseche esa opción  :xD.

Al final a quedado algo tal que así:
Código
  1. #include <iostream>
  2. #include <stdlib.h>
  3. using namespace std;
  4.  
  5. void pedirDatos(int**&,int&,int&);
  6. void imprimirDatos(int**,int,int);
  7.  
  8. int main(){
  9. int **p_m,fil,col;
  10.  
  11. pedirDatos(p_m,fil,col);
  12. imprimirDatos(p_m,fil,col);
  13.  
  14. //liberar memoria;
  15. for(int i=0;i<fil;i++){
  16. delete[] p_m[i];
  17. }
  18.  
  19. delete[] p_m;
  20.  
  21. cin.get();
  22. return 0;
  23. }
  24.  
  25. void pedirDatos(int**& p_m,int &fil,int &col){
  26.  
  27. cout<<"Digite numero de Filas: ";
  28. cin>>fil;
  29. cout<<"Digite numero de Columnas: ";
  30. cin>>col;
  31.  
  32. //Reservar memoria para matriz dinámica.
  33. p_m = new int*[fil]; //Reservando memoria para las filas.
  34. for(int i=0;i<fil;i++){
  35. p_m[i] = new int[col]; //Reservando memoria para columnas
  36. }
  37.  
  38. cout<<"\nDigite elementos matriz: "<<endl;
  39. for(int i=0;i<col;i++){
  40. for(int j=0;j<fil;j++){
  41. cout<<"Digite un numero ["<<i<<"]["<<j<<"]: ";
  42. cin>>*(*(p_m+i)+j);
  43. }
  44. }
  45. }
  46.  
  47. void imprimirDatos(int** p_m,int f,int c){
  48. cout<<"\n------------------------------------\nLa matriz es: "<<f<<"x"<<c<<"\n\n";
  49. for(int i=0;i<f;i++){
  50. for(int j=0;j<c;j++){
  51. cout<<*(*(p_m+i)+j)<<" ";
  52. }
  53. cout<<"\n";
  54. }
  55. }

Esto de los punteros me parece todo un mundo la verdad, para cada cosa me cambian la nomenclatura, yo no se como puedes acordarte de todo esto si no lo usas diariamente jajaja.

PD: No se suponía que un puntero es un referencia al espacio de memoria? y que usando "cin>>puntero" te permite guardar el valor en ese espacio, por qué ahora al usar new hace falta pasarlo como puntero referencia y no lo englobaron en 1 sola categoría???, estas cosas son las que me matan  ;D ;D ;D.

PD2: Donde aprendiste a programar por cierto?, al final te voy a tener que contratar como profesor particular xDDD.

PD3: Acabo de hacer un problema para ver si lo interiorizado todo correctamente y ahora parece que sí, a la primera sin fallos (sin contar erratas que de esas siempre hay xD)

Código
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. void pedirMatriz(int**&,int**&,int&,int&,int&,int&);
  6. bool sumarMatriz(int**,int**,int**&,int,int,int,int);
  7. void mostrarSuma(int**,int,int);
  8.  
  9. int main(){
  10. int **p_m1, **p_m2, c1, f1/*filas y columnas de la matriz dinámica 1*/, c2, f2;
  11. int **suma;
  12. bool coinciden;
  13.  
  14. pedirMatriz(p_m1,p_m2,c1,f1,c2,f2);
  15. coinciden = sumarMatriz(p_m1,p_m2,suma,c1,f1,c2,f2);
  16.  
  17. if (coinciden == true){
  18. mostrarSuma(suma,f1,c1);
  19.  
  20. //Borrar memoria matriz suma (Solo si se crea)
  21. for(int i=0;i<f1;i++){
  22. delete[] suma[i];
  23. }
  24. delete[] suma;
  25. }
  26. else{
  27. cout<<"Las matrices no tienen las mismas dimensiones.";
  28. }
  29.  
  30. //Borrar memoria M[1] y M[2];
  31. for(int i=0;i<f1;i++){
  32. delete[] p_m1[i];
  33. }
  34. delete[] p_m1;
  35.  
  36. for(int i=0;i<f2;i++){
  37. delete[] p_m2[i];
  38. }
  39. delete[] p_m2;
  40.  
  41. //Fin programa
  42. cin.get();
  43. return 0;
  44. }
  45. void pedirMatriz(int**& m1,int**& m2,int& f1,int& c1,int& f2,int& c2){
  46.  
  47. cout<<"Digite num. de filas para M[1]: "; cin>>f1;
  48. cout<<"Digite num. de columnas para M[1]: "; cin>>c1;
  49. cout<<"\nDigite num. de filas para M[2]: "; cin>>f2;
  50. cout<<"Digite num. de columnas para M[2]: "; cin>>c2;
  51.  
  52. //Revervar espacio puntero filas, ya que cada fila apunta al resto de columnas (Como un puntero de un vector encima de otro);
  53. m1 = new int*[f1];
  54.  
  55. //Reservar espacio columnas;
  56. for(int i=0;i<f1;i++){
  57. m1[i] = new int[c1];
  58. }
  59.  
  60. cout<<"\n-----------------------------------------"<<endl;
  61. cout<<"Digite los valores de M[1]: "<<endl;
  62.  
  63. //Empezar recogida de datos M[1];
  64. for(int i=0;i<f1;i++){
  65. for(int j=0;j<c1;j++){
  66. cout<<"Valor de M1["<<i<<"]["<<j<<"]: ";
  67. cin>>*(*(m1+i)+j); //Equivale a m1[i][j]
  68. }
  69. }
  70.  
  71. //Reservar espacio memoria M[2];
  72. m2 = new int*[f2];
  73.  
  74. for(int i=0;i<f2;i++){
  75. m2[i] = new int[c2];
  76. }
  77.  
  78. cout<<"\n-----------------------------------------"<<endl;
  79. cout<<"Digite los valores de M[1]: "<<endl;
  80.  
  81. //Empezar recogida de datos M[1];
  82. for(int i=0;i<f2;i++){
  83. for(int j=0;j<c2;j++){
  84. cout<<"Valor de M2["<<i<<"]["<<j<<"]: ";
  85. cin>>m2[i][j]; //Equivale a *(*(m2+i)+j);
  86. }
  87. }
  88. }
  89.  
  90. bool sumarMatriz(int** m1,int** m2,int**& suma,int f1,int c1,int f2,int c2){
  91. bool coin;
  92.  
  93. if(f1 == f2 && c1 == c2){
  94. //Crear matriz dinamica suma; uso f1 ya que f1 == f2, asi no creo mas variables;
  95. suma = new int*[f1];
  96.  
  97. for(int i=0;i<f1;i++){
  98. suma[i] = new int[c1];
  99. }
  100.  
  101. for(int i=0;i<f1;i++){
  102. for(int j=0;j<c1;j++){
  103. suma[i][j] = m1[i][j] + m2[i][j];
  104. }
  105. }
  106. coin = true;
  107. }
  108. else{
  109. coin = false;
  110. }
  111.  
  112. return coin;
  113. }
  114.  
  115. void mostrarSuma(int** suma,int f1, int c1){
  116.  
  117. cout<<"\n-----------------------------------------"<<endl;
  118. cout<<"La suma de las 2 matrices es: "<<endl;
  119.  
  120. for(int i=0;i<f1;i++){
  121. for(int j=0;j<c1;j++){
  122. cout<<suma[i][j]<<" "; //Es lo mismo que usar: *(*(suma+i)+j);
  123. }
  124. cout<<endl;
  125. }
  126. }

Espero que esto de los punteros no se complique más o al final acabare loco  ;-) ;-) ;-)


Título: Re: Problema con los punteros C++
Publicado por: K-YreX en 27 Agosto 2019, 17:25 pm
Bueno, sigues teniendo un pequeño error. Fíjate que para mostrar la matriz haces:
Código
  1. for(int i = 0; i < filas; ++i){
  2.    for(int j = 0; j < columnas; ++j)
  3.        cout << *(*matriz + i) + j) << " ";
  4.    cout << endl;
  5. }
En cambio en la función <pedirDatos()> para almacenar los valores en la matriz haces:
Código
  1. for(int i = 0; i < columnas; ++i){
  2.    for(int j = 0; j < filas; ++j)
  3.        cout << *(*matriz + i) + j) << " ";
  4.    cout << endl;
  5. }
Por lo que este segundo bloque está mal. En matrices cuadradas no vas a notar la diferencia pero en matrices que no son cuadradas vas a tener errores de acceso a memoria.

Citar
PD: No se suponía que un puntero es un referencia al espacio de memoria? y que usando "cin>>puntero" te permite guardar el valor en ese espacio, por qué ahora al usar new hace falta pasarlo como puntero referencia y no lo englobaron en 1 sola categoría???, estas cosas son las que me matan  ;D ;D ;D.
Cuando pasas un puntero estás pasando su contenido que es la dirección de memoria del dato al que está apuntando.
Código
  1. int numero = 2; // pongamos que se guarda en 0x1 (voy a usar numeros cortos para que sea mas sencillo)
  2. cout << "Numero vale: " << numero << " y su direccion de memoria original es: " << &numero << endl;
  3. // Salida: Numero vale: 2 y su direccion de memoria original es: 0x1
  4.  
  5. // Pasamos la variable por referencia para pasar la direccion de memoria en la que esta guardado <numero> (0x1)
  6. void incrementar(int &numero){ // pasamos 0x1
  7.    ++numero;
  8.    cout << "Numero vale: " << numero << " y su direccion de memoria ORIGINAL es: " << &numero << endl;
  9. }
  10. // Salida: Numero vale: 3 y su direccion de memoria ORIGINAL es: 0x1
  11.  
  12. int *p_numero = &numero; // pongamos que <p_numero> se guarda en 0x5 y dentro de 0x5 guarda la direccion de <numero> 0x1
  13. // Pasamos un puntero por valor, entonces estamos haciendo una copia de su contenido pero su contenido ya es la direccion de memoria de <numero> 0x1
  14. void incrementar(int *p_numero){ // a la funcion llega 0x1 y se guarda en una copia del puntero en 0x13 por ejemplo
  15.    ++(*p_numero);
  16.    cout << "Numero vale: " << *p_numero << " y su direccion de memoria ORIGINAL es " << p_numero << endl;
  17.    cout << "La direccion de memoria del puntero es: " << &p_numero << endl;
  18. }
  19. // Salida: Numero vale: 4 y su direccion de memoria ORIGINAL es: 0x1
  20. //         La direccion de memoria del puntero es: 0x13 // Aqui se ve la direccion de la copia, no 0x5
  21.  
  22. // Pasamos el puntero por referencia, entonces estamos pasando la direccion de memoria EN LA QUE ESTA EL PUNTERO (0x5), no a la que apunta (<numero>)
  23. void incrementar(int *&p_numero){ // a la funcion llega 0x5 que sigue apuntando a 0x1
  24.    ++(*p_numero);
  25.    cout << "Numero vale: " << *p_numero << " y su direccion de memoria ORIGINAL es " << p_numero << endl;
  26.    cout << "La direccion de memoria del puntero ORIGINAL es: " << &p_numero << endl;
  27. }
  28. // Salida: Numero vale: 5 y su direccion de memoria ORIGINAL es: 0x1
  29. //          La direccion de memoria del puntero ORIGINAL es: 0x5
  30. }

Una vez visto esto, el tema es que los operadores <new> y <delete> no actúan en la dirección a la que apunta el puntero, sino en la dirección en la que está el puntero. Por eso si quisieramos hacer <new> o <delete> en el ejemplo anterior tendríamos que hacerlo sobre la dirección de memoria 0x5. Si el puntero lo pasamos por valor, estamos haciendo un <new> sobre 0x13, pero la dirección 0x5 no se ha enterado de lo que le han hecho a 0x13.
Por eso en ese caso hay que pasar el puntero por referencia.

Citar
PD2: Donde aprendiste a programar por cierto?
Me metieron en este mundo en el instituto, me gustó y me quedé. Si quieres un consejo: no te quedes con que tu programa funciona después de cambiar tal cosa, investiga por qué funciona después de ese cambio. No hacen falta programas enormes para aprender, hasta el programa más tonto como el código que he puesto arriba sirve para ver cómo funcionan las direcciones de memoria. Después de 2 años de Ingeniería Informática te puedo asegurar que es mucho mejor aprender por libre. Existen recursos como internet de sobra para poder hacerlo y cada uno tiene su ritmo de aprendizaje, si te metes a aprender en un sistema estandarizado no vas a profundizar en nada y no te va a dar tiempo a practicar todo lo que veas y la programación se aprende programando, no leyendo libros y códigos ya hechos una y otra vez.


Título: Re: Problema con los punteros C++
Publicado por: 98Fran en 27 Agosto 2019, 19:54 pm
Gracias por el consejo, cuando hago algo me gusta saber por qué lo hago y como funciona ese algo para poder entenderlo, ya que si no lo entiendo simplemente estaría copiando y pegando y seria perder el tiempo.

PD: Si lo he entendido bien esto:
Código
  1. void funcion(int**& p_m) // usando new
  2. //seria equivalente a:
  3. void funcion(int m[][100]

La diferencia radicaría en que en la primera se usa para crear una matriz dinámica y así ahorrar espacio en la memoria y en la segunda ya tienes el espacio reservado, no?

PD2: las variables dinámicas no tienes nombre? o solo se les puede llamar a través del puntero del que se crean?


Título: Re: Problema con los punteros C++
Publicado por: K-YreX en 27 Agosto 2019, 21:23 pm
Citar
PD: Si lo he entendido bien esto:
Código
  1. void funcion(int**& p_m) // usando new
  2. //seria equivalente a:
  3. void funcion(int m[][100]
La diferencia radicaría en que en la primera se usa para crear una matriz dinámica y así ahorrar espacio en la memoria y en la segunda ya tienes el espacio reservado, no?
Respecto a esto, más que para qué se usa, es qué estoy haciendo con cada cosa. La primera cosa a tener en cuenta es, dicho de una forma poco exacta es que unos corchetes se pueden sustituir por un asterisco y un asterisco por unos corchetes (hablando de arrays como parámetros). Entonces tenemos estas opciones principalmente:
Código
  1. void funcion1(int **matriz); // pasamos la direccion de memoria del elemento [0][0]
  2. void funcion2(int **&matriz); // pasamos la direccion de memoria que apunta a la direccion de memoria del elemento [0][0]
  3. void funcion3(int matriz[][TAM]); // igual que funcion1() pero necesitamos indicar todas las dimensiones excepto la primera
  4. void funcion4(int &matriz[][TAM]); // igual que funcion2() pero indicando las dimensiones como en la funcion3()
Luego claro está que podemos mezclar asteriscos y corchetes y decir "pues quito un par de corchetes y pongo un asterisco" o al revés. Recalco: lo de intercambiar asteriscos y corchetes es para arrays. Si queremos pasar un puntero que no es un array no podemos usar corchetes.
No puedo explicarte mucho más de esto ya que el tema de los arrays estáticos ha ido evolucionando mucho y no estoy muy puesto en ello pero ahora por ejemplo se permite crear un array estático indicando su tamaño en una variable cosa que en versiones anteriores no se podía y de ahí lo de declarar los tamaños usando <#define> (sobre todo en C) o usando una constante global al comienzo del programa <const int> (en C++).

Citar
PD2: las variables dinámicas no tienes nombre? o solo se les puede llamar a través del puntero del que se crean?
Claro que tienen nombre. El puntero. Lo puedes entender como si al hacer:
Código
  1. int miArray[5];
El compilador por dentro hiciese:
Código
  1. int *miArray = new int[5];
En el primer caso el nombre del array está claro. Y en el segundo? Pues es lo mismo, el nombre es el del puntero que lo está apuntando. Ya que con memoria dinámica se pueden hacer cosas como:
Código
  1. int *miArray = new int[10];
  2. int *otroArray = new int[5];
  3. // Queremos intercambiarlos pero en cuanto asignemos algo a uno de esos punteros, perderemos el array entonces:
  4. int *auxiliar = miArray; // Ahora el primer array tiene dos nombres: <auxiliar> y <miArray>
  5. miArray = otroArray; // Ahora hacemos que el puntero <miArray> apunte al mismo sitio que <otroArray>
  6. otroArray = auxiliar; // Y ahora <otroArray> apunta al mismo sitio que <auxiliar> que era el array original al que apuntaba <miArray>
Otra duda típica en estos casos es: ¿y hago algún <delete> por ejemplo a <auxiliar>? Pues no. El delete no borra el puntero, borra la memoria dinámica a la que apunta ese puntero. Entonces si hacemos por ejemplo:
Código
  1. delete [] auxiliar;
<auxiliar> a dónde estaba apuntando? Al mismo array que <otroArray>. Pues entonces <otroArray> ya sólo es un puntero ya que el array que habíamos reservado, nos lo hemos cargado con ese <delete>.


Título: Re: Problema con los punteros C++
Publicado por: 98Fran en 27 Agosto 2019, 22:15 pm
Bueno saberlo  ;-) ;-) ;-). Creo que ya he visto todo de los punteros creo. No se si hay punteros de funciones (juraría haber visto algo como: void *funcion() en alguna parte, pero no le encuentro sentido ponerle un puntero a una función a no ser que sea un puntero a un valor que devuelva. Supongo que cuando llegue a la parte de POO haré otro post lleno de preguntas xD, a ver si el profe del curso de udemy se pone las pilas y explica un poco como tu y seguro que no vuelvo a poner ningún post más  :xD :xD :xD.

PD: que sería un mensaje sin PD  ;-) ;-) ;-) :silbar:, lo bueno del post es que si cuando empiece la uni se me olvida alguna cosita de los puntero me releo el post y ya estaría  :rolleyes: :rolleyes:  :rolleyes:.


Título: Re: Problema con los punteros C++
Publicado por: K-YreX en 27 Agosto 2019, 23:14 pm
Citar
Creo que ya he visto todo de los punteros creo
Claro que no :xD :xD. Para trabajar a un nivel básico o incluso un poco avanzado ya tienes pero los punteros no son sólo lo que has visto. Como bien dices aunque un poco mezclado tienes por una parte los punteros de tipo <void> y por otra parte los punteros a funciones.

Los punteros de tipo <void> se usan para apuntar a un dato sin especificar el tipo de dato y así mediante estos punteros podemos pasar diferentes tipos de datos a una misma función. Esto da mucha libertad a la hora de trabajar con ello (pero también hay que saber cuándo de verdad compensa usarlos, de momento es mejor que no los uses). A la vez que da libertad también la quita ya que no podemos desreferenciar el puntero (mediante *) para trabajar con su valor sin antes hacer un <cast>.
Código
  1. void incrementar(void *puntero, int size){
  2.    if(size == sizeof(char)){
  3.        char *p_char = (char*)puntero;
  4.        ++(*p_char);
  5.    }
  6.    if(size == sizeof(int)){
  7.        char *p_int = (int*)puntero;
  8.        ++(*p_int);
  9.    }
  10. }
  11.  
  12. int main(){
  13.    char letra = 'a';
  14.    int numero = 1;
  15.    incrementar(&letra, sizeof(letra));
  16.    incrementar(&numero, sizeof(numero));
  17.    cout << letra << " - " << numero << endl;
  18. }
Código:
Salida: b - 2

Por otro lado están los punteros a funciones. Esto sirve para pasarle a una función, otra función.
Código
  1. int sumar(int a, int b){
  2.    return a + b;
  3. }
  4.  
  5. int restar(int a, int b){
  6.    return a - b;
  7. }
  8.  
  9. int realizarOperacion(int (*operacion)(int,int), int a, int b){
  10.    int resultado = (*operacion)(a,b);
  11.    return resultado;
  12. }
  13.  
  14. int main(){
  15.    int a = 4, b = 1;
  16.    int (*realizarResta)(int,int) = restar;
  17.    int resultadoSuma = realizarOperacion(sumar, a, b);
  18.    int resultadoResta = realizarOperacion(realizarResta, resultadoSuma, b);
  19. }
Este es un ejemplo típico de punteros a funciones. Está claro que no parece necesario usarlos pero pueden darse casos en los que sí y entonces pues ahí está la opción de hacerlo así.

Podía haber hecho un último mensaje corto pero eso no es lo mío. Dejo un ejemplo de cada uno de estos y así podríamos decir que este tema del foro queda bastante completo en cuanto a punteros se refiere.
PD: Te recomiendo para tenerlo más a mano hacerte un programa (por ejemplo punteros.cpp o punterosExplicaciones.cpp) y ponerte ahí todo lo que has ido viendo que se puede o no se puede hacer y con algunos comentarios. Y en caso de que necesites recordar algo más en profundidad entonces ya puedes volver aquí y buscar este tema. Suerte :-X


Título: Re: Problema con los punteros C++
Publicado por: 98Fran en 28 Agosto 2019, 00:30 am
Esto es la biblia de los punteros ya xD, lo tengo guardado en la barra de herramientas para tenerlo a la vista entro al chrome y ya le doy a abrir jajaja.

PD: por lo que he visto en el curso no se da más sobre punteros, ya pasa a pilas, a ver que tal jajaja. Acabo de hacer un programa donde podría usar un puntero de una función no?:
Código
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. void pedirDatos(int**&,int**&,int&,int&,int&,int&);
  6. void multiplicarMatrices(int**,int**,int**&,int,int,int);
  7. int multi(int**,int**,int,int,int);
  8. void mostrarMatriz(int**,int,int);
  9.  
  10. int main(){
  11. int **m1,**m2,c1,f1,c2,f2;
  12. int **mMultiplicacion;
  13.  
  14. pedirDatos(m1,m2,f1,c1,f2,c2);
  15. multiplicarMatrices(m1,m2,mMultiplicacion,f1,c2,c1); //c1 == f2 == c_f;
  16. mostrarMatriz(mMultiplicacion,f1,c2);
  17.  
  18.  
  19.  
  20. cin.get();
  21. return 0;
  22. }
  23.  
  24. void pedirDatos(int**& m1, int**& m2, int& f1, int& c1, int& f2, int& c2){
  25.  
  26. //Repetir proceso hasta que las dimensiones de las matrices sean multiplicables;
  27. do{
  28. //Definir filas y columnas M[1];
  29. cout<<"Digite numero de filas de M[1]: "; cin>>f1;
  30. cout<<"Digite numero de columnas de M[1]: "; cin>>c1;
  31.  
  32. //Definir filas y columnas M[2];
  33. cout<<"\nDigite numero de filas de M[2]: "; cin>>f2;
  34. cout<<"Digite numero de columnas de M[2]: "; cin>>c2;
  35.  
  36. cout<<"\n\n";}
  37. while(c1 != f2);
  38. //M[f1][c1] * T[f2][c2] |([c1] == [f2])| ---> = R[f1][c2];
  39.  
  40. //Reservar memoria para matriz puntero m1;
  41. m1 = new int*[f1];
  42. for(int i=0;i<f1;i++){
  43. m1[i] = new int[c1];
  44. }
  45.  
  46. m2 = new int*[f2];
  47. for(int i=0;i<f2;i++){
  48. m2[i] = new int[c2];
  49. }
  50.  
  51. //Declarar variables matriz 1;
  52. for(int i=0;i<f1;i++){
  53. for(int j=0;j<c1;j++){
  54. cout<<"Digite valor de M1["<<i<<"]["<<j<<"]: ";
  55. cin>>m1[i][j]; //es lo mismo que *(*(m1+i)+j);
  56. }
  57. }
  58. cout<<endl;
  59.  
  60. //Declarar variables matriz 2;
  61. for(int i=0;i<f2;i++){
  62. for(int j=0;j<c2;j++){
  63. cout<<"Digite valor de M2["<<i<<"]["<<j<<"]: ";
  64. cin>>m2[i][j];
  65. }
  66. }
  67. cout<<endl;
  68. }
  69.  
  70. void multiplicarMatrices(int** m1,int** m2,int**& mT,int f,int c, int f_c){
  71.  
  72. //Reservar memoria mT;
  73. mT = new int*[f];
  74. for(int i=0;i<f;i++){
  75. mT[i] = new int[c];
  76. }
  77.  
  78. //Empezar multiplicación;
  79. for(int i=0;i<f;i++){
  80. for(int j=0;j<c;j++){
  81. mT[i][j] = multi(m1,m2,f_c,i,j);
  82. }
  83. }
  84.  
  85. }
  86.  
  87. int multi(int** m1,int** m2,int f_c, int x, int y){
  88. int total=0;
  89.  
  90. //Multiplica filas M[1] x columnas M[2]. Maximo de multiplicaciones: c1 == f2 == f_c == c2_f1. Si es 2x3 * 3x3 --> multiplica máximo 3 veces --> MTotal = 2x3;
  91. for(int i=0;i<f_c;i++){
  92. total += (m1[x][i] * m2[i][y]);
  93. }
  94.  
  95.  
  96. return total;
  97. }
  98.  
  99. void mostrarMatriz(int** m,int f,int c){
  100.  
  101. //Mostrar Matriz Total
  102. cout<<"\n-----------------------------------------\n";
  103. cout<<"La Matriz total es:\n";
  104. for(int i=0;i<f;i++){
  105. for(int j=0;j<c;j++){
  106. cout<<m[i][j]<<" ";
  107. }
  108. cout<<endl;
  109. }
  110. }

Podría usar un puntero de la funcion multi al usarla en multiplicarMatrices, aun que como tu dices, a mi me parece lo mismo xD.


Título: Re: Problema con los punteros C++
Publicado por: K-YreX en 28 Agosto 2019, 03:45 am
Te pongo un caso más útil para que veas cómo se podrían usar los punteros a funciones. Imagina que vas a hacer un programa que ordene un array y quieres dar la posibilidad de ordenarlo ascendente y descendentemente. La primera opción que le vendría a cualquiera a la cabeza es esta:
Código
  1. void ordenarAscendente(int *numeros, int size){
  2.    for(size_t i = 1; i < size; ++i)
  3.        for(size_t j = 0; j < size-i; ++j)
  4.            if(numeros[j] > numeros[j+1]){
  5.                numeros[j] += numeros[j+1];
  6.                numeros[j+1] = numeros[j] - numeros[j+1];
  7.                numeros[j] -= numeros[j+1];
  8.            }
  9. }
  10.  
  11. void ordenarDescendente(int *numeros, int size){
  12.    for(size_t i = 1; i < size; ++i)
  13.        for(size_t j = 0; j < size-i; ++j)
  14.            if(numeros[j] < numeros[j+1]){
  15.                numeros[j] += numeros[j+1];
  16.                numeros[j+1] = numeros[j] - numeros[j+1];
  17.                numeros[j] -= numeros[j+1];
  18.            }
  19. }
Tenemos dos funciones que si ves siguen el mismo tipo de ordenamiento (un bubblesort muy simple :xD) pero una de forma ascendente y otra de forma descendente. Tampoco es demasiado trabajo pero imagina que queremos ordenar un array de 50 formas distintas, tendríamos que hacer 50 funciones iguales cambiando únicamente la condición de ordenamiento. Entonces podríamos hacer algo así:
Código
  1. bool mayor(int a, int b){
  2.    return a > b;
  3. }
  4.  
  5. bool menor(int a, int b){
  6.    return a < b;
  7. }
  8.  
  9. void ordenar(int *numeros, int size, bool (*orden)(int,int)){
  10.    for(size_t i = 1; i < size; ++i)
  11.        for(size_t j = 0; j < size-i; ++j)
  12.            if(!orden(numeros[j], numeros[j+1])){
  13.                numeros[j] += numeros[j+1];
  14.                numeros[j+1] = numeros[j] - numeros[j+1];
  15.                numeros[j] -= numeros[j+1];
  16.            }
  17. }
Y esto mismo lo podríamos hacer con otros tipos de ordenamiento. Es decir, hacemos una simple función que determine el tipo de orden a seguir y reutilizamos la función que tiene el algoritmo de ordenamiento.
Luego ya si nos venimos arriba le ponemos unos <template> a ese programa y ya podemos ordenar cualquier tipo de dato (primitivos/objetos) que tengan claro está los operadores que usemos sobrecargados (en este caso < y >). Tampoco quiero adelantarte contenidos, ya lo verás más adelante pero para que veas que conocer los recursos disponibles ayuda a ahorrar muchas líneas de código al programador.

PD: Ahí te he dejado también como curiosidad cómo intercambiar el valor de dos variables sin usar ninguna variable auxiliar.


Título: Re: Problema con los punteros C++
Publicado por: 98Fran en 28 Agosto 2019, 18:55 pm
Hay algunas nomenclaturas que no entiendo como size_t, es de la libreria iostream?, yo de normal le pondría:
Código
  1. for(int i=0;i<size;i++){
  2. for(int j=0;j<size;j++){
  3.        //Aqui el ordenamineto burbuja
  4.        }
  5. }

O lo de ayer tambien con el sizeof, lo unico que se me ocurre es que sean clases por lo poco que he visto java, puede ser?.

PD: Estoy viendo las pilas y ya tengo la primera duda xD. No creo que sea un post tan largo como este pero estaría bien si le echas un vistazo  :xD :xD :xD.


Título: Re: Problema con los punteros C++
Publicado por: MAFUS en 28 Agosto 2019, 21:34 pm
size_t y sizeof son muy básicos: google te los encuentra enseguida. Los buscadores también son una buena herramienta.

Pero te lo respondo aquí:
size_t es un typedef de un entero largo sin signo. Depende de la plataforma.
sizeof es un operador que devuelve los bytes de un tipo o de un objeto.