2008-10-14 3 views
65

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

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

ответ

2

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

57

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

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

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

+5

Что-то быть осторожным здесь, когда вы читаете из файлов, которые были направлены в конвейер с помощью стандартного ввода, является что в этом и большинстве ответов будет добавлен дополнительный фид строки в конце вашего ввода. Не все файлы заканчиваются строкой, но каждая итерация цикла добавляет «std :: endl» в поток. Это не может быть проблемой в большинстве случаев, но если проблема с целостностью файла, это может вернуться, чтобы укусить вас. – Zoccadoum

+0

Это не должно быть самым верным ответом. См. Ниже ответ wiki сообщества. Также, может быть, посмотрите этот вопрос: https://stackoverflow.com/questions/3203452/how-to-read-entire-stream-into-a-stdstring – loxaxs

40

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

#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; 
} 
+2

Nice. Что касается «Я уверен, что он использует какой-то цикл внутри» - любое решение будет. –

+0

Это, кажется, удаляет символы новой строки из ввода, даже если они встречаются прямо посередине. – Multisync

36

Использования петли:

#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)) 
{ 
    ... 
} 

resource

1
while(std::cin) { 
// do something 
} 
+7

Это ужасная катастрофа ответа, так как это практически гарантировано приведет к неправильному коду. –

2

Грустно сторона примечания: я решил использовать 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 МБ ...

+0

Не нужно переписывать свой код на чистый C, просто добавьте 'std :: ios :: sync_with_stdio (false);' перед вашим while-loop. 'cin.tie (NULL);' также может помочь, если вы чередуете чтение и запись. –

0

Подождите, я правильно понимаю вас? Вы используете 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(); 
    } 
0

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

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

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

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

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

+0

вы, ребята, уже знаете, но могут быть полезны для некоторых: 'std :: ostringstream std_input; std_input << std :: cin.rdbuf(); std :: string s = std_input.str() '. у вас есть все входные данные '' '(будьте осторожны с' std :: string', если вход слишком велик) – ribamar

14

После исследования решения 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; 
} 
+2

Вероятно, это канонический ответ. –

+0

Сокращенный. Итак, каковы плюсы или минусы по сравнению с решением KeithB? Да, вы используете 'std :: istreambuf_iterator' вместо' std :: istream_iterator', но зачем? – Multisync

Смежные вопросы