Почему эта операция ввода-вывода зацикливается бесконечно? - PullRequest
0 голосов
/ 03 марта 2011

Я пытаюсь прочитать из текстового файла и токенизировать ввод.Я получал ошибку сегментации, пока не понял, что забыл закрыть свой ifstream.Я добавил вызов close и теперь он зацикливается бесконечно.Сейчас я просто пытаюсь научиться использовать strtok, поэтому код на самом деле не выглядит полным.

<code>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 ]

5 голосов
/ 03 марта 2011

Это while(input.good());, вероятно, не то, что вы хотели ...

4 голосов
/ 03 марта 2011

Используйте это:

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.

Не закрывайте явно () поток (если только вы не хотите обнаруживать и исправлять любые проблемы). Файл будет закрыт, когда объект выйдет из области видимости в конце функции.

1 голос
/ 03 марта 2011

Вы хотите использовать eof(), а не good().

0 голосов
/ 03 марта 2011

Хотя вы уже получили ответы на заданный вопрос, возможно, стоит ответить на некоторые из них, которые должны знать о коде, который вы не задавали:

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

Обычно я просто позволяю потоку автоматически закрываться, когда он выходит из области видимости.

0 голосов
/ 03 марта 2011

Избегайте strtok.Есть другие способы токенизации строки, которые не требуют, чтобы вызываемая функция изменила вашу строку.Тот факт, что он изменяет строку, которую он токенизирует, также может быть причиной цикла здесь.

Но, более вероятно, член good() не является правильным.Попробуйте !input.eof() или аналогичный, в зависимости от того, что вам нужно.

...