🏔️山高万仞,只登一步!
文章目录
- 一.嵌套调用
- [二. 链式访问](#二. 链式访问)
- 三.函数的声明和定义
-
- [3.1 单个文件](#3.1 单个文件)
- [3.2 多个文件](#3.2 多个文件)
- [3.3 static和extern](#3.3 static和extern)
-
- [3.3.1 作用域和生命周期](#3.3.1 作用域和生命周期)
- [3.3.2 static修饰局部变量](#3.3.2 static修饰局部变量)
- [3.3.3 static修饰全局变量](#3.3.3 static修饰全局变量)
- [3.3.4 static修饰函数](#3.3.4 static修饰函数)
- [四. 练习](#四. 练习)
前面我分享了函数的一些基本概念以及易混淆点,但函数最重要的是如何调用和实现,接下来我将分享一些实例,更进一步理解函数的运用!
上篇函数 介绍点击下方链接
C语言------函数(超详细分析)
一.嵌套调用
嵌套调用时函数之间的相互调用,我们可以把函数间的调用类比成用乐高零件拼玩具,每个函数就像是一个乐高零件,只不过这种零件可以重复使用,一个个函数 "堆积" 成一个大的程序。
例:计算某年某月多少天,可以定义两个函数
is_leap_year() 根据年份确定是否是闰年
get_day_of_year() 调用is_leap_year(),再计算每月天数
c
int is_leap_year(int y)
{
if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
return 1;
else
return 0;
}
int get_days_of_year(int y, int m)
{
int days[] = {0, 31,28,31,30,31,30 ,31,31,30,31,30,31 };
// 0 1 2 3 4 5 6 7 8 9 10 11 12
int day = days[m];
if (is_leap_year(y) && m==2)
day += 1;
return day;
}
int main()
{
int y = 0;
int m = 0;
scanf("%d %d", &y, &m);
int d=get_days_of_year(y,m);
printf("%d\n", d);
return 0;
}
调用的scanf,printf,get_days_of_year
get_days_of_year调用的is_leap_year都是嵌套调用
但是函数不能嵌套定义
二. 链式访问
链式访问就是把函数的返回值最为另外一个函数的参数,这样像链条一样把函数串起来就是函数的链式访问
例
c
#include<stdio.h>
int main()
{
int len = strlen("abcdefg");
printf("%zu\n", len);
return 0;
}
如果直接把上述代码中strlen的返回值作为函数的参数,这样就是链式访问
没有中间商赚差价😆
c
#include<stdio.h>
int main()
{
printf("%zu\n", strlen("abcdefg"));
return 0;
}
一个有趣的例子:
c
#include<stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}
可以预测一下这段代码打印输出的结果
首先了解printf函数的返回值是什么
返回打印在屏幕上字符的个数
第三个printf函数打印43,屏幕上打印2字符返回值2;
第二个printf函数打印2,屏幕上打印1字符返回值1;
第一个printf函数打印1
最终打印4321
c
#include<stdio.h>
int main()
{
printf("%d ", printf("%d ", printf("%d ", 43)));
return 0;
}
这段代码打印多少可以猜测一下
三.函数的声明和定义
3.1 单个文件
一般我们使用函数的时候直接就可以使用
例:假如我们写一个函数判断是否是闰年
c
int test(int y)
{
if (((y%4==0)&&(y%100!=0))||(y%400==0))
{
return 1;
}
else
{
return 0;
}
}
int main()
{
int y = 0;
scanf("%d", &y);
test(y);
if (y==1)
{
printf("是闰年\n");
}
else {
printf("不是闰年\n");
}
return 0;
}
上面test()部分包括下面的函数体
是函数的定义,test(y)
是函数的调用
这样正常的写没事,但是把函数的定义放在调用的后面就会出现警告
c
int main()
{
int y = 0;
scanf("%d", &y);
test(y);
if (y==1)
{
printf("是闰年\n");
}
else {
printf("不是闰年\n");
}
return 0;
}
int test(int y)
{
if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
{
return 1;
}
else
{
return 0;
}
}

因此我们要在函数调用前先进行声明
即:
函数要满足先声明再使用,函数的定义也是一种特殊的声明,所以函数定义放在调用之前是可以的
声明格式
int test (int )
1.有返回类型
2.参数的个数和类型
3.要有函数名,参数名可以省略
3.2 多个文件
但是在实际生活中写代码数量很大,因此会把代码都放在多个文件中,根据所写程序的功能和特点进行分类。
方便模块化编程
方便协作
函数的声明,类型的声明放在头文件.h
中,函数的实现文件放在.c
文件中
add.h
c
int Add(int x, int y);
add.c
c
int Add(int x, int y)
{
return x + y;
}
test.c
c
#include<stdio.h>
#include"add.h"
int main()
{
int a = 10;
int b = 20;
int c = Add(a, b);
printf("%d\n", c);
return 0;
}

3.3 static和extern
static和extern 都是C语言中的关键字
static是修饰静态变量,可以用来:
修饰局部变量
修饰全局变量
修饰函数
extern 是用来声明 外部符号
外部符号可以是全局变量 和函数 等
3.3.1 作用域和生命周期
作用域 :是程序设计的概念,一段代码中所用到的名字并不总是有效的,这个名字有效的范围就是作用域 即:可以使用的范围
1.局部变量作用域:变量所在的局部范围
2.全局变量的作用域是整的工程(项目)
例1

例2
**生命周期:**是指变量的创建(申请内存)到变量的销毁(收回内存)的一个时间段
1.局部变量的生命周期是:进入作用域变量创建生命周期开始,出作用域生命周期结束
2.全局变量的生命周期是:整个程序的生命周期(main函数的生命周期)
3.3.2 static修饰局部变量
两个例子了解static的作用
c
void test()
{
int i = 0;
i++;
printf("%d\n", i);
}
int main()
{
int i = 0;
for ( i = 0; i < 5; i++)
{
test();
}
return 0;
}
c
void test()
{
static int i = 0;
i++;
printf("%d\n", i);
}
int main()
{
int i = 0;
for ( i = 0; i < 5; i++)
{
test();
}
return 0;
}
结果
static修饰局部变量改变了变量的生命周期 加static之后出函数的时候是不会销毁的,重新进入函数也不会创建新的变量,直接上次累加的值进行计算
3.3.3 static修饰全局变量

全局变量具有外部连接属性,static修饰之后变成内部连接属性,不能被其他文件访问
3.3.4 static修饰函数

函数同样具有外部连接属性,static修饰之后变成内部连接属性,不能被其他文件访问
static 会把具有外部链接属性的全局变量和函数,变成内部连接属性只能被本身源文件使用,如果不想被其他文件发现就可以使用static修饰
static改变了具有局部变量的存储类型由栈区改为了静态区,局部变量就和全局变量一样,出这个作用域不会销毁等到下次进入函数再次使用。
四. 练习
创建一个整形数组,完成对数组的操作
实现函数init() 初始化数组为全0
实现print() 打印数组的每个元素
实现reverse() 函数完成数组元素的逆置。
c
void Init(int arr[], int sz, int set)
{
int i = 0;
for (i = 0; i < sz; i++)
{
arr[i] = set;
}
}
void Print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void Reverse(int arr[], int sz)
{
int left = 0;
int right = sz - 1;
while (left < right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
int main()
{
int arry[] = { 0,1,2,3,4,5,6,7,8,9 };
int sz = sizeof(arry) / sizeof(arry[0]);
Print(arry, sz);
Reverse(arry, sz);
Print(arry, sz);
Init(arry, sz, 0);
Print(arry, sz);
return 0;
}