C语言如何在scanf中使用宏定义SIZE设置字符串读取长度上限
问题原因
直接写scanf("%SIZEs", str);不生效的核心原因是:C预处理器不会替换双引号包裹的字符串字面量内部的宏标识符,所以字符串里的SIZE不会被展开为定义的数值50。
另外需要注意边界规则:scanf中%s格式符指定的宽度是最多读取的非终止符字符数(不含函数自动追加的末尾'\0'),如果数组长度为SIZE,实际宽度应该设为SIZE-1,否则读满长度时自动追加的'\0'会写出数组边界,造成内存越界。
实现方案
利用C语言编译期自动拼接相邻字符串字面量的特性,配合宏字符串化操作即可实现,代码如下:
#include <stdio.h> #define SIZE 50 // 字符串化中转宏,用于先展开宏参数再转换为字符串 #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) int main(){ char str[SIZE]; // 宏展开后自动拼接为 "%49s",预留1位存储'\0' scanf("%" STR(SIZE-1) "s", str); return 0; }
原理说明
- 宏定义里的
#运算符作用是把宏参数转换为字符串字面量,但如果直接用#x引用宏参数,不会先展开参数内的嵌套宏,因此需要加一层STR_HELPER做中转,先把SIZE-1展开为49,再转换为字符串"49"。 - C标准规定,代码中连续书写的多个字符串字面量,会在编译阶段自动合并为一个完整字符串,因此
"%" STR(SIZE-1) "s"展开后等价于"%49s",完全符合scanf的格式要求。
扩展:读取带空格的整句
%s格式符遇到空格、制表符、换行就会终止读取,如果需要读取包含空格的完整句子,可以替换为字符集匹配格式:
// 最多读取SIZE-1个字符,遇到换行符时停止 scanf("%" STR(SIZE-1) "[^\n]", str);
使用该写法时需要注意,读取完成后换行符会残留在输入缓冲区中,如果后续还有输入操作,需要手动读走残留的换行符,避免影响后续读取逻辑。
内容的提问来源于stack exchange,提问作者jane campbell
相关产品推荐
相关产品推荐

