You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

scanf_s/fgets读取带空格字符串异常:未输入直接输出乱码问题排查

书籍删除函数输入异常问题分析

你的问题场景

我写了一个删除书架书籍的函数,但运行时还没来得及输入书名,程序就直接跳出提示:Please enter the book name to be removed : 儆儆儆儆儆儆儆儆儆儆儆儆儆儆儆儆儆儆儆儆 is not in your bookshelf.,试了scanf_s和注释掉的fgets都没解决,代码如下:

void del() { 
    int temp = checker; 
    char search[30]; 
    printf("Please enter the book name to be removed : "); 
    scanf_s("%[^\n]s", search, 30); 
    //fgets(search, 30, stdin); 
    for (int i = 0; i < checker; i++) { 
        if (strcmp(search, bookshelf[i].name) == 0) { 
            for (int j = i+1; j < checker; j++) { 
                strcpy_s(bookshelf[i].name, 31, bookshelf[j].name); 
                strcpy_s(bookshelf[i].semi_ISBN, 5, bookshelf[j].semi_ISBN); 
                bookshelf[i].page = bookshelf[j].page; 
                i++; 
            } 
            checker--; 
            printf("%s is removed from your bookshelf.\n\n", search); 
        } 
    } 
    if(temp==checker) printf("%s is not in your bookshelf.\n\n", search); 
}

问题出在哪?

这个坑我之前踩过!核心是输入缓冲区里残留的换行符在搞事情:

  • 你在调用这个del()函数之前,肯定有过其他输入操作(比如用scanf输入书籍信息),用户按下的回车会留下一个\n在输入缓冲区里没被处理。
  • 当scanf_s("%[^\n]s", ...)执行时,它的规则是“读取直到遇到换行符为止的所有字符”,但如果缓冲区开头就是\n,它会直接读取失败,根本不会修改search数组的内容。
  • 而search是局部变量,初始化时没赋值,里面全是内存里的随机垃圾值(就是你看到的那些乱码),之后strcmp自然匹配不到任何书籍,直接触发“不在书架”的提示。
  • 换成fgets的话,它会直接把缓冲区里的那个\n读进来,导致search里只有一个换行符,同样匹配不到书籍,也会出问题。

怎么解决?

给你几个靠谱的处理方式,选一个适合你的就行:

  • 方式一:手动清空缓冲区
    在调用输入函数之前,把缓冲区里的残留字符全部读完:

    // 把缓冲区里残留的换行符读完
    while (getchar() != '\n');
    printf("Please enter the book name to be removed : ");
    scanf_s("%[^\n]s", search, 30);
    

    这个方法能彻底清理缓冲区,不管之前留了多少字符都能搞定。

  • 方式二:让scanf_s自动跳过空白
    在格式字符串开头加一个空格,scanf_s会自动跳过所有空白字符(包括换行、空格、制表符):

    printf("Please enter the book name to be removed : ");
    scanf_s(" %[^\n]s", search, 30); // 注意格式串前面的空格
    

    这个更简洁,适合书名不会以空格开头的场景,刚好符合你的需求。

  • 方式三:正确使用fgets
    如果想用fgets,记得处理它读进来的换行符(fgets会把用户按下的回车也读进数组):

    while (getchar() != '\n'); // 先清理残留换行
    printf("Please enter the book name to be removed : ");
    fgets(search, 30, stdin);
    // 去掉末尾的换行符
    search[strcspn(search, "\n")] = '\0';
    

    strcspn会找到第一个换行符的位置,把它改成字符串结束符\0,这样search里就只有纯书名了。

另外提个小建议:你的search数组是30个字符,但scanf_s没限制长度的话,用户输入超过29个字符会导致缓冲区溢出,建议把search改成和bookshelf[i].name一样的大小(比如31),或者在格式串里限制长度:%29[^\n]s,避免溢出风险。


内容的提问来源于stack exchange,提问作者Jenna.P

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 03:57:54