[英]Can't find EOF in fgetc() buffer using STDIN
編輯
問題的解決方案是了解Ctrl-D實際上在做什么。
在一個新的空行上,一個Ctrl-D將發出EOF信號。
但如果行中已有字符,則第一個Ctrl-D會使行的內容回顯到屏幕(但不會寫入STDOUT
)。 如果緩沖區中已有字符,則必須發出第二個Ctrl-D信號EOF
,從而將緩沖區寫入STDOUT
。
這可以通過將輸出重定向到文件來演示。
編輯
我正在使用fgetc()從stdin
讀取輸入。 我循環直到收到EOF。 在循環中,我根據按下Ctrl-D之前鍵入的字符構建一個字符串。 但我無法想出退出循環的方法,因為緩沖區ch = fgetc()讀取不包含EOF。 (EOF僅觸發fgetc()返回其第一個值。)
ungetc()不允許將EOF推入緩沖區,推動任何其他char運行與真實數據混淆的風險,我被卡住! 我已經閱讀了很多答案,但他們沒有解決這個問題,或者不適用於我正在嘗試實現的用例。
我希望能夠在stdin緩沖區上計數,查看等。
我真的不想讀整行(或者一次是X個字符),因為我正在處理來自fgetc()的每個字符( 編輯 )。
關於如何克服這種困境的任何建議? (不使用NCurses)
我正在使用Ubuntu。 EOF = Ctrl-D以下是我正在使用的一些代碼:
這有效,並且與Jonathan的簡單示例相同,但不是我想要的:
int main(int argc, char **argv) {
int inputChr;
do {
inputChr = fgetc(stdin);
if (inputChr != EOF) {
fputc( inputChr, stdout);
}
if (feof(stdin)) {
if (ferror(stdin)) {
perror(NULL);
return errno;
}
}
} while (inputChr != EOF);
return EXIT_SUCCESS;
}
然而,這是卡住但是正在嘗試做我想要的( 編輯 )但是第二次需要Ctrl-D:
char *buildLine (FILE *inputSource, char *currLine, int showTabs, int showNonPrint, int *haveLF) {
int inputChr;
char *thisLine = malloc(1);
int inputSize;
*haveLF = FALSE;
while ( (inputChr = fgetc(inputSource)) != EOF ) {
if (ferror(inputSource)) {
perror(NULL);
} else {
if (inputChr == LF) {
*haveLF = TRUE;
} else {
thisLine = strconcat(thisLine,(char *)&inputChr);
}
}
}
return thisLine;
}
還有一些被問到的代碼:
char * strconcat ( char *str1, char * str2) {
char *newStr = malloc(strlen(str1)+strlen(str2)+1);
if (newStr == NULL) {
return NULL;
}
strcpy(newStr,str1);
strcat(newStr,str2);
return newStr;
}
以下版本按字符處理輸入字符,就cat
。 但我決定在應用一些我需要實現的額外轉換之前先將每個字符處理成一行。 這簡化了狀態機設計,但是嘗試構建線路並不是一個好選擇(不使用NCurses)。 :(
int echoInput( FILE *inputSource, FILE *outputDestination, int numbers, int showEnds) {
int haveNewLine = TRUE;
int lineNo = 1;
int inputChr;
do {
inputChr = fgetc(inputSource);
if (inputChr != EOF) {
if (numbers && haveNewLine) {
long lineNoSize = (long) log10(lineNo)+1; // effectively floor(log10(lineNo)+1) = number digits
char *lineNoStr = (lineNoSize<6)?malloc(8):malloc(lineNoSize+2); // If less than 6 digits, allow for minimum 6 plus tab. Also +1 for terminator.
if (lineNoStr == NULL) {
printf ("Error::Out of Memory");
return ENOMEM;
}
sprintf(lineNoStr,"%6d\t",lineNo); // format lineNo string
fputs(lineNoStr, outputDestination); // send string to output
lineNo++;
haveNewLine = FALSE;
}
if (inputChr == LF) {
if (showEnds) {
fputc('$', outputDestination); // send char to output
}
haveNewLine = TRUE;
}
fputc( inputChr, outputDestination);
}
if (feof(inputSource)) {
if (ferror(inputSource)) {
perror(NULL);
return errno;
}
}
if (ferror(outputDestination)) {
perror(NULL);
return errno;
}
} while (inputChr != EOF);
return EXIT_SUCCESS;
}
這個問題必須有其他變化,並且有足夠好的答案,但這里還有一個。
fgetc()
(以及getc()
和getchar()
)返回的值是int
而不是char
。 它必須是一個int
因為可以返回的值集包括char
每個可能值和一個額外值EOF,它是負數(而字符都是正數)。 雖然EOF最常見的是-1
,但你永遠不應該對這個假設進行編碼。
有兩件事可能出錯:
char c;
while ((c = fgetc(stdin)) != EOF)
如果char
類型被簽名,那么一些字符(通常是0xFF,通常是ÿ,y-umlaut,Unicode U + 00FF,LATIN SMALL LETTER Y WITH DIAERESIS)將被誤解為在達到EOF之前指示EOF。
如果char
類型是無符號的,那么你將永遠不會檢測到EOF,因為分配給c
的值將是0xFF(正),並且永遠不會比較等於EOF(負值)。
你是不對的,你不能使用ungetc()
將EOF推回輸入流。
請注意, Control-D (或Windows上的Control-Z )不會在輸入隊列中添加字符。 相反,它表示沒有可用的字符(略微簡化的東西),這意味着read()
系統調用返回0字節讀取,這意味着EOF。
使用getchar()
和putchar()
將標准輸入復制到標准輸出的簡單程序是:
int c;
while ((c = getchar()) != EOF)
putchar(c);
如果要打開文件並讀取文件,可以調整它以使用fgetc()
或getc()
和fputc()
或putc()
。 關鍵是使用int
來保存讀取的值。
EOF
通常是整數(不是char
),並且它與任何有效字符的值不同。
正常的C樣式是用\\0
來終止你正在構建的字符串。 理論上,理論上可以讀取NUL
字符,如果你想處理這些可能性,你需要記錄讀取的字符數以及讀入的緩沖區。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.