C语言之函数设计(2)

函数的通用性

对于上节课程序中的top函数处理较为复杂的问题,比如计算语数英各个科目的最高分、在分为选修必修、每科人数又不尽相同时,就无法满足上述条件了。

从函数的通用性考虑,至少应该满足下面两个条件:

可以处理任何数组

不仅可以处理数组tensu,而且也可以处理其他任意数组。

可以处理不同元素个数的数组

数组的元素个数不仅只有NUMBER个,还要可以指定数组的元素个数。


让我们用上面的知识来实现接下来程序的运行

数组的传递

#include<stdio.h>

#define NUMBER 5//学生人数

/*返回元素个数为n的数组v中的最大值*/
int max_of(int v[], int n)
	{
		int i;
		int max = v[0];
		
		for(i = 0; i < n; i++)
			if(v[i] > max)
				max = v[i];
		
	return max;
	}

int main()
{
	int i;
	int eng[NUMBER];//英语分数
	int mat[NUMBER];//数学分数
	int max_e, max_m;//最高分
	
	printf("请输入%d名学生的分数。\n", NUMBER);
	
	for(i = 0; i < NUMBER; i++)
	{
		printf("[%d]英语:", i + 1);  scanf("%d", &eng[NUMBER]);
		printf("   数学:");         scanf("%d", &mat[NUMBER]);
	}
	
	max_e = max_of(eng, NUMBER);//英语最高分
	max_m = max_of(mat, NUMBER);//数学最高分
	
	printf("英语最高分=%d\n", max_e);
	printf("数学最高分=%d\n", max_m);

	return 0;
}

函数max_of的作用:找出包含任意个元素的int型数组中元素的最大值,然后返回该值,无需使用tensu或者NUMBER等特定的名称就可以进行说明了。

int max_of(int v[], int n)

进行函数设计时,应尽量提高通用性,比如:

使用上面的函数,它可以是储存英语分数的数组eng,是储存数学分数的数组mat,也可以是储存英语与数学最高分的数组max_e和max_m。

接受数组的形参的声明为“类型名 参数名 [ ]”, 使用别的形参来接受元素个数(这里是int类型的变量n)。

 调用函数时使用的实参只要写声明的数组名称就可以


函数的传递和const类型的修饰符

在学习前面的内容时,我们可以知道被调用函数中作为形参接受到数组,就是函数调用时被作为实参的数组(不能再理解为前面函数学习到的形参是实参拷贝的副本,对形参进行改动而实参不受任何影响),因此对接受到的数组元素进行修改,也会反映到调用时传入的数组中。

我们用程序来演示一下:

/*将数组所有元素的值设置为0*/
#include<stdio.h>

/*把0赋值给n个元素的数组的所要元素*/
void set_zero(int v[], int n)
{
	int i;
	for(i = 0; i < n; i++)
		v[i] = 0;
}
/*显示n个元素的数组v的所有元素并换行*/
void print_array(const int v[], int n)//声明不改变所接受的数组元素的值
{
	int i;
	
	printf("{ ");
	for(i = 0; i < n; i++)
		printf("%d ", v[i]);
	printf("} ");
}
int main()
{
	int arr1[] = {1, 2, 3, 4, 5};
	int arr2[] = {3, 2, 1};
	
	printf("arr1= ");  print_array(arr1, 5); putchar('\n');
	printf("arr2= ");  print_array(arr2, 3); putchar('\n');

	set_zero(arr1, 5);//把0赋值给arr1中的所有元素
	set_zero(arr2, 3);//把0赋值给arr2中的所有元素

	printf("把0赋值给两个数组的所有元素。\n");
	printf("arr1= ");  print_array(arr1, 5); putchar('\n');
	printf("arr2= ");  print_array(arr2, 3); putchar('\n');
}

由于print_array函数的形参v在声明时加上了从const类型修饰符,因此在函数中就不能改写数组v的值了。

v[1] = 5;//错误,不能为const声明的数组元素赋值

如果只是接收数组的元素值而不进行改写的话,在声明接收数组的形参时应该加上const,这样就可以放心调用函数了。


 线性查找(顺序查找)

#include<stdio.h>

#define NUMBER 5//元素个数
#define FAILED -1//查找失败

/*查找元素数为n的数组v中与key一致的元素*/

int search(const int v[], int key, int n)
{
	int i = 0;
	
	while(1)
	{
		if(i == n)
			return FAILED;
		if(v[i] == key)
			return i;
		i++;
	}
}
int main()
{
	int i, ky, idx;
	int vx[NUMBER];
	
	for(i = 0; i < NUMBER; i++)
	{
		printf("vx[%d]:", i);
		scanf("%d", &vx[i]);
	}
	printf("要查找的值:");
	scanf("%d", &ky);
	
	idx = search(vx, ky, NUMBER);//从元素个数为NUMBER的数组vx中查找ky
	
	if(idx == FAILED)
		puts("\a查找失败");
	else
		printf("%d是数组的第%d号元素。\n", ky, idx + 1);
	
	return 0;
}

函数search从元素为n的int型数组v的开头,顺次查找是否存在于key相同的元素,如果有,则返回元素下标,反之返回FAILED。

函数search中的while语句控制的表达式是1,因此只有在执行return语句时才能跳出循环,否则循环将会一直进行下去。

if(i == n)
			return FAILED;
		if(v[i] == key)
			return i;

大家可以看下下面的图:只需要找到相同的元素然后返回下标,如果遍历完数组(i = n)仍未找到就返回FAILED

在满足下面任一条件时,就可以跳出循环:

A.未能找到想要查找的值,最初跳出循环(当i == n成立的时候)

B.找到了想要查找的值(当v[i] == key成立时 )

 像这样从数组开头的元素按照顺序搜索,找出与目标相同元素的一系列操作,称为顺序查找或线性查找


哨兵查找法

进行循环操作的时候,需要不断判断是否满足两个结束循环的条件,虽然操作简单但是当次数积累到一定量时,也是一个不小的负担。

如果数组的大小(元素个数)还有一定的富裕时,我们就可以把想要查找的数值存储到数组末尾的元素v[n]中,这样即使数组中没有想要查找的数值也会满足条件B,条件A也就省略了。

在数组的末尾假的数据称为哨兵,使用哨兵查找的方法称为哨兵查找法,使用此方法可以简化对循环条件的判断。

#include<stdio.h>

#define NUMBER 5//元素个数
#define FAILED -1//查找失败

/*查找元素数为n的数组v中与key一致的元素*/

int search(int v[], int key, int n)
{
	int i = 0;
	
	while(1)
	{
		if(v[i] == key)
			break;
		i++;
	}
	return (i < n) ? i:FAILED;
}
int main()
{
	int i, ky, idx;
	int vx[NUMBER + 1];//多准备一个元素
	
	for(i = 0; i < NUMBER; i++)
	{
		printf("vx[%d]:", i);
		scanf("%d", &vx[i]);
	}
	printf("要查找的值:");
	scanf("%d", &ky);
	
   if((idx = search(vx, ky, NUMBER)) == FAILED)//从元素个数为NUMBER的数组vx中查找ky
		puts("\a查找失败");
	else
		printf("%d是数组的第%d号元素。\n", ky, idx + 1);
	
	return 0;
}

由于函数search需要改变数组v的内容,因此在声明时不能使用const类型的修饰符。

return (i < n) ? i:FAILED;

这个语句是基于条件运算符的判定,具体说就是判断发现元素的值(与key相等的值)是原本就存在数组的元素还是作为哨兵追加的元素。

if((idx = search(vx, ky, NUMBER)) == FAILED)

我们拆开来看,首先是if(),括号里面的表达式也可分为a和b两部分

a部分看做idx = search(vx,ky,NUMBER),使用赋值运算符把函数search的返回值赋值给idx

b部分看做FAILED,使用相等运算符,判断idx = search(vx,ky,NUMBER)FAILED是否相等

到这里我们大概学习了函数的基本知识,到后面我们会学习基本数据类型和数等更加精细的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学海无涯.苦作舟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值