嵌入式学习 day9:函数

嵌入式学习 day9:函数

一、二维字符数组

二维字符数组本质上就是一个字符串数组——每一行存一个字符串。

1. 定义

c

char str[5][32]; // 5行,每行最多31个字符(留1个给\0)

2. 元素的访问

c

str[0] // 访问第0行,代表第0个字符串 str[0][2] // 访问第0行第2列,单个字符

3. 初始化

c

// 方式一:逐字符初始化 char str[5][32] = { {'h', 'e', 'l', 'l', 'o', '\0'}, {'w', 'o', 'r', 'l', 'd', '\0'} }; // 方式二:字符串初始化(最常用) char str[5][32] = {"hello", "world", "how", "are", "you"}; // 方式三:全部置零 char str[5][32] = {0};

4. 输入与输出

c

char str[5][32] = {0}; // 输入5个字符串 for (int i = 0; i < 5; i++) { scanf("%s", str[i]); // str[i] 本身就是地址,不用加& } // 输出5个字符串 for (int i = 0; i < 5; i++) { printf("str[%d] = %s\n", i, str[i]); }

⚠️ 二维字符数组的每一行都是一个一维字符数组,str[i]本身就是字符串的首地址,所以scanf不用加&

二、函数

1. 为什么需要函数?

有些操作要反复做——比如求两个数的最大值、判断闰年。每次都把同样的代码复制粘贴一遍,代码会变得又臭又长,改一个地方要改好几处。

函数就是把重复的代码封装起来,哪里需要就调用哪里

2. 函数的定义

c

函数类型 函数名(数据类型 形参1, 数据类型 形参2, ...) { 函数体; return 返回值; }

几个要点

  • 函数名:规则和变量名一样,见名知意

  • 形参:函数要处理的数据通过形参传进来

  • 函数类型:返回值的数据类型,不写默认int,没有返回值就写void

  • 返回值:函数运行完的结果,通过return返回

c

// 例子:求两个整数中较大的那个 int max(int a, int b) { return (a > b) ? a : b; }

3. 函数的调用

c

int result = max(10, 20); // result = 20

传参规则

  • 实参个数和形参个数必须一一对应

  • 类型不匹配时会自动转换(按形参类型转)

4. 函数的声明

如果被调函数写在主调函数下面,需要先声明:

c

// 声明(告诉编译器有这个函数) int max(int a, int b); int main(void) { int m = max(10, 20); return 0; } // 定义 int max(int a, int b) { return (a > b) ? a : b; }

如果被调函数写在主调函数上面,就不需要声明了。

三、变量的作用域和生存周期

1. 作用域(哪里能用)

  • 局部变量:在函数或代码块({})内定义,只能在这个范围内使用

  • 全局变量:在所有函数外面定义,整个文件都能用

c

int global = 100; // 全局变量 void func(void) { int local = 10; // 局部变量 printf("%d\n", global); // ✅ 能用全局 } int main(void) { printf("%d\n", local); // ❌ 错误!main里看不到local printf("%d\n", global); // ✅ 能用全局 return 0; }

2. 生存周期(什么时候存在)

  • 局部变量:执行到定义时开辟空间,出了作用域就回收

  • 全局变量:程序启动时就存在,程序结束才回收

四、变量的存储类型

1. auto(自动型,默认)

c

auto int a; // 等价于 int a;
  • 存在栈区

  • 不初始化就是随机值

  • 进入作用域时开辟,退出时回收

2. register(寄存器存储)

c

register int a;
  • 尽量放在CPU寄存器里(更快)

  • 如果寄存器满了,等价于auto

3. extern(外部声明)

声明变量或函数是在别处定义的,多文件编程时用。

4. static(静态存储)

  • 作用域受限:只能在当前文件里用,防止多文件命名冲突

  • 生命周期延长:程序启动时分配,程序结束才回收

  • 默认初始化为0

c

static int count; // 默认值为0 static void helper(void) { } // 只能在当前文件用

五、函数传参方式

值传递(C语言默认方式)

c

void swap(int a, int b) { int tmp = a; a = b; b = tmp; } int main(void) { int x = 10, y = 20; swap(x, y); printf("x=%d, y=%d\n", x, y); // 还是 10, 20,没变! return 0; }

值传递的本质是"拷贝"——实参把自己的值复制一份给形参,形参怎么改都不影响实参。

六、今日总结

今天学了二维字符数组函数,核心要点如下:

二维字符数组

  1. 本质是字符串数组,每一行存一个字符串

  2. 定义:char 数组名[行数][列数]

  3. 初始化:char str[3][32] = {"hello", "world", "C"};

  4. 访问:str[i]代表第i个字符串,str[i][j]代表第i个字符串的第j个字符

  5. 输入输出:scanf("%s", str[i])不用加&

函数部分

  1. 函数三要素:定义(写逻辑)、调用(用逻辑)、声明(告诉编译器)

  2. 作用域:局部变量只在当前{}内有效,全局变量整个文件都能用

  3. 生存周期:局部变量随函数调用而生、随函数结束而灭,全局变量随程序

  4. static关键字:让变量生命周期延长到程序结束,同时限制作用域在当前文件

  5. 值传递:C语言传参是"拷贝",形参改变不影响实参

今日感悟

以前所有逻辑都堆在main函数里,写着写着很容易看混。把功能拆成一个个小函数之后,main函数变成了"目录",一眼就能看懂整个程序的流程,简洁易懂。