
ASCLL码表1. 引言从字符到字符串在 C 编程中字符char和字符串string是最基础、最常用的数据类型之一。无论是处理用户输入、文件读写、网络通信还是实现各种文本处理算法都离不开对字符和字符串的操作。然而C 中的字符与字符串处理有着独特的历史背景和多种实现方式从传统的 C 风格字符串到现代的 Cstd::string再到宽字符和多字节字符的支持形成了一个丰富而复杂的体系。本文将深入探讨 C 中字符与字符串的各个方面包括字符类型char,wchar_t,char8_t,char16_t,char32_tC 风格字符串字符数组的原理与操作Cstd::string类的全面使用字符串字面量的各种形式字符编码与国际化支持性能优化与最佳实践2. 字符类型不只是 charC 提供了多种字符类型以适应不同的编码需求和国际化场景。2.1 基本字符类型 charchar是最基本的字符类型通常占用 1 字节8 位可以表示 ASCII 字符集中的 128 个字符。在大多数系统中char默认是有符号的signed char但具体实现可能有所不同。// char 类型的基本使用 char ch1 A; // 字符字面量 char ch2 65; // ASCII 码值 char ch3 \n; // 转义字符换行 char ch4 \x41; // 十六进制表示A char ch5 \101; // 八进制表示A // 输出验证 std::cout ch1: ch1 std::endl; // 输出: A std::cout ch2: ch2 std::endl; // 输出: A std::cout ASCII of ch1: static_castint(ch1) std::endl; // 输出: 65竞赛考点提示在 GESP 和 CSP-J/S 中经常考察字符与 ASCII 码的转换、转义字符的使用。记住常见 ASCII 码A65a97048。2.2 宽字符类型 wchar_twchar_t用于表示宽字符通常用于支持 Unicode 字符。其大小取决于编译器实现Windows 上通常为 2 字节Linux 上通常为 4 字节。#include bits/stdc.h using namespace std; int main() { // wchar_t 的使用 wchar_t wch1 LA; // 宽字符字面量 wchar_t wch2 L中; // 中文字符 wchar_t wstr[] LHello, 世界!; // 宽字符串 // 宽字符输出需要设置本地化 #include locale wcout.imbue(locale()); wcout L宽字符: wch2 endl; wcout L宽字符串: wstr endl; return 0; }竞赛考点提示NOIP 高级组可能涉及宽字符的基本概念但实际编程题中较少使用。了解其存在即可。2.3 固定宽度字符类型C11 起C11 引入了固定宽度的字符类型明确指定了字符的编码方式char8_t用于 UTF-8 编码C20 起char16_t用于 UTF-16 编码char32_t用于 UTF-32 编码#include bits/stdc.h using namespace std; int main() { // 固定宽度字符类型C11/20 char8_t utf8_char u8A; // UTF-8 字符 char16_t utf16_char u中; // UTF-16 字符 char32_t utf32_char U; // UTF-32 字符表情符号 // 对应的字符串字面量 const char8_t* utf8_str u8UTF-8 字符串; const char16_t* utf16_str uUTF-16 字符串; const char32_t* utf32_str UUTF-32 字符串; return 0; }竞赛考点提示GESP 和 CSP-J/S 主要考察基本char类型这些新类型了解即可。2.4 有符号与无符号 charchar、signed char和unsigned char是三种不同的类型#include bits/stdc.h using namespace std; int main() { char c1 A; // 可能是 signed 或 unsigned取决于编译器 signed char c2 -128; // 明确有符号范围-128 到 127 unsigned char c3 255; // 明确无符号范围0 到 255 // 类型转换注意事项 int ascii1 c1; // 可能产生符号扩展问题 int ascii2 static_castunsigned char(c1); // 安全转换 return 0; }竞赛考点提示注意字符类型转换时的符号扩展问题这在 CSP-J/S 的编程题中可能成为陷阱。3. C 风格字符串字符数组C 风格字符串本质上是字符数组以空字符\0作为结束标志。3.1 声明与初始化#include bits/stdc.h using namespace std; int main() { // 多种初始化方式 char str1[] Hello; // 自动计算大小6 字节包含 \0 char str2[10] World; // 指定大小剩余部分填充 \0 char str3[] {H, e, l, l, o, \0}; // 字符数组初始化 char str4[10]; // 未初始化需要后续赋值 // 错误示例 // char str5[5] Hello; // 错误数组太小无法容纳 \0 // char str6[]; // 错误没有初始值无法确定大小 return 0; }竞赛考点提示GESP 和 CSP-J 经常考察字符数组的初始化、大小计算和结束符\0的重要性。3.2 常用操作函数C 标准库提供了一系列字符串操作函数需要包含头文件cstring。#include bits/stdc.h using namespace std; int main() { char str1[20] Hello; char str2[] World; char str3[20]; // 字符串长度不包含 \0 cout str1 length: strlen(str1) endl; // 5 // 字符串复制 strcpy(str3, str1); // str3 Hello strncpy(str3, str2, 3); // str3 Worlo注意不会自动添加 \0 str3[3] \0; // 手动添加结束符 // 字符串连接 strcat(str1, ); // str1 Hello strcat(str1, str2); // str1 Hello World // 字符串比较 int cmp1 strcmp(apple, banana); // 负数apple banana int cmp2 strcmp(hello, hello); // 0相等 int cmp3 strcmp(zoo, apple); // 正数zoo apple // 字符串查找 char text[] The quick brown fox jumps over the lazy dog; char* found strstr(text, fox); // 查找子串 if (found) { cout Found at position: (found - text) endl; } // 字符查找 char* ch_pos strchr(text, q); // 查找字符 if (ch_pos) { cout q found at: (ch_pos - text) endl; } return 0; }竞赛考点提示必须熟练掌握strlen、strcpy、strcat、strcmp、strstr、strchr等函数的使用这是 CSP-J/S 和 NOIP 的必考内容。3.3 安全版本函数C11为了防范缓冲区溢出C11 标准引入了带边界检查的安全版本函数#include bits/stdc.h using namespace std; int main() { // 安全版本函数需要定义 __STDC_LIB_EXT1__ #define __STDC_WANT_LIB_EXT1__ 1 #include cstring char dest[10]; const char* src This is a very long string that might overflow; // 传统函数危险 // strcpy(dest, src); // 可能缓冲区溢出 // 安全版本 errno_t err strcpy_s(dest, sizeof(dest), src); if (err ! 0) { cout Buffer overflow prevented! endl; } return 0; }竞赛考点提示竞赛中通常使用传统函数但要知道缓冲区溢出的风险和安全函数的存在。3.4 优缺点分析优点内存布局简单与 C 语言兼容在某些嵌入式或性能敏感场景中更高效可以直接操作内存灵活性高缺点容易发生缓冲区溢出需要手动管理内存和结束符长度计算需要遍历整个字符串O(n) 复杂度缺乏现代面向对象的封装和安全性4. C std::string现代字符串处理std::string是 C 标准库提供的字符串类封装了字符数组的管理提供了丰富的成员函数。4.1 基本使用#include iostream #include string int main() { // 多种构造方式 std::string s1; // 空字符串 std::string s2 Hello; // 从 C 风格字符串构造 std::string s3(World); // 直接构造 std::string s4(5, A); // 重复字符构造AAAAA std::string s5(s2); // 拷贝构造 std::string s6(s2, 1, 3); // 子串构造ell从位置1开始长度3 std::string s7 std::string(Hello) World; // 临时对象 // 赋值操作 s1 C String; // 赋值 s1.assign(Assigned, 4); // 赋值前4个字符Assi // 获取 C 风格字符串 const char* c_str s2.c_str(); // 返回 const char* const char* data_ptr s2.data(); // C17 起与 c_str() 相同 return 0; }竞赛考点提示CSP-S 和 NOIP 中std::string的使用频率远高于 C 风格字符串必须熟练掌握各种构造方式。4.2 字符串操作#include iostream #include string int main() { std::string str Hello, C World!; // 长度和容量 std::cout Length: str.length() std::endl; // 17 std::cout Size: str.size() std::endl; // 17与 length 相同 std::cout Capacity: str.capacity() std::endl; // 当前分配的容量 std::cout Empty: (str.empty() ? Yes : No) std::endl; // 访问字符 char first str[0]; // H不检查边界 char second str.at(1); // e检查边界越界抛出异常 char last str.back(); // !C11 char front str.front(); // HC11 // 修改内容 str.append( Welcome!); // 追加字符串 str.push_back(!); // 追加单个字符 str.insert(7, Modern ); // 在位置7插入 str.erase(5, 2); // 从位置5删除2个字符 str.replace(7, 3, Standard); // 从位置7开始替换3个字符 // 查找 size_t pos1 str.find(World); // 查找子串 size_t pos2 str.find(W); // 查找字符 size_t pos3 str.find(Java); // 未找到返回 std::string::npos // 提取子串 std::string sub1 str.substr(7); // 从位置7到结尾 std::string sub2 str.substr(0, 5); // 前5个字符 // 比较 int cmp str.compare(Hello, C World!); // 返回0表示相等 // 清空和释放内存 str.clear(); // 清空内容 str.shrink_to_fit(); // 释放多余内存C11 return 0; }竞赛考点提示find、substr、erase、insert等函数是字符串处理题目的核心必须熟练掌握。4.3 字符串与数值转换#include iostream #include string #include sstream #include cstdlib // 用于 C 风格转换 int main() { // 字符串转数值C11 起 std::string num_str 123.45; int int_val std::stoi(num_str); // 转整数 long long_val std::stol(num_str); // 转长整数 float float_val std::stof(num_str); // 转单精度浮点数 double double_val std::stod(num_str); // 转双精度浮