指针与函数
(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不在数组中!
每次程序运行的结果可能不一样。
指针笔记(中篇)先到这啦!感谢阅读!
觉得有帮助的话不要忘记给个👍哇!