如何在C语言中使用含俄文字母的数组?解决俄语元音统计代码的编译报错问题
解决俄语元音统计的窄化转换错误
嘿,我来帮你搞定这个问题!那个「narrowing conversion of '53429' from 'int' to 'char' inside { }」的错误,核心原因是俄语西里尔字母的编码值超出了默认有符号char的范围,再加上你用的gets函数本身已经被废弃,咱们一步步来修正:
错误根源分析
- 字符编码与
char的局限:默认情况下,char是8位有符号类型,取值范围是-128~127。而俄语元音(比如А、Ё)在常见编码里的数值都超过了这个范围:- 如果是UTF-8编码,俄语字符是多字节(比如
А是0xD0 0x90两个字节),用单字节char数组根本没法正确存储单个字符; - 如果是单字节编码(比如CP1251),
А的数值是192,转换成有符号char会变成负数,编译器在初始化数组时会把这个数值当成int类型,再转成char就触发了「窄化转换」的错误提示。
- 如果是UTF-8编码,俄语字符是多字节(比如
gets函数的安全问题:gets已经被C11标准彻底废弃,它不会检查输入长度,很容易导致缓冲区溢出,引发程序崩溃甚至安全漏洞。
修复方案:使用宽字符处理俄语
最通用、移植性最好的方法是用宽字符类型wchar_t,它能容纳Unicode码点,完美支持俄语等非ASCII字符。下面是修改后的代码:
#include <stdio.h> #include <wchar.h> #include <string.h> #include <locale.h> int main() { // 设置区域为俄语UTF-8,确保宽字符输入输出正常 setlocale(LC_ALL, "ru_RU.UTF-8"); wchar_t stroka[100]; // 俄语元音的宽字符版本(包含大小写) wchar_t glasnii[] = {L'А', L'Е', L'И', L'Ю', L'Ё', L'Ы', L'У', L'Э', L'О', L'Я', L'а', L'е', L'и', L'ю', L'ё', L'ы', L'у', L'э', L'о', L'я'}; int count = 0; wprintf(L"Введите строку: "); // 用fgetws代替gets,安全读取宽字符字符串 fgetws(stroka, sizeof(stroka)/sizeof(wchar_t), stdin); // 去掉fgetws读取的换行符 size_t len = wcslen(stroka); if (len > 0 && stroka[len-1] == L'\n') { stroka[len-1] = L'\0'; len--; } // 双重循环统计元音 for (int i = 0; i < len; i++) { for (int j = 0; j < sizeof(glasnii)/sizeof(wchar_t); j++) { if (stroka[i] == glasnii[j]) { count++; break; // 找到匹配就跳出内层循环,优化效率 } } } wprintf(L"\nКоличество гласных: %d\n", count); return 0; }
关键改动说明
wchar_t类型:替换char为wchar_t,用来存储宽字符,每个俄语元音都是单个wchar_t值;- 宽字符函数:用
wprintf、fgetws、wcslen代替对应的单字节函数,确保宽字符的输入输出和长度计算正确; - 区域设置:添加
setlocale(LC_ALL, "ru_RU.UTF-8"),让系统识别俄语UTF-8编码,否则宽字符可能显示乱码; - 安全输入:用
fgetws代替gets,指定最大读取长度,避免缓冲区溢出; - 优化内层循环:找到匹配的元音后用
break跳出,减少不必要的比对。
备选方案:用无符号单字节字符(仅适用于单字节编码环境)
如果你坚持用单字节char,可以把数组声明为unsigned char(取值范围0~255),这样就能容纳CP1251等单字节编码的俄语字符,避免窄化转换错误。但这种方法依赖系统默认编码为单字节俄语编码,移植性差,不推荐:
#include <stdio.h> #include <string.h> int main() { unsigned char stroka[100]; unsigned char glasnii[] = {'А', 'Е', 'И', 'Ю','Ё','Ы','У','Э','О','Я','а','у', 'о', 'ы', 'и', 'э', 'я', 'ю', 'ё','е'}; int count = 0; printf("Введите строку: "); // 用fgets代替gets,安全读取 fgets((char*)stroka, sizeof(stroka), stdin); size_t len = strlen((char*)stroka); if (len > 0 && stroka[len-1] == '\n') { stroka[len-1] = '\0'; len--; } for (int i = 0; i < len; i++) { for (int j = 0; j < sizeof(glasnii)/sizeof(unsigned char); j++) { if (stroka[i] == glasnii[j]) { count++; break; } } } printf("\nКоличество гласных: %d\n", count); return 0; }
内容的提问来源于stack exchange,提问作者user14873340




