指针的进阶(各种指针类型以及数组与指针传参)(分析两段有趣的代码)

字符指针

写法1

char a = 'w';
char*p = &a;

*代表p为指针,char代表指针指向的内容类型是char类型
写法2


#include <stdio.h>
int main()
{
    
    
	char arr[] = "abcdef";
	char* p1 = arr;
	*p1 = 'w';
	

	char* p2 = "abcdef";
	*p2 = 'w';
	return 0;
}

在这里插入图片描述
仔细观察写法二,我们把字符串放入p2中实际上是将字符串的首元素地址放入p2中,而这样写代表着字符串是一个常量字符串,不能被修改,若想修改要将它放入数组中来修改

指针数组

指针数组是一个存放指针的数组
例如
int a = 10;
int b = 20;
int* arr[] = { &a,&b };
arr[] 放入的就是两个一级指针
利用指针数组实现类似的二维数组

int main()
{
    
    
	int arr1[] = {
    
     1,2,3,4,5 };
	int arr2[] = {
    
     2,3,4,5,6 };
	int arr3[] = {
    
     3,4,5,6,7 };
	int* arr[] = {
    
     arr1,arr2,arr3 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
    
    
		int j = 0;
		for (j = 0; j < 5; j++)
		{
    
    
			printf("%d ", *(arr[i] + j));
		}
		printf("\n");
	}
	return 0;
}

数组指针

数组指针是指向数组的指针
例1

int arr[10] = {
    
     1,2,3,4,5 };
	int(*p)[10] = &arr;
	//但一般很少会这样写

二维数组传参

void print(int(*p)[5], int a, int b)
{
    
    
	int i = 0;
	for (i = 0; i < 2; i++)
	{
    
    
		int j = 0;
		for (j = 0; j < 5; j++)
		{
    
    
			printf("%d ", *(*(p+i)+j));
		}
		printf("\n");
	}
}
int main()
{
    
    
	int arr[2][5] = {
    
     0,1,2,3,4,5,6,7,8,9 };
	print(arr, 2, 5);
}

void print(int(*p)[5], int a, int b)
{
    
    
	int i = 0;
	for (i = 0; i < 2; i++)
	{
    
    
		int j = 0;
		for (j = 0; j < 5; j++)
		{
    
    
			printf("%d", p[i][j]);
		}
		printf("\n");
	}
}
int main()
{
    
    
	int arr[2][5] = {
    
     0,1,2,3,4,5,6,7,8,9 };
	print(arr, 2, 5);
}

二维数组的数组名是首元素的地址
二维数组的首元素是第一行
即二维数组数组名是第一行的地址
既然是第一行的地址,而二维数组可以看作是一行一行的一维数组累加在一起,那么可以把第一行的地址看作是一个一维数组的地址,那么传入数组的地址,我们就要拿一个数组指针接收

至于* (* (p+i)+j),假设把二维数组的第一行看作一维数组arr,那么二维数组名即为&arr, p即 * &arr,得到arr, (arr+j)即访问第一行的每一元素,(p+i)即(&arr+i),也就是跳过一行

那么判断一下**int( * arr[10])[5]**是什么
由于优先级的原因,arr先与[10]结合,说明arr是一个数组,我们除去arr[10]那么剩下的就是数组元素类型,所以数组元素类型为int(*)[5], 代表是一个指针,从往外看,看到[],说明指针指向的内容是数组,数组的元素是int类型,并且元素个数为5,我们不难看出,它是一个数组指针,即arr是一个可以存放10数组指针的数组

一级指针传参

#include <stdio.h>
void print(int *p, int sz)
{
    
    
int i = 0;
for(i=0; i<sz; i++)
{
    
    
printf("%d\n", *(p+i));
}
}
int main()
{
    
    
int arr[10] = {
    
    1,2,3,4,5,6,7,8,9};
int *p = arr;
int sz = sizeof(arr)/sizeof(arr[0]);
//一级指针p,传给函数
print(p, sz);
return 0;
}

一级指针传参用一级指针接收,因为一级指针传过去的是arr,所以用一个一级指针接收,除此之外,若有一个整形数组,传数组名,也可以用一级指针接收

二级指针传参

二级指针传参用二级指针接收,除此之外,若有一个一级指针数组数组名,也可用用二级指针接收

函数指针

int Add(int x, int y)
{
    
    
	return x + y;
}
int main()
{
    
    
	int a = 10;
	int b = 20;
	int (*p)(int, int) = Add;
	//int ret = (*p)(a, b);
	int ret = p(a, b);
	printf("%d", ret);
	return 0;
}

Add就是函数的地址,&Add与Add是一回事
(*p)代表p为指针,往外看,看到(),说明指针指向的内容一个函数,函数的参数类型(int,int),函数的返回值int,所以p为一个函数指针
当我们想用Add()时,只需要 *p 就找到了Add,之后再加上要传入的实参,就可以使用函数了,Add(a,b)
,其实p里存放的是Add,那么就可以把p看作Add,所以不用 加 *也可以,只不过为了方便理解,加上了 *

有趣的代码

代码1
( * (void ( * )())0)()
从0下手,0前边的(void ( * )()仔细看的话,可以看出它是一个函数指针,只是这个函数没有参数,返回类型是void,在(void (
)()的基础上又加一个(),意思就是将0强制类型转换为(void (
)()类型,那么0就是一个函数指针,在0这个地址处存放着一个函数,这个函数返回类型是void,无参数, (void (* )())0前面又有一个* ,解引用这个函数指针,即调用这个函数,调用这个函数,函数无参数,直接在(* (void (* )())0)基础上加()
代码2
void ( * signal(int , void( * )(int)))(int)
由于优先级的原因,signal先与()结合,说明signal是一个函数,函数的参数是(int , void( * )(int)),有了函数名,又有了函数参数,现在缺一个返回类型,void ( * signal(int , void( * )(int)))(int),去掉函数名,与函数参数,即为返回类型,void( * )(int),返回类型是一个函数指针,参数是int,返回类型是void

函数指针数组

**void(*p)(int)**是一个函数指针,在它的基础上给p后面加上[],p先与[]结合形成数组,即void( * p[5])(int),除去数组名与[5]即数组元素类型,可以看出元素类型为函数指针

指向函数指针数组的指针

在函数指针数组void( * p[5])(int)基础上,改为void ( * (*p)[5]) (int)

函数指针数组的应用

int Add(int x, int y)
{
    
    
	return x + y;
}
int Sub(int x, int y)
{
    
    
	return x - y;
}
int Mul(int x, int y)
{
    
    
	return x * y;
}
int Div(int x, int y)
{
    
    
	return x / y;
}
void menu()
{
    
    

	printf("****************************\n");
	printf("*****1.乘法***2.除法*********\n");
	printf("*****3.加法***4.减法*********\n");
	printf("*****0.退出*****************\n");

}

int main()
{
    
    
	int a = 20;
	int b = 10;
	int(*arr[5])(int, int) = {
    
     0,Mul,Div,Add,Sub };
	int input = 0;
	do
	{
    
    

		menu();
		scanf("%d", &input);
		if (input == 0)
		{
    
    
			printf("退出计算机\n");
		}
		else if (input >= 1 && input <= 4)
		{
    
    
			printf("请输入两个值");
			scanf("%d %d", &a, &b);
			int ret = arr[input](a, b);
			printf("%d\n", ret);
		}
		else
			printf("输入错误\n");
	} while (input);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wan__xia/article/details/129213606
今日推荐