user1781966
user1781966

Reputation:

reading until the end of file in C++

I'm trying to read till the end of a file for a phonebook app that im converting from C to C++. When I print the the results from the file i get this:

johnny smith
(Home)3
(Cell)4
x☺> x☺>
(Home)4
(Cell)4

it should print:

johnny smith
(Home)3
(Cell)4

Right now I'm using while(!infile.eof()) which i've read is a poor practice, but when I use infile.getline() I get a repeat of the first and last name, and the format is all jacked up. Is there anyway(or another way) to get rid of the junk at the end of the input or another way to read till the end of file in C++ that fixes this. I've been reading about different solutions, but the one a lot of sites seem to agree on is fgets, which is what I had with the original C version, but obviously fgets doesn't work with ifstream which is what I'm using. here is the code:

void contacts:: readfile(contacts*friends ,int* counter, int i,char buffer[],char    user_entry3[])
{
   ifstream read;
   read.open(user_entry3,ios::in);
   int len;
   contacts temp;
   *counter=0;
   i=0; 

     while (!read.eof()) { 
       temp.First_Name=(char*)malloc(36); 
       temp.Last_Name=(char*)malloc(36); 

       read>>temp.First_Name>>temp.Last_Name;

       read>>buffer;
       len=strlen(buffer);
       if(buffer[len-1]=='\n')
          buffer[len-1]='\0';

       temp.home=(char*)malloc(20); 
       strcpy(temp.home, buffer);

       read>>buffer;
       len=strlen(buffer);
       if(buffer[len-1]=='\n')
       buffer[len-1]='\0';


       temp.cell=(char*)malloc(20); 
       strcpy(temp.cell, buffer); 

      friends[i].First_Name=(char*)malloc(MAXNAME);
      friends[i].Last_Name=(char*)malloc(MAXNAME);
      friends[i].home=(char*)malloc(MAXPHONE);
      friends[i].cell=(char*)malloc(MAXPHONE);


  //adds file content to the structure
      strcpy(friends[*counter].First_Name,temp.First_Name);
      strcpy(friends[*counter].Last_Name,temp.Last_Name);
      strcpy(friends[*counter].home,temp.home);
      strcpy(friends[*counter].cell,temp.cell);


     (*counter)++;
     i++; 

   }
   //closes file and frees memory
    read.close();
    free(temp.Last_Name);
    free(temp.First_Name);
    free(temp.home);
    free(temp.cell);
}

Upvotes: 5

Views: 38093

Answers (2)

melpomene
melpomene

Reputation: 85757

  1. Don't use !eof(). It checks whether the last read failure was due to reaching the end of the file. It does not predict the future.

  2. Don't use malloc in C++. If you do, check the return value for errors!

  3. Don't use operator>> for char *. There's no size check so that's just asking for buffer overflows.

  4. The '\n' check on buffer is useless. operator>> for strings stops at whitespace.

  5. You're blindly strcpying a string of unknown length into temp.home of size 20. That's another buffer overflow.

  6. ... I kind of stopped reading there. If you want to read stuff from a file but stop on eof/error, you can do something like this:

.

string a, b, c;
while (true) {
    if (!(in >> a)) break;
    if (!(in >> b)) break;
    if (!(in >> c)) break;
    do_stuff_with(a, b, c);
}

Upvotes: 8

Dietmar Kühl
Dietmar Kühl

Reputation: 153792

Do not use eof() to determine if you reached end of file. Instead, read what you want to read and then check if you successfully read the data. Obce reading failed you may use eof() to determine if the error is down to having reached the end of the file before producing an error report about a format error.

Since you mentioned that you read that using !infile.eof() is good practice: Can you point us at the source of this wrong information? This information need correction.

Upvotes: 7

Related Questions