C语言中scanf将带重音字母计为2字符的问题解决方法
问题解决:scanf限制UTF-8字符数而非字节数
问题根源
scanf("%20s")中的20是字节数限制,而非Unicode字符数。像é这类UTF-8编码的字符占2个字节,所以20字节只能容纳10个é,导致输出时后半部分丢失。
解决方案
方案1:使用宽字符版scanf(优先满足你的scanf使用需求)
改用wchar_t类型存储字符串,配合wscanf的%20ls格式符,此时宽度限制的是宽字符数(即Unicode字符数),直接实现20个字符的限制。
代码示例:
#include <wchar.h> #include <stdio.h> int main() { wchar_t name[21]; // 20个宽字符 + 终止符 int num1, hour, minute; char flag; // 适配你的格式判断逻辑 if (wscanf(L"%d %20ls %d:%d %hc", &num1, name, &hour, &minute, &flag) == 5) { wprintf(L"输入的名称:%ls\n", name); // 其他处理逻辑 } return 0; }
- 注意:
%hc用于在wscanf中读取普通char类型的字符(对应你格式中的最后一个%c),若需读取宽字符则用%lc。 - 确保终端编码为UTF-8,且编译环境支持宽字符(现代编译器默认支持)。
方案2:用窄字符数组,读取后截断为20个UTF-8字符
如果必须使用char数组,先读取足够多的字节(比如80字节,覆盖20个最多4字节的UTF-8字符),再手动截断到20个合法的UTF-8字符,避免截断到字符中间导致乱码。
实现代码:
#include <stdio.h> #include <string.h> // 将UTF-8字符串截断为max_chars个字符 void truncate_utf8(char *dest, const char *src, size_t max_chars) { size_t char_count = 0; while (*src != '\0' && char_count < max_chars) { if ((*src & 0x80) == 0) { // 单字节ASCII字符 *dest++ = *src++; char_count++; } else if ((*src & 0xE0) == 0xC0) { // 双字节UTF-8字符 if (char_count + 1 > max_chars) break; *dest++ = *src++; *dest++ = *src++; char_count++; } else if ((*src & 0xF0) == 0xE0) { // 三字节UTF-8字符 if (char_count + 1 > max_chars) break; *dest++ = *src++; *dest++ = *src++; *dest++ = *src++; char_count++; } else if ((*src & 0xF8) == 0xF0) { // 四字节UTF-8字符 if (char_count + 1 > max_chars) break; *dest++ = *src++; *dest++ = *src++; *dest++ = *src++; *dest++ = *src++; char_count++; } else { // 无效UTF-8字节,跳过 src++; } } *dest = '\0'; // 添加字符串终止符 } int main() { char temp_name[81]; // 足够容纳20个UTF-8字符 char name[21]; int num1, hour, minute; char flag; // 原格式判断,仅加宽name的读取字节数 if (scanf("%d %80s %d:%d %c", &num1, temp_name, &hour, &minute, &flag) == 5) { truncate_utf8(name, temp_name, 20); printf("输入的名称:%s\n", name); // 其他处理逻辑 } return 0; }
关键说明
- 方案1更简洁,直接利用宽字符特性解决计数问题,适合大多数现代环境。
- 方案2需手动处理UTF-8编码细节,兼容性更强,适合无法使用宽字符的场景。
内容的提问来源于stack exchange,提问作者Thewhyap
相关产品推荐
相关产品推荐

