Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: maikelowen en 2 Enero 2015, 20:25 pm



Título: Array de estructuras + funciones
Publicado por: maikelowen en 2 Enero 2015, 20:25 pm
Primeramente Saludos. :D
Se me plantea la siguiente duda... ¿cómo a traves de una función podemos devolver un array de estructuras? Por ejemplo:

struct personas{

int edad;
string nombre;

};

personas funcion(){



return ¿?

}

int main (){

personas p[2];

}



Es decir se supone que yo introduciré tanto la edad para p[0] y p[1] y lo mismo con el nombre... pero como se hace para devolver con la función todo esto y pasarlo a otro array que yo me invente..por ejemplo personas pNuevo[2];

Es que cuando es solo una cosa no tengo problema...por ejemplo:


struct persona {
int edad;
string nombre;

}

personas funcion(){

persona p;

return p;
}

int main(){

personas W;

W=funcion();
// A  p  se supone que ya le he introducido tanto el nombre como la edad.

cout<<W.nombre;
cout<<W.edad;

}


El problema lo tengo cuando es mas de una personas.


Un saludo y gracias de antemano.Disculpen si no me entienden del todo... :-X


Título: Re: Array de estructuras + funciones
Publicado por: Yoel Alejandro en 3 Enero 2015, 00:34 am
Hola maikelowen

Eso que planteas no presenta ningún problema ya que en C/C++ el nombre de un arreglo no es más que un apuntador al tipo de dato almacenado en el arreglo. Así dicho tipo de dato sea una estructura. Lo comprenderás más plenamente al leer el tema "Apuntadores en C" en un buen libro de texto o alguna buena página web.

Te pongo un ejemplo. El programa siguiente pide al usuario los datos de 2 personas y los almacena en un arreglo de registros de personas. A continuación, y para verificar que los datos han sido guardados correctamente, los muestra en pantalla.

La primera función, pide los datos al usuario registrarPersonas() pide los datos por consola, y los almacena en un arreglo de struct's. La segunda función mostrarPersonas() recibe dicho arreglo como argumento (que como ya dije no es más que un apuntador al primer struct guardado en el vector), e imprime los datos de los primeros 2 elementos (personas) guardados.

Está codificado para C++, ya que vi que en tu código original incluiste la clase string. Si lo quieres estrictamente para C, házmelo saber.

Código
  1. #include <iostream>
  2. #include <string>
  3.  
  4. using namespace std;
  5.  
  6. struct persona {
  7. int edad;
  8. string nombre;
  9. };
  10.  
  11. void registrarPersonas( struct persona *, int );
  12. void mostrarPersonas( struct persona *, int );
  13.  
  14. int main () {
  15.  
  16. struct persona p[10];
  17.  
  18. /* registra 2 personas */
  19. registrarPersonas( p, 2 );
  20.  
  21. /* muestra los datos de las 2 personas */
  22. mostrarPersonas( p, 2);
  23.  
  24. return 0;
  25. }
  26.  
  27. /* Registra datos de N personas en el arreglo */
  28. void registrarPersonas( struct persona *p, int N ) {
  29.  
  30. int i;
  31.  
  32. for ( i = 0; i < N; i++ ) {
  33. cout << "Persona " << i+1 << ":" << endl;
  34. cout << "   " << "nombre: ";
  35. getline(cin, p[i].nombre );
  36.  
  37. cout << "   " << "edad: ";
  38. cin >> p[i].edad;
  39. cout << endl;
  40.  
  41. while ( cin.get() != '\n' ) ; /* limpiar buffer de entrada */
  42. }
  43. }
  44.  
  45. /* Imprime los datos de las primeras N personas en el arreglo */
  46. void mostrarPersonas( struct persona *p, int N ) {
  47.  
  48. int i;
  49.  
  50. cout << "Imprimiendo datos:" << endl << endl;
  51. for ( i = 0; i < N; i++ ) {
  52. cout << "Persona " << i+1 << ":" << endl;
  53. cout << "   " << "nombre: " << p[i].nombre << endl;
  54.  
  55. cout << "   " << "edad: " << p[i].edad << endl << endl;
  56. }
  57. }

Observa el resultado en la consola:


=========================================================
Persona 1:
   nombre: maria a
   edad: 14

Persona 2:
   nombre: jose e. p.
   edad: 31

Imprimiendo datos:

Persona 1:
   nombre: maria a
   edad: 14

Persona 2:
   nombre: jose e. p.
   edad: 31
=========================================================



Título: Re: Array de estructuras + funciones
Publicado por: maikelowen en 3 Enero 2015, 13:05 pm
Muchas gracias yoel_alejandro, pero la función no me gustaría que fuera de tipo void. Por eso en mi caso pues que era de tipo struct...bueno en mi caso "personas", porque quiero devolver un array de estructuras mediante un return...pero no se como se hace :(


Título: Re: Array de estructuras + funciones
Publicado por: Orubatosu en 3 Enero 2015, 14:19 pm
Supongo que quieres hacer algo como esto:

Código
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. struct persona {
  5.    string nombre;
  6.    int edad;
  7. };
  8.  
  9. persona La_funcion (string nam, int ed){
  10.    persona retorno;
  11.    retorno.nombre = nam;
  12.    retorno.edad = ed;
  13.    return retorno;
  14.  
  15. }
  16.  
  17. int main(){
  18.   string nam = "Pepe";
  19.   int ed = 22;
  20.   persona El_Pepe = La_funcion (nam, ed);
  21.   cout << El_Pepe.nombre << endl;
  22.   cout << El_Pepe.edad << endl;
  23. }
  24.  


Así llamas a una función para que devuelva un struct, en el caso de un array del mismo, se hace del mismo modo.

Obviamente se puede abreviar, pero para hacerlo mas claro lo he puesto en plan "basto"

Lo de devolver un array... bueno, ahi ya es algo mas complejo, ya que deberías de meter todos los valores a la vez en la función, o pasarla por parámetro, o construir el array fuera de la función e ir añadiendo valores a la misma llamando a la función


Título: Re: Array de estructuras + funciones
Publicado por: maikelowen en 3 Enero 2015, 14:34 pm
Se me ha ocurrido hacerlo de la siguiente forma, que opinas:

/*
 * File:   main.cpp
 * Author: owen
 *
 * Created on 30 de diciembre de 2014, 22:03
 */

#include <cstdlib>
#include <string>
#include <iostream>

using namespace std;


struct personas {
   
    string nombre;
    int edad;
   
   
   
};
   
   
personas funcionIntroduccionDatos(){
   
    personas p;
   
    cout<<"Introduzca nombre: ";
    cin>>p.nombre;
    cout<<"Introduzca edad: ";
    cin>>p.edad;
   
    return p;
   
   
   
   
}   





int main(int argc, char** argv) {
   
    string palabra;
    int contador=0;
   
    personas P[5];
   
    //Limpio Array
   
    for(int i=0;i<5;i++){
            P.nombre=" ";
            P.edad=0;
        }
   
   
    do{
   
        cout<<"Desea introduccir datos de persona (Si o No): ";
        cin>>palabra;
        if(palabra=="Si"){
           
        P[0+contador]=funcionIntroduccionDatos();
        contador++;     
               
        }
       
       
       
       
    }while(palabra=="Si");
   
   
    cout<<"Datos almacenados: "<<endl;
   
    for(int i=0;i<5;i++){
        cout<<"Nombre: "<<P.nombre<<endl;
        cout<<"Edad: "<<P.edad<<endl;
        }
   
   
    return 0;
   
   
   
}


Título: Re: Array de estructuras + funciones
Publicado por: Blaster en 3 Enero 2015, 15:22 pm
¿cómo a traves de una función podemos devolver un array de estructuras?
Es decir se supone que yo introduciré tanto la edad para p[0] y p[1] y lo mismo con el nombre... pero como se hace para devolver con la función todo esto y pasarlo a otro array

Puedes hacer algo asi:

Código
  1. typedef struct
  2. {
  3.    int edad;
  4.    string nombre;
  5. } persona;
  6.  
  7. persona* registrarPersonas( persona* datos, int n);
  8.  
  9. int main(void)
  10. {
  11.    persona datos[2];
  12.    persona* info;
  13.  
  14.    info = registrarPersonas(datos, 2);
  15.  
  16.    for(int i = 0; i < 2; i++)
  17.        cout << "Nombre: " << info[i].nombre << "\nEdad: "   << info[i].edad << endl;
  18.  
  19.    return 0;
  20. }
  21. persona* registrarPersonas( persona* datos, int n)
  22. {
  23.    for(int i = 0; i < n; i++)
  24.    {
  25.        cout << "Nombre: ";
  26.        getline(cin, datos[i].nombre );
  27.  
  28.        cout << "Edad: ";
  29.        cin >> datos[i].edad;
  30.        cin.ignore();
  31.    }
  32.    return datos;
  33. }
  34.  

Un Saludo


Título: Re: Array de estructuras + funciones
Publicado por: maikelowen en 3 Enero 2015, 18:55 pm
A eso era lo que queria llegar... pero no entiendo muy bien como está puesto todo... ;(


Título: Re: Array de estructuras + funciones
Publicado por: Yoel Alejandro en 4 Enero 2015, 02:25 am
maikelowen ...

Eso de "una función que devuelva un array" (un array de cualquier cosa) es delicado en C. Recuerda que las variables que se declaren dentro del cuerpo de una función son locales, es decir, se destruyen al terminar la ejecución de la función, y por lo tando sus valores quedan indefinidos. Esto es, dichos valores pueden conservarse o no, es algo impredecible.

Si vas a construir una función cuyo propósito sea actualizar los valores de los elementos de un array, dicho array ha de ser declarado FUERA de la función. Por ejemplo, sea un código que actualice por teclado los valores de un array de tres elementos. Tal  vez pienses en algo como

Código
  1. int * f ( void );
  2.  
  3. int main() {
  4.  
  5. /* tomar tres valores desde el teclado */
  6. int *x = f();
  7.  
  8. /* imprimir */
  9. cout << "Los numeros son: " << x[0] << ", " << x[1] << ", " << x[2] << endl << endl;
  10.  
  11. return 0;
  12. }
  13.  
  14. /* Lee tres valores enteros del teclado, y los almacena  en vector */
  15. int * f ( void ) {
  16.  
  17. int x[3];
  18.  
  19. cout << "1er numero: ";
  20. cin >> x[0];
  21.  
  22. cout << "2do numero: ";
  23. cin >> x[1];
  24.  
  25. cout << "3er numero: ";
  26. cin >> x[2];
  27.  
  28. cin.ignore();
  29.  
  30. return x;
  31. }

Pues, dicho código es incorrecto y de hecho el compilador podría informarte al respecto con un mensaje como "'warning: address of local variable ‘x’ returned", indicándote que estás devolviendo una variable local como retorno de la función.

Puede que este código funcione bien, o puede que no.  Es lo que llamamos una técnica de programación potencialmente peligrosa. Algo más apropiado sería:

Código
  1. void f( int * );
  2.  
  3. int main() {
  4.  
  5. /* tomar tres valores desde el teclado */
  6. int x[3];
  7.  
  8. f(x);
  9.  
  10. /* imprimir */
  11. cout << "Los numeros son: " << x[0] << ", " << x[1] << ", " << x[2] << endl << endl;
  12.  
  13. return 0;
  14. }
  15.  
  16. /* Lee tres valores enteros del teclado, y almacena  en vector */
  17. void f ( int *x ) {
  18.  
  19. cout << "1er numero: ";
  20. cin >> x[0];
  21.  
  22. cout << "2do numero: ";
  23. cin >> x[1];
  24.  
  25. cout << "3er numero: ";
  26. cin >> x[2];
  27.  
  28. cin.ignore();
  29. }

donde declarar el array x FUERA de la función f, y entonces invocas a f(x) con el nombre del array como argumento de entrada, y no como valor de retorno.

Parece extraño que si la función devuelve el array actualizado, entonces dicho array deba pasarse como argumento de ENTRADA, en lugar de devolverse como SALIDA ¡¡¡Pero así es C   :-\!!!, y la razón es que los arrays son técnicamente apuntadores a una zona de memoria que contiene ciertos datos, en lugar de ser objetos abstractos como en la P.O.O.

En lenguajes de programación orientados a objeto, como MATLAB, sí es permitido tener entidades de objeto como valores de retorno de una función. Tal vez este comportamiento se puede emular en C++ mediante referencias a objeto, pero ese sería otro tema.

============================================================================
Es posible poner a la función a devolver un array "a juro", indicando que devuelva una copia de su propio argumento como valor de retorno (ojo que es una copia de su argumento, no el mismo argumento como tal). Pero eso sería algo redundante, por ejemplo:

Código
  1. int * f( int * );
  2.  
  3. int main() {
  4.  
  5. /* tomar tres valores desde el teclado */
  6. int x[3];
  7. int * y;
  8.  
  9. y = f(x);
  10.  
  11. /* imprimir */
  12. cout << "Los numeros son: " << x[0] << ", " << x[1] << ", " << x[2] << endl << endl;
  13.  
  14. return 0;
  15. }
  16.  
  17. /* Lee tres valores enteros del teclado, y almacena  en vector */
  18. int * f ( int *x ) {
  19.  
  20. cout << "1er numero: ";
  21. cin >> x[0];
  22.  
  23. cout << "2do numero: ";
  24. cin >> x[1];
  25.  
  26. cout << "3er numero: ";
  27. cin >> x[2];
  28.  
  29. cin.ignore();
  30.  
  31. return x;
  32. }

Funciona igual que antes, sólo que ahora devuelve una copia de x como retorno. Ahora, ¿qué sentido tiene tener en main() dos array's, uno x, y otro y, para tener el segundo como copia del primero?
Es lo que te hizo Blaster cuando definió en el main() los arreglos datos e info, ambos serán la misma cosa luego de llamar la función invocarPersonas(), entonces bastaba dejar sólo el primero.