C语言——6-函数
有时候,我们经常会遇到在一个程序中,对一个数组进行输入,如 :
int a[10];
for(int i = 0 ;i < 10;i++)
{
scanf("%d",&a[i]);
}...
int b[5];
for(int i = 0;i < 5;i++)
{
scanf("%d",&b[i]);
}上面的这两处代码,功能是相同的,只是数组名 和 元素个数 等参数不一样.
参数不一样, 代码形式是一样的,对于同一功能而参数不同的代码实现,
能不能用一个代码完成? 重复利用代码.
函数
1 什么是函数?
函数它本不叫函数, 本名 function (功能)
函数是完成某个功能的指令序列的封装.
C语言的指令(语句) 必须在函数内部.
if()
{
}//不可以的
int a = 5;//C语言的声明和定义
a = 10;//不可以, 语句要在函数内部C程序/C代码 是由函数组成的,函数是由指令(语句)组成的.
func()
{
单语句
if语句
switch语句
for语句
while语句
}
语句 --> 函数 --> C文件 --> C工程
. . .
. . .
. . .函数可以实现代码复用,以及模块化设计.
结构化程序设计者 主张把一个大任务分成 多个功能函数式来完成.
前面的作业 : 不用排序,把一个整型的无序的有正有负的数组里面 的负数放在非负数的前面.
功能 1
如 : 数组的输入
功能 2
如 : 转换(操作)
功能 3
如 : 数组的输出整个C工程,可以有多个源文件(.c/.h) , 可以有多个函数,
但是 ==有且仅有一个 main 函数==, main函数是程序的入口 和 出口.
工程
1.c 2.c 3.c
main() main()
{} {} //错误
整个工程只能有一个main函数, 他是程序的入口和出口.
2 如何来设计函数呢?
函数 : 实现一个具体的功能(或 任务)
有一个任务 : 天气太热了, 要打开空调.
(1) 明确函数的功能是什么?
要完成什么任务, "目标" , "需求分析, 问题分析"
定义一个"任务名/函数名" : C语言标识符规范
"见其名知其意"
一旦确定了"函数名" : 这个名字在代码中就有了确定的含义了,就代码这个函数的既定功能/函数
如 :
find_max
array_sum
....
==> 确定 函数名 具体的功能
(2) 完成该目标需要哪些输入资源/已知条件?
输入参数 : "完成任务需要哪些输入资源"
空调遥控器, 支持遥控的手机
如 :
目标是 求一个数组的最大值 , find_max
"数组类型" "数组名" "数组元素的个数" ...
/*
find_max : 求要给一个数组的最大值
@a : 数组名, 数组的类型必须是 int
@n : 数组元素的个数
*/
find_max(int a[],int n)
{
}
函数的形式参数(形参) : 可以有多个 也可以没有
//参数的类型, 具体个数,具体含义,.... 统统由设计者(完成这个功能的人)指定
函数名(类型1 参数1,类型2 参数2,.....) //形参的类型列表
{
}
函数名(void) //void可以省略
{
}
(3) 完成该目标后的返回结果? 返回值
返回值就是函数执行后,返回结果
如 :
0 表示失败
1 表示成功了
2 遥控器坏了
3 空调没插电
4 空调坏了
......
例子 :
/*
find_max : 求要给一个数组的最大值
@a : 数组名, 数组的类型必须是 int
@n : 数组元素的个数
返回值 :
返回 数组a中n个元素的最大值
最大值的类型是 int
*/
int find_max(int a[],int n)
{
}有时候函数执行只有一个结果(如 : 必定会成功, 或只要你去执行, 结果不关注)
函数的返回值 可以定为 void ,表示该函数无返回值.
void func(int a) { }
###
(4) 功能的具体实现 : 算法及代码的实现
/*
find_max : 求要给一个数组的最大值
@a : 数组名, 数组的类型必须是 int
@n : 数组元素的个数
返回值 :
返回 数组a中n个元素的最大值
最大值的类型是 int
*/
int find_max(int a[],int n)
{
//函数的具体的代码实现
//"遍历"
}
3 一个例子
任务 :
写一个函数, 求两个整数的和.
(1) 明确目标(任务) "求和" ==> 定义一个"任务名/函数名 sum (2) 确定任务的输入参数 两个整数 a 第一个加数 b 第二个加数 sum(int a,int b) {} (3) 确定任务返回值及含义 含义 : a + b 类型 : int /* sum :求和, 求两个整数的和 @a : 第一个加数 @b : 第二个加数 返回值 : 返回 a + b的和 */ int sum(int a,int b) {} (4) 算法及代码的具体实现 /* sum :求和, 求两个整数的和 @a : 第一个加数 @b : 第二个加数 返回值 : 返回 a + b的和 */ int sum(int a,int b) { int s; s = a + b; return s; } void func() { return ; }
4 return 语句
return : 返回语句, 用来结束一个函数的
语法 :
return 表达式;//带返回值的返回,返回的值就是 "表达式的值" //此时要求 函数的返回值的类型 为typeof(表达式) 或 兼容 return ;//不带返回值的返回 //此时要求函数的返回值类型为 void
5 函数调用
5.1 什么是函数调用呢?
函数调用是 调用一个已经写好的函数去执行.
"执行一个任务/执行一个功能代码"
5.2 如何调用函数呢?
a : 需要确定调用哪个函数?
指定要调用的那个函数的函数名.
b : 确定函数调用时的实际参数("实参")
形式参数 : 定义函数时, 指定的参数, "形参" 实际参数 : 调用函数时, 指定的参数 , "实参"实参可以是任意的表达式, 只需要一个值.
==指定实参时, 只需要指定参数的的值,而不需要指定实参的类型.==
int m = 3; int n = 4; sum(m,n);//m , n 为实参 sum(3,5);//3 ,5 为实参 sum(3 + 5,7);//3+5 , 7为实参 sum(int m,int n);//error ,实参传入时,不需要指定类型
5.3 函数调用表达式
函数名(实参列表) ----> 函数调用表达式
sum(m,n) --> 函数调用表达式 sum(3,5) --> 函数调用表达式 sum(3+5 , m/n) --> 函数调用表达式 ....函数调用表达式的值是什么?
就是调用函数时, 函数的返回值, 函数执行时 return 语句后面的那个表达式的值.
当然 ,如果该没有返回值, void,该函数调用表达式 , 就没有值.
例子 :
void func() { } m = func();//error int abc() { //假设abc的实现中,没有return 语句 } m = abc();//可以的,但是 m 的值, 是"不确定的值" so ,有返回值的函数在实现时, 一定要 return 一个值.
5.4 函数调用的过程到底是怎样的呢?
sum(3,8)
函数的调用过程 :
把实参的值, 赋值给相对应的形参,
然后再跳转到 被调用的函数内部(如 : sum )去执行,(函数中形参和变量会分配空间)
直到遇到 return 语句 或 函数结束,就返回 .(函数调用时分配的空间会释放,用完就释放)
return 语句后面的表达式的值, 就是函数调用表达式的值.
练习 :
写一个函数 ,判断一个正整数 x 是否为 质数(prime)
//1.明确函数的功能 is_prime //2.函数需要输入的资源(参数) is_prime(int x) //3.完成目标的返回结果 返回值 : 1 表示x是质数 0 表示x不是质数 /* is_prime : 判断一个数是否是质数 @x : 要判断的那个整数 返回值 : 1 表示x是质数 0 表示x不是质数 */ int is_prime(int x) { } //4.具体的算法和代码的实现 /* is_prime : 判断一个数是否是质数 @x : 要判断的那个整数 返回值 : 1 表示x是质数 0 表示x不是质数 */ int is_prime(int x) { int i; for(i = 2 ;i < x/2;i++) { if(x%i == 0) { //x有一个因子 i ,肯定不是质数 return 0; } } return 1; }2. 写一个函数,判断以三个整数为边, 是否可以组合一个三角形(triangle)./* is_triangle : 判断三边是否可以组成三角形 @a : 第一条边 @b : 第二条边 @c : 第三条边 返回值 : 返回 1 ,表示这三条边可以组成一个三角形 返回 0 ,表示这三条边不可以组成一个三角形 */ int is_triangle(double a,double b,double c) { if( (a + b > c) && (a + c > b) && (b + c > a) ) { return 1; } else { return 0; } }
6 函数声明
什么是声明?
C语言声明是指 声明一个名字是个什么东西.
如 : int a;//变量的声明, 声明a是一个int 类型的对象. float c; ...函数声明 :
声明一个名字 是一个某某类型的函数.
函数不仅有名字,还有返回值,还有形式参数....
函数如何来声明呢?
函数的返回值类型 函数名(函数形式参数的类型列表);例子 :
//sum函数的声明 ==> 告诉编译器 sum是一个函数,带两个int类型,返回值是int 类型 int sum(int ,int); /* sum :求和, 求两个整数的和 @a : 第一个加数 @b : 第二个加数 返回值 : 返回 a + b的和 */ int sum(int a,int b) { int s; s = a + b; return s; }
有一个任务 :
写一个函数 ,求一个数组的最大值.
1.目标名 : find_max 2.确定传入的参数 : 传入一个数组???? 数组作为函数的参数???
7 数组作为函数的参数
当一个函数的形式参数是一个数组时, 函数声明/函数实现的时候,
数组作为形式参数, 该如何来描述?
数组作为函数的形式参数,描述如下 :
数组元素的类型 数组名[],数组元素的个数要传入 :
(1) 数组名(数组的首地址,指针)
(2) 数组元素的个数
7.1 一维数组作为函数的形式参数
int a[10] = {1,2,3,4,5,6,7,8,9,10}; /* find_max : 找一个一维数组的最大值,只求一维数组 int类型元素的数组的最大值 @a : 元素类型为int 的数组名 @n : 元素的个数,求 n 个元素中的最大值 返回值 : 返回最大值 */ int find_max(int b[],int n) { //b[0] b[1] ... b[n-1] return max; }#include <stdio.h> /* find_max : 找一个一维数组的最大值,只求一维数组 int类型元素的数组的最大值 @a : 元素类型为int 的数组名 @n : 元素的个数,求 n 个元素中的最大值 返回值 : 返回最大值 */ int find_max(int b[],int n) { //b[0] b[1] ... b[n-1] int max = b[0]; for(int i = 1;i < n;i++) { if(b[i] > max) { max = b[i]; } } return max; } int main() { int a[10] = {1,2,3,4,250,6,7,8,9,10}; int max; max = find_max(a,10); printf("%d\n",find_max(a,10)); printf("%d\n",max); return 0; }练习 :
1.写一个函数,实现从键盘上输入一个整型数组的每个元素的值.
2.写一个函数,实现打印一个整型数组的每个元素的值.
3.写一个函数,实现求一个整型数组的最小值.
4.写一个函数,实现一个整型数组的和.
5.写一个函数,判断一个整型数组是否为升序.
#include <stdio.h> /* input_array : 从键盘上输入数组每一个元素的值,然后保存到相应的数组中去 @x : 要传入的 int 类型的数组名 @n : 要传入的数组个数 返回值 : 无 */ void input_array(int x[],int n) { for(int i = 0;i < n;i++) { scanf("%d",&x[i]); } } /* print_array : 打印数组中每一个元素的值 @x : 要传入的 int类型的数组名 @n : 要传入的数组元素个数 返回值 : 无 */ void print_array(int x[],int n) { for(int i = 0;i < n;i++) { printf("%d ",x[i]); } printf("\n"); } /* get_min : 获取一个数组中的最小值 @a : 数组名 @n : 数组元素的个数 返回值 : 返回 数组中的最小值 */ int get_min(int a[],int n) { int min = a[0]; for(int i = 1;i < n;i++) { if(a[i] < min) { min = a[i]; } } return min; } /* array_sum : 数组求和 @a : 数组名 @n : 数组元素个数 返回值 : 返回 数组和 */ int array_sum(int a[],int n) { int sum = 0; for(int i = 0; i < n;i++) { sum = sum + a[i]; } return sum; } /* is_shengxu : 判断一个数组是否升序 @a : 数组名 @n : 数组元素的个数 返回值 : 返回 1 表示数组升序 返回 0 表示不是升序 */ int is_shengxu(int a[],int n) { for(int i = 0; i < n-1;i++) { if(a[i] > a[i + 1]) { return 0; } } return 1; } int main() { int a[10]; int min; //输入10个元素到数组a中去 input_array(a,10); // //数组的最小值 // min = get_min(a,10); // //数组和 // int sum = array_sum(a,10); //打印数组a的10个元素 print_array(a,10); // printf("min = %d\n",min); // printf("sum = %d\n",sum); printf("min = %d\n",get_min(a,10)); printf("sum = %d\n",array_sum(a,10)); int s = is_shengxu(a,10); if(s) { printf("这个数组是升序数组\n"); } else { printf("这个数组不是升序数组\n"); } return 0; }
7.2 二位数组作为函数形式参数
不管你是几维数组,数组用作函数形式参数时 : 数组元素的类型 数组名[],元素的个数 如果你实际要传入的数组是 : int a[10]; 那么我们函数的参数设计应该是 : f(int x[],int n) //设计时 f(a,10) 实际调用 如果你实际要传入的数组是 : double b[30]; 那么我们函数的参数设计应该是 : f(double x[],int n) f(a,30) 实际调用 如果你实际要传入的函数的数组是 : int a[3][4]; 那么我们函数的参数设计应该是 : f(int[4] x[],int n) f(int x[][4], int n) //二维数组的参数设计 f(a,3) 实际调用int a[3][4]; //int[4] a[3]; double b[3]; 假设需要把数组a当做参数,传入一个函数 xxx xxx(a,3); //函数调用时传实参 : 数组名 元素个数 那么xxx这个函数的形式参数如何定义呢? 数组元素的类型 数组名[],元素个数 ==> int[4] x[] , int n ==> int x[][4] ,int n ==> xxx(int x[][4],int n) //函数只能接收 列数为4 的二维数组 { //x[0][0] x[0][1] x[0][2] x[0][3] //x[1][0] ... x[1][3] //... //x[n-1][0] ... x[n-1][3] } int b[4][5]; xxx(b,4);//error ,类型不匹配练习 :
写一个函数,求一个二维数组中的最大值.
int a[5][4] = { 1,2,3,4, 1,2,30,4, 1,2,3,4, 1,2,3,4 };/* find_max_v2 :求一个类型为int[4] 的数组的最大值(二维数组的最大值) @x : 数组名 @n : 数组元素的个数 返回值 : 返回 二位数组的最大值 */ int find_max_v2(int x[][4],int n) { //x[0][0] x[0][1] x[0][2] x[0][3] //x[1][0] ... x[1][3] //... //x[n-1][0] ... x[n-1][3] int max = x[0][0]; int i,j; for(i = 0 ; i < n; i++) { for(j = 0;j < 4;j++) { if(x[i][j] > max) { max = x[i][j]; } } } return max; }#include <stdio.h> /* find_max_v2 :求一个类型为int[4] 的数组的最大值(二维数组的最大值) @x : 数组名 @n : 数组元素的个数 返回值 : 返回 二位数组的最大值 */ int find_max_v2(int x[][4],int n) { //x[0][0] x[0][1] x[0][2] x[0][3] //x[1][0] ... x[1][3] //... //x[n-1][0] ... x[n-1][3] int max = x[0][0]; int i,j; for(i = 0 ; i < n; i++) { for(j = 0;j < 4;j++) { if(x[i][j] > max) { max = x[i][j]; } } } return max; } int main() { int a[5][4] = { 1,2,3,4, 1,2,30,4, 1,2,3,4, 1,2,3,4 }; //int b[4][5]; printf("%d\n",find_max_v2(a,5)); return 0; }
作业 :
(1) 写一个函数,求两个数的最大值.
(2) 写一个函数,求两个数的最小值.
(3) 写一个函数,判断整数a是否是整数b的倍数.
(4) 求100000000!末尾有多少个0? (用函数实现)
-
写一个函数, 完成如下功能 :
给一个数组中的元素进行排序. int a[10] = {1,3,5,7,9,2,4,6,8,10};
用两种方法给他们进行排序.
(1) 采用 冒泡排序法.
-
写一个函数,完成如下功能 :
在一个有序的数组中插入一个元素后, 依然保准其有序.
int a[6] = {1,3,5,7,9};
8.3 递归练习
(1) 写一个函数, 求一个整型数组的和.
1.任务目标 "求和" array_sum 2.确定输入参数 array_sum(int a[],int n) 3.确定返回值 /* array_sum :求一个整型数组的和 @a : 数组名 @n : 数组元素的个数 */ int array_sum(int a[],int n) { } 4.算法和思路 /* array_sum :求一个整型数组的和 @a : 数组名 @n : 数组元素的个数 返回值 : 返回 数组和 */ int array_sum(int a[],int n) { if(n == 1) { return a[0]; } else if(n == 0) { return 0; } else if(n > 1) { return array_sum(a,n-1) + a[n-1]; } }(2) 求一个一维数组的最大值, "用递归"
1.明确任务目标 find_max 2.输入参数 find_max(int a[],int n) 3.确定返回值 /* find_max : 求一维数组的最大值 @a : 数组名 @n : 数组元素的个数 返回值 : 返回 最大值 */ int find_max(int a[],int n) { } 4.算法和思路 /* find_max : 求一维数组的最大值 @a : 数组名 @n : 数组元素的个数 返回值 : 返回 最大值 */ int find_max(int a[],int n) { if(n == 1) { return a[0]; } else if(n > 1) { int m = find_max(a,n -1 ); return m > a[n-1] ? m : a[n-1]; } }
浙公网安备 33010602011771号