指针的进阶

指针的进阶(各类指针的使用和进阶)

指针(地址的由来):32位机器拥有32根物理的地址线(电线),每一根电线都会释放电信号,我们将电信号转化为0,1(正负电)的数字用来存储,这样我们就得到了32位二进制数字组成的二进制序列,将不同的数据用不同的二进制序列存储起来就得到了其对应的位置,我们将这个位置称为地址.(64位机器同理)

一.字符指针

所有的特殊指针或者特殊数组,都只看结尾的两个字来理解本质如:字符指针的本质就是指针只是指向的位置是字符.
字符指针通常用来记录字符或字符串某个位置的地址例如:

int main()
{
 char str1[] = "hello c.";
 char str2[] = "hello c.";
 const char *str3 = "hello c.";
 const char *str4 = "hello c.";
 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;
}

这道例题的结果是:str1和str2 not same. str3和str4 same
是因为数组在初始化时就会为其分配一定大小的空间,它们的地址并不相同所以它们只是存储了相同的内容.但是str3和str4是同时指向了hello中h的地址,为了节省空间所以它们的地址是一样的.(在C语言中并没有规定明确可不可以这样写但是大部分编译器都默认为可以这样操作)
其中str3和str4只指向了h的地址它们并没有将整个字符串存储下来因为它们的大小不够,所以当使用字符指针去指向字符串时,指针指向的是其首元素地址和数组有些类似.

二.数组指针

多用于遍历二维数组
数组指针的本质仍然是指针,只是指向的位置是数组。
其写法:

int main()
{
	int arr[] = {1,2,3,,4,5};
	int (*p) [] = arr;
	return 0;
}

由于[]的优先级会高于* 所以在写的时候我们要将(*p)括起来以确保它是一个指针,如果不写就是p[]先结合的结果为:一个存放int * 类型元素的数组称为指针数组。

三.指针数组

其本质是数组:一种存放的元素类型为指针的数组

int main()
{
	int *arr[] = {1,2,3,,4,5};
	int *p [] = arr;
	return 0;
}

这里的arr里存放的都是整形指针,而p就指向了这个整形指针数组中的首元素地址.可以通过p去访问到arr数组中的元素,适用于当不能直接使用数组时却需要使用到数组的内容用指针数组.

四.数组和指针的传参

在进行传参前我们需要了解数组名,数组名首元素地址和&数组名之间的关系:
通常来讲数组名就是数组首元素的地址但有两个例外:
1.当sizeof中只写了sizeof(数组名)时此时的数组名代表整个数组进行判断大小
2.当&数组名的时候我们取出的视为整个数组的地址

在写代码时我们通常会使用到函数,那我们就要考虑其的参数,及返回值类型,
当一个函数的形参写的是一个一级指针时我们可以传参的参数形式可以是:
数组名,一级指针
当一个形参是由二级指针构成时,我们的实参可以为:
数组指针,二级指针,二维数组

五.函数指针

其本质还是指针不过是指向了函数的地址。
数组,整形,浮点型,结构体等都有地址那么函数也不例外:我们对函数进行取地址再输出观察

这里可以看出函数也有其自己的地址,我们继续来观察其函数的函数名和函数之间的关系
在这里插入图片描述
所以我们发现了,函数和函数名的地址是一样的它不同于数组和数组名
其函数指针的写法是:

int add (int x,int y)
{
	return x+y;
}
int main()
{
	int x = 0;
	int y = 2;
	add(x,y);//代表是一个加法函数,将x,y传参过去
	int (*p)(int ,int) = add;
	printf("%d\n",p(3,5))//可以观察到确实得到了数字8也就说明确实可以用p来调用函数
	return 0;
}

它的指针名称是p 写法不是 int(*)(int ,int) p ,而是int (*p)(int ,int)这是语法

六.函数指针数组

本质仍然是数组:一种存放的数据类型为函数指针的数组
其写法为: int (* p[])(int ,int)
p先与[]结合代表其是一个数组其存放的数据类型是 int(*)(int ,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 div1(int x, int y)
{
	return x / y;
}

void menu()//菜单函数
{
	printf("*****1.add 2.sub*****\n");
	printf("*****3.mul 4.div*****\n");
	printf("*****  0.exit*****\n");
}

int main()
{
	//制作一个简易的整形计算器
	int input = 0;
	menu();
	printf("请选择您需要的方法:\n");
	do 
	{
		scanf_s("%d", &input);
		if (input != 0)
		{
			int (*p[])(int, int) = { NULL,add,sub,mul,div1 };
			printf("请选择两个操作数:\n");
			int x = 0;
			int y = 0;
			scanf_s("%d %d", &x, &y);
			printf("%d\n", p[input](x, y));
			Sleep(500);
			menu();
			printf("请选择您需要的方法:\n");
		}
	}while (input);
	return 0;
}

其中int (*p[])(int, int) = { NULL,add,sub,mul,div1 };因为数组的下标是从0开始的所以我们选择用NULL空指针去占一个位置用来让其与菜单menu保持一致。
我们可以发现由于p是函数指针数组所以当我们使用的时候就不必先以前一样一直使用switch中的case语句一句一句的判断然后使用函数,我们只用完成函数之后在数组中当作新的元素个数加入就好,节省了很大的空间也便利了不少。

七.指向函数指针数组的指针

其本质还是指针,不过是指向函数指针数组的指针
写法:int (*(*p)[]) (int ,int)此后就可以开始套娃了,可以再写一个数组存放的是指向函数指针数组的指针…
这些指针和数组的使用玩法看不同的场景

八.回调函数

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

qsort函数的使用

用冒泡排序模拟实现qsort()函数

qsort和用冒泡排序模拟实现qsort函数在这篇博客中

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老幺*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值