【问题标题】:fgets() keeps getting skipped before entering loop [duplicate]fgets()在进入循环之前一直被跳过[重复]
【发布时间】:2019-05-22 20:18:10
【问题描述】:

试图删除一个字符,但对fgets 的调用被跳过/跳过。在不同的计算机上,它按应有的方式运行,但由于某种原因,它会跳过并基本上跳到程序的末尾。有任何想法吗?

【问题讨论】:

  • 您正在混合面向行的输入fgets() 和面向字符的输入。(getchar())。它们以不同的方式处理换行符,因此像您看到的那样的交互是程序员通常不期望的。解决方案是在给定的流上使用一种输入方法或另一种输入方法,并且永远不要混合它们(例如,对所有输入使用fgets(),并在需要时从输入字符串中提取单个字符)。
  • 跳过和跳跃是什么意思?你试过出道吗?
  • 注意:j--; 什么都不做,j 被重置,for (j = i; ... 每次遇到循环。

标签: c string stdin fgets


【解决方案1】:

您的代码中有几个问题,但我看不出有任何fgets() 跳过或跳过的原因。 getchar() 函数从stdin 中读取下一个字符。一般我们在给getchar()函数输入时,输入字符后按ENTER键。这在输入流中留下了\n 字符,可以被下一个调用的输入函数使用。但是在您的情况下,您没有在 getchar() 之后调用任何其他输入函数。
[尝试在 fgets() 上方调用 getchar() 并输入为 - 输入字符后跟 ENTER 键。您将看到 fgets() 被跳过,因为它消耗了输入流 stdin 中剩余的 \n 字符。]

问题 1:
看看这句话:

str[j] = str + 1;

由于str 是一个char 数组,str[j] 表示位置j 的字符,str + 1 是指针。因此,此分配不兼容,因为您试图将 char * 类型分配给 char。应该是:

str[j] = str[j + 1];

问题 2:
您的代码存在逻辑问题。它无法处理要删除的字符在输入字符串中连续出现的场景。测试您的代码输入,例如“Hello World”[字符 l 连续出现]。您的程序输出将是[修复问题 1 后]

Enter a sentence: 
Hello World
This is the sentence: Hello World

Enter character to remove: 
l
Sentence after removal: Helo Word        <==== character l not removed

您的程序无法处理这种特殊情况,因为一旦删除了一个字符,在下一次迭代中它就会从下一个字符开始。

问题 3:
strlen() 返回类型是 size_t 并且您正在使用 char 类型来接收它的返回值。相反,您应该使用 size_t 类型。
getchar() 返回类型是int [因为它在到达输入流末尾时返回特殊值EOF]。您正在使用char 类型变量接收getchar() 返回值。

还有一点(这不是问题,但您应该意识到并采取预防措施):
来自fgets()[强调我的]

从给定的文件流中最多读取 count - 1 个字符并将它们存储在 str 指向的字符数组中。 如果出现文件结尾或找到换行符,则停止解析,在这种情况下,str 将包含该换行符。 如果没有发生错误,则在最后一个字符之后的位置写入一个空字符写到str。

因此,您传递给fgets() 的输入缓冲区可能包含换行符('\n')。例如,如果您输入 Hello World 后跟 ENTER 键,则输入缓冲区 str 将在其中包含 "Hello World\n"。在您的情况下,这不会导致任何问题,但很少会导致额外的循环迭代。您可以像这样从str 缓冲区中删除\n

fgets(str, 100, stdin);
str[strcspn(str, "\n")] = 0; // This will remove the trailing newline character from input buffer

另外,您应该检查fgets() 返回。如果失败,fgets() 返回NULL

把这些放在一起,你可以这样做:

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

int main() {
    char str[100];
    size_t i, j, len;
    int r;

    printf("Enter a sentence: \n");
    if (fgets(str, 100, stdin) == NULL) {
        fprintf (stderr, ("fgets failed"));
        return -1;
    }

    str[strcspn(str, "\n")] = 0;
    printf("This is the sentence: %s\n", str);

    printf("Enter character to remove: \n");
    r = getchar();

    /*If getchar returns EOF, no need to go through character removal logic*/
    if (r != EOF) {
        len = strlen(str);

        i = 0;
        while (str[i] != '\0') {
            if (str[i] == (char)r) {
                for (j = i; j < len; j++) {
                    str[j] = str[j+1];
                }
                len--;
            }
            else
                i++;
        }
    }

    printf("Sentence after removal: %s\n", str);
    return 0;
}

输出:

# ./a.out
Enter a sentence: 
Hello World
This is the sentence: Hello World
Enter character to remove: 
l
Sentence after removal: Heo Word

# ./a.out
Enter a sentence: 
zzzzz
This is the sentence: zzzzz
Enter character to remove: 
z
Sentence after removal: 

# ./a.out
Enter a sentence: 
aazz
This is the sentence: aazz
Enter character to remove: 
a
Sentence after removal: zz

【讨论】:

  • 非常好的、彻底的、有启发性的回应!
  • @H.S.是否有可能当我在此之后编写更多由 fgets() 组成的代码时,这部分会以某种方式被其他 fgets() 搞砸
  • @SketchupGalaxy 不,不会。只要确保彻底阅读fgets() 并处理输入可能大于传递给fgets() 的缓冲区大小的情况。你可能需要这个 - how-to-clear-input-buffer-in-c
【解决方案2】:

尝试将r = getchar(); 更改为scanf("%c\n", &amp;r);

另外,您的循环有一些错误或不一致:

  1. 您正在为str[j] 分配一个指针的值。应该将str[j+1] 的值分配给str[j]
  2. 那么内循环的结尾应该是len-1
  3. j-- 完全没有效果。
  4. 你应该在完成后以\0结束你的字符串,否则你会打印垃圾(在我的例子中是一堆\ns)。

把所有东西放在一起:

    for (i = 0; i < len; i++) {
        if (str[i] == r) {
            for (j = i; j < len-1; j++) {
                str[j] = str[j+1];
            }
            len--;
        }
    }
    str[len] = '\0';
    printf("Sentence after removal: %s\n", str);

如果你想在阅读完字符串末尾的\n之后删除它,你可以这样做

    str[len] = '\0';
    len--;

在循环之前。

【讨论】:

  • scanf("%c\n", &amp;r); 是一个弱建议。输入'\n'后函数没有及时返回,而是等待。
猜你喜欢
  • 2015-05-28
  • 1970-01-01
  • 2014-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-19
相关资源
最近更新 更多