C语言一维字符数组与二维整型数组全面详解(知识点+坑点+实操)

前言

今天系统学习了C语言数组中两大核心内容:一维字符型数组(字符串存储载体)二维整型数组(表格/矩阵存储)。C语言本身没有string字符串类型,所有字符串操作都依赖字符数组实现;二维数组则是处理多行多列数据的基础,本文整理核心知识点、使用规范、高频易错坑点,附带实操要点,方便复习与查阅。

一、一维字符型数组(字符串专用)

1. 核心基础概念

  1. C语言无独立字符串类型,字符串必须存储在字符数组中
  2. 字符串硬性规则:末尾必须存在结束标记 \0(ASCII值等价于数字0);
  3. 字符数组 = 连续char空间,既可存单个字符,也可存完整字符串。

2. 定义格式

char 数组名[常量长度];
  • 数组长度必须是常量,不能用变量;
  • 长度预留:必须多分配1字节给末尾\0,例如存hello至少定义char str[6]

3. 四种初始化方式

// 方式1:逐个字符赋值,手动加\0
char str[6] = {'h','e','l','l','o','\0'};

// 方式2:双引号整体初始化(自动补\0,推荐)
char str[6] = "hello";
char str[6] = {"hello"};

// 方式3:局部初始化,未赋值元素自动补0(\0)
char str[6] = {'h','e','l'}; 

// 方式4:省略长度,编译器自动计算长度(包含\0)
char str[] = "hello";

区分关键:

  • '0':字符0,ASCII码48;
  • 0 / '\0':字符串结束符,ASCII码0,打印到这里终止字符串输出。

4. 字符串输入输出函数

输出
  1. printf("%s", str);
    从数组首地址开始打印,直到遇到\0停止。
  2. puts(str);
    自动打印字符串,末尾自带换行\n,无需手动加换行符。
输入
  1. scanf("%s", str);
    • 无需加&,数组名本身代表首地址;
    • 致命缺陷:空格、回车会截断输入,无法读取带空格的句子。
  2. gets(str);
    • 支持读取带空格整行输入;
    • 自动丢弃输入回车,替换为\0
    • 严重缺陷:无缓冲区长度校验,极易内存越界,新标准C已废弃。

5. 四大字符串库函数(头文件<string.h>

函数 功能 核心注意事项
strlen(str) 统计字符串有效字符长度(不含\0 只算到\0,和sizeof完全区分
strcpy(dst, src) 字符串拷贝 目标数组空间必须足够容纳源字符串+\0,否则越界
strcat(str1, str2) 字符串拼接 str1剩余空间要存下拼接后全部字符,防止溢出
strcmp(str1, str2) 字符串逐字符比较ASCII 返回值:0相等、>0 str1更大、<0 str2更大

6. 重点区分:strlen vs sizeof

char str[20] = "hello";
strlen(str); // 结果5,只统计有效字符,忽略数组总大小
sizeof(str); // 结果20,获取整个数组占用的内存字节总数

7. 易踩坑易错点

  1. 忘记预留\0空间
    错误:char str[5] = "hello"; 数组长度5,放不下hello+\0,无结束符,打印乱码。
  2. 混淆'0''\0'
    判断字符串结束只能用\0,不能用字符'0'
  3. scanf读取带空格字符串失效
    输入hello world只会读到hello,空格终止读取。
  4. 数组越界写入
    strcpy/strcat不校验长度,源字符串过长会覆盖数组以外内存,程序崩溃。
  5. 未初始化字符数组直接打印
    数组剩余空间是随机脏数据,无\0会持续向后乱打印。
  6. gets函数禁用
    无边界保护,存在严重安全漏洞,项目中禁止使用。

8. 课堂实操练习考点

  1. 不使用strlen,手写代码统计字符串长度;
  2. 不使用strcpy,手动循环实现字符串拷贝;
  3. 不使用strcat,手动拼接两个字符串;
  4. 不使用strcmp,手动逐字符对比字符串;
  5. 统计字符串中大写、小写、数字、空格字符数量。

二、二维整型数组(矩阵/表格数据)

1. 核心基础概念

  1. 二维数组 = 数组的数组,外层一维数组的每个元素又是一维数组;
  2. 存储逻辑:行、列,格式 数组名[行][列],模拟表格、矩阵;
  3. 内存存储规则:行优先连续存储,同一行元素紧挨着,再存下一行。

2. 定义格式

int 数组名[行数][列数];
// 示例:2行3列整型数组
int a[2][3];

强制规则:行数、列数必须是常量,不能为变量

3. 元素访问

下标从0开始,数组名[行下标][列下标]

int a[2][3];
a[0][0] = 1; // 第一行第一列
a[1][2] = 6; // 第二行第三列

禁止下标越界:2行下标只能0/1,3列下标只能0/2。

4. 三种初始化方式

// 1. 平铺全部初始化(按行顺序填充)
int a[2][3] = {1,2,3,4,5,6};

// 2. 分行初始化(可读性最高,推荐)
int a[2][3] = {{1,2,3},{4,5,6}};

// 3. 局部初始化,未赋值元素自动补0
int a[2][3] = {{1,2},{3}}; 
// 剩余空位全部填充0

// 4. 省略行数初始化(列数绝对不能省略)
int a[][3] = {1,2,3,4,5,6}; // 自动识别2行

关键限制:二维数组初始化列下标不可省略,行可以省略。

5. 数组空间计算

总字节 = 单个int字节数 × 行数 × 列数

int a[2][3];
int total = sizeof(a);       // 整个数组总字节
int row_size = sizeof(a[0]); // 单行占用字节
int col_cnt = sizeof(a[0]) / sizeof(a[0][0]); // 列数
int row_cnt = sizeof(a) / sizeof(a[0]);       // 行数

6. 常规遍历方式(双层for循环)

外层循环控制行,内层循环控制列:

#include <stdio.h>
int main(void)
{
    int a[2][3] = {{1,2,3},{4,5,6}};
    int i,j;
    // 遍历打印全部元素
    for(i=0; i<2; i++)
    {
        for(j=0; j<3; j++)
        {
            printf("%d ", a[i][j]);
        }
        printf("\n");
    }
    return 0;
}

7. 重点注意事项

  1. 存储顺序:行优先,内存连续排布,不存在分行隔离;
  2. 下标从0开始,最大下标 = 定义长度-1;
  3. 局部初始化空缺元素默认填充0;
  4. 作为函数参数时,二维数组必须指定列大小。

8. 易踩坑易错点

  1. 初始化省略列数
    错误:int a[2][] = {1,2,3}; 编译器无法识别单行长度,直接报错。
  2. 下标越界访问
    定义a[2][3],访问a[2][0]a[0][3],读写未知内存,程序乱码/崩溃。
  3. 单层循环遍历二维数组
    逻辑混乱,无法区分行列,标准场景必须双层循环。
  4. 用变量定义行列长度
    C标准数组长度必须常量,int n=3; int a[2][n]; 标准C语法报错。
  5. 混淆行列循环顺序
    外层行、内层列写反,输出表格行列颠倒。

三、今日学习总结

  1. 一维字符数组是C语言字符串唯一存储载体,\0是字符串核心标识,区分strlensizeof是高频考点;
  2. 字符串输入输出各有优劣,scanf不能读空格,gets存在安全缺陷;四大字符串库函数操作必须保证数组空间充足;
  3. 二维整型数组本质是数组嵌套,行优先连续存储,初始化只能省略行数,列数不可省略;
  4. 两类数组最高频Bug:下标越界、空间分配不足、混淆结束符/初始化默认值;
  5. 配套练习重点:手动实现字符串库函数、双层循环遍历矩阵、字符统计、数组倒置/排序。
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐