写在前面:文中出现的概念结论性内容转自课堂课件,其余代码,理解内容为笔者所著
目录:
1. 函数的概念
2. 库函数
2.1 标准库和头文件
2.2 库函数的使用方法
double sqrt (double x);
//sqrt 是函数名
//x 是函数的参数,表⽰调⽤sqrt函数需要传递⼀个double类型的值
//double 是返回值类型 - 表⽰函数计算的结果是double类型的值
#include <stdio.h>
#include <math.h>
int main()
{
double d = 16.0;
double r = sqrt(d);
printf("%lf\n", r);
return 0;
}
运行结果:

3. 自定义函数
3.1 函数的语法形式
其实⾃定义函数和库函数是⼀样的,形式如下:
ret_type fun_name(形式参数)
{
}
3.2 函数的举例
举个例子:
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
//输⼊
scanf("%d %d", &a, &b);
//调⽤加法函数,完成a和b的相加
//求和的结果放在r中
//to do
//输出
printf("%d\n", r);
return 0;
}
#include <stdio.h>
int Add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 0;
int b = 0;
//输⼊
scanf("%d %d", &a, &b);
//调⽤加法函数,完成a和b的相加
//求和的结果放在r中
int r = Add(a, b);
//输出
printf("%d\n", r);
return 0;
}
int Add(int x, int y)
{
return x + y;
}
4. 形参和实参
#include <stdio.h>
int Add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 0;
int b = 0;
//输⼊
scanf("%d %d", &a, &b);
//调⽤加法函数,完成a和b的相加
//求和的结果放在r中
int r = Add(a, b);
//输出
printf("%d\n", r);
return 0;
}
4.1 实参
4.2 形参
在上面代码中,第2行定义函数的时候,在函数名 Add 后的括号中写的 x 和 y ,称为形式参数,简 称形参。实际上,如果只是定义了 Add 函数,而不去调用的话, Add 函数的参数 x 和 y 只是形式上存在的,不会向内存申请空间,不会真实存在的,所以叫形式参数。
形式参数只有在函数被调用的过程中为了存放实参传递过来的值,才向内存申请空间,这个过程就是形参的实例化
4.3 实参和形参的关系
虽然我们提到了实参是传递给形参的,他们之间是有联系的,但是形参和实参各自是独立的内存空间。
#include <stdio.h>
int Add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 0;
int b = 0;
//输⼊
scanf("%d %d", &a, &b);
//调⽤加法函数,完成a和b的相加
//求和的结果放在r中
int r = Add(a, b);
//输出
printf("%d\n", r);
return 0;
}
5. return 语句
6. 数组做函数参数
⽐如:写⼀个函数将⼀个整型数组的内容,全部置为-1,再写⼀个函数打印数组的内容。
#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
set_arr();//设置数组内容为-1
print_arr();//打印数组内容
return 0;
}
#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int sz = sizeof(arr)/sizeof(arr[0]);
set_arr(arr, sz);//设置数组内容为-1
print_arr(arr, sz);//打印数组内容
return 0;
}
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");
}
7. 嵌套调用和链式访问
7.1 嵌套调用
嵌套调用就是函数之间的互相调用
假设我们计算某年某月有多少天?如果要函数实现,可以设计2个函数:
• is_leap_year():根据年份确定是否是闰年
int is_leap_year(int y) //定义函数1,用来处理年份
{
if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0)) //判断是否为闰年,闰年返回值1
return 1;
else
return 0; //不是闰年返回0
}
int get_days_of_month(int y, int m) //定义函数2,用来处理月份
{
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
//开头为0的原因是将下标可以与月份相对应,可以直接通过下标找到月份
//将所有月份可能出现的天数进行汇总
int day = days[m]; //将数组中对应的值赋给m,例:m为6则找到6对应的days赋给(day)为30
if (is_leap_year(y) && m == 2) //只有在闰年并且为2月份的时候,2对应的28才会+1变为29
day += 1; //(如果为闰年左边是1,如果是2月右边也是1,两边都是真,运行day+=1)
return day;
}
int main()
{
int y = 0;
int m = 0;
scanf("%d %d", &y, &m);
int d = get_days_of_month(y, m); //调用函数,对于输入的y和m的值进行处理
printf("%d\n", d);
return 0;
}
7.2 链式访问
所谓链式访问就是将⼀个函数的返回值作为另外⼀个函数的参数,像链条⼀样将函数串起来就是函数的链式访问。
#include <stdio.h>
int main()
{
int len = strlen("abcdef");//1.strlen求⼀个字符串的⻓度
printf("%d\n", len);//2.打印⻓度
return 0;
}
#include <stdio.h>
int main()
{
printf("%d\n", strlen("abcdef"));//链式访问
return 0;
}
例:求下面代码运行出的结果
#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}
8. 函数的声明和定义
8.1 单个文件
例:判断闰年的代码
#include <stido.h>
//判断⼀年是不是闰年
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;
}
可见,函数的定义放在了调用函数的前面,那么如果我们将二者位置调换再运行会有什么结果呢?
int main()
{
int y = 0;
scanf("%d", &y);
int r = is_leap_year(y);
if (r == 1)
printf("闰年\n");
else
printf("⾮闰年\n");
return 0;
}
int is_leap_year(int y)
{
if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
return 1;
else
return 0;
}

在vs2022上运行会出现报错
#include <stido.h>
int is_leap_year(int y);//函数声明
int main()
{
int y = 0;
scanf("%d", &y);
int r = is_leap_year(y);
if (r == 1)
printf("闰年\n");
else
printf("非闰年\n");
return 0;
}
int is_leap_year(int y)
{
if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
return 1;
else
return 0;
}
首先进行函数的声明后就可以正常运行了
8.2 多个文件
//函数的定义
int Add(int x, int y)
{
return x+y;
}
//函数的声明
int Add(int x, int y);
#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;
}
8.3 static 和 extern
8.3.1 static 修饰局部变量
代码1
//代码1
#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;
}
代码2
//代码2
#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;
}
8.3.2 static 修饰全局变量
代码1:
add.c
int g_val = 2018;
#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;
int main()
{
printf("%d\n", g_val);
return 0;
}
8.3.3 static 修饰函数
与以上两种情况类似
int Add(int x, int y)
{
return x+y;
}
test.c
#include <stdio.h>
extern int Add(int x, int y);
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
代码2:
static int Add(int x, int y)
{
return x+y;
}
#include <stdio.h>
extern int Add(int x, int y);
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}

被折叠的 条评论
为什么被折叠?



