目录
一.函数的概念
函数(function):也可以被翻译为子程序。在C语言中函数就是用来完成某个特定任务的一段代码。
在C语言中我们一般会见到两类函数
1.库函数
2.自定义函数
二.库函数
1.标准库
2.头文件
三.自定义函数
1.函数的语法形式
ret_type fun_name(形式参数)
{
}
1. ret_type指的是函数的返回类型
返回类型可以是void也可以是int,前者表示什么都不返回,后者表示返回整形。
2.fun_name指的是函数名
3.( )中放的是函数的参数
4.{ }括起来的是函数体
函数体就是完成函数功能的过程。
2.函数的举例
我们可以先尝试写一个加法函数:
#include<stdio.h>
int Add(int x,int y)
{
return x + y;
}
int main()
{
int a,b;
scanf("%d %d",&a,&b);
int ret = Add(a,b);
printf("%d\n",ret);
return 0;
}
在以上代码中我们可以发现,Add()这个函数就是加法函数用来实现两个整形变量相加的过程。
因为函数的计算结果是整形,所以我们需要让函数的返回类型为整形。
而且是两个整形变量相加,故我们需要两个形式参数。
3.形参和实参
在函数的使用过程中,
我们通常把函数分为实参和形参
实参:实际参数就是真实传递给函数的参数。
4.实参和形参的关系
![](https://img-blog.csdnimg.cn/direct/4d9d499518fa4d2aa156150c9e7cca38.png)
![](https://img-blog.csdnimg.cn/direct/dbb6a5a152c74446bfd62cd55d25b65d.png)
四.return 语句
return
在我们学习C语言的过程中,我们经常会看到return语句。那么return语句到底怎么使用呢?
return 表达式 ;
功能:return关键字终止其出现的函数的执行,并将控制(以及表达式的值(如果给定))返回给调用函数。默认情况下,函数返回一个整数值。要定义其他类型的返回值,函数的名称前面要加上类型。如果函数的类型为void,则会省略return语句。
注意事项:
1.return后面可以是一个数值,也可以是一个表达式,如果是表达式,则先执行表达式,在返回表达式的结果。
2.return后面也可以什么都没有,直接写return;这种写法是函数的返回类型为void的时候
3.如果return返回的值与函数的返回类型不一样,系统会自动将返回的值转化为函数的返回类型。
4.return语句执行后,函数就彻底结束,后面的代码就不再执行了.
5.如果函数中存在if等分支语句,则要保证每一种情况下都有return返回,否则编译器会报错。
五.数组做函数的参数
比如:我们需要写两个函数分别对数组进行设置和输出,那么我们应该如何实现呢?
#include<stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
set_arr();
print_arr();
return 0;
}
主函数我们已经完成了
剩下我们就需要完成数组的设置和输出这个两个函数了
set_arr();
假设我们将数组的元素全部设置为-1;
我们需要给函数传递的参数就是arr和数组的大小;数组的打印也是同理;
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int sz = sizeof(arr) / sizeof(arr[0]);
set_arr(arr,sz);
print_arr(arr,sz);
return 0;
}
set_arr()
void set_arr(int arr[],int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
arr[i] = -1;
}
}
print_arr()
void print_arr(int arr[],int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
那么我们就已经完成了这两个函数的代码。
故整个程序:
#include<stdio.h>
void set_arr(int arr[],int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
arr[i] = -1;
}
}
void print_arr(int arr[],int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int sz = sizeof(arr) / sizeof(arr[0]);
print_arr(arr, sz);
set_arr(arr,sz);
print_arr(arr,sz);
return 0;
}
注意事项
六.嵌套调用和链式访问
1.嵌套调用
嵌套调用就是函数之间的互相调用。
习题:计算某年某月有多少天?
为了完成这道题,我们可以设计两个函数:
首先,我们需要判断是否为闰年,在计算这个月是多少天?
is_leap_year():根据年份判断是不是闰年;
判断闰年的条件:可以被4整除不能被100整除或者可以被400整除
int is_leap_year(int y)
{
if (((y % 4 == 0 && y % 100 != 0)) ||( y % 400 == 0))
{
return 1;
}
else
{
return 0;
}
}
get_day_0f_month():
int get_day_of_month(int y,int m)
{
int day[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
// 1 2 3 4 ..... 12
int days = day[m];
if ((is_leap_year(y) == 1) && m == 2)
{
days += 1;
}
return days;
}
主函数
#include<stdio.h>
int main()
{
int y;
int m;
scanf("%d %d",&y,&m);
printf("%d",get_day_of_month(y,m));
}
我们可以看出get_day_0f_month()函数中调用了is_leap_year()函数;这就是函数的嵌套调用;
当然main函数中也的调用了scanf和printf函数
注意:函数之间可以嵌套调用,但是不能嵌套定义;
2.链式访问
#include <stdio.h>
int main()
{
int len = strlen("abcdef");//1.strlen求⼀个字符串的⻓度
printf("%d\n", len);//2.打印⻓度
return 0;
}
当然,我们可以直接将是strlen的返回值作为printf函数的参数,这就是链式访问;
#include <stdio.h>
int main()
{
printf("%d\n", strlen("abcdef"));//链式访问
return 0;
}
3.printf()函数
看一下这段代码的执行结果是什么?
#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 321)));
return 0;
}
答案是 32131
为什么呢?
这时候就需要我们深入了解printf函数
Return Value
Each of these functions returns the number of characters printed, or a negative value if an error occurs.
printf函数返回的就是打印在屏幕上的字符个数。如果发生错误,就返回负数。
在上面的代码中,
第一个printf函数打印321
第二个printf函数打印3
第三个printf函数打印1
所以最终是32131.
七.函数的定义与声明
在一个文件中
一般我们使用使用函数的时候直接写出来即可。
用红色圈出来的部分就是函数的定义,
画橙色线条的地方就是函数的调用。
这是函数的定义放在函数的调用之前
如果我们将函数的定义放在函数的调用之后,这时候就需要函数的声明。
这时候发生警告,函数get_day_of_month函数未定义
为什么呢?
因为C语⾔编译器对源代码进⾏编译的时候,从第⼀⾏往下扫描的,当遇到的get_day_of_month函数调⽤的时候,并没有发现前⾯有get_day_of_month的定义,就报出了上述的警告。
在多个文件中
⼀般在企业中我们写代码时候,代码可能⽐较多,不会将所有的代码都放在⼀个⽂件中;我们往往会根据程序的功能,将代码拆分放在多个⽂件中,交给多个程序员进行编写。
⼀般情况下,函数的声明、类型的声明放在头⽂件(.h)中,函数的实现是放在源⽂件(.c)⽂件中。
add.c
//函数的定义
int Add(int x, int y)
{
return x+y;
}
//函数的声明
int Add(int x, int y);
源.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;
}
注意:在引用我们自己写的头文件时,用 " "
八.static和extern
static是静态的意思。
1.修饰局部变量
2.修饰全局变量
3.修饰函数
extern是外部的意思
用来声明外部符号
1.作用域和声明周期
生命周期:指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的⼀个时间段。
1. 局部变量的⽣命周期是:进⼊作⽤域变量创建,⽣命周期开始,出作⽤域⽣命周期结束。
2.static修饰局部变量
首先我们看两个代码
//代码一
#include <stdio.h>
void test()
{
int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for (i = 0; i < 5; i++)
{
test();
}
return 0;
}
//代码二
#include<stdio.h>
void test()
{
//static修饰局部变量
static int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for (i = 0; i < 5; i++)
{
test();
}
return 0;
}
运行结果:
代码一:11111
代码一中,test函数中的局部变量i是每次进入函数先创建(生命周期开始)并赋值为0
然后加1,再打印,最后再出函数的时候,生命周期结束(释放内存)
代码二:12345
代码二中,我们从结果观察来看,i的值有累加的效果,其实test函数中的i创建好了后,出函数的时候是不会销毁的,重新进入函数也不会重新创建变量,直接上次积累的值继续计算。
总结:static修饰局部变量改变了变量的⽣命周期,只有程序结束,变量才销毁,内存才回收。但是作⽤域不变的。
3.static修饰全局变量和extern
4.static修饰函数
正常情况下
一个函数在整个工程中都可以使用,如果一个函数只想在所在的源⽂件内部使⽤,不想被其他源⽂件使⽤,就可以使⽤ static 修饰。
如果文章有问题的话。可以在评论区指出。或者私信我,会尽快更改的,以免误导读者。
求个赞!!!