C语言指针plus版

        本篇文章,我们将一起探讨指针高级版

一、指针数组、数组指针

        1.1 指针数组

        就是存放指针的数组,因此指针数组是一个数组,不是指针

        例如:

    int* pa[5];      //整型指针的数组
    char* pb[2];   //字符型指针的数组
    int** pc[3];     //二级整型指针的数组

         1.2 数组指针

        意为指向数组的指针

        例如:

    int(*pa)[5];      //指向整型数组的指针
    char(*pb)[3];   //指向字符型数组的指针

        这里其实就是pa先和“ * ”结合,因为“ [ ] ”他的优先级高于“ * ”

        那么下面这个是数组还是指针?

    int* (*pa)[3];

        一步一步来看,( *pa )是一个指针,这个指针指向一个数组( * pa ) [ 3 ],这个数组的类型为int*

        所以他是一个指向 int* 型数组的指针

        1.3 数组名和&数组名

        上面讲述了指向数组的指针,那么他接收的是什么呢?

        例如:

        以下打码打印出的结果是什么?

int main()
{
	int arr[5] = { 1,2,3,4,5 };
	printf("%p\n", arr);
	printf("%p\n", &arr);
	return 0;
}

        这里可以看出arr和&arr打印的地址都是一样的,那么他两的意思是一样的吗?

int main()
{
	int arr[5] = { 1,2,3,4,5 };
	printf("%p\n", arr + 1);
	printf("%p\n", &arr + 1);
	return 0;
}

        我们打印+1以后的结果来看一下

        这里他俩的结果就不一样了

        原因是arr是数组的首元素的地址,而&arr是整个数组的地址,因此arr + 1跳过4个字节,而&arr + 1跳过的是5 * 4 = 20个字节

二、 函数指针

        2.1 函数指针的定义

        函数指针就是指向函数的指针

        例如:

void test()
{
	int arr[5] = { 1,2,3,4,5 };
	printf("%p\n", arr + 1);
	printf("%p\n", &arr + 1);
}

int main()
{
	void (*pf)() = test;
	(*pf)();
	return 0;
}

        因此可以看出,函数指针的定义为:

void (*pfun1)( );

        2.2 函数指针数组

        就是一个存放了函数指针的数组

        定义为:

    void (*pf[5])( ) = { 0 };

        2.3 函数指针数组的应用

        合理运用函数指针数组可以帮我们简化很多代码,例如计算器的实现:
        

 void menu()
{
	 printf("********************************\n");
	 printf("*****   1.add      2.sub   *****\n");
	 printf("*****   3.mul      4.div   *****\n");
	 printf("*****   0.exit             *****\n");
	 printf("********************************\n");

}

 //加
 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;
 }

int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	do
	{
		menu();
		printf("请输入:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入两个操作数:");
			scanf("%d %d", &x, &y);
			ret = add(x, y);
			printf("%d\n", ret);
			break;
		case 2:
			printf("请输入两个操作数:");
			scanf("%d %d", &x, &y);
			ret = sub(x, y);
			printf("%d\n", ret);
			break;
		case 3:
			printf("请输入两个操作数:");
			scanf("%d %d", &x, &y);
			ret = mul(x, y);
			printf("%d\n", ret);
			break;
		case 4:
			printf("请输入两个操作数:");
			scanf("%d %d", &x, &y);
			ret = div(x, y);
			printf("%d\n", ret);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

        上面这个计算器的代码是不是略显繁琐

        这里我们就可以运用函数指针数组将上面的加减乘除的函数装起来


//函数指针数组
int(*pf[5])(int, int) = { NULL,add,sub, mul,div };
 
int main()
 {
	 int input = 0;
	 int x = 0;
	 int y = 0;
	 int ret = 0;
	 do
	 {
		 menu();
		 printf("请输入:");
		 scanf("%d", &input);
		 if (input >= 1 && input <= 4)
		 {
			 printf("请输入两个操作数:");
			 scanf("%d %d", &x, &y);
			 ret = (*pf[input])(x, y);
			 printf("%d\n", ret);
		 }
		 else if (input == 0)
		 {
			 printf("退出计算器\n");
			 break;
		 }
		 else
		 {
			 printf("输入错误\n");
		 }
	 } while (input);
	 return 0;
 }

        这样代码就简化了很多

三、回调函数

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

        例如上述计算器的函数还可以简化为:

void calc (int(*pf)(int, int))
{
	int x = 0;
	int y = 0;
	int ret = 0;
	printf("请输入两个操作数:");
	scanf("%d %d", &x, &y);
	ret = pf(x, y);
	printf("%d\n", ret);
}

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请输入:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			calc(add);
			break;
		case 2:
			calc(sub);
			break;
		case 3:
			calc(mul);
			break;
		case 4:
			calc(div);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

        这样的代码是不是更简化了

        3.1 回调函数的应用

        回调函数还有个典型的运用例子,qsort( )函数的调用,qsort可以对任何类型的变量进行排序。话不多说,直接上代码

int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1) - (*(int*)e2);
}

int main()
{
	int arr[10] = { 5,2,4,3,6,8,9,7,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr,sz,sizeof(int),cmp_int);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

        也可以自己写一个练习一下

int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1) - (*(int*)e2);
}

void swap(char* e1, char* e2, size_t width)
{
	size_t i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *(e1 + i);
		*(e1 + i) = *(e2 + i);
		*(e2 + i) = tmp;
	}
}

void new_qsort(const void* base, size_t sz, size_t width, int(*pf)(const void*e1, const void*e2))
{
	
	size_t i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		size_t j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (pf((char*)base + j * width,(char*)base + (j + 1) * width) > 0)
			{
				//交换
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

int main()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	new_qsort(arr,sz,sizeof(int),cmp_int);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

       本章内容就到这里, 下一期我们说说常见的指针题型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值