咱们直接进入主题,先看名字,根据对应名称的后两位进行初步理解
函数指针,强调这是一个指针;指针数组,强调这是一个数组;
指针函数,强调是一个函数;数组指针,强调是一个指针。
是不是很绕口?接下来,咱们就详细解释其中的内涵,各个指针之间的不同
函数指针
根据咱们之前对于指针的了解,指针是一串内存地址,指向的内容可以是常量的地址,也可以是变量的地址。那我们思考,能不能指向一个函数的地址呢?
函数在内存中也有自己的存储位置,这个存储位置就是函数的入口地址。就像变量有内存地址一样,函数也有。
函数指针定义
函数指针是一种特殊的指针,它存储的是函数的入口地址。通过函数指针,可以调用它所指向的函数。
#include<stdio.h>
int main ()
{
void (*p)();//定义一个函数指针,无返回值,无参数值,没有进行初始化,只是定义
return 0;
}
详细的格式是: 返回类型(*指针变量名)(形式参数类型)
指针类型名 = 指向的函数 //指向函数的初始化
变量名 = (*指针变量名)(实际参数)//对函数返回值赋值
返回类型:是指函数执行完后,给函数指针返回的值的对应类型,要与函数中返回值的类型相同。
形式参数类型:要与函数中,定义的形式参数类型相同。
因此,对于函数指针的定义,只需要复制对应函数的格式,进行修改即可
#include<stdio.h>
void sum()
{
printf("hello_world");
}
int main ()
{
void (*p)();//函数指针的定义,格式与函数格式相似
p = sum;//指针的指向
return 0;
}
对于有参数,有返回值的类型,可以选择新定义一个变量,将返回值赋值;也可以直接将表达式输出。
#include<stdio.h>
int sum(int num)
{
int num2;
num2 = ++num;
return num2;
}
int main ()
{
int a;
int num1 = 100;
int (*p)(int num);//函数指针的定义
p = sum;//指针的指向
a = (*p)(num1);//传入实际参数
printf("%d\n",a);
printf("%d\n",(*p)(num1));//直接输出表达式
return 0;
}
对于函数指针使用的好处:可以根据输入值的不同,而对指针指向的函数进行调整,指向不同的函数,实现不同的操作。
示例:
下面这个例子:根据输入值的不同,返回不同值:1--返回大数;2--返回小数;3--返回两数之和;其他--返回错误
获取大数,小数,两数之和的函数中,使用三目运算符进行判断
#include<stdio.h>
int getMin(int data1,int data2)//返回小数
{
return data1<data2?data1:data2;
}
int getMax(int data1,int data2)//返回大数
{
return data1>data2?data1:data2;
}
int getSum(int data1,int data2)//返回两数之和
{
return data1+data2;
}
int getAns(int data1,int data2,int (*p)(int data1,int data2))//回调函数雏形
{
int ans;
ans = (*p)(data1,data2);//函数指针的调用
return ans;
}
int main ()
{
int num1 = 10;
int num2 = 20;
int cmd;
printf("请输入1(最大值),2(最小值),3(两数之和)\n");
scanf("%d",&cmd);//接受键盘输入的值
//定义一个函数指针
int (*p)(int data1,int data2);
int end_ans;//最后返回的结果
switch(cmd){//根据输入的值,决定指针指向的函数
case 1:
p = getMax;
break;
case 2:
p = getMin;
break;
case 3:
p = getSum;
break;
default://输入之外结果,返回错误
printf("error");
break;
}
end_ans = getAns(num1,num2,p);//获取结果函数, //对于实际参数的传入
printf("%d\n",ans);
return 0;
}
指针函数
接下来,解释指针函数。根据字面含义,代表的是函数。
用户自定义一个函数,函数的返回值可以是整型,实型,字符型等,同时也可以返回指针型数据,也就是地址。
指针函数定义
#include<stdio.h>
int a(int x,int y)
{
pass;
}
在这段代码中,定义了一个名叫'a'的函数,返回值是整型数据
#include<stdio.h>
int *a(int x,int y)
{
pass;
}
在这段代码中,唯一不同的是,a前面有了 * 号。
所以,如果我们根据符号的优先级进行理解:
()的优先级高于*,所以 a 先与()结合,显然是函数形式。再与*结合,表明此函数是指针型函数。最前面的 int,表明返回的指针指向整型变量。
这一段代码是对指针函数的简单使用。
#include<stdio.h>
int *sum(int num)//定义一个指针函数
{
int * p2;
p2 = #//指针指向num地址
num++;
return p2;//返回值是内存地址
}
int main ()
{
int *p;
int a = 100;
p = &a;//指针p指向a的地址
p = sum(a);
printf("%d",*p);
return 0;
}
示例:获取两个整数值,函数封装的形式比较两个值的大小,并且输出较大的那个值
#include<stdio.h>
int* getMax(int num1, int num2) {
int* result;//定义一个指针
if (num1 > num2) {
result = &num1;
} else {
result = &num2;
}
return result;//返回指针的内存地址
}
int main ()
{
int num1,num2;
int *p;
puts("输入两个整数值:");
scanf("%d%d",&num1,&num2);
p = getMax(num1,num2);//p接收函数返回的地址
printf("其中最大值是%d",*p);//*,取值运算符获取p指向的地址的对应值
return 0;
}
数组指针
我们还是先根据字面含义,数组指针,意味着是指针。
详细阐述,就是一个指针,指向的是一个数组。常用于对二维数组中元素的指向。
我们都知道,在二维数组中,每一个元素都是一个一维数组。所以我们可以用数组指针完成对其中的元素的指向。
数组指针的定义
#include<stdio.h>
int main ()
{
int arr[3][4] = {0};//定义一个3行4列的二维数组
int (*p)[4] = arr;//定义一个数组指针,指向二维数组
int (*p2)[4] = &(arr[0]);//定义一个数组指针,指向二维数组的首地址
return 0;
}
基本格式:
元素类型 (* 指针变量名)[数组长度]
元素类型要与指向的数组中的元素类型相同。
数组长度要与指向的数组长度相同。
初始化:
对于二维数组,数组名代表该二维数组的首地址,同时,二维数组的第一个元素的地址,也代表该二维数组的首地址。所以,我们可以直接用数组指针指向二维数组的数组名,或者二维数组的第一个元素地址。
以下这段代码,就是对数组指针的简单应用:应用数组指针输出二维数组中的值
#include<stdio.h>
int main ()
{
int arr[3][4] = {{1,2,3,4},
{5,6,7,8},
{9,10,11,12},};//定义一个3行4列的二维数组
int (*p)[4] = arr;//定义一个数组指针,指向二维数组
for(int i;i<3;i++){
for(int j = 0;j<4;j++){
printf("%d\t",*(*(p)+j));//输出一维数组中的元素
}
printf("\n");
p++;//指针的偏移
}
return 0;
}
解释:根据数组的知识,数组中的元素的内存地址都是连续的,所以我们可以利用这一点,使指针进行偏移,实现对于数组的遍历。
第一次for循环,实现对于一维数组的遍历(也就是二维数组中的元素),i<3,因为二维数组中一共有3个元素。
第二层for循环,是对每一个一维数组中的元素进行遍历:j<4,因为在每一个一维数组中,都只有4个元素。
对*(*(p)+j)解释:
*(p)表示是对p解引用,获取到一维数组的首地址,也是一维数组中第一个元素的地址。
*(p)+j :是对一维数组中元素的遍历,随着j的递增,指针指向下一位。
*(*(p)+j) : 根据一维数组的元素的地址,对一维数组中的元素进行取值。
p++:
当输出二维数组的第一个一维数组后,对p向后偏移,指向第二个元素,也就是二维数组中第二个一维数组。
案例:有一个3行4列的二维数组,代表3个学生,每个学生有四门考试成绩,要求输入学生编号,输出该学生的考试成绩
#include<stdio.h>
int * getposperson(int num,int(*p)[4])//形参:编号,数组指针
{
int *pos;
pos = (int*)(p+num);//,对数组指针进行偏移,指向下一个数组
return pos;//返回子数组的地址
}
int main ()
{
int a[3][4] = {
{77,88,99,66},
{54,67,12,77},
{99,78,12,88}};//定义一个二维数组
int num = 0;
int ans ;
//printf("请输入你要查看的学生编号(0,1,2):");
//scanf("%d",&num);
int *ppos;//定义一个指针
for(int j;j<3;j++){
ppos = getposperson(j,a);//指针接受 指针函数 返回的地址
for(int i = 0;i<4;i++){
if((*(ppos))<60){
printf("第%d位学生,第%d门课程不合格,成绩是:%d\n",j+1,i+1,(*ppos));
}
ppos++;
}
}
指针数组
顾名思义,代表的是一个数组
详细的说,就是一个数组,其中存放的元素都是指针,这些指针可以指向不同的对象或数组元素。
对于指针数组的定义
元素指针类型 * 数组名称 [数组长度]、= 初始化内容;
#include<stdio.h>
int main ()
{
int a,b,c;
int *p [3]={&a,&b,&c};
return 0;
}
元素指针类型要和指向的元素的数据类型相同。
数组长度与存放的指针个数相同。
初始化内容存放获取的地址。
对于指针数组的简单应用
#include<stdio.h>
int main ()
{
int a = 10;
int b = 20;
int c = 30;
int *p [3]={&a,&b,&c};
for(int i = 0;i<3;i++){
printf("%d\n",*(p[i]));//遍历出a,b,c的值
}
return 0;
}
函数指针数组:即指针数组中存放的地址都是函数
每一个函数的名,都代表该函数的内存地址
所以,我们可以将函数地址存放到数组中,根据键盘输入的值不同,使p指向不同的函数,实现不同的功能
示例:
#include<stdio.h>
int getMin(int data1,int data2)//返回小数
{
return data1<data2?data1:data2;
}
int getMax(int data1,int data2)//返回大数
{
return data1>data2?data1:data2;
}
int getSum(int data1,int data2)//返回两数之和
{
return data1+data2;
}
int getAns(int data1,int data2,int (*p)(int data1,int data2))//回调函数雏形
{
int ans;
ans = (*p)(data1,data2);//函数指针的调用
return ans;
}
int main ()
{
int a = 10;
int b = 20;
int cmd = 0;
/*
printf("请输入1(最大值),2(最小值),3(两数之和)\n");
scanf("%d",&cmd);*/
//定义一个函数指针数组
int (*p[3])(int ,int)={getMin,getMax,getSum};//定义一个函数指针数组-----指针数组:数组中每一个元素都是一个指针
for(int i = 0;i<3;i++){
cmd = (*p[i])(a,b);//函数指针数组的调用
printf("cmd = %d\n",cmd);
}
return 0;
}
相较于文章开头使用函数指针,要简洁很多。
OK,对于这四类的区别,解释完毕,大家还有什么疑惑,评论区讨论或者私信。希望大家在以后的C语言学习生涯中,更上一层楼!!!!

被折叠的 条评论
为什么被折叠?



