C语言——6-函数

0 一个问题

有时候,我们经常会遇到在一个程序中,对一个数组进行输入,如 :

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 语句后面的表达式的值, 就是函数调用表达式的值.

练习 :

  1. 写一个函数 ,判断一个正整数 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? (用函数实现)

  1. 写一个函数, 完成如下功能 :

    给一个数组中的元素进行排序. int a[10] = {1,3,5,7,9,2,4,6,8,10};

    用两种方法给他们进行排序.

    (1) 采用 冒泡排序法.

  2. 写一个函数,完成如下功能 :

    在一个有序的数组中插入一个元素后, 依然保准其有序.

    int a[6] = {1,3,5,7,9};

 

void Funs_Maopao(int a[],int size)
{   int temp;
    for(int i=0;i<size;i++)
    {
        for(int j=0;j<size-1-i;j++)
        {
            if(a[j]>a[j+1])
            {
                temp=a[j];
                a[j]=a[j+1];
                a[j+1]=temp;
            }
        }
    }
}
 
 
 
#include<stdio.h>
int main()
{
    int m;
    int a[6]={1,3,5,7,9};
    scanf("%d",&m);
    int i;
    for(i=0;i<6;i++)
    {
        while( m > a[i] )
        {
            for(int j=5;j>i;j--)
           {
                a[j]=a[j-1];
           }
           a[i+1]=m;
           break;
        }
    }

    for(int i=0 ; i<6 ; i++)
    {
        printf("%d ",a[i]);
    }
    return 0;
}

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];
     }
	}

 

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2023-07-12 20:01  风恬月淡时  阅读(59)  评论(0)    收藏  举报