C语言“指针”的保姆级理解

有很多人被指针应当如何理解给难住了,其实单说理解指针,并不多难

我将尽可能简略但易懂地解释指针,希望对你有所帮助

I.理解C语言中的存储

C语言中,最小的单位是bit(比特),它用来储存0或1。

因为电极有正负两极,所以以0、1为主体的二进制就成为不二之选。

而8个比特位就是一个字节(1 byte)。

一个字节(数字为示意)
00101000

当我们说将数据存到一个地方时

其实它所存的地方都有一个编号,用来表示这数据存在哪

一串串的数据储存起来

就跟一栋楼一样一层层的

我们说的电脑32位,就是说电脑的地址线有32根

再加上二进制

说明内存能存的数据组成数量有2^{^{32}}

64位同理

II.地址

如上所述,每一个数据都有它的地址

这个地址要用来查找数据在哪

这样以后你要用到数据时

直接通过地址来调取数据就好了

int main()
{
	int a = 10;
	&a;//按F10,在调试、窗口、监视里可以找到&a的地址
	//a在此处的地址是0x0000000000000004。为什么有0x呢?这是十六进制的标志。
	return 0;
}

这一串代码是在干什么?

int是在向内存申请一块空间用来存放a的数据

而&就是告知地址

按住F10

在逐步找到监视之后

你可以清楚地发现a的地址&a是多少

在这里a的地址是0x0000000000000004

0x是表明后面的数字是以16进制的形式出现的

0000000000000004这一串就是告知a的数据储存在哪里

储存的地方就是一个叫0000000000000004的地方

相信你也知道地址是怎么回事了

那这和指针有什么关系呢?

III.指针的实质

数据是需要一个地址来指向它的

这样计算机就知道怎么调用这个数据了

但问题是我们人要获取这个地址还是麻烦些的

于是就想到可 以用一个“盒子”来储存这个地址

以后程序员只要找到“盒子”

就也可以反向推出地址,进而推到数据

这个“盒子”就是指针

你也可以理解成它是地址的地址

那它是如何工作的?

#include <stdio.h>
int main()
{
	int a = 0;
	int* p = &a;//*是声明变量是指针,用指针来储存a变量的地址
	*p = 20;//这里的*相当于侦探,照着地址反向追踪。其表达的是指针p所指的对象是多少,这里也就是将a改为了20。
	printf("%d\n", a);
	return 0;
}

我们可以看到

我们先用int为a申请了一个空间,并将a初始化为0

紧接着我们将a的地址,也就是&a

存储到了指针p里面

而int*则是表明后面的p是个指针,而不是普通的变量名称

由此,我们创立了个指针p

它储存了&a

而下一行的*p则是表示指针p所指向的对象

由于指针p存的是&a

自然我们顺着地址回去找到的对象就是a

*p = 20;其实就变身为了a = 20;

因此最后输出的结果就是20,而不是0

IV.由地址找数据

指针类型也是有大小的

看看这一段代码:

#include <stdio.h>
//int main()
//{
//	printf("%zu\n", sizeof(char*));//%zu是专门打印sizeof的结果的。
//	printf("%zu\n", sizeof(short*));
//	printf("%zu\n", sizeof(int*));
//	printf("%zu\n", sizeof(long*));//在64位系统上,指针变量都是8字节;32位系统上,指针变量都是4字节。
//	return 0;
//}

最后输出的结果要么都是4,要么都是8,这是为什么?

还记得前面的a的地址吗?

0x0000000000000004

我们再来审视一下它

0x是16进制的标识

我们就把它先去掉不记

剩下的就是0000000000000004

那为什么是这样?

int main()
{
	int a = 10;
	&a;//按F10,在调试、窗口、监视里可以找到&a的地址
	//a在此处的地址是0x0000000000000004。为什么有0x呢?这是十六进制的标志。
	return 0;
}

这就要回到这个代码

让我们想想int占4个字节

我们存储自然就是32个bit位

0000 0000 0000 0000 0000 0000 0000 0000

我们的a的值是10

那么按照二进制,就是1010

储存在这64位中就会改变成

0000 0000 0000 0000 0000 0000 0000 1010

那二进制要转成十六进制呢?十六进制是0~9、a、b、c、d、e

不用10、11之类的是因为10其实和之前的0、1重合了

所以用a、b......来代替

那转成十六进制,自然就是

0 0 0 0 0 0 0 a

也就是00 00 00 0a

那这是什么东西呢?

自然就是我们储存的数据

这好像和0x0000000000000004没有关系

因为0x0000000000000004是个假地址!

是的,由于程序没有真正运行,所以它的地址是虚假的

要获得一个真地址怎么办?

#include <stdio.h>
int main()
{
	int a = 0;
	a = 10;
	printf("%p\n", &a);//打印地址用%p,而且一定是&a而不是a,因为&才告诉地址。
	return 0;
}

在printf那行设置断点再调试

用鼠标点击该行左侧的灰色边栏(行号旁边),会出现一个红色圆点,表示断点已设置。

断点之后调试

得到了真实地址0x000000FC00BFF914

再将真实地址输入到内存窗口

选择列为4

你发现地址后面跟着的就是0a 00 00 00

眼不眼熟?

是的,这就我们推理出来的00 00 00 0a倒序的样子

倒序是因为在内存中存储是小端序(低字节在前)

也就是说这段0a 00 00 00

就是我们储存的a = 10

这也就是数据

我们至此通过地址找到了原本储存的数据

这下你知道为什么需要一个指针了吧?

因为指针的本质也相当于一个地址

只不过这个地址是由我们来设的

我们通过设置指针的名字(比如p)

再将变量的地址存到p里面

这样,我们就可以通过调用指针p

来完成这一系列的由地址找数据

只不过这些过程我们不需要再看到了

我们只需要在代码里调用p

余下的留给计算机去做。

如果你学过结构体和函数

那你应该可以看懂这段代码

#include <stdio.h>
struct Lee
{
	float height;
	char sex[10];
	float  weight;
	int tele;
};
void print(struct Lee* ps)
{
	printf("%f\n %s\n %f\n %d\n", (*ps).height, (*ps).sex, (*ps).weight, (*ps).weight);//这里的(*ps).可以替换成ps->。
}
int main()
{
	struct Lee s = { 178,"male",80.1,14596238451 };
	print(&s);
	return 0;
}

在这里,我们就把结构体s的值赋予到指针ps里面了

从而完成数据的调用

这就是指针的作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值