【C 语言入门】Day09 二维字符数组、函数基础与变量存储类型全解析

📅 2026/7/30 4:48:10 👁️ 阅读次数 📝 编程学习
【C 语言入门】Day09 二维字符数组、函数基础与变量存储类型全解析

本文为 C 语言学习第九天的知识点整理,涵盖二维字符数组用法、函数的定义 / 调用 / 声明,以及变量作用域、生存周期和四种存储类型详解

文章目录

  • 1. 二维字符型数组
    • 1.1 功能与定义
    • 1.2 元素访问
    • 1.3 五种初始化方式
  • 2. 函数基础
    • 2.1 函数的作用
    • 2.2 函数的定义
    • 2.3 函数的调用
    • 2.4 函数的声明
  • 3. 变量的作用域与生存周期
    • 3.1 作用域(空间维度:哪里能用)
    • 3.2 生存周期(时间维度:存在多久)
  • 4. 变量的四大存储类型
    • 4.1 auto 自动型(局部变量默认)
    • 4.2 register 寄存器型
    • 4.3 extern 外部声明
    • 4.4 static 静态存储(重点考点)
  • 今日知识点总结

1. 二维字符型数组

1.1 功能与定义

二维字符数组的核心作用是存储和操作多个字符串,可以理解为 “字符串数组”—— 每一行存放一个独立的字符串。

语法格式:

char 数组名[行数][每行最大字符数];

示例:

char str[5][32]; // 共5行,每行最多存31个有效字符 + 1个结束符'\0'

注意:每行长度要预留一个位置给字符串结束符\0,因此 32 字节的行最多存放 31 个有效字符。

1.2 元素访问

二维字符数组有两种常用访问粒度:

  • 访问单个字符str[行号][列号],得到一个char类型字符
  • 访问一整行字符串str[行号],得到一个字符数组首地址,可直接当作字符串使用
str[0][2]; // 访问第0行第2列的单个字符 str[0]; // 访问第0行的整串字符,等价于字符串首地址

1.3 五种初始化方式

方式 1:逐个字符赋值(最原始)
char str[5][32] = { {'h', 'e', 'l', 'l', 'o', '\0'}, {'w', 'o', 'r', 'l', 'd', '\0'}, {'h', 'o', 'w', '\0'}, {'a', 'r', 'e', '\0'}, {'y', 'o', 'u', '\0'} };

手动写每个字符,必须手动补充\0结束符。

方式 2:字符串逐行大括号包裹
char str[5][32] = {{"hello"}, {"world"}, {"how"}, {"are"}, {"you"}};

每个字符串用双引号,系统自动追加\0

方式 3:省略内层大括号(最常用)
char str[5][32] = {"hello", "world", "how", "are", "you"};

按顺序依次给每行赋值,写法最简洁。

方式 4:全零初始化
char str[5][32] = {0};

所有元素初始化为\0,即空字符串。

方式 5:省略行数
char str[][32] = {"hello", "world", "how", "are", "you"};

列数不能省略,行数可以省略,编译器会根据初始化的字符串数量自动计算行数。

2. 函数基础

2.1 函数的作用

  1. 避免重复代码:相同逻辑只写一次,多处调用,减少代码冗余
  2. 模块化编程:将复杂程序拆分为多个功能模块,每个函数负责一个功能,提升代码可读性与可维护性

2.2 函数的定义

函数定义就是写出函数的具体实现代码,语法格式:

返回值类型 函数名(数据类型1 形参1, 数据类型2 形参2, ...) { 函数体语句; return 返回值; }
四个核心概念
  1. 函数名:命名规则与变量名一致,遵循标识符命名规范
  2. 形参(形式参数):定义在函数括号内,用来接收外部传入的数据,描述函数的处理方式
  3. 返回值类型(函数类型):函数执行结束后返回结果的数据类型
    • 若返回值类型与return后的值类型不一致,以函数类型为准,自动强制转换
    • 不写函数类型时,C 语言默认为int类型
    • 无返回值的函数必须显式写void,不能省略
  4. 返回值:函数运行的最终结果,通过return返回给主调函数

2.3 函数的调用

语法:

函数名(实参1, 实参2, ...);
关键规则
  1. 主调函数与被调函数:主动发起调用的是主调函数,被调用执行的是被调函数
  2. 参数传递:调用时实参的值会拷贝一份传递给形参,是值传递
    • 实参与形参的个数必须一一对应
    • 若类型不匹配,实参会自动强制转换为形参的类型再传递
  3. 函数调用的本质:函数调用表达式的类型 = 函数的返回值类型,值 = return 返回的值

2.4 函数的声明

函数声明的作用是告诉编译器有这个函数存在,解决 “函数定义在调用之后” 的编译报错问题。

规则:

  • 被调函数定义在主调函数上方:无需声明,可直接调用
  • 被调函数定义在主调函数下方:必须在调用之前进行函数声明

声明格式:

返回值类型 函数名(形参类型列表);

例如:int add(int a, int b);或简写为int add(int, int);


3. 变量的作用域与生存周期

这是两个完全不同维度的概念,务必区分清楚:

3.1 作用域(空间维度:哪里能用)

指变量能够被合法访问的代码范围。

  1. 局部变量:作用域限定在定义该变量的最近一对大括号{}内,出了括号就无法访问
  2. 全局变量:作用域覆盖整个当前源文件,配合extern可扩展到工程内其他文件

3.2 生存周期(时间维度:存在多久)

指变量从被分配内存空间,到空间被系统回收的整个时间段。

  • 局部变量:进入代码块时创建,离开时销毁
  • 全局变量:程序启动时创建,程序结束时销毁

4. 变量的四大存储类型

存储类型直接决定了变量的存储位置、生存周期、默认初始值,完整定义语法:

存储类型 数据类型 变量名;

例如:auto int a;等价于我们平时写的int a;

4.1 auto 自动型(局部变量默认)

  • 存储位置:内存栈区
  • 作用域:局部作用域,仅最近的{}内可用
  • 生存周期:执行到定义语句时开辟空间,离开作用域立即回收
  • 初始值:未手动初始化时为随机垃圾值
  • 特点:局部变量默认就是auto类型,关键字通常省略不写

4.2 register 寄存器型

  • 存储位置:建议存入 CPU 内部寄存器(读写速度远快于内存);寄存器不足时自动退化为auto存入栈区
  • 作用域:仅局部作用域,只能修饰局部变量
  • 生存周期:与auto一致,离开作用域立即回收
  • 初始值:未初始化时为随机值

4.3 extern 外部声明

  • 核心作用:声明而非定义,告诉编译器 “这个全局变量 / 函数在其他源文件中已经定义”,用于跨文件访问
  • 存储位置:不分配新空间,对应变量本身存放在静态区
  • 易错点extern只做声明,不能附带初始化,例如extern int a;正确,extern int a = 10;错误

4.4 static 静态存储(重点考点)

  • 存储位置:内存静态区(数据段)
  • 生存周期:编译阶段就分配空间,程序运行全程存在,程序结束后才回收
  • 初始值:未手动初始化时,默认自动赋值为0
  • 核心特性整个程序运行中只初始化一次

根据修饰对象不同,效果分为两类:

① static 修饰局部变量
  • 作用域不变:仍然只能在当前{}内访问
  • 生命周期延长:离开作用域后空间不回收,下次进入代码块时保留上一次的值
② static 修饰全局变量 / 函数
  • 生命周期不变:仍然是程序全程存在
  • 作用域收缩:原本可跨文件访问的全局变量,加static后只能在当前源文件内使用,其他文件无法通过extern调用,起到封装和避免命名冲突的作用

今日知识点总结

  1. 二维字符数组本质是字符串数组,str[i]代表第 i 行字符串,str[i][j]代表单个字符;初始化时行数可省、列数不可省。
  2. 函数包含定义、调用、声明三要素;值传递是实参向形参拷贝数据,形参修改不影响实参。
  3. 作用域看空间范围,生存周期看存在时长,二者不可混淆。
  4. 四种存储类型中,static是最高频考点:修饰局部变量延长生命周期,修饰全局变量收缩作用域,且全程只初始化一次、默认值为 0。