42

私はCプログラミング言語を読んでいて、これまでのところすべてを理解しています。getchar()しかし、とに出くわしたとき、putchar()それらの使用法、より具体的には、次のコードが何をするのかを理解できませんでした。

main()
{
    int c;
    while ((c = getchar()) != EOF)
       putchar(c);
}

main()関数、整数の宣言cwhileループを理解しています。しかし、私はwhileループ内の状態について混乱しています。このCコードの入力と出力は何ですか。

これが基本的で愚かな質問である場合は申し訳ありませんが、本を読み進めて混乱する前に、簡単な説明を探しています。

4

8 に答える 8

37

このコードは、次のように明確に記述できます。

main()
{
    int c;
    while (1) {
        c = getchar();            // Get one character from the input
        if (c == EOF) { break; }  // Exit the loop if we receive EOF ("end of file")
        putchar(c);               // Put the character to the output
    }
}

EOF入力がなくなると文字が受信されます。この名前は、ユーザー入力(ファイルの特殊なケース)ではなく、実際のファイルから入力が読み取られる場合にわかりやすくなります。


[余談ですが、通常、main関数は次のように記述する必要がありますint main(void)。]

于 2012-05-23T13:23:22.147 に答える
25

getchar()標準入力から文字を読み取る関数です。ENDOFFILEに到達したことを示すためにCEOFで使用される特殊文字です。

通常、標準入力がコンソール(つまり、ファイル)以外の場合EOFから文字が返されます。getchar()

次のようにUNIXでプログラムを実行する場合:

$ cat somefile | ./your_program

次に、終了するとすぐgetchar()にすべての文字を返します。somefileEOFsomefile

このようにプログラムを実行する場合:

$ ./your_program

EOFそして、コンソールを介して(CTRL+DUnixの場合はCtrlキーを押しながら、Windowsの場合はCTRL + Zキーを押して)を送信すると、getchar()も返さEOFれ、実行が終了します。

于 2012-05-23T13:24:34.090 に答える
7

現在のC標準で記述されたコードは

#include <stdio.h>

int main(void)
{
    int c;
    while ((c = getchar()) != EOF)
       putchar(c);
}

ループは次のように書き直すことができます

int c;
while (1) {
    c = getchar();
    if (c != EOF)
        putchar(c);
    else
        break;
}

これは次のように読みます

  • 永遠に繰り返す
    • 標準入力から入力の次の文字(「バイト」)を取得し、に格納しますc
    • 当該文字の読み取り中に例外的な状態が発生しなかった場合
      • 次に、格納されている文字c標準出力に出力します
    • そうしないと
      • ループを壊す

多くのプログラミング言語は、通常のプログラムフローを中断する例外を発生させることにより、例外条件を処理します。Cはそのようなことをしません。代わりに、失敗する可能性のある関数には戻り値があり、例外的な条件は特別な戻り値によって通知されます。これは、特定の関数のドキュメントから確認する必要があります。の場合getchar、C11標準のドキュメントには(C11 7.21.7.6p3)と記載されています。

  1. このgetchar関数は、が指す入力ストリームから次の文字を返しますstdin。ストリームがファイルの終わりにある場合、ストリームのファイルの終わりインジケーターが設定され、をgetchar返しますEOF。読み取りエラーが発生すると、ストリームのエラーインジケーターが設定され、getcharが返されますEOF

EOF<0である整数定数であり、通常の戻り値は>=0であると他の場所で述べられています-unsigned charゼロは。に拡張されますint

ストリームがファイルの終わりにあるということは、すべての入力が消費されたことを意味します。標準入力の場合、Unix / Linux端末でCtrl+を入力し、Windowsコンソールウィンドウで+を入力することにより、キーボードからこれを引き起こすことができます。もう1つの可能性は、プログラムがキーボードからではなくファイルまたはパイプから入力を受け取ることです。その場合、入力が完全に消費されるたびにファイルの終わりが通知されます。DCtrlZ

cat file | ./myprogram

また

./myprogram < file

上記のフラグメントが示すように、実際には2つの異なる条件がgetchar返される可能性があります。ファイルの終わりに到達した、実際のエラーが発生したEOFかのいずれかです。これは、戻り値だけから推測することはできません。代わりに、関数とを使用する必要があります。標準入力でファイルの終わりに達した場合、真の値を返します。エラーが発生した場合はtrueを返します。feofferrorfeof(stdin)ferror(stdin)

実際のエラーが発生した場合、errnoによって定義された変数<errno.h>にはエラーコードが含まれます。この関数perrorを使用すると、人間が読める形式のエラーメッセージにプレフィックスを付けて自動的に表示できます。したがって、例を次のように拡張できます。

#include <stdio.h>
#include <errno.h> // for the definition of errno
#include <stdlib.h> // for exit()
int main(void)
{
    int c;
    while ((c = getchar()) != EOF)
       putchar(c);

    if (feof(stdin)) {
        printf("end-of-file reached\n");
        exit(0);
    }
    else if (ferror(stdin)) {
        printf("An error occurred. errno set to %d\n", errno);
        perror("Human readable explanation");
        exit(1);
    }
    else {
        printf("This should never happen...\n");
        exit('?');
    }
}

ファイルの終わりをトリガーするには、^DLinuxの新しい行でCtrl + D(ここではとして表示)を使用します。

% ./a.out
Hello world
Hello world
^D
end-of-file reached

(ここでの入力がラインバッファリングされているため、入力が出力のあるライン内でインターリーブされていないことに注意してください)。

同様に、パイプラインを使用しても同じ効果を得ることができます。

% echo Hello world | ./a.out
Hello world
end-of-file reached

エラーをトリガーするのは少し注意が必要です。bashシェルでは、コマンドラインに追加するzshことで、標準入力を閉じて、どこからも入力されないようにすることができます。<&-

% ./a.out <&-
An error occurred. errno set to 9
Human readable explanation: Bad file descriptor

不正なファイル記述子、または標準入力-ファイル記述子番号0がまったく開かれなかったため、無効であったことをEBADF意味します。

エラーを生成するもう1つの楽しい方法は、ディレクトリから標準入力を読み取ることです。これによりEISDIR、Linuxでerrnoが設定されます。

% ./a.out < / 
An error occurred. errno set to 21
Human readable explanation: Is a directory

実際には、の戻り値putcharもチェックする必要があります。同様にEOF、エラーが発生した場合、または次のように記述された文字が返されます。

while ((c = getchar()) != EOF) {
    if (putchar(c) == EOF) {
        perror("putchar failed");
        exit(1);
    }
}

そして今、標準出力をにリダイレクトすることでこれをテストできます/dev/full-しかし、落とし穴があります-標準出力はバッファリングされているので、プログラムの最後ではなく、すぐにバッファをフラッシュさせるのに十分な書き込みが必要です。から無限のゼロバイトを取得します/dev/zero

 % ./a.out < /dev/zero > /dev/full
 putchar failed: No space left on device

intPSの戻り値を格納するには、常に型の変数を使用することが非常に重要ですgetchar()文字を読み取っても、// plain使用は常に間違っていsignedunsignedcharます。

于 2017-08-08T22:39:12.830 に答える
4

コマンドラインで-1を入力してもプログラムが終了しないという事実に混乱したかもしれません。これは、-と1の2文字として読み取られるためgetchar()です。cへの割り当てでは、文字はASCII数値に変換されます。この数値は、cによってアクセスされるメモリ位置に格納されます。

次にputchar(c)、この値を取得し、ASCIIテーブルを検索して、印刷される文字に変換し直します。

表は0から始まるため、ASCIIテーブルで小数点以下1の値を見つけることは不可能だと思います。したがってgetchar()、さまざまなプラットフォームでのさまざまなソリューションを考慮する必要があります。getchar()プラットフォームごとにバージョンがあるのでしょうか?

このEOFが通常のASCIIにないのは奇妙だと思います。印刷できない最初の文字の1つである可能性があります。たとえば、End-of-lineはASCIIです。

ファイルをWindowsからLinuxに転送するとどうなりますか?EOFファイルの文字は自動的に更新されますか?

于 2012-10-21T11:37:15.280 に答える
4

getchar() 関数は、キーボードから文字を読み取ります(つまり、stdin

while指定されたループ内の条件でgetchar()は、各反復の前にが呼び出され、受信した値が整数に割り当てられcます。

stdinここで、Cでは、標準入力( )はファイルのようなものであることを理解する必要があります。つまり、入力はバッファリングされます。入力は、実際に消費されるまでバッファに残ります。 stdin実際には標準の入力ストリームです。

getchar()入力バッファで次に使用可能な値を返します。

プログラムは基本的に、キーボードから読み取ったものをすべて表示します。\n(改行)、スペースなどのような空白を含みます。

つまり、入力は、ユーザーがキーボード(stdin通常はキーボードを意味します)を介して提供する入力です。そして、出力は私たちが入力として提供するものです。

私たちが提供する入力は、文字ごとに読み取られ、数字として指定しても文字として扱われます。

getchar()EOFファイルの終わりに達した場合にのみ戻ります。ここで関係する「ファイル」はstdinそれ自体(標準入力)です。

キーボードを介して提供する入力が保存されている場所に存在するファイルを想像してみてください。それはstdinです。この「ファイル」は無限のファイルのようなものです。だからいいえEOF

一度に処理できるよりも多くの入力を提供した場合getchar()(Enterキーを押して入力として提供する前)、余分な値は消費されずに入力バッファーに保管されます。getchar()は入力から最初の文字を読み取り、それをc putchar(c)`に格納し c and printますwith

whileループの次の反復中に、前の反復中に指定された、まだ含まれている追加の文字が、パーツとともにstdin取得され ます。ここで、入力バッファに何も残らなくなるまで同じプロセスが繰り返されます。while ((c = getchar()) != EOF)c=getchar()

putchar()これにより、反復中に複数の文字が入力として指定された場合、一度に1文字ではなく文字列を返すように見えます。

例:入力があった場合
abcdefghijkl
、出力は同じでした
abcdefghijkl

この動作が必要ない場合は、fflush(stdin);を追加できます。直後putchar(c);。これにより、ループは各反復中に提供された入力の最初の文字のみを出力します。

例:入力があった場合
adgbad
のみaが印刷されます。

stdin入力は、Enterキーを押した後にのみ送信されます。

putchar()は。の反対ですgetchar()。出力を標準出力ストリーム(stdout通常はモニター)に書き込みます。

EOFファイルに存在する文字ではありません。これは、関数によってエラーコードとして返されるものです。

whileただし、通常はギブループを終了することはできません。入力バッファは、キーボードから何かが入ってくるとすぐに空になり(出力に表示するため)、stdinが与えられませんEOF

手動でループを終了する場合は、キーボードを使用して、Linuxでは+ 、Windowsでは+EOFを押して送信でき ます。ctrlD
ctrlZ

例えば:

while ((c = getchar()) != EOF)
{

   putchar(c);
   fflush(stdin);
}
printf("\nGot past!");

キーの組み合わせを押してを与えると、プログラムを終了する前にEOFメッセージが表示されます。Got past!

まだ空でない場合stdinは、このキーの組み合わせを2回押す必要があります。一度このバッファをクリアしてから、シミュレーションします。EOF

編集:中の括弧の余分なペアは、によって返された値が最初に割り当てられてから、その値がと比較c = getchar()されることを確認するためのものです。while ((c = getchar()) != EOF)getchar()cEOF

この余分な括弧がない場合、式は事実上、2つの値のいずれかを持つことができることwhile (c = (getchar() != EOF) )を意味します:(真の場合)または(偽の場合)これは明らかに意図されたものではありません。c10

于 2017-08-08T14:07:44.197 に答える
1
 getchar()

入力から文字を取得します。

 c = getchar()

この割り当ての値は、割り当て後の左側の値、または読み取られた文字の値です。の値EOFはデフォルトでです-1

 ((c = getchar()) != EOF)

値がそれ以外のものであるEOF限り、つまり、条件がtrueである限り、ループは繰り返され続けます。値が値EOFになると、条件全体の値になり0、ループが中断されます。

追加の括弧c = getchar()はコンパイラー用であり、条件内で割り当てを実行したかったことを強調しています。これは、通常、入力したいと想定して==警告するためです。

 main() {
     int c;
     while ((c = getchar()) != EOF)
         putchar(c);
 }

したがって、コード全体が実際に入力内容をエコーバックします。文字の値を条件内に割り当て、cループの本体に出力して、ファイルの終わりが検出されたときにのみ終了します。

于 2016-12-29T19:12:21.923 に答える
0

|と同様の方法で 上記のpipeコマンドを使用すると、システムでリダイレクトを使用して、上記のコードを使用して、通常はCTRL-ZまたはCTRL-Dで表される終わり(EOF)に達するまで、ファイルのすべての文字コンテンツを表示できます。

コンソールの場合: ProgramName < FileName1.txt

また、FileName1から読み取ったもののコピーを作成するには、次のことができます。 ProgramName < FileName1.txt > CopyOfInput.txt

これは、うまくいけばあなたの理解を助けるためにあなたのプログラムを複数の方法で示しています。

-お役に立てば幸いです。

于 2012-05-24T06:02:18.707 に答える
0
main(){
int c;
while ((c = getchar()) != EOF)
   putchar(c);
}

実際、c = getchar()は、ユーザーがコンソールに入力する文字を提供し、その値は、ファイルの終わりを表すEOFでチェックされます。ファイルの最後でEOFが検出されました。(c = getchar())!= EOFはc!=EOFと同等です。今、私はこれがはるかに簡単だと思います。さらに質問がある場合はお知らせください。

于 2016-06-19T14:25:05.870 に答える