Чтение из файла: C для переполнения стека

Я пытался прочитать файл в C/C++ и смог сделать это для C но сталкиваюсь с некоторыми проблемами с C++,

Справочная информация: файл, который я пытаюсь прочитать, имеет следующую структуру

i = %3d; j = %3d; a = %3d; b = %3d;
i = %3d; j = %3d; a = %3d; b = %3d;
...

У меня есть код, который работает в C является следующим:

#include <stdio.h>
#include <fstream>
#define MAXSIZE 32

int main()
{
FILE* inputfile = fopen("temp.txt","r");
int i,j,a,b;

while (!feof(inputfile))
{
fscanf(inputfile,
"i = %3d; ""j = %3d; ""a = %3d; ""b = %3d;\n",
&i, &j, &a, &b);

printf("%3d %3d %3d %3d\n", i,j,a,b);
}

fclose(inputfile);
return 0;
}

При попытке написать эту программу в C++ Я пробовал:

int main()
{
ifstream inputfile( "temp.txt" ,ios::in);
int i,j,a,b;

while (!std::cin.eof())
{
inputfile >> "i = " >> i >> "; j = " >> j >> "; a = " >> a >> "; b = " >> b >> ";\n";
printf("%3d %3d %3d %3d\n", i,j,a,b);
}
return 0;
}

Но я не совсем уверен, как я должен идти о форматировании
inputfile >> "i = " >> i >> "; j = " >> j >> "; a = " >> a >> "; b = " >> b >> ";\n";
Любая помощь будет оценена. Спасибо!

Редактировать: Проблема, с которой я сталкиваюсь, заключается в том, что последняя строка неправильно отформатирована. Поскольку мой файл находится в форме, указанной в вопросе, я не могу написать inputfile >> i >> j >> a >> b;,

0

Решение

Предполагая, что вы можете сойти с рук, просто игнорируя i =, j = и так далее, и просто нужно прочитать числа, одной из возможностей будет создание фасета ctype, который классифицирует эти символы как пробелы. Наполните поток локалью, включающей этот фасет, и просто прочитайте ваши цифры:

#include <iostream>
#include <algorithm>
#include <locale>
#include <vector>
#include <sstream>

struct digits_only: std::ctype<char> {
digits_only(): std::ctype<char>(get_table()) {}

static std::ctype_base::mask const* get_table() {
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);

std::fill(&rc['0'], &rc['9'], std::ctype_base::digit);
return &rc[0];
}
};

class record {
int i, j, a, b;
public:
friend std::istream &operator>>(std::istream &is, record &r) {
return is >> r.i >> r.j >> r.a >> r.b;
}

friend std::ostream &operator<<(std::ostream &os, record const &r) {
return os << r.i << "\t" << r.j << "\t" << r.a << "\t" << r.b;
}
};

int main() {
std::stringstream in("i=1 j = 2 a = 10 b = 20\ni = 3 j = 4 a = 30 b = 40");
std::locale numbers(std::locale(), new digits_only);
in.imbue(numbers);

std::vector<record> records{ std::istream_iterator<record>(in),
std::istream_iterator<record>() };

std::cout << "i\tj\ta\tb\n";
for (auto const & r : records)
std::cout << r << "\n";
}

Что касается того, лучше это или хуже, чем просто использование scanfЯ бы сказал, что вопрос открыт. Это явно дольше в целом. OTOH, большая часть дополнительной длины в коде выше от моего решения обернуть i, j, a а также b в структуру их собственного. Хотя это только предположение, я думаю, что вы наверное хочу сделать это в любом случае.

В обмен на некоторую дополнительную длину вы получаете безопасность типов, и если у вас есть несколько различных частей кода, которые должны читать подобные записи, это намного больше удобства.

Вопреки утверждению Бена Фойгта, фактическое тестирование показывает, что ввод-вывод с использованием iostreams может полностью конкурировать с функциями stdio C (и в некоторых случаях быстрее). Я не достаточно тестировал этот конкретный случай, чтобы убедиться, что он быстрее, медленнее или примерно таким же, но я провел достаточно другое тестирование, чтобы с достаточной уверенностью сказать, что далеко не предрешено, что функции C stdio будут существенно Быстрее.

Итог: вполне возможно, что продолжать использовать scanf это хороший выбор — но опять же, это может и не быть.

1

Другие решения

Просто используйте оригинальный код. Лучше в каждый путь:

  • Это работает (кроме случаев, когда файл заканчивается пустой строкой, см. Ниже).
  • Это проверено.
  • Это работает быстрее.
  • Это совершенно справедливо как на C, так и на C ++.
  • Компилируется быстрее.

Тем не менее, я предложу одно улучшение:

while (4 == fscanf(inputfile,
"i = %3d; ""j = %3d; ""a = %3d; ""b = %3d;\n",
&i, &j, &a, &b))
{
printf("%3d %3d %3d %3d\n", i,j,a,b);
}
if (!feof(inputfile)) {
// read failed and the reason wasn't hitting the end of the file
// maybe you've been keeping track of line numbers and
// can report where the invalid input was found
}

Тестирование EOF перед попыткой чтения слишком рано. Флаг EOF устанавливается только после того, как чтение достигнет конца файла. Если последнее успешное чтение действительно нашло '\n'тогда EOF не будет установлен. В коде iostreams была та же ошибка, в дополнение к проблеме, связанной с промежуточным текстом.


Примечание: вы никогда не заметите разницу в скорости для пользовательского ввода или даже для вывода на терминал. Но для файлового ввода-вывода (включая перенаправленный stdin или stdout) функции stdio.h значительно превосходят iostreams.

3

По вопросам рекламы ammmcru@yandex.ru