【问题标题】:Input of multiple char arrays isn't working [duplicate]多个字符数组的输入不起作用[重复]
【发布时间】:2021-12-11 18:41:52
【问题描述】:
char toFind[100];
char replace[100];
int pos = 0;
printf("Enter a text: ");
scanf("%[^\n]", str);
printf("Enter a search pattern: ");
scanf("%[^\n]", toFind);
printf("Enter a substitute: ");
scanf("%[^\n]", replace);
pos = strnfnd(0, toFind);
strins(pos, replace);
printf("Der Text ist: %s", str);

此代码示例让我读取 str 的值,但跳过了其他两个 scanf。我不知道为什么。 我该怎么做才能解决这个问题?

Ps:str是一个全局char数组

【问题讨论】:

  • 快速修复:在对scanf() 的第二次和第三次调用中,在%[^n] 之前放置一个空格。但是您最好使用fgets() 代替。这里已经有很多类似的问题了。
  • 请将"%[^\n]" 更改为" %[^\n]" 并添加空格以过滤输入缓冲区中的前一个换行符。第一个是无害的。
  • 什么是strstrnfndstrins 是什么,如果后者与问题无关,为什么它们在您的代码中?请阅读:minimal reproducible example
  • 什么是字符串?
  • 在我看来你应该考虑使用fgets而不是scanf

标签: c scanf newline c-strings conversion-specifier


【解决方案1】:

你的scanf()使用有问题:scanf("%[^\n]", str);

  • 您没有指定要存储到str 中的最大字符数,因此用户键入的足够长的行将导致未定义的行为。这是黑客可以尝试和利用的典型软件缺陷。您可以通过将限制指定为 scanf("%99[^\n]", str);

    来防止这种情况发生
  • 您没有读取用户输入的尾随换行符,因此下一次调用scanf("%[^\n]", toFind); 将失败,因为输入流中没有与'\n' 不同的字符,因为第一个待处理字节是'\n',或者EOF.

  • 您没有检查scanf()调用的返回值,因此您无法检测到上述输入错误。

  • 但请注意,如果用户立即输入,scanf("%99[^\n]", str); 将失败,并且str 在这种情况下不会被修改。

在此任务中使用fgets() 而不是scanf() 更安全:

char str[100];
char toFind[100];
char replace[100];
int pos = 0;
printf("Enter a text: ");
if (!fgets(str, sizeof str, stdin)) {
    printf("input error\n");
    return 1;
}
str[strcspn(str, "\n")] = '\0'; /* strip the trailing newline if any */
printf("Enter a search pattern: ");
if (!fgets(toFind, sizeof toFind, stdin)) {
    printf("input error\n");
    return 1;
}
toFind[strcspn(toFind, "\n")] = '\0'; /* strip the trailing newline if any */
printf("Enter a substitute: ");
if (!fgets(replace, sizeof replace, stdin)) {
    printf("input error\n");
    return 1;
}
replace[strcspn(replace, "\n")] = '\0'; /* strip the trailing newline if any */
pos = strnfnd(0, toFind);
strins(pos, replace);
printf("Der Text ist: %s\n", str);

【讨论】:

    【解决方案2】:

    scanf这个电话之后

    scanf("%[^\n]", str);
    

    换行符'\n' 仍然存在于输入缓冲区中。

    所以scanf的下一个电话

    scanf("%[^\n]", toFind);
    

    读取输入直到遇到换行符'\n' 什么都不读取。

    你应该写例子

    scanf("%[^\n]%*c", str);
    

    从输入缓冲区中删除换行符'\n'

    这是一个演示程序

    #include <stdio.h>
    
    int main( void )
    {
        char s[100];
        
        scanf( "%99[^\n]%*c", s );
        puts( s );
        
        scanf( "%99[^\n]", s );
        puts( s );
    
        return 0;
    }
    

    在这种情况下,如果输入字符串,例如像

    Hello
          World
    

    那么输出将是

    Hello
          World
    

    另一种更简单的方法是在格式字符串前面加上一个空格。例如

    scanf(" %[^\n]", toFind);
          ^^^^
    

    在这种情况下,所有前导空白字符都将被跳过。

    这是一个演示程序。

    #include <stdio.h>
    
    int main( void )
    {
        char s[100];
        
        scanf( "%99[^\n]", s );
        puts( s );
        
        scanf( " %99[^\n]", s );
        puts( s );
    
        return 0;
    }
    

    这种情况下如果输入如上所示的字符串就是

    Hello
          World
    

    那么程序输出将是

    Hello
    World
    

    【讨论】:

    • 您不需要%*c 删除换行符(将必须删除一个字符)。 scanf 确实有你提到的过滤器。
    • @WeatherVane 但有时需要前导空格。在输入字符串中:)
    • 没错,格式字符串不区分,在这种情况下fgets 可能会更好。
    【解决方案3】:

    这取决于您运行编译代码的位置 - 操作系统。在某些情况下,当按下“Enter”键时,会在输入流(10 和 13)中发出两个字节,而不是 '\n' (10)。在这种情况下,您需要刷新额外的符号。检查 cmets 以了解确切的实现。

    【讨论】:

    • 添加空格将过滤输入流中任意数量的空格(包括无空格)。换行符是否有 1 个或 2 个字符无关紧要,因为 OP 没有刷新它们中的任何一个。
    猜你喜欢
    • 2018-12-11
    • 2012-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-16
    • 1970-01-01
    • 1970-01-01
    • 2015-12-15
    相关资源
    最近更新 更多