详细讲解:C语言(指针3)

 

目录

​编辑

908ccaa765e34e48bf9be17c397b8a02.png字符指针变量

fb8c0c9e52bf407a97b2fa71151da0c1.png来自剑指offer笔试题

94cdb1eb50e84944a1a7b7b1bc9849b2.png数组指针

091f35cb09c546f7a46fbe729d464a0d.png⼆维数组传参的本质

dd67c738031143ae9e24c40656dd60c1.png函数指针

3246814943c3496fb93dfd2102b0b954.png函数指针创建

d697311ad4884fc28da58a723b24165d.png函数指针的使用

98091cb0810749179c80182b31225900.png两段有趣的代码

0f9542ddf9af4392a509fe0ab399ba4d.pngtypedef关键字

37f6a55764c14a71ae2ba026d8614867.png但是对于数组指针和函数指针稍微有些区别

65c59887e89f43f1a0fed640459c7b9d.png函数指针数组

3e59b30e8144424a8e62242a1e4b23d4.png转移表


字符指针变量

在指针的类型中我们知道有⼀种指针类型为字符指针char*

p指向了a的地址解引⽤拿到了w然后打印

9e86c7ef79d84976b51428bf022e5965.png

62f921f7b16c4b689013e74afdfb7002.png


f57436137df54f41afe30293f7fd03d4.png来自剑指offer笔试题

我们可以看到str1和str2的内容一样但是空间不一样,所以走else。

str3和str4的空间是一样的走if,因为str3和str4的内容是一样的编译器会把str4的空间指向str3的空间,所以空间是一样的

a3d85e90d38347ef846af37c4b36c426.png


63ad337505ea4f1f8aad75d7d8476c4f.png数组指针

数组指针是一个指向数组的指针

数组指针初始化就是取地址给数组指针就可以了

int(*p)[10]

如果不加()的话p会和[10]结合就不是指针了,所以要加()。

下面这代码,int是指向的数组的类型,(*p)说明p是一个指针,[10]是指向的数组有10个元素,&arr是整个数组

ecaa28f995b94b8f82b4a5b16e5053c3.png

356bceaee014495a9bee12b9e0ff52f7.png


5f4dba315853454c941f06969d1bad31.png⼆维数组传参的本质

下面这代码就是把二维数组传参给⼀个add函数,让add来实现打印

⼆维数组传参本质上也是传递了地址,传递的是第⼀
⾏这个⼀维数组的地址。

在二维数组中也可以理解为多个一维数组

175cb388c7da4cd98d4f917974a2e93f.png

那么形参也是可以写成指针形式的

24b6f5f1a7e342e89ee04672a9625a4a.png

ba3d1788622a422794d74193a4f0bafa.png函数指针

函数指针是用来存放函数地址的,未来可以通过地址调用函数

4766f259d4104a6fae5ab897340d5584.png

那么函数是否有地址呢
我们做个测试:

我们可以看到函数是有地址的

06d5d4e9ac054e7ab0059de01739e798.png


59a3c4fe0e774966b4c21ec5438ce228.png函数指针创建

函数指针变量的写法其实和数组指针⾮常类似

105c5d75b49d4fea9a7f2273dd7d40d7.png

1a71617b28894201b698772d980370d7.png

可以写成&arr也可以不写都是等价的

6361825f0469478fb3b5606c0b07800b.png


89c6cd8795294f09b6be70f261fc3f91.png函数指针的使用

这2个打印方式都是可以的p( 5 , 6) 编译器会变成(*p)(5 , 6)

7dd55b665f6f4c2eb2c6d9f84b2973b2.png

fcccc137a484460791e4a8a27e0ec969.png两段有趣的代码

( * ( void  ( * ) ( ) ) 0 ) ( );

这个代码是把0强制类型转换成函数指针,0也是一个函数指针,只不过没有返回值

69d729376bba4f6a92b82162171b59bf.png

void (*signal(int , void(*)(int)))(int); 

void ( * signal ( int  ,  void ( * ) ( int ) ) ) ( int ); 

void(其实这里就是变)(int)

ff95d9bced2946c0b5470463799c3254.png


cf16cd475d664a9e87acd2b2d99b5ec5.pngtypedef关键字

typede是用来类型重命名的,可以将复杂的类型,简单化

我们可以看到下面这个代码,把无符号的整型重命名为u_int

 unsigned int 写起来不⽅便,如果重命名成 u_int 就⽅便多了

9a8dcf352dd84463a636a35b7f8c553c.png


ff90dcefa4f84fa1862482b0893cd04b.png但是对于数组指针和函数指针稍微有些区别

数组指针

我们要将int(*)[10]重命名为arr我们可以写成这样

f2bdcabe152e429db6114990f7852f4a.png

函数指针

我们要将int(*)(int ,int)函数指针重命名为ahh我们可以这样写

5da16e9e93214f8c9154fce0f52a0d7a.png

函数指针数组

我们要将int(*  [10])(int ,int)重命名为att我们可以这样写

cb989f1cd66842dbaeba08c736e71e40.png


a92e513192024545836b40efe7b62c46.png函数指针数组

把函数的地址存放到数组里,那这个数组就叫函数指针数组

我们可以通过下标来访问函数地址并且传参数过去

d6e50095db6a4c659f65c1506b681b64.png

//打印菜单
void day()
{
	printf("***************************\n");
	printf("*** 1.加法      2.减法 ****\n");
	printf("*** 3.乘法      4.除法 ****\n");
	printf("***************************\n");
}
//加法
int add(int x, int y)
{
	return x + y;
}
//减法
int add1(int x, int y)
{
	return x - y;
}
//乘法
int add2(int x, int y)
{
	return x * y;
}
//除法
int add3(int x, int y)
{
	return x / y;
}
int main()
{
	int a = 0;
	int b = 0;
	int f = 0;
	do
	{
		//打印菜单
		day();
		//                          0  1   2    3     4
		int (*arr[5])(int, int) = { 0,add,add1,add2,add3 };
		//用来访问函数指针数组的下标
		scanf("%d", &f);
		printf("请输入2个数值:");
		//用来传参给函数
		scanf("%d %d", &a, &b);
		//          通过下标访问然后传参
		printf("%d\n", arr[f](a, b));
	} while (f);

	return 0;
}

5c6dfba3043e4b3298e51be7faf82f04.png转移表

下面这代码是一个计算器,我们可以发现switch里有很多重复的,

还有当我们需要计算%,&,|,<< , >>这些的话要一个一个添加,我们就会发现代码非常重复很多的printf , scanf

void day()
{
	printf("***************************\n");
	printf("*** 1.加法      2.减法 ****\n");
	printf("*** 3.乘法      4.除法 ****\n");
	printf("***************************\n");
}
//加法
int add(int x,int y)
{
	return x + y;
}
//减法
int add1(int x, int y)
{
	return x - y;
}
//乘法
int add2(int x, int y)
{
	return x * y;
}
//除法
int add3(int x, int y)
{
	return x / y;
}
int main()
{
	int a = 0;
	int b = 0;
	int r = 0;
	do
	{
		day();
		scanf("%d", &a);
		switch (a)
		{case 1:
			printf("请输入2个数值:");
			scanf("%d %d", &a,&b);
			 r = add(a,b);
			printf("%d\n", r);
			break;
		case 2:
			printf("请输入2个数值:");
			scanf("%d %d", &a, &b);
			r = add1(a, b);
			printf("%d\n", r);
			break;
		case 3:
			printf("请输入2个数值:");
			scanf("%d %d", &a, &b);
			r = add2(a, b);
			printf("%d\n", r);
			break;
		case 4:
			printf("请输入2个数值:");
			scanf("%d %d", &a, &b);
			r = add3(a, b);
			printf("%d\n", r);
			break;
		default:
			break;
		}
	} while (a);

}

我们可以使用函数指针数组的形式来访问这些函数

这样就没有那么多重复的内容了

我们要添加%,&,|,<< , >>的话也就只用添加计算函数和函数指针数组里的函数名

//打印菜单
void day()
{
	printf("***************************\n");
	printf("*** 1.加法      2.减法 ****\n");
	printf("*** 3.乘法      4.除法 ****\n");
	printf("***************************\n");
}
//加法
int add(int x, int y)
{
	return x + y;
}
//减法
int add1(int x, int y)
{
	return x - y;
}
//乘法
int add2(int x, int y)
{
	return x * y;
}
//除法
int add3(int x, int y)
{
	return x / y;
}
int main()
{
	int a = 0;
	int b = 0;
	int f = 0;
	do
	{
		//打印菜单
		day();
		//                          0  1   2    3     4
		int (*arr[5])(int, int) = { 0,add,add1,add2,add3 };
		//用来访问函数指针数组的下标
		scanf("%d", &f);
		printf("请输入2个数值:");
		//用来传参给函数
		scanf("%d %d", &a, &b);
		//          通过下标访问然后传参
		printf("%d\n", arr[f](a, b));
	} while (f);

	return 0;
}

还有一种方法就是通过arr函数把要计算的函数传过去,int(*p)(int ,int)函数指针接收地址。

这个函数指针存放着计算函数的地址,我们就可以通过p来把参数传过去

//打印菜单
void day()
{
	printf("***************************\n");
	printf("*** 1.加法      2.减法 ****\n");
	printf("*** 3.乘法      4.除法 ****\n");
	printf("***************************\n");
}
//加法
int add(int x, int y)
{
	return x + y;
}
//减法
int add1(int x, int y)
{
	return x - y;
}
//乘法
int add2(int x, int y)
{
	return x * y;
}
//除法
int add3(int x, int y)
{
	return x / y;
}
int arr(int(*p)(int, int))
{
	int a = 0;
	int b = 0; 
	int r = 0;
	printf("请输入2个数值:");
	scanf("%d %d", &a, &b);
	r = p(a, b);
	printf("%d\n", r);
}
int main()
{
	
	int f = 0;
	do
	{
		day();
		scanf("%d", &f);
		switch ( f)
		{
		case 1:
			arr(add);
			break;
		case 2:
			arr(add1);
			break;
		case 3:
			arr(add2);
			break;
		case 4:
			arr(add);
			break;
		default:
			break;
		}
	} while (f);
}

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值