一句话说清C语言中函数指针,指针函数,数组指针,指针数组

        咱们直接进入主题,先看名字,根据对应名称的后两位进行初步理解

函数指针,强调这是一个指针;指针数组,强调这是一个数组;

指针函数,强调是一个函数;数组指针,强调是一个指针。

        是不是很绕口?接下来,咱们就详细解释其中的内涵,各个指针之间的不同

  函数指针

        根据咱们之前对于指针的了解,指针是一串内存地址,指向的内容可以是常量的地址,也可以是变量的地址。那我们思考,能不能指向一个函数的地址呢?

     函数在内存中也有自己的存储位置,这个存储位置就是函数的入口地址。就像变量有内存地址一样,函数也有。

函数指针定义

        函数指针是一种特殊的指针,它存储的是函数的入口地址。通过函数指针,可以调用它所指向的函数。

#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地址
	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语言学习生涯中,更上一层楼!!!!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值