0

I am trying to read from a text file and tokenize the input. I was getting a segmentation fault until I realized I forgot to close my ifstream. I added the close call and now it loops infinitely. I'm just trying to learn how to use strtok for now, that is why the code doesn't really look complete.

void loadInstructions(char* fileName)
{
   ifstream input;
   input.open(fileName);
   while(!input.eof());
   {
      string line; 
      getline (input,line);
      char * lineChar = &line[0];
      //instruction cmd; //This will be used later to store instructions from the parse
      char * token;
      token = strtok (lineChar," "); 
      // just trying to get the line number for now
      int lineNumber = atoi(token);
      cout << lineNumber << "\n";
   }
   input.close();
}

input file:(one line)

5 +8 0 0 25

4

5 回答 5

5

This while(input.good()); is probably not what you intended...

于 2011-03-03T02:11:58.970 回答
4

Use this:

string line; 
while(getline (input,line))
{

If the getline() works then the loop is entered.
If you try and read past the EOF then it will fail and the loop will exit.

So this should word as expected.

Rather than using strtok() (which damages the string) and atoi() which is non portable.
Use std::stringstream

    std::stringstream  linestream(line);

    int lineNumber;
    linestream >> lineNumber; // reads a number from the line.

Don't explicitly close() the stream (unless you want to detect and correct for any problems). The file will be closed when the object goes out of scope at the end of the function.

于 2011-03-03T02:14:27.663 回答
1

You want to use eof() not good().

于 2011-03-03T02:09:25.210 回答
0

Avoid strtok. There are other ways to tokenize a string that do not require the called function to modify your string. The fact that it modifies the string it tokenizes could also be what causes the loop here.

But more likely, the good() member is not the right one. Try !input.eof() or similar, depending on what you need.

于 2011-03-03T02:12:20.300 回答
0

While you've already gotten some answers to the question you asked, perhaps it's worth answering some you should have about the code that you didn't ask:

void loadInstructions(char* fileName)

Since the function isn't going to modify the file name, you almost certainly want to change this to:

void loadInstructions(char const *fileName)

or

void loadInstructions(std::string const &fileName)

ifstream input;
input.open(fileName);

It's much cleaner to combine these:

ifstream input(fileName);

or (if you passed a string instead):

ifstream input(fileName.c_str());

while(!input.eof());

This has already been covered.

  string line; 
  getline (input,line);
  char * lineChar = &line[0];
  //instruction cmd; //This will be used later to store instructions from the parse
  char * token;
  token = strtok (lineChar," "); 
  // just trying to get the line number for now
  int lineNumber = atoi(token);

Most of this is just extraneous. You can just let atoi convert directly from the original input:

string line;
getline(input, line);
int lineNumber = atoi(line);

If you're going to tokenize more later, you can use strtol instead:

char *end_ptr;
int lineNumber = strtol(line, &end_ptr, 10);

This will set end_ptr to point just past the end of the part that strtol converted.

I'd also consider an alternative though: moving your code for reading and parsing a line into a class, and define operator>> to read those:

struct line { 
    int number;
    operator int() { return number; }
};

std::istream &operator>>(std::istream &is, line &l) {
// Just for fun, we'll read the data in an alternative fashion.
// Instead of read a line into a buffer, then parse out the first number,
// we'll read a number from the stream, then ignore the rest of the line.
// I usually prefer the other way, but this is worth knowing as well.

    is >> l.number;

    // When you're ready to parse more, add the extra parsing code here.

    is.ignore(std::numeric_limits<std::istream::pos_type>::max, '\n');
    return is;
}

With this in place, we can print out the line numbers pretty easily:

std::copy(std::istream_iterator<line>(input),
          std::istream_iterator<line>(),
          std::ostream_iterator<int>(std::cout, "\n"));

input.close();

I'd usually just let the stream close automatically when it goes out of scope.

于 2011-03-03T02:45:08.513 回答