指针的深度剖析及理解。

    上次我们说过指针就是地址,还有它的一些基本知识如:指针类型,指针运算,指针表达式解析,而今天我们该开始深度解析一下这个指针了。今天主要研究的是指针,数组以及函数之间的联合运用。虽然指针与数组有很多运用的地方相似,但是我们必须知道指针和数组不一样,是不同的类型。

1.首先看看指针数组:它其实是一个存放指针的数组。如:

int *arr1[10];
char *arr2[4];
char **arr3[5];

这三个都是指针数组,但是他们存放的指针类型不同,一个是int*,一个是char*,最后一个是char**。

2.数组指针:它是一个指向数组类型的指针。

数组指针的定义:int (*p)[10];//p先和*结合,说明p是一个指针变量,然后指针指向的是一个大小为10个整形数组的数组。所以p是一个指针,指向一个数组。同时我们要注意:[]的优先级要高于*,所以必须加上()先和*结合。

int arr[10]={0};
arr;//表示数组首元素的地址。
&arr;//表示数组的地址。
printf("%p\n",arr);
printf("%p\n",arr+1);
printf("%p\n",&arr+1);

结果是:

007DF864
007DF868
007DF88C

arr+1表示数组第二个元素的地址,所以+1表示加(int)4。&arr+1表示下一个数组的地址,相当于加上40.

数组的地址应该如何存储:

int arr[10]={0};
int *p1=&arr;
int (*p2)[10]=&arr;

p2更适合,因为它是数组指针,而且此时p2后面的[]里必须与定义的数组一样,否则会报错。

举例:将一个二维数组传参:

#include<stdio.h>
#include<Windows.h>
void print1(int arr[3][5])
{}
void print2(int arr[][5])
{}
void print3(int **arr)
{}
void print4(int (*arr)[5])
{}
int main()
{int arr[3][5]={0};
print1(arr);//OK
print2(arr);//OK
print3(arr);//NO.实参与形参类型不兼容
print4(arr);//OK
system("pause");
return 0;}

二维数组在传参时需要降维成指向其类型的一级指针。同时数组名后的[][],前一个可以忽略不填,但是后一个必须填写与定义一样的,否则会报错。

3.函数指针:它是一个指向函数的指针。函数的地址保存:

void test()
{
	printf("hehe\n");
}
void(*pfun1)();//函数指针,可以用来存放函数的地址。
void*pfun2();//函数的声明。
首先要能存地址就必须是指针,所以pfun1可以,它先与* 结合是个指针,指向的函数无参数,返回值类型为void。再看两个有趣的代码:
(*(void(*))0)();//表示调用函数。

void(*signal(int,void(*)(int)))(int);//函数的定义,参数是int和void(*)(int),返回值类型是void*(int).
4.函数指针数组:它是一个存放着函数地址的数组。它的定义:

int (*parr1[10])();

函数指针数组的应用:转移表(计算器例题):

(1)普通方法。
#include<stdio.h>
#include<Windows.h>
int add(int a,int b)
{
	return a+b;
}
int sub(int a,int b)
{
	return a-b;
}
int mul(int a,int b)
{
	return a*b;
}
int chu(int a,int b)
{
	return a/b;
}
void menu()
{
	printf("++++++++++++++++++++++++++++++++++++++++++++++\n");
	printf("++++++   Welcome to my cultilate        ++++++\n");
	printf("++++++    1.add              2.sub      ++++++\n");
	printf("++++++    3.mul              4.chu      ++++++\n");
	printf("++++++++++++++++++++++++++++++++++++++++++++++\n");
	printf("Please select: \n");
}
int main()
{
	int select=0;
	int x,y;
	int ret=0;
	while(1)
	{
		menu();
		scanf("%d",&select);
		switch(select)
		{
		case 1:
			printf("Please input the data: \n");
			scanf("%d %d",&x,&y);
			ret=add(x,y);
			break;
		case 2:
			printf("Please input the data: \n");
			scanf("%d %d",&x,&y);
			ret=sub(x,y);
			break;
		case 3:
			printf("Please input the data: \n");
			scanf("%d %d",&x,&y);
			ret=mul(x,y);
			break;
		case 4:
			printf("Please input the data: \n");
			scanf("%d %d",&x,&y);
			ret=chu(x,y);
			break;
		default:
			printf("Input error!\n");
			break;
		
		}
		printf("%d\n",ret);
	}
	system("pause");
	return 0;
}
(2)转移表。
#include<stdio.h>
#include<Windows.h>
#pragma warning(diszble:4996)
int add(int a,int b)
{
	return a+b;
}
int sub(int a,int b)
{
	return a-b;
}
int mul(int a,int b)
{
	return a*b;
}
int chu(int a,int b)
{
	return a/b;
}
void menu()
{
	printf("++++++++++++++++++++++++++++++++++++++++++++++\n");
	printf("++++++   Welcome to my cultilate        ++++++\n");
	printf("++++++    1.add              2.sub      ++++++\n");
	printf("++++++    3.mul              4.chu      ++++++\n");
	printf("++++++++++++++++++++++++++++++++++++++++++++++\n");
	printf("Please select: \n");
}
int main()
{
	int select=1;
	int x,y;
	int ret=0;
	int (*p[5])(int x,int y)={0,add,sub,mul,chu};
	while(select)
	{
		menu();
		scanf("%d",&select);
		if((select<=4&&select>=1))
		{
			printf("Please inut the data; \n");
			scanf("%d %d",&x,&y);
			ret=(*p[select])(x,y);
		}
		else{
			printf("input error\n");
		}
		printf("%d\n",ret);
	}
	system("pause");
	return 0;
}
这两种方法一看就知道第二种简单便利许多,这就是定义函数指针数组的好处。

5.指向函数指针数组的指针:首先它是一个指针,指针指向一个数组,数组的元素都是函数指针。定义:
void (*(*ppfunArr)[10])(const char*)=&pfunArr;//指向函数指针数组pfunArr的指针ppfunArr。

6.回调函数:是一个通过函数指针调用的函数。如果你把函数的指针作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。它不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于该事件或条件进行响应。

qsort应用:

#include<stdio.h>
#include<Windows.h>
int my_com(void *x,void *y)
{
	int *a=(int *)x;
	int *b=(int *)y;
	if(*a<*b)
	{
		return -1;
	}
	else if(*a>*b)
	{
		return 1;
	}
	else{
		return 0;
	}

}
int main()
{
	int i=0;
	int a[]={1,33,56,4,2,8,0,54,3,23};
	int len=sizeof(a)/sizeof(a[0]);
	qsort(a,len,sizeof(int),my_com);
	for(i=0;i<len;i++)
	{
		printf("%d ",a[i]);
	}
	system("pause");
	return 0;
}
(2)自己编写的qsort
#include<stdio.h>
#include<Windows.h>
int int_com(void *x,void *y)
{
	int *a=(int *)x;
	int *b=(int *)y;
	if(*a>*b)
	{
		return 1;
	}else if(*a<*b)
	{
		return -1;
	}
	else{
		return 0;
	}
}
void my_swaq(char *x,char *y,int size)
{
	while(size--)
	{
		*x^=*y;
		*y^=*x;
		*x^=*y;
		x++;y++;
	}
}
int my_qsort(void *a,int len,int size,int(*com)(void *,void *))
{
	int i=0;
	int flag=0;
	for(;i<len-1;i++)
	{int j=0;
	for(;j<len-1-i;j++)
	{
		if(com((char *)a+j*size,(char *)a+(j+1)*size)>0)
		{
			my_swaq((char *)a+j*size,(char *)a+(j+1)*size,size);
			flag=1;
		}
	}
	if(flag==0)
	{
		break;
	}
	}
}
int main()
{
	int i=0;
	int a[]={1,33,56,4,2,8,0,54,3,23};
	int len=sizeof(a)/sizeof(a[0]);
	my_qsort(a,len,sizeof(int),int_com);
	for(i=0;i<len;i++)
	{
		printf("%d ",a[i]);
	}
	system("pause");
	return 0;
}
以上差不多就是指针的深度剖析内容了,说难不难,说简单也不简单,希望大家能够好好学习这一块,这对我们以后的学习很重要。











 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值