为什么这个IO操作无限循环?

时间:2011-03-03 02:04:35

标签: c++ ifstream strtok atoi

我正在尝试从文本文件中读取并标记输入。我收到了一个分段错误,直到我意识到我忘了关闭我的ifstream。我添加了close调用,现在它无限循环。我现在只是想学习如何使用strtok,这就是为什么代码看起来并不完整。

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();
}

输入文件:(一行)

5 +8 0 0 25

5 个答案:

答案 0 :(得分:5)

while(input.good());可能不是你想要的......

答案 1 :(得分:4)

使用此:

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

如果getline()有效,则输入循环 如果您尝试读取EOF,那么它将失败并且循环将退出。

所以这应该按预期说出来。

而不是使用不可移动的strtok()(损坏字符串)和atoi() 使用std :: stringstream

    std::stringstream  linestream(line);

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

不要显式关闭()流(除非你想检测并纠正任何问题)。当对象在函数末尾超出范围时,文件将被关闭。

答案 2 :(得分:1)

您想使用eof()而不是good()

答案 3 :(得分:0)

避免使用strtok。还有其他方法来标记不需要被调用函数来修改字符串的字符串。它修改了它标记的字符串的事实也可能是导致循环的原因。

但更有可能的是,good()成员不是正确的成员。请尝试!input.eof()或类似,具体取决于您的需求。

答案 4 :(得分:0)

虽然你已经对你提出的问题得到了一些答案,但也许值得回答你应该关于你没有问过的代码的一些答案:

void loadInstructions(char* fileName)

由于该功能不会修改文件名,因此您几乎肯定希望将其更改为:

void loadInstructions(char const *fileName)

void loadInstructions(std::string const &fileName)

ifstream input;
input.open(fileName);

将这些结合起来要清晰得多:

ifstream input(fileName);

或(如果您传递了一个字符串):

ifstream input(fileName.c_str());

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);

这大部分都是无关紧要的。您可以直接从原始输入转换atoi

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

如果您稍后要进行更多标记,则可以改为使用strtol

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

这会将end_ptr设置为刚好超过strtol转换的部分的结尾。

我还考虑了另一种选择:将代码移动到一个类中读取和解析一行,并定义operator>>来读取它们:

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;
}

有了这个,我们可以很容易地打印出行号:

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

input.close();

我通常只是让它在超出范围时自动关闭。