私はCプログラミング言語を読んでおり、これまでのところすべてを理解しています。ただし、getchar()
とputchar()
に出会ったとき、それらの使用法、具体的には次のコードの動作を理解できませんでした。
_main()
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
_
main()
関数、整数の宣言c
およびwhile
ループを理解しています。それでも、while
ループ内の条件について混乱しています。このCコードの入力と出力は何ですか。
これが基本的で愚かな質問であれば申し訳ありませんが、本を読み進めて混乱する前に、簡単な説明を探しています。
getchar()
は、標準入力から文字を読み取る関数です。 EOF
は、[〜#〜] c [〜#〜]で使用される特殊文字で、END OF FILEに到達したことを示します。
通常、標準入力がコンソール(ファイルなど)以外の場合、getchar()
からEOF
文字が返されます。
このようにプログラムをUNIXで実行する場合:
_$ cat somefile | ./your_program
_
getchar()
は、somefile
が終了するとすぐにEOF
およびsomefile
のすべての文字を返します。
このようにプログラムを実行する場合:
_$ ./your_program
_
そして、EOF
をコンソールから送信します(Unixでは_CTRL+D
_を、WindowsではCTRL + Zを押すことで)、getchar()
もEOF
と実行を返します。終了します。
コマンドラインに-1を入力してもプログラムが終了しないという事実に戸惑うかもしれません。 getchar()
はこれを2つの文字、-と1として読み取るため、cへの割り当てで、文字はASCII数値に変換されます。この数値は、 cによってアクセスされるメモリの場所。
次に、putchar(c)
がこの値を取得し、ASCIIテーブルを検索し、文字に変換して出力します。
テーブルが0から始まるため、ASCIIテーブルで値-1 10進数を見つけることは不可能です。したがって、getchar()
は異なるプラットフォームで異なるソリューションを考慮する必要があります。プラットフォームごとにgetchar()
バージョンがありますか?
このEOFが通常のasciiにないことは奇妙だと思います。印刷できない最初の文字の1つである可能性があります。たとえば、行末はASCII。
WindowsからLinuxにファイルを転送するとどうなりますか? EOFファイル文字は自動的に更新されますか?
getchar() 関数はキーボードから文字を読み取ります(つまり、stdin
)
指定されたwhile
ループ内の条件では、各反復の前にgetchar()
が呼び出され、受信した値が整数c
に割り当てられます。
さて、Cでは、標準入力(stdin
)は like ファイルであることを理解する必要があります。つまり、入力はバッファリングされます。入力は、実際に消費されるまでバッファに残ります。 stdin
は、実際には 標準入力ストリーム です。
getchar()
は、入力バッファで次に使用可能な値を返します。
プログラムは基本的に、キーボードから読み取られたものをすべて表示します。 \n
(改行)、スペースなどの空白を含む.
つまり、入力はユーザーがキーボードを介して提供する入力です(stdin
は通常キーボードを意味します)。そして、出力は入力として提供するものです。
提供する入力は文字ごとに読み取られ、数字として与えられた場合でも文字として扱われます。
getchar()
は、ファイルの終わりに達した場合にのみEOF
を返します。ここで関心のある「ファイル」はstdin
自体(標準入力)です。
キーボードを介して提供する入力が保存されているファイルが存在することを想像してください。 stdin
です。この「ファイル」は 無限のファイル のようなものです。したがって、EOF
はありません。
getchar()
が一度に処理できる以上の入力を提供する場合(Enterを押して入力として提供する前)、余分な値は入力バッファに消費されずに格納されます。 getchar()
は入力から最初の文字を読み取り、c and print
cwith
putchar(c) `に保存します。
while
ループの次の反復中に、前の反復中に指定された、まだstdin
にある余分な文字は、while ((c = getchar()) != EOF)
の間にc=getchar()
部分とともに取得されます。入力バッファに何もなくなるまで同じプロセスが繰り返されます。
これにより、反復中に複数の文字が入力として与えられた場合、putchar()
が一度に1文字ではなく文字列を返しているように見えます。
例:入力がabcdefghijkl
出力は同じでしたabcdefghijkl
この動作が望ましくない場合は、putchar(c);
の直後に fflush(stdin); を追加できます。これにより、ループは各反復中に提供された入力の最初の文字のみを出力します。
例:入力がadgbad
a
のみが出力されます。
Enterキーを押した後にのみ、入力はstdin
に送信されます。
putchar() はgetchar()
の反対です。出力を標準出力ストリーム(stdout
、通常はモニター)に書き込みます。
EOF
は、ファイルに存在する文字ではありません。関数によってエラーコードとして返されたものです。
ただし、通常はgive while
ループを終了することはできません。入力バッファは、キーボードから何かが入力されるとすぐに(出力に表示するために)空になり、stdin
はEOF
を与えません。
ループを手動で終了するには、キーボードを使用してEOF
を送信します。 ctrl+D Linuxおよび
ctrl+Z Windowsで
例えば:
while ((c = getchar()) != EOF)
{
putchar(c);
fflush(stdin);
}
printf("\nGot past!");
キーの組み合わせを押してEOF
を指定すると、プログラムを終了する前にメッセージGot past!
が表示されます。
stdin
が じゃない すでに空の場合は、このキーの組み合わせを2回押す必要があります。このバッファーをクリアしてからEOF
をシミュレートします。
編集:c = getchar()
のwhile ((c = getchar()) != EOF)
を囲む括弧の余分なペアは、getchar()
によって返される値が最初にc
に割り当てられることを確認することです。 それ 値はEOF
と比較されます。
この余分な括弧がない場合、式は実質的にwhile (c = (getchar() != EOF) )
になり、c
は次の2つの値を持つことができます:1
(trueの場合)または0
(forの場合) false)これは明らかに意図したものではありません。
現在の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.6p )と書かれています:
getchar
関数は、stdin
が指す入力ストリームから次の文字を返します。ストリームがファイルの終わりにある場合、ストリームのファイルの終わりインジケータが設定され、getchar
はEOF
を返します。読み取りエラーが発生すると、ストリームのエラーインジケーターが設定され、getchar
はEOF
を返します。
EOF
は0未満の整数定数であり、通常の戻り値は0以上である-_unsigned char
_はint
にゼロ拡張されていると他の場所で述べられています。
ファイルの終わりにあるストリームは、すべての入力が消費されたことを意味します。標準入力の場合、次のように入力してキーボードからこれを引き起こすことができます。 Ctrl+D Unix/Linux端末および Ctrl+Z Windowsコンソールウィンドウで。別の可能性は、プログラムがキーボードからではなくファイルまたはパイプから入力を受信することです。その入力が完全に消費されるたびに、ファイルの終わりが通知されます。
_cat file | ./myprogram
_
または
_./myprogram < file
_
上記のフラグメントが言うように、実際にはgetchar
がEOF
を返す2つの異なる条件があります。 end-of-file に到達したか、 or 実際のエラーが発生しました。これは、戻り値だけから推測することはできません。代わりに、関数feof
およびferror
を使用する必要があります。 feof(stdin)
は、標準入力でファイルの終わりに達した場合に真の値を返します。エラーが発生した場合、ferror(stdin)
はtrueを返します。
実際のエラーが発生した場合、_<errno.h>
_で定義された変数errno
にはエラーコードが含まれます。関数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('?');
}
}
_
ファイルの終わりをトリガーするには、Linuxの新しい行でCtrl + D(ここでは_^D
_と表示)を使用します。
_% ./a.out
Hello world
Hello world
^D
end-of-file reached
_
(ここで input がどのように行バッファリングされるかに注意してください。したがって、入力は出力内の行内でインターリーブされません)。
同様に、パイプラインを使用して同じ効果を得ることができます。
_% echo Hello world | ./a.out
Hello world
end-of-file reached
_
エラーをトリガーすることはもう少し難しいです。 bash
およびzsh
シェルでは、コマンドに_<&-
_を追加することにより、どこからでも来ないように、標準入力を closed にできます。ライン:
_% ./a.out <&-
An error occurred. errno set to 9
Human readable explanation: Bad file descriptor
_
不良ファイル記述子、またはEBADF
は、標準入力-ファイル記述子番号0が開かれていないため無効であったことを意味しますまったく。
エラーを生成する別の楽しい方法は、 directory から標準入力を読み取ることです。これにより、LinuxでerrnoがEISDIR
に設定されます。
_% ./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
_にリダイレクトすることでこれをテストすることができます-しかし、落とし穴があります-標準出力はバッファリングされているので、 enough を記述してバッファをプログラムの最後ではなく、すぐにフラッシュします。 _/dev/zero
_から無限のゼロバイトを取得します:
_ % ./a.out < /dev/zero > /dev/full
putchar failed: No space left on device
_
追伸getchar()
の戻り値を格納するには、常にint
型の変数を使用することが非常に重要です。 文字を読み取りますが、 signed
/unsigned
/plain char
は常に間違っています 。
main(){
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
実際には、c = getchar()はユーザーがコンソールに入力する文字を提供し、その値はEOF End Of Fileを表します。EOF最後のファイル。(c = getchar())!= EOFはc!= EOFと同等です。今ではこれがはるかに簡単だと思います。さらにクエリがある場合はお知らせください。
_ getchar()
_
入力から文字を取得します。
_ c = getchar()
_
この割り当ての値は、割り当て後の左側の値、または読み取られた文字の値です。 EOF
の値はデフォルトで_-1
_です。
_ ((c = getchar()) != EOF)
_
値がEOF
以外の値である限り、つまり、条件がtrueである限り、ループは反復し続けます。値がEOF
になると、条件全体の値は_0
_になり、ループが中断されます。
c = getchar()
の周りの追加の括弧は、通常__==
_を入力することを想定して警告するため、条件内で実際に割り当てを行いたいことを強調するためのコンパイラー用です。
_ main() {
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
_
したがって、コード全体が実際に入力内容をエコーバックします。文字の値を条件内のc
に割り当ててから、ループの本体に出力し、ファイルの終わりが検出された場合にのみ終了します。
|と同様の方法で上記のパイプコマンドを使用すると、システムでリダイレクトを使用して、上記のコードを使用して、ファイルのすべての文字コンテンツを、通常はCTRL-ZまたはCTRL-Dで表される末尾(EOF)に達するまで表示できます。
コンソールで:ProgramName < FileName1.txt
FileName1から読み取ったもののコピーを作成するには、次のようにします。ProgramName < FileName1.txt > CopyOfInput.txt
これは、理解を助けるために、プログラムを複数の方法で示しています。
-助けてくれることを願っています。