Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как читать до EOF из cin в С++

Автор вопроса: CommunityОтветов: 9

Я кодирую программу, которая считывает данные непосредственно с пользовательского ввода, и мне было интересно, как я могу (без циклов) читать все данные до EOF со стандартного ввода. Я рассматривал возможность использования cin.get( input, '\0' ), но '\0' на самом деле не является символом EOF, который просто читается до EOF или '\0', в зависимости от того, что наступит раньше.

Или использование циклов единственный способ сделать это? Если да, то как лучше всего?

c++inputiostream

Ответы

Ответ 1 · рейтинг 81 · trotterdylan

Единственный способ прочитать переменный объем данных из stdin - это использовать циклы. Я всегда обнаруживал, что функция std::getline() работает очень хорошо:

std::string line;
while (std::getline(std::cin, line))
{
    std::cout << line << std::endl;
}

По умолчанию getline() читается до новой строки. Вы можете указать альтернативный символ завершения, но EOF сам по себе не является символом, поэтому вы не можете просто сделать один вызов getline().

Ответ 2 · рейтинг 56 · Degvik

Использование циклов:

#include <iostream>
using namespace std;
...
// numbers
int n;
while (cin >> n)
{
   ...
}
// lines
string line;
while (getline(cin, line))
{
   ...
}
// characters
char c;
while (cin.get(c))
{
   ...
}

ресурс

Ответ 3 · рейтинг 51 · KeithB

Вы можете сделать это без явных циклов, используя итераторы потока. Я уверен, что он использует какой-то внутренний цикл.

#include <string>
#include <iostream>
#include <istream>
#include <ostream>
#include <iterator>

int main()
{
// don't skip the whitespace while reading
  std::cin >> std::noskipws;

// use stream iterators to copy the stream to a string
  std::istream_iterator<char> it(std::cin);
  std::istream_iterator<char> end;
  std::string results(it, end);

  std::cout << results;
}

Ответ 4 · рейтинг 31 · Community

Изучив решение KeithB с помощью std::istream_iterator, я обнаружил std:istreambuf_iterator.

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

#include <iostream>
#include <iterator>
#include <string>

int main()
{
  std::istreambuf_iterator<char> begin(std::cin), end;
  std::string s(begin, end);
  std::cout << s;
}

Ответ 5 · рейтинг 6 · Community

Вероятно, самый простой и в целом эффективный:

#include <iostream>
int main()
{
    std::cout << std::cin.rdbuf();
}

При необходимости используйте поток других типов, например std::ostringstream, в качестве буфера вместо стандартного потока вывода здесь.

Ответ 6 · рейтинг 3 · Community

Печальное примечание: я решил использовать C++ IO, чтобы соответствовать коду на основе повышения. Из ответов на этот вопрос я выбрал while (std::getline(std::cin, line)). Используя g++ версии 4.5.3 (-O3) в cygwin (mintty), я получил пропускную способность 2 МБ/с. Microsoft Visual C++ 2010 (/O2) увеличил скорость до 40 МБ/с для того же кода.

После перезаписи ввода-вывода на чистый C while (fgets(buf, 100, stdin)) пропускная способность подскочила до 90 МБ/с в обоих протестированных компиляторах. Это имеет значение для любого ввода размером более 10 МБ...

Ответ 7 · рейтинг 2 · luke

Вы можете использовать std::istream::getline() ( или предпочтительнее версия, которая работает с std::string), чтобы получить всю строку . У обоих есть версии, которые позволяют указать разделитель (символ конца строки). По умолчанию для строковой версии используется '\n'.

Ответ 8 · Community

Подожди, я правильно тебя понял? Вы используете cin для ввода с клавиатуры и хотите прекратить чтение ввода, когда пользователь вводит символ EOF? Зачем пользователю когда-либо вводить символ EOF? Или вы имели в виду, что хотите прекратить чтение из файла в EOF?

Если вы на самом деле пытаетесь использовать cin для чтения символа EOF, то почему бы просто не указать EOF в качестве разделителя?

// Needed headers: iostream

char buffer[256];
cin.get( buffer, '\x1A' );

Если вы хотите прекратить чтение из файла в EOF, просто используйте getline и еще раз укажите EOF в качестве разделителя.

// Needed headers: iostream, string, and fstream

string buffer;

    ifstream fin;
    fin.open("test.txt");
    if(fin.is_open()) {
        getline(fin,buffer,'\x1A');

        fin.close();
    }

Ответ 9 · Community

Один из вариантов - использовать контейнер, например.

std::vector<char> data;

и перенаправлять все входные данные в эту коллекцию, пока не будет получено EOF, т.е.

std::copy(std::istream_iterator<char>(std::cin),
    std::istream_iterator<char>(),
    std::back_inserter(data));

Однако используемому контейнеру может потребоваться перераспределение памяти слишком часто, или вы закончите с исключением std::bad_alloc, когда вашей системе не хватит памяти. Чтобы решить эти проблемы, вы можете зарезервировать фиксированное количество N элементов и обрабатывать это количество элементов изолированно, т.е.

data.reserve(N);
while (/*some condition is met*/)
{
    std::copy_n(std::istream_iterator<char>(std::cin),
        N,
        std::back_inserter(data));

    /* process data */

    data.clear();
}

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы