在之前博文中已经给大家把函数的基础内容进行了详细介绍,那么函数能否相互调用或将上一个函数的值作为下一个函数的参数呢?这就涉及到了本章节所说函数的嵌套调用和链式访问。
一、嵌套调用
我们可以将函数间嵌套调用视为乐高积木的拼接,每一个函数都是一个乐高零件,不同的乐高零件拼接在一起就可以组成不同的成品(程序)。
我们以下面一个程序为例:
请写一个程序来计算某年某月有多少天。
如此我们就先写出主函数部分,如下图:
我们在主函数内调用了一个函数 get_days_of_month() ,故接下来我们就要对这个函数进行定义。
我们知道一年十二个月份中,2月比较特殊,2月只有28或29两种情况而不存在30和31这两种,且只有闰年时2月有29天,故我们在 get_days_of_month() 这个函数内还要调用一个函数来判断是否为闰年,我们将这个函数命名为 is_a_leap_year() ,故我们总共要定义两个函数,具体内容如下图:
对 is_a_leap_year() 定义:
对 get_days_of_month() 定义:
解释一下为何在定义Days[ ] 数组时要把第一个元素设置为0:
第一个元素设置为0后,我们下标所对应的m经实例化传递过来的值就可以对应上某月的月份了
比如:主函数调用处输入为month==1,那么实例化的形参m就是1,对应元素就为下标为1的数组第二个元素31。
运行结果:
注意:函数之间可以相互嵌套调用,但函数之间是不能嵌套定义的,即一个函数内不能定义新函数
二、链式访问
链式访问就是将一个函数的返回值作为另外一个函数的参数,像锁链一样将函数串联起来
举例如下:
图一为分步执行两条语句,图二为将 strlen 的返回值直接作为 printf 函数的参数,即链式访问。
我们再来看一下上一个博文中 printf 相互之间链式访问的例子:
printf的返回值是打印的字符的数量,所以最内部的在打印完43后,传递给第二个printf的返回值是2(2个字符),所以第二个printf就会打印2从而传递给第一个printf的返回值为1(1个字符)。故最终打印结果为4321。
当在每个%d后加个空格后,因为空格也是一个字符,所以最内部的 printf 的返回值变为3,如此第二个 printf 就打印 3和空格 ,其返回值就为2,故最后最外层 printf 打印2,最终结果为4332。
三、static 和 extern
下面我们来介绍一下C语言中的两个关键字static与extern
static表示静态,用来修饰变量和函数。
extern 则是用来声明外部符号
在具体讲述之前,我们先来讲述一下 作用域 与 生命周期 的概念
1、作用域
是程序设计概念,一段代码中所用到的名字并不总是可用的,而限定这个可用性的代码范围就是这个名字的作用域
(1)局部变量的作用域是变量所在的局部范围(同一个大括号内)
(2)全局变量的生命周期是整个程序的生命周期
如下图:因为局部变量 i 的作用域为159行~162行大括号内,故超出作用域的第16行 printf 函数就会报错
我们若将 i 定义在主函数的大括号内或定义为全局变量,那么就可以正常运行。如下图:
2、生命周期
生命周期指的是变量的创建到变量的销毁之间的一个时间段。
(1)局部变量的生命周期是:进入作用域时变量创建,生命周期开始。出作用域生命周期结束,变量销毁。
(2)全局变量生命周期是:整个程序的生命周期。
3、static修饰局部变量
在 print_num() 函数内我们定义了一个局部变量 a ,在主函数循环内调用是想实现a的自增输出,但结果却全是1,原因就是局部变量a在每次函数被调用后进入下一次循环前就会超出自身生命周期,从而变量值销毁,故之后的循环就都只会重复同一操作,只是打印输出1。
但当我们用 static 修饰局部变量 a 后,运行如下:
如此一来,局部变量 a 就可以实现变量自增,输出1234567。
综上对比,我们不难看出static其实在修饰变量时是改变了变量的生命周期,改变了变量的生命周期本质上就是改变了变量的存储类型,将局部变量由原本存储的栈区存储到静态区,而存储在静态区的变量和全局变量是一样的,只有程序结束变量才销毁,内存回收,但变量原本的作用域不发生变化。
4、static修饰全局变量与extern的使用
ID.c
test.c
extern 是用来声明外部符号,若一个1个全局的符号在文件1中定义,在文件2中想要使用,就可以用extern进行声明后使用。
再看下面两张图,若全局变量被static修饰了呢?
如此一来在编译时就会出现链接性错误
原因是因为一个全局变量被static修饰后,使得这个全局变量就只能在本源文件内使用,不能在其余源文件内使用。
本质原因为:全局变量自身本就具有外部链接属性,在其余文件内想使用只要进行对应声明就可使用,一旦被static修饰后,外部链接属性就变成了内部连接属性,只能在自己的源文件内使用了,其余文件无论如何也无法使用。
5、static修饰函数与extern声明函数
(1)
yes_yes.c
test.c
(2)
yes_yes.c
test.c
综合(1)与(2)中的代码,static与extern在函数上的使用和在全局变量的使用是基本一样的。
写作不易,求各位哥哥姐姐叔叔婶婶给个三连好吗(* ̄︶ ̄) (* ̄︶ ̄)