C语言重点笔记五(中)——指针(指针与函数)

指针与函数

(1)指针作为函数的参数:

下面来演示交换两个整型变量的值:

首先我们来看看失败的案例:

/*交换失败*/
#include <stdio.h>									
void swap(int num1,int num2);						
int main(){
	int num1,num2;
	printf("输入整数num1:");
	scanf("%d",&num1); 
	printf("输入整数num2:");
	scanf("%d",&num2);
	printf("交换前:");
	printf("num1=%d,num2=%d\n",num1,num2);
	swap(&num1,&num2);							/*调用函数:void swap(int x,int y);*/ 
	printf("交换后:");
	printf("num1=%d,num2=%d\n",num1,num2);
	return 0; 
}
void swap(int x,int y){
	int t;
	t=x;
	x=y;
	y=t;
}

 运行结果:

输入整数:num1:2

输入整数:num2:6

交换前:num1=2,num2=6

交换后:num1=2,num2=6

原因:

程序第4~16行是main()函数,第17~22行是swap()函数。
在main()函数中,从键盘上输入的两个整数存放在变量numl和num2中。第12行调用swap()函数,变量num1和num2作为实参传递给swap()函数的形参x和y。
在swap()函数被调用前,numl的值为2,num2的值为6。在swap()函数被调用后,num1的值仍为2,num2的值仍为6,它们的值并未得到交换。
当调用一个带参数的函数时,实参变量的值被传递给形参,无论函数中形参的值如何改变,实参变量的值都不会受到影响。这种函数参数传递方式称为值传递(pass-by-value)。

下面来看正确的程序:

/*交换成功*/ 
#include <stdio.h>										
void swap(int *x,int *y);								
int main(){
	int num1,num2;
	printf("输入整数num1:");
	scanf("%d",&num1); 
	printf("输入整数num2:");
	scanf("%d",&num2);
	printf("交换前:");
	printf("num1=%d,num2=%d\n",num1,num2);
	swap(&num1,&num2);								/*调用void swap(int *x,int *y);*/
	printf("交换后:");
	printf("num1=%d,num2=%d\n",num1,num2);
	return 0; 
}
void swap(int *x,int *y){
	int t;
	t=*x;
	*x=*y;
	*y=t;
}

 运行结果:

输入整数:num1:2

输入整数:num2:6

交换前:num1=2,num2=6

交换后:num1=6,num2=2

解释:

程序第4~16行是main ( )函数,第17~22行是swap )函数。

在main ()函数中,从键盘上输入的两个整数存放在变量num1和num2中。

第12行调用swap()函数,swap ()函数有两个指针参数,必须使用取地址运算符“&”将实参变量的地址传递给swap函数,因此变量num1和num2地址( & num1和& num2 )作为实参传递给swap( )函数的形参x和y,这样形参x和y中分别存放了变量num1和num2的地址,形参x指向变量num1所在的内存单元,形参y指向变量num2所在的内存单元。
在swap()函数中,必须使用解引用运算符“*”来访问形参x和y所指向的内存单元中的值,也就是*x和变量num1代表同一内存单元,只要在函数中改变了*x的值,就改变了变量num1的值,*y的情况相同。
在swap()函数被调用前,num1的值为2,num2的为6,在swap()函数被调用后,num2的值为2,它们的值得到了交换。
当调用一个带指针参数的函数时,实参变量的地址被传递给形参,形参和实参共享相同的变量,函数中形参的值改变了,实参变量的值也会受到影响。这种函数参数传递方式称为引用传递(pass-by-reference)或共享传递(pass-by-sharing)。

(2)指针作为函数的返回值:
指针即可以作为函数的参数,也可以作为函数的返回值,当函数的返回值为指针时,该函数称为指针型函数。指针型函数通常用来获取指针所指向的对象的值。

指针型函数的一般形式如下:

函数类型 *函数名(形式参数表);

括号运算符()的优先级高于指针运算符" * ",函数名先与后面的()结合,表明这是一个函数。

函数名之前的" * ",表明函数返回值是一个指针。

演示求两个整数的最大值:

/*求两个整数的最大值*/
#include <stdio.h>
int *max(int *x,int *y);
int main(){
	int num1,num2;
	int *result ;
	printf("输入整数num1:");
	scanf("%d",&num1);
	printf("输入整数num2:");
	scanf("%d",&num2);
	result=max(&num1,&num2);								//调用max()函数,将num1和num的地址作为实参传递给max()函数的形参 x 和 y; 
	printf("%d和%d的最大数是%d\n",num1,num2,*result);
	return 0;
} 															//x和y分别存放了实参num1和num2的地址,所有形参*x和实参num1指向同一储存单元,形参y情况相同 
int *max(int *x,int *y){							//*x和*y分别是num1和num2的别名 
	if(*x>*y)
		return x;
	else
		return y;
	
}

运行结果:

输入整数num1:5

输入整数num2:2

5和2的最大数是:5

程序第4~14行是main()函数。第15~20行是max()函数。
程序第11行调用max()函数,将变量num1和num2的地址作为实参传递给max()函数的形参x和y,这样形参x和y中分别存放了实参num1和num2的地址,形参x指向实参 num1所在的存储单元,形参y指向实参num2所在的存储单元,也就是形参*x和实参num1代表同一存储单元,形参*y的情况相同。
在max()函数中,*x是numl的别名,*y是num2的别名,如果numl的值大于num2的值,返回num1的地址,否则返回num2的地址。调用max()函数后,指针 result可以指向变量num1,也可以指向变量num2。
程序第12行通过对指针result使用解引用运算符“*”输出最大数5。
这里需要特别注意的是,不能把一个指向局部变量的指针作为指针型函数的返回值。因为在函数内部声明的局部变量是非持久的,当函数调用结束后,局部变量生命期结束,这时局部变量的内存地址是无意义的,不要试图访问指向这样地址的指针。

上面的程序看起来很简单,但是最重要的是理解其中指针的用法。

(3)指向函数的指针:

如果通过函数名单元函数,那么每次执行时调用的总是同一个函数;如果通过函数指针调用函数,执行中调用的是哪个函数,就要看指针当时指向哪个函数。显然采用函数指针的方法带来了灵活性。

①演示使用函数指针调用函数:

/*使用函数指针调用函数*/
#include <stdio.h>
int sum(int,int);
int difference(int,int);
int product(int,int);
int main(){
	int num1,num2,result;
	int (*fp) (int,int);			//声明函数指针 
	printf("输入整数num1:");
	scanf("%d",&num1);
	printf("输入整数num2:");
	scanf("%d",&num2);
	fp=sum;							//函数指针指向sum()函数 
	result=fp(num1,num2);			//通过函数指针调用sum() 函数,将两整数的和保存在变量return中 
	printf("%d+%d=%d\n",num1,num2,result);
	fp=difference;						//同上 
	result=fp(num1,num2);
	printf("%d-%d=%d\n",num1,num2,result);
	fp=product;							//同上 
	result=fp(num1,num2);
	printf("%d*%d=%d\n",num1,num2,result);
	return 0;
} 
int sum(int x,int y){
	return x+y;
}
int difference(int x,int y){
	return x-y;
}
int product(int x,int y){
	return x*y; 
}

运行结果:

输入整数:num1:10

输入整数:num2:5

10+5=15

10-5=5

10*5=50

        程序第6~23行是main()函数。第24~26行是sum()函数,求两个整数的和。第27~29行是
difference()函数,求两个整数的差。第30~32行是product函数,求两个整数的积。
        在main()函数中,第8行声明了函数指针;第13行使函数指针指向sum()函数,第14行通过函数指针调用sum()函数,将两个整数的和保存在变量result中;第16行使函数指针指向difference()函数,第17行通过函数指针调用difference()函数,将两个整数的差保存在变量result中;第19行使函数指针指向product()函数,第20行通过函数指针调用product()函数,将两个整数的积保存在变量result中。

函数指针更重要的用途是作为函数参数,从而实现函数回调。函数回调,就是在某个函数中,至少有一个参数为函数指针,在函数体中通过该函数指针调用另一个函数。回调函数就是一个通过函数指针调用的函数。

②演示使用函数指针回调函数:

#include <stdio.h>
int sum(int,int);
int difference(int,int);
int product(int,int);
int any_function(int (*fp) (int,int),int ,int );
int main(){
	int num1,num2,result;
	int (*fp) (int,int);
	printf("输入整数num1:");
	scanf("%d",&num1);
	printf("输入整数num2:");
	scanf("%d",&num2);
	result=any_function(sum,num1,num2);				//相当于result=sum(num1,num2) ,在括号中实现了fp=sum,即通过函数指针回调sum()函数 
	printf("%d+%d=%d\n",num1,num2,result);
	result=any_function(difference,num1,num2);
	printf("%d-%d=%d\n",num1,num2,result);
	result=any_function(product,num1,num2);
	printf("%d*%d=%d\n",num1,num2,result);
	return 0; 
} 
int sum(int x,int y){
	return x+y;
}
int difference(int x,int y){
	return x-y;
}
int product(int x,int y){
	return x*y;
}
int any_function(int (*fp) (int,int),int x,int y){
	return fp(x,y);
}

运行结果:

输入整数:10

输入整数:5

10+5=15

10-5=5

10*5=50

程序第30~32行是any_function()函数,第一个参数是函数指针形参,它所指向的函数有两个整型参数并返回整型值;第二和第三个参数都是整型形参,传递给函数指针所指向的函数。
在main()函数中,第13行将sum函数作为实参传递给any_function()函数的函数指针形参,第31行通过函数指针回调sum()函数,返回两个整数的和;第15行将difference()函数作为实参传递给any_function()函数的函数指针形参,第31行通过函数指针回调difference()函数,返回两个整数的差;第17行将product()函数作为实参传递给any_function()函数的函数指针形参,第31行通过函数指针回调product()函数,返回两个整数的积。

(4)qsort()函数和bsearch()函数

快速排序(quick sort)是目前公认的一种比较好的排序算法,由C.A.R.Hoare在1962年提出。C语言提供了一个基于快速排序算法的标准库qsort()。可以对任意数组进行排序。为了使用qsort()函数,必须包含stdlib.h头文件。

演示qsort()函数:

//comp()函数 :比较函数 
//eg.升序:	int comp(const void *p,const void *q){
//			return (*(int *)p - *(int *)q);
//	}
//   降序: int comp(const void *p,const void *q){
//			return (*(int *)q - *(int *)p);
//				比较函数有两个参数,它们是通用指针,分别指向两个需要比较的数组元素。比较函数返回一个整数。 
//				如果第一个参数指向的数组元素大于第二个参数指向的数组元素,返回正整数 ;
//				如果第一个参数指向的数组元素等于第二个参数指向的数组元素,返回0 ;
//				如果第一个参数指向的数组元素小于第二个参数指向的数组元素,返回负整数 。 
//qsort()函数 :对数组进行升序 (需要用到比较函数) 
//eg.	void qsory(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
//				第一个参数base指向需要排序的起始地址(一般情况下即数组名),第二个参数nmemb指定数组元素个数,第三个参数size指定数组元素大小(以字节为单位),
//				第四个参数compar是函数指针,指向一个比较函数,一般情况下,compar就是比较函数名。qsort()函数没有返回值。 
//printfArray():打印数组元素 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int comp(const void *p, const void *q);
void printfArray(int list[],int arraySize);
int main(){
	const int ARRAY_SIZE = 10;
	int i,array[ARRAY_SIZE];
	srand(time(NULL));
	for(i=0;i<ARRAY_SIZE;++i)
		array[i] = rand() % 100;		//生成随机数 
	printf("排序前:");
	printfArray(array,ARRAY_SIZE);
	qsort(array,ARRAY_SIZE,sizeof(int),comp);			//升序:使用qsoet()函数和comp()函数 
	//qsort(array(需要排序的数组名); ARRAY_SIZE(数组array的元素个数); sizeof(int)(数组array的元素大小); comp(比较函数名)) 
	printf("排序后:");
	printfArray(array,ARRAY_SIZE);
	return 0;
} 
int comp(const void *p,const void *q){
	return (*(int *)p-*(int *)q);
	//const表示不能修改参数值
	//void *p表示通用指针
	//(double *p) 强制转换成该数据类型 
}
//比较函数的参数p和q是通用指针,数组array是整型数组,不能通过通用指针直接访问数组array的元素,必须通过强制类型转换为整型指针 (int *)p和(int *)q ;
//然后通过解引用运算符 “* ”获取p和q所指向的数组元素值  *(int *)p和*(int *)q。 
void printfArray(int list[],int arraySize){
	int i;
	for(i=0;i<arraySize-1; ++i)
		printf("%d ",list[i]);
		printf("%d\n",list[arraySize-1]);
}

运行结果:

排序前:21 82 76 96 4 12 21 8 98 19

排序后:4 8 12 19 21 21 76 82 96 98

结合上面的注释进行理解。

在C语言中,也提供了一个基于二分查找算法的标准库函数bsearch()函数,可以对任意有序数组进行查找。为了使用bsearch()函数,必须包含stdlib.h头文件。

演示bsearch()函数:


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int comp(const void *p,const void *q);
void printArray(int list[],int arraySize);
int main(){
	const int ARRAY_SIZE=10;
	int i,key,array[ARRAY_SIZE];
	int *pItem;
	srand(time(NULL));
	for(i=0;i<ARRAY_SIZE;++i)
		array[i]=rand()%100;								//产生随机整数并存放在数组中 
	qsort(array,ARRAY_SIZE,sizeof(int),comp);
	printf("已排序的数组:");
	printArray(array,ARRAY_SIZE);
	printf("输入需要查找的值:");
	scanf("%d",&key);
	pItem=(int *)bsearch(&key,array,ARRAY_SIZE,sizeof(int),comp);
	//					(key(指向需要查找的关键字地址);array(指向需要查找的有序数组的起始地址,即数组名);nmemb(指定有序数组元素个数);
	//					size(指定有序数组元素大小(以字节为单位);compar(函数指针,指向一个比较函数(比较1函数名))
	//		bsearch()函数返回值是一个指针。如果查找到元素,返回指向该元素的指针,否则返回空指针NULL。 
	//调bsearch()函数在数组array中查找变量key的值;
	
	if(pItem)
		printf("查找成功:%d在数组中!",key);
	else
		printf("查找失败:%d不在数组中!",key);
	return 0;
}
int comp(const void *p,const void *q){
	return (*(int *)p-*(int *)q);
}
void printArray(int list[],int arraySize){
	int i;
	for(i=0;i<arraySize-1;++i)
	printf("%d ",list[i]);
	printf("%d\n",list[arraySize-1]);
}

运行结果:

已排序的数组:8 9 36 41 51 67 69 76 93 99

输入需要查找的值:51

查找过程:51在数组中!

已排序的数组:13 30 38 39 39 45 48 76 88 99

输入需要查找的值:55

查找失败:55不在数组中!

每次程序运行的结果可能不一样。

指针笔记(中篇)先到这啦!感谢阅读!

觉得有帮助的话不要忘记给个👍哇!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

تچ快乐杂货店يچ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值