【深入指针理解3】

字符指针变量

 常见写法!!!

int main()
{
	char ch = 'w';
	char *pc = &ch;
	*pc = 'x';
	printf("%c\n", ch);
	return 0;
}

看下面代码!!!

int main()
{
	const char* pstr = "hello world";
	printf("%s\n", pstr);
	printf("%c\n", "hello world"[0]);
	printf("%c\n", pstr[0]);
	return 0;
}

有些代码就写的很奇怪,const char*pstr = “hello world”;这句代码是什么意思?"hello world "这个字符串是怎么存储的,其实是这样的,pstr是指针变量,里面存的是地址,从这个地址开始在字符常量区存放"hello world ",由于在字符常量区的字符串是不可变的,所以在存储同样的字符串时,只会存储一份。
 下面是摘自《剑指offer》的一道面试题!
1
1

int main()
{
	char str1[] = "Hello world";
	char str2[] = "Hello world";
	char* str3 = "Hello world";
	char* str4 = "Hello world";
	if (str1 == str2)
	{
		printf("str1 and str2 are same\n");
	}
	else {
		printf("str1 and str2 are not same\n");
	}
	if (str3 == str4)
	{
		printf("str3 and str4 are same\n");
	}
	else {
		printf("str3 and str4 are not same\n");
	}

	return 0;
}

1
很简单,str1和str2是两个字符数组,在栈区会开辟两块不同的空间,str3和str4是指针,“Hello world”这个字符串会在字符常量区开辟,指针只要指向这块空间就可以!!!

数组指针变量

 这个也很简单,数组指针变量是一个变量,它的类型是数组指针类型,就这么简单,只不过是存数组地址的一个指针变量.

//typedef一下跟能理解这个代码
typedef int( *pArrint)[10]  ;
int main()
{
	int arr[10] = { 1,2,3,4,5,6 };
	int(*pArr1)[10] = &arr;
	pArrint pArr2 = &arr;
	//数组指针变量pArr
	//数组指针类型 int(* )[10];
	return 0;
}

1

二维数组传参

//这儿形参的形式其实也是数组指针变量
//一般就用这种写法,指针的写法不好写坐标
void Print(int arr[][5],int row,int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	printf("\n");
}
int main()
{
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	Print(arr, 3, 5);
	return 0;
}

 把数组指针变量作为形参,来接受一维数组的地址!!!

void Print(int(*pArr)[5], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			//不建议写成这种东西,你怎么看二维数组的坐标?
			//这种写法只是在存储的角度,能让你更好的认识!
			printf("%d ", *((*(pArr + i)) + j));
		}
		printf("\n");
	}
}

int main()
{
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	Print(arr, 3, 5);
	return 0;
}

函数指针变量

 函数指针变量的本质是变量,它是在内存中的一块空间,它的类型是:函数指针类型,用来接受函数的地址,具体接受的是函数的那个地址?我不能理解,通过写代码发现,好像是在代码编译期间,函数的地址已经确定了,好像是代码在转化成汇编代码之后,函数对应的汇编代码的首地址。(我不能确定合适还说不合适?)

 函数指针变量的写法:

void test()
{
	printf("hehe\n");
}

int main()
{
	printf("test:%p\n", test);
	printf("test:%p\n", &test);
	return 0;
}

1
 上面的代码表明函数的名字这个变量里面存的就是函数的地址,&函数名打印出来的也是函数的地址?这儿有疑问?跟数组名一样?总感觉不舒服,你想一下,函数名里面存的是函数的地址,&函数名应该是函数名的地址而不是函数的地址?

函数指针变量的使用

void test()
{
	printf("hehe\n");
}


int main()
{
	//函数指针变量接受函数的地址
	void(*pf)() = test;
	//直接调用
	pf();
	//优先级问题
	(*pf)();
	return 0;
}

1
 下面是chatdpt的结果!!!

1
在这里插入图片描述

关于函数指针变量的两段代码

int main()
{
	//调用0地址处的函数,怎么写?
	//这个我现在还是不理解
	(*(void(*)())0)();
	return 0;
}

1

1
1
1
1
1
 从我的角度解释一下这个代码。其实也没那么复杂!!!
(void (* )())0;这个把0转换成函数指针类型,这儿是什么意思?也就是说把0强转成0地址,(* (void(* )()0)(),然后对0地址解引用操作,也就是通过地址找到相应的函数,进行调用。所以,以后在用函数指针调用函数的时候,一定要加上*。

 这个代码用typedef 简化一下,就更容易理解!!!

typedef void(*Pf)();
int main()
{
	//简化这个代码
	(*(void(*)())0)();
	(*(Pf)0)();
	//把0地址转化成Pf类型,解引用进行调用;
	return 0;
}

 看下面一个跟复杂的代码!!!

int main()
{
	//写一个signal函数的声明
	void(*  signal(int, void(* )(int)) )(int);
	return 0;
}

 void(* signal(int, void(* )(int)) )(int);这个代码很复杂,首先应该明确的是signal是什么?是函数名还是指针?*signal()从优先级的角度来说()的优先级高于 *这就确定了signal是函数名,在看后面给出了形参,进一步验证了这个想法,那么前面就是返回值,可以写成这个形式就更明确了,语法不支持这种写法,但是容易理解。
(void( * )(int)signal (int,void( * )(int));
<返回值+函数名+参数>这个东西typedef 一下更形象!!!

typedef void(*pFun_signal)(int);
int main()
{
   //写一个signal函数的声明
   void(*  signal(int, void(* )(int)) )(int);
   pFun_signal signal(int, pFun_signal);
   return 0;
}

1
1
1

函数指针数组

 所谓的函数指针数组就是把同一类型的函数的地址放到一个数组里面。
定义如下;

typedef int(* pF )(intint );
int main()
{
	//定义函数指针数组
	int(*pfArr[10])(int , int);
	//typedef一下更明确
	pF pfArr[10]; //这样跟正常的数组的定义就一样了!!!
	return;
}
<font face = "楷体" size = 5 color = blue>&emsp;下面是函数指针数组的例子!!!</font>
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("***0.Exit   1.Add    *********\n");
	printf("***2.Sub    3.Mul    *********\n");
	printf("***4.Div             *********\n");
	printf("******************************\n");
}

int main()
{
	int(*pFarr[5])(int x, int y) = { 0,Add,Sub,Mul,Div };
	int Input = 0;
	do {
		Menu();
		printf("请选择:>");
		scanf("%d", &Input);
		if (Input>=1&&Input<=4)
		{
			int x = 0;
			int y = 0;
			printf("请输入两个操作数:>");
			scanf("%d%d", &x, &y);
			int ret =  (*pFarr[Input])(x, y);
			printf("%d\n", ret);
		}
		else if (Input >= 5)
		{
			printf("输入错误,请重新输入!\n");
		}
		else {
			printf("退出系统!!!\n");
			break;
		}
	} while (Input);
	return 0;
}

 利用函数指针的例子!!!可以减少代码的冗余性!!!

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  Calc(int(*pf)(int x, int y))
{
	int x = 0;
	int y = 0;
	printf("1请输入两个操作数:>");
	scanf("%d%d", &x, &y);
	int ret = (*pf)(x, y);
	printf("%d\n", ret);
}
void Menu()
{
	printf("******************************\n");
	printf("***0.Exit   1.Add    *********\n");
	printf("***2.Sub    3.Mul    *********\n");
	printf("***4.Div             *********\n");
	printf("******************************\n");
}

int main()
{
	int Input =0;
	do {
		Menu();
		printf("请选择:>");
		scanf("%d", &Input);
		switch (Input)
		{
		case 0: {
			printf("退出系统!!!\n");
			break;
		}
		case 1: {
			Calc(Add);
			break;
		}
		case 2: {
			Calc(Sub);
			break;
		}
		case 3: {
			Calc(Mul);
			break;
		}
		case 4: {
			Calc(Div);
			break;
		}
		default: {
			printf("输入错误,请重新输入!!!");
		}
		}
	} while (Input);
	return 0;
}

 完结!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值