文章目录
六、数组做函数参数
在使用函数解决问题的时候,难免会将数组作为参数传递给函数,在函数内部数组进行操作
比如:写一个函数将一个整型数组的内容,全部置为-1,再写一个函数打印数组的内容。
#include<stdio.h>
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
set_arr();
printf_arr();
return 0;
}
set_arr函数要能够对数组内容进行设置,就得把数组作为参数传递给函数,同时函数内部再设置数组每个元素得时候,也得遍历数组,需要知道数组得元素个数。
所以我们需要给set_arr传递2个参数,一个是数组,另外一个是数组得元素个数。
#include<stdio.h>
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int se = sizeof(arr)/sizeof(arr[0]);
set_arr(arr,sz);//设置数组内容为-1
printf_arr(arr,sz);//打印数组内容
return 0;
}
数组作为参数传递给了set_arr和printf_arr函数了。
这里我们需要知道数组传参得几个重点知识:
- 函数的形式参数要和函数的实参个数匹配
- 函数的实参是数组,形参也是可以写成数组形式的
- 形参如果是一维数组,数组大小可以省略不写
- 形参如果是二维数组,行可以省略,但是列不能省略
- 数组传参,形参是不会创建新的数组的
- 形参操作的数组和实参的数组是同一个数组
void set_arr(int arr[],int sz)
{
int i = 0;
for(i = 0;i < sz;i++)
{
arr[i] = -1;
}
}
void printf_arr(int arr[],int sz)
{
int i = 0;
for(i = 0;i <sz;i++)
{
printf("%d ",arr[i])
}
printf("\n");
}
七、嵌套调用和链式访问
7.1 嵌套调用
嵌套调用就是函数之间的互相调用,每个函数就像一个乐高零件,正式因为多个乐高零件互相无缝的配合才能搭建出精美的乐高玩具,也正是因为函数之间有效的互相调用,最后写出来了相对大型的程序。
假设我们计算某年某月有多少天?如果要函数实现,可以设计2个函数:
- is_leap_year() :根据年份确定是否闰年
- get_days_of_month():调用is_leap_year确定是否闰年后,再根据月计算这个月的天数
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_month(int y, int m)
{
int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int d = days[m];
if(is_leap_year(y)&& m ==2 )//闰年的2月多1天
d += 1;
return d;
}
int main()
{
int year = 0;
int month = 0;
scanf("%d %d", &year, &month);
//计算year年month月的天数 2024年 10 月有多少天?
int d = get_days_of_month(year, month);
printf("%d\n", d);
return 0;
}
这一段代码,完成了一个独立的功能。反应了不少函数的调用:
- main函数调用scanf、printf、get_days_of_month
- get_days_of_month函数调用is_leap_year
7.2 链式访问
所谓链式访问就是将一个函数的返回值作为另一个函数的参数 ,像链条一样将函数串起来就是函数的链式访问。
比如:
int main()
{
size_t len = strlen("abc"); //strlen返回的值是size_t类型的
printf("%zd\n", len);//打印长度
return 0;
}
前面的代码完成了写了2条语句,但如果把strlen的返回值直接作为printf函数的参数呢?这样就是就是一个链式访问的例子了。
int main()
{
printf("%zd\n", strlen("abc"));//链式访问
return 0;
}
再看一个有趣的代码,下面代码执行的结果是什么呢?
#include<stdio.h>
int main()
{
printf("%d",printf("%d",printf("%d",43)));
return 0;
}
这个代码的关键是明白printf函数的返回是啥?
int printf(const char * format,...);
所以屏幕上最终打印:4321
八、函数的声明和定义
8.1 单个文件
一般我们在使用函数的时候,直接将函数写出来就使用了。
比如:我们要写一个函数判断一年是否是闰年。
#include<stdio.h>
//如果是闰年返回1
//否则返回0
int is_leap_year(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):
//判断
int r = is_leap_year(y);//函数的调用
if(r == 1);
printf("闰年\n");
else
printf("不是闰年\n");
return 0;
}
//函数的调用
当我们将两个函数的顺序进行上下调换呢?会发生什么样的结果
这是因为C语⾔编译器对源代码进⾏编译的时候,从第⼀⾏往下扫描的,当遇到第7⾏的
函数调⽤的时候,并没有发现前⾯有is_leap_year的定义,就报出了上述的警告。
那我们应该如何解决呢?
就是函数调用之前先声明一下,is_leap_year这个函数,声明函数只要交代清楚:函数名,函数的返回类型和函数的参数。
8.2 多个文件(重要)!!
工程中写代码,我们不止需要一个代码。代码量会比较大,如果我们把所以代码都放在一个文件中,就不合适了
1.不便于协作
2.代码也不够清晰
在工程中,一个工程中会有多个文件
.h 文件
.c 文件
如果要调用其他的文件,需要在自己头文件中声明的函数,使用" *** ".
add.c
//函数的定义
int add(int x,int y)
{
return x+y;
}
add.h
//函数的声明
int add(int x,int y);
test.c
#include<stdio.h>
#include "add.h"
int main()
{
int x = 20;
int y = 30;
//函数的调用
int c = add(a,b);
printf("%d\n",c);
return 0;
}
有了函数声明和函数定义的理解,我们写代码就更加方便了。
8.3 static和extern
static和extern都是c语言中的关键字。
static是静态的意思,可以用来:
- 修饰局部变量
- 修饰全局变量
- 修饰函数
extern是用来声明外部符号的。
在讲解之前我们先了解一下:作用域和生命周期。
- 作用域:是程序设计概念,通常来说,⼀段程序代码中所⽤到的名字并不总是有效(可⽤)的,⽽限定这个名字的可⽤性的代码范围就是这个名字的作⽤域。
- 局部变量的作⽤域是变量所在的局部范围
- 全局变量的作⽤域是整个⼯程(项⽬)
- 生命周期:指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的⼀个时间段。
- 局部变量的⽣命周期是:进⼊作⽤域变量创建,⽣命周期开始,出作⽤域⽣命周期结束
- 全局变量的⽣命周期是:整个程序的⽣命周期
8.3.1 static 修饰局部变量
下面我们看两端代码:
//代码1
void test()
{
int n = 5;
n++;
printf("%d ", n);
}
int main()
{
int i = 0;
for (i = 0; i < 5; i++)
{
test();
}
return 0;
}
//输出6 6 6 6 6
//代码2
void test()
{
static int n = 5; //static修饰局部变量
n++;
printf("%d ", n);
}
int main()
{
int i = 0;
for (i = 0; i < 5; i++)
{
test();
}
return 0;
}
//输出6 7 8 9 10
对比代码1和代码2的效果,我们可以看出static修饰局部变量的意义。
代码1:test函数中的局部变量i是每次进入test函数先创建变量,并赋值为0,然后++,再打印,出函数的时候变量生命周期将要结束(释放内存)。
代码2:我们输出结果来看,i的值有累加的效果。前边加上static修饰,出函数的时候不会销毁重新进入函数不会重新创建变量,直接上次累积的数值继续计算。
结论:static修饰局部变量改变了变量的生命周期,生命周期改变了变量的存储类型
使用建议:未来一个变量出了函数后,我们还行继续保留值,可以在函数之前使用static来进行修饰。
8.3.2 static修饰全局变量
代码1:
add.c
int g_val = 2018;
test.c
#include<stdio.h>
extern int g_val;
int main()
{
printf("%d\n",g_val);
return 0;
}
代码2:
add.c
static int g_val = 2018;
test.c
#include<stdio.h>
extern int g_val; //extern是用来声明外部符号的
int main()
{
printf("%d\n",g_val);
return 0;
}
extern 是用来声明外部符号的,如果一个全局的符号在A文件中定义,在B文件中想使用,就可以使用extern进行声明,然后使用。
代码1正常,代码2在编译的时候会出现链接性错误。(全局变量被static修饰之后,外部链接属性就变成了内部链接属性,只能在文件内部使用了,其他源文件,即使声明了,也是无法正常使用的)
使用建议:如果一个全局变量,只想在所在的源文件内部使用,不想被其他文件发现,就可以使用static修饰。
8.3.3 static修饰函数
使用建议:⼀个函数只想在所在的源⽂件内部使⽤,不想被其他源⽂件使⽤,就可以使⽤static饰。
完结
2024/11/28 Thursday
有任何疑问可以在此私聊博主>_<!!!