函数传参与变量生命周期,C语言后半段的几个关键点
把函数和数组结合起来用之后,才算真正摸到C语言模块化编程的门。简单记一下这几块的核心,免得以后翻笔记。
一、函数和一维整型数组
数组传给函数的时候,传过去的不是整个数组,是首元素的地址。所以函数里改了数组元素,外面的数组也跟着变——这跟普通变量的值传递不一样。
c
void print_array(int a[], int len)
{
// 这里 sizeof(a) 求的是指针大小,不是整个数组大小
}
几个要注意的点:
– 形参写 int a[] ,方括号里的常量写不写都行,编译器都当成指针处理
– 本质传的是首地址,所以必须单独把长度传进去
– 函数内部用数组跟外面一样,就是 sizeof(数组名) 不行了,退化成指针了
二、函数和一维字符数组
跟整型数组类似,但有个区别:字符数组存的是字符串,末尾有 '\\0' 结束标志,所以不用传长度,函数自己能找到结尾。
c
void print_str(char str[])
{
// 靠 '\\0' 判断结束
}
当然, sizeof(str) 在函数里同样是指针大小,别搞错。
三、函数和二维整型数组
二维数组传参,列数不能省,行数可以省:
c
void print_2D_array(int a[][4], int hang)
{
// 列数必须写死
}
为什么列数不能省?因为编译器得知道一行有多长,才能算 a[i][j] 的地址。行数可以传参数进去,列数不行。
函数里算列数: sizeof(a[0]) / sizeof(a[0][0]) ,行数算不了,得靠参数传。
四、函数和二维字符数组
二维字符数组就是存多个字符串的。传参跟二维整型数组一个道理,列数必须写:
c
void print_2DC_array(char str[][100], int hang)
{
}
每一行就是一个字符串,用 str[i] 就能访问第 i 个字符串。
五、变量的作用域和生命周期
这一块容易搞混,分开看就清楚了。
作用域(空间角度)——变量在哪能用
– 局部变量:定义在 {} 里面,出了 {} 就用不了
– 全局变量:定义在所有函数外面,到处都能用
同名的时候遵循就近原则,内层的会把外层的"遮住"。
生命周期(时间角度)——变量活多久
– 局部变量:进函数的时候开辟空间,出函数就回收,不初始化是随机值
– 全局变量:程序运行前就开辟,程序结束才回收,默认初始化为 0
– static 修饰的局部变量:作用域还是局部,但生命周期变成了全局的——函数退出了它还在,下次调用还能接着用
内存分布上,局部变量在栈区,全局变量和 static 变量在数据区(初始化的在 .data,没初始化的在 .bss)。
存储类型关键字
– auto :默认的,局部变量都是 auto,一般不写
– static :修饰局部变量延长生命周期;修饰全局变量或函数,限制只能在当前文件里用
– register :建议编译器把变量放寄存器里,只是建议,不一定真放;寄存器变量不能取地址
– extern :声明外部的全局变量或函数,告诉编译器这个东西在别的文件里定义了
函数传参、作用域、生命周期,把这几个概念理清楚,写代码的时候就不容易出莫名其妙的 bug 了。尤其是 static 和数组传参,初学的时候最容易踩坑。


