PROBLEMA con la funcion miembro getline() e ignore()

Iniciado por .:BlackCoder:., 26 Julio 2010, 06:07 AM

0 Miembros y 1 Visitante están viendo este tema.

.:BlackCoder:.

Wenas... no se si es por el tiempo sin programar o wtf pero tengo problemas con getline() Lo explico en el codigo:

Código (cpp) [Seleccionar]
#include <cstdlib>
#include <iostream>
#include <fstream>

using namespace std;

int main(int argc, char *argv[])
{
   ofstream sal("Agenda.txt");
   sal<<"Pedro Perez                  :"<<18<<endl;//Agrego un nombre y espacios
   sal<<"Maria Rodriguez              :"<<56<<endl;//para completar 29 caracteres
   sal.close();                                                     //mas el ':'
   
   ifstream ent("Agenda.txt");
   int c=2;
   char reg[c][30];
   int edad[c];
   for (int i=0;ent;i++){
       ent.getline(reg[i],30);//Aca deberia extraer los 29 caracteres y agregar a reg un '\0'
       ent.ignore();//Aca ignorar el ':'
       ent>>edad[i];//Pes leer la edad
       ent.ignore();//Ignorar el fin de linea...
   }
   
   cout<<reg[0]<<"T"<<edad[0]<<endl;//Mostrar tal cual como esta en el archivo
   cout<<reg[1]<<"T"<<edad[1]<<endl;//La T era un ':', pero lo use para ver
                                   //si conseguia el error

   ent.close();
   
   system("PAUSE");
   return EXIT_SUCCESS;
}


Me imagino el error esta en getline()... La use pasandole como delimitador ':' y funciono pero igual me quedo la duda de porque no funciona...

Gracias a quien pueda aclarar la duda...

Saludos...


Asi es como "funciona" bueno mas o menos porque el for da una vuelta de mas... como que si no consigue el EOF, pero no se porque el ejemplo de arriba no lo hace =.=

Código (cpp) [Seleccionar]
    ofstream sal("Agenda.txt");
    sal<<"Pedro Perez                  :"<<18<<endl;
    sal<<"Maria Rodriguez              :"<<34<<endl;
   
    sal.close();
    ifstream ent("Agenda.txt");
    char name[2][30];
    int age[2];
    for (int i=0;ent;i++){
        ent.getline(name[i],31,':');
        cout<<name[i];
        ent>>age[i];
        cout<<age[i]<<endl;
        ent.ignore();
        cout<<i<<endl;
    }
   
    ent.close();
   

Por favor alguien que me aclare porque no funciona el code del mensaje anterior y porque este da una vuelta de mas...


Saludos...
"No te esfuerzes por saber mas, esfuerzate por ser el mejor en lo que sabes... Y asi sabras mas" .:BlackCoder:. jajaja




Littlehorse

Código (cpp) [Seleccionar]
    for (int i=0;ent;i++){
        ent.getline(name[i],31,':');
        cout<<name[i];
        ent>>age[i];
        cout<<age[i]<<endl;
        ent.ignore();
        cout<<i<<endl;
    }



El problema es que en este tipo de lecturas es que encontras el final cuando intentas leer en el, y no cuando leíste el ultimo elemento. Por eso mismo en este tipo de casos se comprueba o bien el valor exitoso del método utilizado en la lectura u métodos similares a ::eof. De lo contrario, imprimis ya pasado el EOF del archivo y por esa razon el ciclo tiene iteraciones de mas.

En cuanto al primer código, getline es bastante particular y setea failbit por varias razones. En el caso que se extraigan n-1 caracteres y no se encuentre el delimitador, failbit se setea por tanto las siguientes operaciones pueden fallar.

Código (cpp) [Seleccionar]
    for (int i=0;ent;i++){
        ent.getline(reg[i],30);//Aca deberia extraer los 29 caracteres y agregar a reg un '\0'
       //logic error. failbit set
        if(ent.fail())//if failbit set
        ent.clear();//all flags set to default =goodbit
        ent.ignore();//Aca ignorar el ':'
        ent>>edad[i];//Pes leer la edad
        ent.ignore();//Ignorar el fin de linea...
    }


Obviamente esa no es la solución ya que es ignorar el error, pero es simplemente para que veas que por ahí van los tiros.

Lo ideal es parsear el archivo correctamente sin dejar nada al azar, pero igualmente la segunda solucion que pusiste puede funcionar correctamente siempre que se chequeen los flags de error y el final del archivo. También ten en cuenta que ignore tiene parámetros que puedes utilizar para sacarle mas provecho y evitar que ignore posibles datos necesarios.

::fail
::bad
::eof

Me dijiste antes que tenias otras dudas así que cualquier cosa ya sabes.

Saludos!
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

.:BlackCoder:.

Jumm ahora me doy cuenta que toy grave  :xD cuando getline setea el failbit las operaciones siguientes fallan? Eso no lo tengo claro, crei q setear el failbit no tenia importancia, que solo era para cuando uno quiera verificar errores y todo eso...

Weno lo que viene es un code larguito  :xD pero pes como siempre quise hacer algo mas complejo, Agregar y quitar "registros" (Noten las comillas) a un archivo, pero de TEXTO, y ya se que lo ideal segun casi todos es que sea binario, pero pes lo quiero hacer en forma texto... en el fichero se deben ver mas o menos asi los registros:

Pedro Perez                  :18
Maria Rodriguez              :34
Ana Vergara                  :55

Un nombre completado con espacios para conseguir 29 caracteres mas ':' para... ni se para que digamos que para complicarme mas  :xD y un entero que segun yo es la edad... mas su respectivo fin de linea...

Tengo este code, con una funcion contar() que cuenta los "registros", una funcion extraer() que los extrae e ingresa  en un vector de estructuras, otra ordenar() que ordena el vector de registros y otra agregaralfi() que pes agregar los registros al ficheros: El code funciona mas o menos xD: el problema es que despues de agregar a una persona me aparecio:

Pedro Perez                  :18
Maria Rodriguez              :34
Ana Vergara                  :55
Ð>:0
:0
:0
Antonio Mendoza              :10

:xD Pero hace alguito el pobre code, esta muy feo y obviamente se puede mejorar pero quiero empezar por reparar esos simbolos extraños.... Aca lo dejo:

Código (cpp) [Seleccionar]
#include <cstdlib>
#include <iostream>
#include <fstream>

using namespace std;

struct person{
    char name[30];
    int age;
};

void extraer(person* Persona);
int contar();
void ordenar(person* Persona);
void agregaralfi(person *Persona);

int main(int argc, char *argv[])
{
    int op;
    do{
        cout<<"1.Ingresar una persona al archivo"<<endl;
        cout<<"2.Ver todas las personas del archivo"<<endl;
        cout<<"3.Salir"<<endl;
        cin>>op;
       
        if (op == 1){
            person *Persona, aux;
            Persona= new person [contar()+1];
            cin.ignore();
            cout<<"Ingrese el nombre: ";
            cin.getline(aux.name,30);
            cout<<"Ingrese la edad: ";
            cin>>aux.age;
            Persona[contar()]= aux;
            agregaralfi(Persona);
            delete[] Persona;
        }
        else if (op == 2){
            person *Persona;
            Persona= new person [contar()];
            extraer(Persona);
            for (int i=0;i<contar();i++)
                cout<<Persona[i].name<<Persona[i].age<<endl;
            delete[] Persona;
        }
        cout<<"\n\n\n";
    }while (op != 3);
   
   
   
    cin.get();
    return EXIT_SUCCESS;
}

void extraer(person* Persona){
    ifstream ent("Agenda.txt");
    int c=contar();
   
    for (int i=0;i<c;i++){
        ent.getline(Persona[i].name,31,':');
        ent>>Persona[i].age;
        ent.ignore();
    }

    ent.close();
}

int contar(){
    ifstream ent("Agenda.txt");
    int c=0;
    while (ent) if (ent.get() == '\n') c++;
    ent.close();
    return c;
}

void ordenar(person* Persona){
    int c=contar();
    for (int i=0;i<c-1;i++)
        for (int j=i+1;j<c;j++)
        if (Persona[i].name > Persona[j].name){
            person AUX=Persona[i];
            Persona[i]=Persona[j];
            Persona[j]=AUX;
        }
}

void agregaralfi(person *Persona){
    int c=contar()+1;
    ofstream sal("Agenda.txt",ios::app);
    for (int i=0;i<c;i++)
        sal<<Persona[i].name<<':'<<Persona[i].age<<endl;
    sal.close();
}


Muchas gracias littlehorse, disculpa la molestia y pes espero tu ayuda para luego si fortalecer el code...

Saludos...
"No te esfuerzes por saber mas, esfuerzate por ser el mejor en lo que sabes... Y asi sabras mas" .:BlackCoder:. jajaja




Littlehorse

CitarJumm ahora me doy cuenta que toy grave  :xD  cuando getline setea el failbit las operaciones siguientes fallan? Eso no lo tengo claro, crei q setear el failbit no tenia importancia, que solo era para cuando uno quiera verificar errores y todo eso...

Si, tiene importancia. Las operaciones siguientes realizadas en ese stream fallaran hasta que se vuelva al estado normal de ese stream.

En cuanto al código, lo depuraste? tienes idea de mas o menos donde se produce el error? si sabes donde se produce la falla, especifica las lineas.
Si no encontraste la falla en la logica, prueba revisando los valores de los datos paso por paso hasta encontrar el problema.
Mañana lo miro atentamente a ver que encuentro, pero mientras prueba depurando.

Saludos!

An expert is a man who has made all the mistakes which can be made, in a very narrow field.

.:BlackCoder:.

#4
Me imagino que el pedu esta en agregaralfi()... Estoy casi seguro, horita voy a comer, luego le doy y le doy otra vez  :xD ya estuve toda la tarde en eso, que me ciente otro rato no quiere decir nada... :laugh:

EDITO:

Mmmm el problema era una tonteria aca esta el code, lo hire editando poco a poco, se esperan criticas, consejos, ordenes  :xD lo que sirva:

Código (cpp) [Seleccionar]
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <iomanip>

using namespace std;

struct person{
   char name[30];
   int age;
};

void extraer(person* Persona);
int contar();
void ordenar(person* Persona);
void agregaralfi(person *Persona);

int main()
{
   int op;
   do{
       cout<<"1.Ingresar una persona al archivo"<<endl;
       cout<<"2.Ver todas las personas del archivo"<<endl;
       cout<<"3.Salir"<<endl;
       cin>>op;
       
       if (op == 1){
           person *Persona, aux;
           Persona= new person [contar()+1];
           cin.ignore();
           cout<<"Ingrese el nombre: ";
           cin.getline(aux.name,30);  //Aca lee los 30-1 caracteres y no hay problemas...
           cout<<"Ingrese la edad: ";
           cin>>aux.age;                  //con esta lectura con cin, no dices que al leer los 30-1 caracteres habran errores?
           extraer(Persona);      //Me faltaba esto por eso mostraba esas loqueras
           Persona[contar()]= aux;
           agregaralfi(Persona);
           delete[] Persona;
       }
       else if (op == 2){
           person *Persona;
           Persona= new person [contar()];
           extraer(Persona);
           for (int i=0;i<contar();i++){
               cout<<Persona[i].name<<Persona[i].age<<endl;
               cout<<strlen(Persona[i].name)<<endl;}
           delete[] Persona;
       }
       cout<<"\n\n\n";
   }while (op != 3);
   
   
 
   system("PAUSE");
   return EXIT_SUCCESS;
}

void extraer(person* Persona){
   ifstream ent("Agenda.txt");
   int c=contar();
   
   for (int i=0;i<c;i++){
       ent.getline(Persona[i].name,30,':');
       ent>>Persona[i].age;
       ent.ignore();
   }

   ent.close();
}

int contar(){
   ifstream ent("Agenda.txt");
   int c=0;
   while (ent) if (ent.get() == '\n') c++;
   ent.close();
   return c;
}

void ordenar(person* Persona){
   int c=contar();
   for (int i=0;i<c-1;i++)
       for (int j=i+1;j<c;j++)
       if (Persona[i].name > Persona[j].name){
           person AUX=Persona[i];
           Persona[i]=Persona[j];
           Persona[j]=AUX;
       }
}

void agregaralfi(person *Persona){
   int c=contar()+1;
   ofstream sal("Agenda.txt",ios::app);
   for (int i=0;i<c;i++)
       sal<<setiosflags(ios::left)<<setw(29)<<Persona[i].name<<':'<<Persona[i].age<<endl;
   sal.close();
}


Saludos...
"No te esfuerzes por saber mas, esfuerzate por ser el mejor en lo que sabes... Y asi sabras mas" .:BlackCoder:. jajaja




leogtz

Si tu programa no va a tener soporte para línea de comandos no tiene caso que utilices (argc y argv), es como declarar variables y no usarlas.
Código (perl) [Seleccionar]

(( 1 / 0 )) &> /dev/null || {
echo -e "stderrrrrrrrrrrrrrrrrrr";
}

http://leonardogtzr.wordpress.com/
leogutierrezramirez@gmail.com

.:BlackCoder:.

Ok... Algo mas? Ya modifique un par de cosas, como por ejemplo le agregue un manipulador para darle formato sin tener que precionar espacios  :xD Luego le agrego un par de funciones...

Saludos...
"No te esfuerzes por saber mas, esfuerzate por ser el mejor en lo que sabes... Y asi sabras mas" .:BlackCoder:. jajaja




leogtz

#7
No uses system(), y menos para una tarea irrelevante como pausar el programa, utiliza algo como cin.get()

Un buen hábito de programación es declarar las clases o estructuras empezando con mayúscula.

Estás usando C++ pero de manera estructurada, podrías usar un poco de POO y las funciones que usas hacerlas funciones miembro de la clase.
Código (perl) [Seleccionar]

(( 1 / 0 )) &> /dev/null || {
echo -e "stderrrrrrrrrrrrrrrrrrr";
}

http://leonardogtzr.wordpress.com/
leogutierrezramirez@gmail.com

.:BlackCoder:.

La verdad que aunque me gusta C++ no soy bueno con la POO  :xD pero voy a intentarlo... y lo de los nombre ya lo sabia pero todo empezo desde una cadena person  :xD Ya voy a ver si hago algo orientado a objetos... aunque como es que vas a meter esas funciones como miembros? tu pensaste en que person sea una struct miembro de una clase? o que la clase sea person?...

Saludos
"No te esfuerzes por saber mas, esfuerzate por ser el mejor en lo que sabes... Y asi sabras mas" .:BlackCoder:. jajaja




leogtz

No, no me di a entender.

Yo crearía una clase llamada Agenda, y apartir de ahí agregar sus funciones miembro como:

extraer
contar
ordenar

Etc, etc.
Código (perl) [Seleccionar]

(( 1 / 0 )) &> /dev/null || {
echo -e "stderrrrrrrrrrrrrrrrrrr";
}

http://leonardogtzr.wordpress.com/
leogutierrezramirez@gmail.com