質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

1835閲覧

C++ : Ctrl + D(EOF送信)をしたあとも標準入力をしたい。

yoshiki_iwasa

総合スコア23

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/11/08 04:20

質問概要

Q: ctrl+D を押したあと、std::cin.getline() で標準入力を受け取り続けることはできますか?

C++ でcatコマンド(オプションなし)を作ろうとしています。その過程で行き詰まり質問しています。

質問詳細

cat コマンドを作成するにあたって、再現できない挙動があります。
それは、cat コマンドで標準入力待ち状態で、<文字>+Ctrl D 押したときのものです。
再現手順を以下に示します。

zsh

1$ cat 2   <- 標準入力まち 3 ddd<space> <-ここで ctrl+ D を押下すると 'ddd ddd' と表示される。このあとも入力を続けることが可能。 4

上記の挙動を再現したいのですが、Ctrl + D が押された瞬間にプログラムの標準入力にEOF が送られてしまい、追加で入力ができません。

以下に、自分が書いているコードを記載します。

C++

1#include <iostream> 2 3int main() 4{ 5 char input[20]; //簡単のため、大きさ20にしている。 6 while(1) 7 { 8 std::cin.getline(input, 20);//標準入力取得 9 if (std::cin.eof()) // Ctrl + D が押されたらこの中に入る。 10 { 11 std::cout << input; 12 } 13 else 14 { 15 std::cout << input << std::endl;//通常の入力であればこっち 16 } 17 std::cin.clear(); 18 } 19}

このプログラムの挙動をいかに示します(実行ファイル名はa.out

zsh

1 2$ ./a.out 3<- 標準入力まち 4ddd <- enter押下 5ddd 6 7ddd <-ctrl Dを2回押下すると、 'ddd ddd' となるが、これ以降入力を受け付けなくなる。

自分が所望する挙動は、cat コマンドの様に、Ctrl + D を押したあとでも、押す前と変わらず入力ができることです。

どなたかお力を貸してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

Ctrl-Dの挙動はアプリでどうこうしているものではなく、OSの判断(正確にはtty/ptyドライバ)によるものなので、C++でどうこうするものではありません。
※逆に言えば、catと条件は同じ。

それはそれとして、cat側では行頭から数文字入力してCtrl-D 1回なのに対し、C++アプリ側では2回と条件が合っていません。揃えて比較するようにしてください。

投稿2020/11/08 05:01

angel_p_57

総合スコア1672

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

ちょっとstd::cinでの書き方が分からないので、Cで書いてみます。

C

1#include <stdio.h> 2#include <unistd.h> 3 4int main() 5{ 6 char input[20]; 7 int n; 8 9 while(1) 10 { 11 n = read(0,input,sizeof input); 12 switch(n){ 13 case 0: // EOF 14 return 0; 15 case -1: // ERROR 16 perror("read"); 17 return 1; 18 default: 19 write(1,input,n); 20 } 21 } 22}

Unix/Linuxの端末は(デフォルトでは)、プログラムにデータを渡す(システムコールのreadがリターンする)ケースが2つあり、
(1) Enter(\r)を押すと\nに書き換えた上で入力データに追加して、プログラムにそれまでの入力データを渡す
(2) Ctrl-Dを押すと、そのキーデータを入力データに追加せずに、プログラムにそれまでの入力データを渡す

これ以外の、Ctrl-Cなど割り込み関係のキー、BSなど行編集関係のキーはそれぞれ処理され、A等一般のキーは単に入力データに追加されます。

つまり、
aaaEnterだと、"aaa\n"の4バイトがプログラムに渡ります。
aaaCtrl-Dだと、"aaa"の3バイトがプログラムに渡ります。
・行頭(または前回Ctrl-Dの直後)でEnterだと、"\n"の1バイトがプログラムに渡ります。
・行頭(同)でCtrl-Dだと、0バイトがプログラムに渡ります(入力データ無しでreadがリターン)。

プログラムでは、read0を返すとEOFだと判断するのが普通です(対象がファイル等の場合、ファイルの末尾に達すした後は0を返すので)。
が、さらにreadするのは可能です。ファイル等の場合は0を返すだけですが、端末の場合はさらに入力が可能です。

Cのfopen/fread/getc/fcloseや、C++のstd::cinだと、readに一皮かぶせているので、プログラムから見た動作が上記と異なります。
std::cinで上記プログラムと同等のことが出来るのかどうかは分かりません。出来なさそうな気がしますが。

投稿2020/11/08 10:23

otn

総合スコア84498

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2020/11/08 10:37

(1a)のケースがありました。Ctrl-J (\n)を押した場合でも同様。
yoshiki_iwasa

2020/11/16 04:48

お返事いただいてからコメントを返すのに時間がかかってしまってすいません。結局、std::cin ではできないという結論にいたり、read() を使ってさっと終わらせました。 自分の学校ででた課題なのですが、意図が結局よくわからなかったです(stdcin では cat みたいな動きをさせることはできないよって言いたかった????) 丁寧な解説をしていただいてありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問