字符串与字符指针——没有 string 类型的世界
C 语言没有 string 类型这是很多初学者的误区。C 语言没有内置的 string 类型。字符串在 C 里就是char数组末尾加一个\0空字符标记结束。char str[] hello; // 内存布局h e l l o \0 // 共 6 字节最后的 \0 是字符串结束标记字符串的两种创建方式方式 1字符数组可修改char str[] hello; str[0] H; // OK数组在栈上可以修改 printf(%s\n, str); // Hellochar str[] hello会把字符串复制到栈上的数组里。方式 2字符指针不可修改char *str hello; str[0] H; // 未定义行为可能崩溃char *str hello让str指向字符串常量所在的只读内存区。修改它就是写只读内存——未定义行为通常段错误。实际项目中需要修改内容 →char str[]只读访问 →char *str更省内存多处共用同一份\0的重要性char s1[] {h, e, l, l, o}; // 没有 \0 char s2[] {h, e, l, l, o, \0}; // 有 \0 char s3[] hello; // 自动加 \0s1不是合法的字符串——没有\0结束标记。所有字符串函数都依赖\0判断结束printf(%s, s1); // 一直读到碰到 \0 为止——越界输出垃圾值 strlen(s1) // 一直数到碰到 \0 为止——越界返回随机值 strcpy(dest, s1) // 一直复制到碰到 \0 为止——越界可能覆盖别的数据sizeof vs strlenchar s[] hello; printf(%zu\n, sizeof(s)); // 6整个数组含 \0 printf(%zu\n, strlen(s)); // 5实际字符数不含 \0sizeof是编译时确定的算整个数组大小strlen是运行时计算的遍历到\0为止声明字符数组时要多留 1 字节给\0char name[5]; // 能存 4 个字符 1 个 \0 char name[100]; // 能存 99 个字符 1 个 \0字符串比较不能用 char s1[] hello; char s2[] hello; if (s1 s2) // 错比较的是两个数组的地址永远不等 if (strcmp(s1, s2) 0) // 对比较内容s1和s2是两个不同的数组地址不同永远返回假。strcmp 返回值strcmp(s1, s2) 0 // 相等 strcmp(s1, s2) 0 // s1 在 s2 前面字典序 strcmp(s1, s2) 0 // s1 在 s2 后面常用字符串函数#include string.h char s[] hello; strlen(s) // 5字符串长度 strcpy(dest, src) // 复制 src 到 dest不安全 strncpy(dest, src, n) // 最多复制 n 字节安全 strcat(dest, src) // 拼接 src 到 dest 末尾 strcmp(s1, s2) // 比较内容strcpy 的安全隐患char small[5]; char big[] hello world; strcpy(small, big); // 缓冲区溢出small 只有 5 字节strcpy不检查目标数组大小超出的部分会覆盖相邻内存。实际项目中用strncpychar dest[10]; strncpy(dest, src, sizeof(dest) - 1); // 最多复制 9 字节 dest[sizeof(dest) - 1] \0; // 手动确保 \0 结尾字符串遍历char s[] hello; // 方式1下标 for (int i 0; s[i] ! \0; i) { printf(%c, s[i]); } // 方式2指针 for (char *p s; *p ! \0; p) { printf(%c, *p); }字符串数组指针数组灵活char *fruits[] {apple, banana, cherry}; printf(%s\n, fruits[0]); // apple printf(%c\n, fruits[1][0]); // b字符串长度可以不同每个char *指向各自的字符串常量。二维数组安全char fruits[3][10] {apple, banana, cherry};内存连续不指向只读区但每行长度固定浪费空间。main 的命令行参数int main(int argc, char *argv[]) { for (int i 0; i argc; i) { printf(%s\n, argv[i]); } return 0; }argv就是指针数组argv[0]是程序名后续是参数。常见误区速查误区正确理解C 有 string 类型没有就是 char 数组加\0char *s hello; s[0] H未定义行为只读区不能改比较字符串比较的是地址用strcmpstrlen包含\0不包含strcpy安全不安全可能溢出用strncpychar s[5] hello能存 5 字节但需要 6 字节含\0溢出总结C 语言没有 string 类型字符串是\0结尾的 char 数组char str[]可修改栈上副本char *str不可修改只读区sizeof算整个数组含\0strlen不含\0字符串比较用strcmp比较的是地址strcpy不安全实际项目用strncpy声明字符数组时多留 1 字节给\0