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
相关产品推荐
相关产品推荐

