fgets()在进入循环之前一直被跳过

时间:2018-12-23 00:42:51

标签: c string stdin fgets

曾经尝试删除一个字符,但是对fgets的调用被跳过/跳过。在不同的计算机上,它可以正常运行,但是由于某种原因,它会跳过并基本上跳到程序末尾。有任何想法吗?

2 个答案:

答案 0 :(得分:3)

您的代码中有几个问题,但是我看不到fgets()被跳过或跳过的任何原因。 getchar()函数从stdin读取下一个字符。通常,当我们为getchar()函数提供输入时,我们输入字符并按ENTER键。这将\n字符留在了输入流中,可以由下一个调用的输入函数使用。但是对于您而言,您不会在getchar()之后调用任何其他输入函数。
[尝试在getchar()上方调用fgets(),然后输入:-输入一个字符,然后按ENTER键。您将看到fgets()被跳过,因为它消耗了输入流\n中剩余的stdin字符。]

问题1:
看这句话:

str[j] = str + 1;

由于strchar数组,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() [我的重点]

  

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

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

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

答案 1 :(得分:1)

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

此外,您的循环中存在一些错误或不一致之处:

  1. 您正在将指针的值分配给str[j]。应该为str[j]分配str[j+1]的值。
  2. 然后,内部循环的结尾应为len-1
  3. j--完全无效。
  4. 完成后,您应该以{{1​​}}结尾字符串,否则将打印垃圾(在我的情况下,这是一堆\0 s)。

将所有内容放在一起:

\n

如果您想在阅读后删除字符串末尾的 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

在循环之前。