C语言设置UTF-8代码页后scanf读取特殊字符字符串截断问题
问题根因
字符串截断和SetConsoleCP/SetConsoleOutputCP的UTF-8编码配置无关,核心是代码存在两处内存定义与访问的错误:
- 结构体字段定义错误:
char* prod[50]声明的是长度为50的char指针数组,不是用来存储字符内容的字符数组。32位编译环境下每个指针占4字节,写入UTF-8编码的Açucar时,'A'占1字节、'ç'占2字节,3个字节写满第一个指针的前3字节空间后,第4字节的内存默认值为0x00,被printf识别为字符串终止符,因此输出到'A'就截断。 scanf用法错误:对数组名取地址&lojas[x].prod属于类型不匹配的未定义行为;%[^\n]本身就是完整的字符串匹配规则,后面额外加的s是无效写法;同时没有给字符串读取设置长度上限,存在缓冲区溢出风险。
移除UTF-8编码配置后看似读取正常,只是因为系统默认ANSI编码下'ç'只占1字节,暂时没触发内存里的0值截断,属于未定义行为的偶然表现,本质问题没有修复。
修复方案
按以下步骤修改代码即可同时解决截断和乱码问题,不需要依赖<locale.h>,在Embarcadero Dev-C++环境下可直接运行:
- 修正结构体的商品名字段,改为定长字符数组,预留足够空间存储UTF-8多字节字符
- 修正
scanf的传参、格式符,增加字符串读取长度限制避免溢出 - 控制台输出前增加缓冲区刷新,避免UTF-8模式下提示语显示异常
修复后的完整代码:
#define NOMINMAX #include <windows.h> #include <stdio.h> #include <stdlib.h> typedef struct { float preco; int quant; char prod[100]; // 修正:定长字符数组,预留100字节存商品名 } info; void imprime(info j) { printf("|| Produto: %s || preço: %.2f || quantidade: %d ||\n", j.prod, j.preco, j.quant); } int main() { SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); system("color 0F"); info lojas[50]; for (int x = 0; x < 1; x++) { printf("Digite o nome do produto: "); fflush(stdout); // 刷新输出缓冲区,保证提示语正常显示 scanf(" %99[^\n]", lojas[x].prod); // 限制最长读取99字符,避免溢出,去掉多余的&和s printf("\nDigite o preço do produto: "); fflush(stdout); scanf(" %f", &lojas[x].preco); printf("\nDigite a quantidade desejada do produto: "); fflush(stdout); scanf(" %d", &lojas[x].quant); system("cls"); } for (int x = 0; x < 1; x++) { imprime(lojas[x]); } return 0; }
验证说明
- 输入
Açucar时,UTF-8编码的多字节字符会完整写入字符数组,不会出现截断,控制台可正常输出带特殊字符的内容,无乱码 - 代码增加了字符串读取长度限制,避免用户输入过长内容导致的内存越界问题
内容的提问来源于stack exchange,提问作者Nikolas Rian
相关产品推荐
相关产品推荐

