一、字符数组概述C语言没有专门的字符串类型一切字符串操作都靠字符数组完成。cchar str[20]; // 定义一个能存20个字符的数组1. 字符数组的存储字符数组的每个元素存一个字符末尾用\0ASCII码为0标识字符串结束。cchar str[6] {h, e, l, l, o, \0}; // 内存布局h e l l o \0感悟\0是字符串的终止符它告诉printf和puts到这里就停了。没有它函数会一直往下读内存里的垃圾数据直到碰巧遇到一个0为止——这就是为什么字符数组初始化时一定要考虑\0的位置。2. 三个容易混淆的零写法含义ASCII码0整数零00000000\0字符串结束符00000000与0等价0字符零0011000048感悟0、\0、0这三个东西看起来像实际完全不同。刚开始写代码的时候经常搞混尤其是用strlen统计长度时明明字符串里有0字符长度却按实际字符数算——因为strlen只认\0作为结束标志而0只是普通字符。搞清楚它们之间的区别字符串相关的代码就少了一半的Bug。二、字符数组的初始化1. 全部初始化cchar str[6] {h, e, l, l, o, \0}; char str[6] {hello}; // 自动加 \0 char str[6] hello; // 最常用写法2. 部分初始化cchar str[6] {h, e, l, l, o}; // 少了 \0剩余元素补0即 \0 // str 内容是h e l l o \0 char str[6] {h, e}; // 剩余4个元素自动补0 char str[6] {0}; // 全部置零常用写法感悟部分初始化自动补0的特性在清空字符串时特别实用——写一个char str[32] {0};整个数组就全是\0了不用写循环逐个赋值。这是C语言提供的语法糖用好了能省不少事。3. 默认初始化省略数组长度cchar str[] {h, e, l, l, o, \0}; char str[] {hello}; char str[] hello; // 长度为6包含\0⚠️ 实际开发中不建议省略长度容易造成数组越界。三、字符串的输入与输出1. 输出方式cchar str[20] hello world; printf(str %s\n, str); // %s 控制符专门输出字符串 puts(str); // 输出后自动加换行⚠️puts比printf多打印一个换行符。2. 输入方式cchar str[32] {0}; scanf(%s, str); // 不能接收带空格的字符串 gets(str); // 可以接收带空格的字符串但不安全已废弃scanf 与 gets 的区别scanf(%s)gets()能否接收空格❌ 遇到空格停止✅ 整行读取安全性较好不检查边界已废弃感悟gets已经被废弃了因为它不检查数组边界输入过长会导致缓冲区溢出。实际项目中推荐用fgets替代。虽然学校练习里可能还会用gets但心里要清楚——写代码不光要能用还要安全。四、字符串常用操作1. 获取字符串长度 —— strlencchar str[32] hello; int len strlen(str); // len 5不含 \0⚠️strlen统计的是从开头到\0之间的字符个数不包含\0sizeof获得的是数组占用总字节数。cchar str[32] hello; printf(%lu\n, strlen(str)); // 5 printf(%lu\n, sizeof(str)); // 322. 字符串拷贝 —— strcpycchar str[32] {0}; strcpy(str, hello world); // 将 hello world 拷贝到 str 中⚠️ 目标空间必须足够大否则会内存越界访问。3. 字符串拼接 —— strcatcchar str1[32] hello; char str2[32] world; strcat(str1, str2); // str1 变为 helloworld⚠️ 目标空间必须能容纳拼接后的完整字符串。感悟strcat的工作原理是先找到目标字符串的\0然后从这里开始往后面粘贴源字符串的内容最后再补一个\0。理解了这个过程就明白了为什么目标数组要足够大——否则\0被覆盖后找不到结束位置程序就会越界访问。4. 字符串比较 —— strcmpcint ret strcmp(str1, str2); // ret 0 → 两个字符串相等 // ret 0 → str1 大于 str2 // ret 0 → str1 小于 str2比较规则从左到右逐字符比较ASCII码第一个不同的字符决定大小。感悟字符串比较不是比长短而是比字典序——apple和banana比较先看第一个字符 a vs ba 小所以整体就小后面的字符都不用看了。这和查字典是一个道理。五、二维数组1. 定义与访问二维数组本质上是数组的数组——可以理解为一个表格。cint a[2][3]; // 2行3列 // 元素a[0][0] a[0][1] a[0][2] // a[1][0] a[1][1] a[1][2]2. 存储顺序二维数组在内存中按行连续存储先存第0行再存第1行。cint a[2][3] {1, 2, 3, 4, 5, 6}; // 内存布局1 2 3 4 5 63. 初始化c// 全部初始化 int a[2][3] {1, 2, 3, 4, 5, 6}; int a[2][3] {{1, 2, 3}, {4, 5, 6}}; // 按行清晰 // 部分初始化未赋值的补0 int a[2][3] {1, 2, 3, 4}; int a[2][3] {{1, 2}, {3}}; // 默认初始化行可省列不可省 int a[][3] {1, 2, 3, 4, 5, 6}; // 自动推断为2行⚠️ 二维数组行数可以省略编译器自动推断但列数不能省略。4. 二维字符数组存储多个字符串时用二维字符数组cchar str[3][10] {hello, world, C}; // 存放3个字符串每个最长9个字符留1个给\0六、今日总结今天学习了字符数组和二维数组核心要点如下字符数组字符串用\0标识字符串结束0、\0、0要区分清楚初始化推荐char str[32] {0};或char str[32] hello;输入用scanf(%s)无空格或gets可空格但不安全常用函数strlen求长度、strcpy拷贝、strcat拼接、strcmp比较操作字符串时务必保证数组空间足够防止越界二维数组本质是数组的数组按行连续存储定义数据类型 数组名[行数][列数]初始化时行可省列不可省今日总结感悟字符数组让我第一次意识到——原来C语言里压根没有字符串类型这种东西所谓的字符串就是普通字符数组加上一个\0的约定。这就是C语言的设计哲学不提供复杂的封装只提供简单的原材料怎么用全看你。习惯了高级语言字符串的同学可能觉得不方便但正是这种不替你做决定的设计给了程序员最大的掌控力。字符串函数的练习我建议自己动手实现一遍——用循环写一个strlen、写一个strcpy能帮你真正理解字符串在内存中是怎么存放和操作的。在纸上画一画数组的格子填上字符比盯着代码硬想要有效得多。