web-dev-qa-db-ja.com

C ++でcinからEOFまで読み取る方法

ユーザー入力から直接データを読み取るプログラムをコーディングしていますが、標準入力からEOFまですべてのデータを(ループなしで)読み取ることができるのか疑問に思っていました。 cin.get( input, '\0' )を使用することを検討していましたが、'\0'は実際にはEOF文字ではなく、EOFまたは'\0'のいずれか早い方まで読み取ります。

または、それを行う唯一の方法はループを使用していますか?もしそうなら、最良の方法は何ですか?

71
Guille

Stdinから可変量のデータを読み取ることができる唯一の方法は、ループを使用することです。 std::getline() 関数が非常にうまく機能することが常にわかっています。

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

デフォルトでは、getline()は改行まで読み取ります。別の終了文字を指定できますが、EOFはそれ自体が文字ではないため、getline()を1回呼び出すことはできません。

63
trotterdylan

ストリームイテレータを使用すると、明示的なループなしで実行できます。内部で何らかのループを使用していると確信しています。

#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;
}
47
KeithB

ループの使用:

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

リソース

41
Degvik

std::istream_iteratorを使用してKeithBのソリューションを調査した後、 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;
}
22
Richard Smith

おそらく最も単純で一般的に効率的:

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

必要に応じて、ここでは標準出力ストリームの代わりにstd::ostringstreamなどの他のタイプのストリームをバッファーとして使用します。

5
FrankHB

std :: istream :: getline() (または、できれば std :: stringで動作するバージョン )関数を使用して、行全体を取得できます。どちらにも、区切り文字(行末文字)を指定できるバージョンがあります。文字列バージョンのデフォルトは「\ n」です。

2
luke

悲しいことに、ブーストベースのコードとの整合性を保つために、C++ IOを使用することにしました。この質問への回答から、while (std::getline(std::cin, line))を選択しました。 cygwin(mintty)でg ++バージョン4.5.3(-O3)を使用すると、2 MB/sのスループットが得られました。 Microsoft Visual C++ 2010(/ O2)は、同じコードで40 MB/sになりました。

IOを純粋なC while (fgets(buf, 100, stdin))に書き換えた後、テストされた両方のコンパイラでスループットが90 MB/sに跳ね上がりました。これは、10 MBを超える入力に対して違いをもたらします...

2
liborm

待って、あなたを正しく理解していますか?キーボード入力に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
derpface
while(std::cin) {
 // do something
}
0
Bryan

1つのオプションは、コンテナを使用することです。

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