第八章 函数初探

函数(function)

  • 是完成特定任务的独立程序代码

  • 语法规则定义了函数的结构和使用方式

  • 好处:

    • 可以省去编写重复代码的苦闷
    • 可以让程序更加模块化,提高代码可读性
    • 方便后期修改、完善

函数的种类

  • 种类

    • 内置函数
      • 由C语言系统提供
      • 需要在程序前包含定义函数的头文件

    见图h

    h

    • 自定义函数
      • 不带参数
      • 带参数

常用的内置函数

见图i、j

i

j

  • system函数常见用法:

    1、system(“pause”); //冻结屏幕,便于观察程序的执行结果

    2、system(“cls”); //清屏操作

    3、system(“color 4E”); //修改背景色及前景色

    4、system(“shutdown /r /t 180”); //设置自动关机

内置函数补充

  • malloc()
    • malloc的全称是memory allocation,中文叫动态内存分配,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存
    • 分配长度为num_bytes字节的内存块
    • 函数原型:extern void * malloc(unsigned int num_bytes)
    • 如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL
    • 当内存不再使用时,应使用free()函数将内存块释放(原始内存中的数据保持不变)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdlib.h>
void main()
{
int * num;
int i;
num = (int *)malloc(sizeof(int) * 5);
num[4] = 9;
for(i = 0;i < 5;i++)
{
printf("%d\n",num[i]);
}
free(num);//用完释放内存
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdlib.h>
void main()
{
int * num;
int i;
num = calloc(5,sizeof(int));
num[4] = 9;
for(i = 0;i < 5;i++)
{
printf("%d\n",num[i]);
}
free(num);//用完释放内存
}

注意1:

calloc作用与molloc类似

1、不需要强转,直接返回数组

2、两个参数,默认初始化数组元素

注意2:

关于free函数:

1、必须是通过molloc、calloc或relloc分配内存的指针

2、释放的指针必须是初始分配的地址,进行运算后需要恢复

  • realloc()
    • 原型:extern void *realloc(void *mem_address, unsigned int newsize);
    • 用法:#include <stdlib.h> 有些编译器需要#include <alloc.h>
    • 功能:改变mem_address所指内存区域的大小为newsize长度
    • 说明:如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL
    • 当内存不再使用时,应使用free()函数将内存块释放(原始内存中的数据保持不变)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <stdlib.h>
int main()
{
//演示动态分配内存
int i;
int* nums;
//nums = calloc(5, sizeof(int));//拥有初始化
//nums = (int*)malloc(20);//为前面的指针动态分配了20个字节的空间
nums = (int*)malloc(sizeof(int) * 5);
//等价于:int nums[5]
//为指针动态分配空间后,指针就变成了数组

for (i = 0; i < 5; i++)
{
printf("请输入第%d个元素:", i + 1);
scanf_s("%d", nums + i);
}
printf("数组元素为:\n");
for (i = 0; i < 5; i++)
{
printf("%d\t", *(nums + i));
}

free(nums);//释放动态分配的内存
nums = NULL;
}

自定义函数

  • 函数定义
1
2
3
4
return_type function_name([datatype1 arg1],[datatype arg2,[...]])
{
//函数体
}
  • 函数三要素
    • 返回值类型
    • 函数名
    • 参数列表

书写自定义函数

  • 自定义函数的完整写法
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
//函数原型
int sum(int,int);
int main()
{
......
}
//函数定义
int sum(int num1,int num2)
{
//函数实现的代码
}
  • 注意:

    1、函数原型与函数定义的头部类似,最后以分号结尾

    2、函数原型中的参数名称可以省略,只写参数类型

练习:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/*
需求:
三种图形的面积计算公式如下:
圆:s = PI * r * r;
矩形:s = width * height;
三角形:s = width * height / 2;
使用函数分别实现三种图形的面积计算,打印计算结果
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

//函数原型
void calcCircle();//计算圆的面积
void calcRectangle();//j计算矩形面积
int calcSum();//求1-100之间偶数和

//计算圆的面积(函数实现)
void calcCircle()
{
double radius, s;
printf("请输入圆的半径:");
scanf_s("%lf", &radius);
s = 3.14 * pow(radius, 2);
printf("半径为%.2lf的圆面积为:%.2lf\n", radius, s);
}
void calcRectangle()
{
double width, height; //矩形的宽和高
double s;//矩形的面积
printf("请输入矩形的宽:");
scanf_s("%lf", &width);
printf("请输入矩形的高:");
scanf_s("%lf", &height);
if (width <= 0 || height <= 0)
{
printf("宽和高不能为负数\n");
return;//返回值,只能返回一个值,不能返回多个值
}
s = width * height;
printf("矩形的面积为:%.lf\n", s);
}
int calcSum()
{
//1-100之间的偶数和
int sum = 0;
int i = 1;
for (i = 1; i <= 100; i++)
{
if (i % 2 == 0)
{
sum+=i;
}
}
//将计算好的结果返回
return sum;
}
int main()
{

/*
三种图形的面积计算公式如下:
圆:s = PI * r * r;
矩形:s = width * height;
三角形:s = width * height / 2;
使用函数分别实现图形的面积计算,打印计算结果
*/
//书写函数的步骤:完成函数三要素
//误区:不要一开始就去考虑如何完成某个功能
calcCircle();//调用计算圆面积的函数
calcRectangle();//调用计算矩形面积的函数
//需要返回值吗?
//函数名是什么?
//需要给这个函数参数吗?
int sum = calcSum();
printf("1-100之间的偶数和为:%d\n", sum);
}

带返回值的函数

  • C语言中的返回值
    • 关键字:return
    • 只能返回一个值,不能返回多个值
    • 返回值类型必须与原型中的返回值类型匹配
    • return会立即终止函数并返回,可返回空值

函数示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/*
书写函数实现数组元素的查找,要求返回找到的元素下标
书写函数实现冒泡排序并返回排序后的数组
书写函数要求用户输入密码(六位,错误则重新输入),返回并打印用户输入的正确密码
*/

//书写函数实现数组元素的查找,要求返回找到的元素下标
int search();
//书写函数实现冒泡排序并返回排序后的数组

//书写函数要求用户输入密码(六位,错误则重新输入),返回并打印用户输入的正确密码


int main()
{
int index = search();
printf("找到的元素下标是:%d\n", index);
return 0;
}

int search()
{
int nums[] = { 34,56,78,3,2, };
int i;
//要查找的数字,所查找数字的下标,没有找到index为-1
int searchNum, searchINdex = -1;
printf("请输入要查找的整形数字:");
scanf_s("%d", &searchNum);
for (i = 0; i < 5; i++)
{
if (searchNum == nums[i])
{
searchINdex = i;//记录下查找的下标
//return searchNum;
break;
}
}
//返回查找到的元素下标
return searchINdex;
}

带参函数

  • 形式参数和实际参数
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
//int,int - 形式参数
int sum(intint);
int main()
{
...
}
//a,b-形式参数
int sum(int a,int b)
{
return a + b;
}
1
2
3
4
5
6
7
int main()
{
int num1 = 10;
int num2 = 20;
int result = sum(num1,num2); //实际参数
printf("结果:%d\n",result);
}
  • 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <stdlib.h>

//自行实现pow参数
//求第一个参数的n次幂
//double num1, double num2 --- 形式参数
double power(double, int); //函数原型

int main()
{
//实际参数 - 调用
printf("%d的%d次幂等于:%.lf", 5, 2, power(5, 2));
return 0;
}
double power(double num1, int num2) //函数定义
{
double result = 1;
int i;
for (i = 0; i < num2; i++)
{
result *= num1;//累乘
}
return result;
}
  • 练习
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/*
圆面积
矩形面积
三角形面积
*/

//根据传入的半径,返回面积
double calcCircle(double);
//对用户的输入进行非负验证/让用户输入正确的值/拿到用户所输入的正确值
int validate(double); //验证输入的double类型数据是否为正数
//double input();//函数内直接让用户输入,如果不符合要求就重新录入,返回录入正确的数字

double calcRectangle(double, double);//计算矩形的面积

double calcTriangle(double, double);//计算三角形的面积

int main()
{
//思考:在本列中,那些功能是比较通用的?是可以书写成函数多此调用的?
//用户输入的必须是正数
//打印面积
double radius; //用户输入的半径
double width, height;//图形的宽和高
double width2, height2;//三角形的底和高
double s;//图形的面积
int choice;

printf("1.圆\n");
printf("2.矩形\n");
printf("3.三角形\n");
printf("支持三种图形的面积,请选择:\n");
scanf_s("%d", &choice);
switch (choice)
{
case 1:
printf("请输入求面积的圆的半径:");
do {
scanf_s("%lf", &radius);//录入
if (!validate(radius))
{
printf("所录入的内容不能为负,请重新输入:");
}
} while (!validate(radius));//当验证不通过的时候,重新录入
s = calcCircle(radius);//调用计算圆面积的方法
break;
case 2:
printf("请输入求面积的矩形的宽和高:");
do {
scanf_s("%lf%lf", &width, &height);
if (!validate(width) || !validate(height))
{
printf("请输入两个不为负的值:");
}
} while (!validate(width) || !validate(height));
//验证通过之后,调用函数计算图形的面积
s = calcRectangle(width, height);
break;
case 3:
printf("请输入求面积的三角形的底和高:");
do {
scanf_s("%lf%lf", &width2, &height2);
if (!validate(width2) || !validate(height2))
{
printf("请输入两个不为负的值:");
}
} while (!validate(width2) || !validate(height2));
//验证通过之后,调用函数计算图形的面积
s = calcTriangle(width2, height2);
break;
default:
printf("只能选择1-3的数字!");
}

//需要的用户的输入进行非负验证 - 书写函数

printf("图形的面积为:%.2lf\n", s);
//在函数中实现的是 各图形的计算过程
return 0;
}

double calcCircle(double radius)
{
//pow函数可以自己定义
double s = 3.14 * pow(radius, 2);
//返回计算好的面积值
return s;
}
//验证输入的double类型数据是否为正数
int validate(double num)
{
return num > 0; //如果num>0,会返回一个非零值,表示真
}
//根据传入的矩形宽和高,返回矩形面积
double calcRectangle(double width, double height)
{
return width * height;
}
//根据传入的三角形底和高,返回三角形面积
double calcTriangle(double width2, double height2)
{
return width2 * height2 / 2;
}

递归

  • 函数调用自己的过程称为递归(recursion)
1
2
3
4
5
6
7
8
9
10
int factorial(int num)
{
if(num == 1)//退出条件
return 1;
else
{
num = num * factorial(num - 1);
return num;
}
}
1
2
3
4
5
6
#include <stdio.h>
int main()
{
//计算5的阶乘
int result = factorial(5);
}

使用递归时的注意点:

1、有反复的执行过程(调用自己)

2、有跳出反复执行过程的条件(出口)

更新于

请我喝[茶]~( ̄▽ ̄)~*

Chen 微信支付

微信支付

Chen 支付宝

支付宝

Chen 贝宝

贝宝