1

The code (pasted below) is supposed to read the input file and then parse the data into the proper place in the structure.

IF the file being read has no blank spaces the data is read properly. But once the data has blank lines then the file gets stuck in a infinite loop.

I have been reading about skipping blank lines/ empty lines.

I try using the "if (buffer[0] == '\n')" then read another line. but it isn't working at all!

Does some one know the code that will allow ( i was using a while loop in case there were more than one blank line.) me to skip the blank lines and allow the code to parse all the data.

The file being read would look like this

"
<student>
<first>
1FRED
</first>
<mi>
J

</mi>
<last>
JOHNSON

</last>
<ssn>     
123456788
</ssn>    

</student>
<STUDENT>

<FIRST>
2SUSIE
</FIRST>
<MI>
Q
</MI>
<LAST>
WATSON
</LAST>
<SSN>
234567899
</SSN>
</STUDENT>
"

Here's the code:

#include <iostream>
#include <cstdlib>
#include <fstream>
#include <stdio.h>
#include <cstring>
#include <strings.h>

using namespace std;

struct record
{
char first [20];
char mi   [1];
char last  [20];
int  ssn;
};

void filename (char ifname [], struct record *student[]);
void structfill (fstream & infile, struct  record  *student[]);

int main ()
{

system ("clear");

fstream infile;
char ifname [256];
struct record * student [50];
filename (ifname, student);

return 0;
}
 /*******************************************************************/
void filename (char ifname [],record *student [])
 {
fstream infile;
cout << "Enter name of file to read from: ";
cin.getline (ifname, 256);
cout << endl;
infile.open (ifname);
    if (!infile.is_open ())
    {
    cerr << "FILELOOP!: Unable to open input file " << ifname
         << endl;
    exit (1);
    }
structfill (infile, student);
 }
/*******************************************************************/
void structfill (fstream & infile, record *student [])
{
char buffer [81];
int buffernumber [81];
int n=0;
int f=0;

 infile.getline (buffer,81);
 while (!infile.eof ())
{

 if (strncasecmp (buffer, "<student>",9)==0)
 {

 student[n] = new record;
 while ((strncasecmp (buffer, "</student>",10) != 0))
 {
      infile.getline (buffer, 81);
    if (strncasecmp (buffer, "<first>",7)==0)
      {
      infile.getline (buffer, 81);
      if (buffer[0] == '\n')
      {
      infile.getline (buffer, 81);
      cout << "-----";
      }
      strcpy (student[n]->first, buffer);
      }
    if (strncasecmp (buffer, "<mi>",4)==0)
      {
      infile.getline (buffer,81);
      if (buffer[0] == '\n')
      infile.getline (buffer, 81);
      strcpy (student[n]->mi, buffer);
      }
    if (strncasecmp (buffer, "<last>",4)==0)
      {
      infile.getline (buffer, 81);
      if (buffer[0] == '\n')
      infile.getline (buffer, 81); 
      strcpy (student[n]->last, buffer);
      }
    if (strncasecmp (buffer, "<ssn>",4)==0)
      {
      infile.getline (buffer, 81);
      if (buffer[0] == '\n')
      infile.getline (buffer, 81); 
      }  
} n++;   
infile.getline (buffer,81);
}
}
for (int a =0; a < n; a++){
cout << student[a]->first << " " << student[a]->mi << " " << student[a]->last << a <<   endl;
}
}
user3304639
  • 51
  • 1
  • 10

3 Answers3

1

Why don't you use std::getline instead?

If you're trying to skip over whitespace, then you can use the streams to your benefit as by default streams skip over whitespace.

Example:

string filename = "students.txt";
ifstream ifile(filename.c_str());

string temp;
//tokenize the file by newlines (getline reads up to newlines by default)
//so this way, it'll read and store data up to a newline each time
while(getline(ifile, temp)) {
    //at this point you can use another stream (i.e. a stringstream)
    //to perform other manipulations on the tokenized data.
    //example: read a number of characters using the getline method
    //of the stream: e.g.: `cin.getline()`
    //In my example, I am tokenizing each line by whitespace and outputting
    //the tokens:
    istringstream iss(temp);
    while(iss >> temp) {
        cout << temp << " ";
    }
    if (!temp.empty())
        cout << endl;
}

It should be noted that if you're using whitespace to tokenize your lines, you no longer have to check for them (using the above method).

jrd1
  • 10,358
  • 4
  • 34
  • 51
  • @user3304639: What don't you understand? Could you elaborate, please? – jrd1 Feb 16 '14 at 07:33
  • I have not learned the sting class. I have been using strtok to tokenize the line in the past. I dont see what part of your code is tokenizing the line? – user3304639 Feb 16 '14 at 14:59
  • @user3304639: the string class has nothing to do with the tokenizing as it is merely storing the data. The tokenization occurs in two places: 1) when the contents _up to a new line character_ is read (using `std::getline`) into `temp`. This data is then used to _initialize_ the input string stream (aka `std::istringstream`) `iss`, which utilizes the fact that C++ streams skip over whitespace and for each successful reading of the data, that information is stored in `temp` which is output to the screen in my example. – jrd1 Feb 16 '14 at 15:22
  • @user3304639: it should be noted that only the first part is truly valid and applicable to your problem (storing and tokenizing the string up to a newline). The other one was mainly done for completeness. – jrd1 Feb 16 '14 at 15:23
0

Not an answer to your question, neither is this causing your code to misbehave (at least with your test case), but the number of bytes argument in your last two strncasecmp calls are wrong.

DigitalEye
  • 1,456
  • 3
  • 17
  • 26
0

First reason why you are seeing an infinite loop is because you are not getting past reading the first line in your file (the double quote character). This because you are doing this:

infile.getline (buffer,81);
while (!infile.eof ())
{

    if (strncasecmp (buffer, "<student>",9)==0)
    {
        ...
    }
}

Double-quotes gets read into buffer after the first getline call and then you don't read anything else and remain stuck in an infinite loop because you are expecting to read "" tag before everything else in the file. Move the getline call inside your while loop. This will allow you to read through your file line by line.

Even after this correction, there are other things wrong here, you are not stripping away tag/special characters from "buffer" before you save the buffer's contents in your student data. For instance, one of your student records has its "last" set to "". I assume you just want "JOHNSON". Also things go wrong when you are reading "", your "record.mi" is just an array with one char (why array?), but your buffer for this entry is 3 characters and your strcpy fails at this point.

Why not use a C++ xml parsing library? See this for some suggestions.

Community
  • 1
  • 1
DigitalEye
  • 1,456
  • 3
  • 17
  • 26