为什么在我使用 CTRL+D 退出循环后不等待我输入字符串

Why doesn't it wait for me to input string after I exit the loop using CTRL+D

提问人:petyr 提问时间:1/28/2023 最后编辑:Steve Friedlpetyr 更新时间:1/28/2023 访问量:82

问:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char c, char_array[100];
    int i = 0;
    printf("Enter characters (press CTRL+D to end):\n");
    while(fgets(char_array+i,sizeof(char_array)-i,stdin)) {
        i = i + strlen(char_array+i);
        if(char_array[i-1] == EOF)
            break;
    }
    char_array[i-1] = '\0';
    strtok(char_array,"\n");
    printf("\nEnter a string:\n");
    char string[100];
    fgets(string,sizeof(string),stdin);
    printf("\nCharacter Array: %s\n", char_array);
    printf("String: %s\n", string);
    return 0;
}

这是代码,我尝试了许多不同的变体(更简单),但它总是有同样的问题......我输入字符,按 CTRL+D,它结束,无需等待我输入字符串。请帮忙

我尽了我所能,但我就是做不到它,我的朋友也做不到......我有和考试,我需要在最多 3 天内完成,所以我需要我能得到的所有帮助。

C 循环 scanf fgets eof

评论

2赞 Weather Vane 1/28/2023
因为您结束了输入流。您可以使用空字符串来终止循环。
2赞 Weather Vane 1/28/2023
About 不是输入中的实际字符,而是信号值。循环结束是因为返回了,而不是因为在字符串输入中找到了 。if(char_array[i-1] == EOF)EOFfgets()NULLEOF
1赞 Eric Postpischil 1/28/2023
@WeatherVane:在输入某些字符(不是回车/回车)后按 Control-D 不会结束输入流。它将字符发送到程序,之后另一次读取将获得更多字符(一旦输入)。(在输入/返回后按 Control-D 也不会结束输入流。这将导致返回空指针,但您可以清除 EOF 和错误指示器并继续。fgets
1赞 Eric Postpischil 1/28/2023
if(char_array[i-1] == EOF)是不正确的。 通常是从某些例程(如 )返回的值。 不放入缓冲区。EOFintgetcharfgetsEOF
2赞 Eric Postpischil 1/28/2023
@petyr:没有。首先,这个问题不合适。其次,在不知道“有效”是什么意思的情况下,不可能编写一个“有效”的程序。每个程序都有一些规范。这可能是一份正式的文件,说明它应该做什么,但是,即使是家庭作业,也有一些关于程序应该做什么的声明。您尚未说明该程序应该做什么。它应该读取输入直到已满吗?直到按下 return 或 enter?直到第一次返回 null 指针?别的?然后呢?char_arrayfgets

答:

0赞 Allan Wind 1/28/2023 #1
  1. fgets()在流关闭时返回。在 Linux 上,如果终端缓冲区不为空,则 Ctrl-D 将刷新终端缓冲区(但不会返回,因为它保持行缓冲状态),并且需要第二个 Ctrl-D 来触发流的 EOF 状态。NULLfgets()

  2. 如果数组已满,您还希望终止循环,否则它是一个无限循环:

#define ARRAY_LEN 100

//...

    while(i < ARRAY_LEN - 1 && fgets(char_array + i, ARRAY_LEN - i,stdin)) {
  1. fgets()不会作为正在读取的字符串的一部分发出,所以这是不正确的,并且由于 stdin 是行缓冲的,如果缓冲区已满,则最后一个字符是 either 或 any,如果最后一个字符被读取,这可能是 or (无论字符是否带符号,但这仍然是错误的):EOF\n-10xff
        if(char_array[i-1] == EOF)
            break;
  1. 下一行:
    char_array[i-1] = '\0';

如果数组已满(即数据丢失),则删除最后一个字符,即我们最后读取的任何字符(即数据丢失)。\n

  1. 当输入流处于状态时,第二个将返回 NULL。您可以在调用之前清除该状态以获取第二个字符串。如果流确实结束了,如 ,当然,第 2 个返回 NULL 再次。EOFfgets()clearerr(stdin)fgets()echo "hello world" | ./your_programfgets()

我建议你用一个空行来表示输入的结束:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ARRAY_LEN 100

int main() {
    printf("Enter characters (empty line to end):\n");
    char char_array[ARRAY_LEN];
    for(size_t i = 0; i < ARRAY_LEN - 1; i += strlen(char_array)) {
        if(!fgets(char_array + i, ARRAY_LEN - i, stdin)) {
            printf("fgets() failed\n");
            return 1;
        }
        if(char_array[i] == '\n') {
            char_array[i] = '\0';
            break;
        }
    }
    strtok(char_array, "\n");
    printf("Enter a string:\n");
    char string[ARRAY_LEN];
    char *rv = fgets(string,sizeof(string),stdin);
    printf("Character Array: %s\n", char_array);
    printf("String: %s\n", string);
}

和示例会话:

Enter characters (empty line to end):
hello
world

Enter a string:
friend
Character Array: hello
String: friend

评论

0赞 Dúthomhas 1/28/2023
每个人系统上的 EOF 都是 ,但重要的一点是,它是一个于有效输入的可用范围的位值。A 可以是有符号的,也可以是无符号的,但返回的有效值将始终为最大值 0..255(设置了 8 位),其中设置了所有位。-1chargetchar()-1
0赞 Allan Wind 1/28/2023
@Dúthomhas 谢谢。我调整了 EOF 和 -1 的答案。什么将 EOF 定义为 -1?除了 7.4 之外,我在 C 标准中没有看到它“也不能表示为无符号字符”。没错,因此理论上用户可以输入0xff编码的任何内容并进行比较等于 EOF,但我指出这不会发生。我们不是在谈论 getchar(),而是在谈论 fgets(),即 chars。
1赞 Chris Dodd 1/28/2023
@AllanWind,stdio.h 头文件将 EOF 定义为 -1。标准 (7.21.1) 仅指定它是一个宏,可扩展为类型为负数的值。int
1赞 Peter - Reinstate Monica 1/28/2023
@ChrisDodd 您的 stdio.h 将其定义为 -1 ;-)。
1赞 Dúthomhas 1/28/2023
根据 POSIX,EOF 可以是任何负数。 只是最简单的目标,我不知道有任何系统不是它 - 但我从来不需要关心或验证,因为重点是在返回值中设置了高位,而有效的字符输入不能设置这些位。-1
0赞 Chris Dodd 1/28/2023 #2

对于 stdio 流,error/eof 是粘性的 -- 也就是说,一旦发生错误或 eof 条件,对 的进一步操作将继续返回 EOF 或 NULL (取决于函数),而不是尝试进一步读取或写入任何内容。FILE *

要重置 上的 eof 状态,您需要调用 。完成此操作后,您可以从终端读取其他输入。FILE *clearerr(stdin)