C语言——深入理解指针(1)

目录

1.内存和地址

[a 内存的理解](#a 内存的理解)

[b 如何理解编址](#b 如何理解编址)

2.指针变量和地址

[a 取地址操作符](#a 取地址操作符)

[b 指针变量](#b 指针变量)

[c 解引用操作符](#c 解引用操作符)

[d 指针变量的大小](#d 指针变量的大小)


1.内存和地址

a 内存的理解

假想这样一个场景,你的朋友找你玩,到了你家小区,如何让她迅速的找到你家呢?当然有很多方法,最直接有效的方法是你告诉她你家在几栋几号,这样就可以通过编号来迅速找到你。此时几栋几号就是你的地址。

当然,计算机CPU在处理数据的时候,需要的数据是在内存中读取的,处理后的数 据也会放回内存中,那么如何高效简洁的管理空间呢?其实也是把内存划分为⼀个个的内存单元,每个内存单元的大小取1个字节。

当然,需要我们了解一下计算机的进制转换,

1字节(byte)= 8比特(bit);++比特是计算机中的最小内存单位++

1KB =1024字节; 1MB=1024KB

1GB = 1024 MB; 1TB=1024GB

b 如何理解编址

CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置,而因为内存中字节很多,所以需要给内存进行编址(就如同宿舍很 多,需要给宿舍编号⼀样)。 计算机中的编址,并不是把每个字节的地址记录下来,而是通过硬件设计完成的。 正如钢琴、吉他上面没有写上"都瑞咪发嗦啦"这样的信息,但演奏者照样能够准确找到每⼀个琴弦的每⼀个位置,这是因为制造商已经在乐器硬件层面上设计好了,并且所有的演奏者都知道。本质是⼀种约定出来的共识!

首先要明白计算机有很多硬件,这些硬件不完全相同,但是要分工协作共同完成工作,那么怎么能实现这个功能呢?那就更简单了,就是用线将它们连接起来。而我们真正需要注意的一个线叫做地址总线,可以这么理解,32位的计算器有32条这样的线,每个线有两种状态,分别是0和1,那么32根线一共能表示2^32种状态,这样的每个状态就是我们的一个地址,他们分别储存在不同的硬件上,地址信息被下达给内存,在内存上,就可以找到该地址对应的数据,将数据在通过数据总线传入CPU内寄存器。

简单的说,内存单元的编号==地址

一句话简明的说,地址就是指针,内存单元的编号 == 地址 == 指针

2.指针变量和地址

a 取地址操作符

在c语言中,我们创建一个变量的实质就是向内存申请一块空间 ,举个例子,我们创建一个变量a

cpp 复制代码
int a = 10;//这个实质是向内存申请4个空间来存放a的数值

就是这个东西,每一个字节有一个编号

那我们如何获取a的地址呢?,这里就要用到取地址符号了&

取地址符号是单目操作符号,我们之前

结合我们常使用的打印数字来说明

cpp 复制代码
#include <stdio.h>
int main()
{
	int a = 10;
	printf("%d", &a);

	return 0;
}

这里这个取地址符号就取出a中较小地址,进行打印处理

我们这里用%p打印处理看看

虽然我们这里是较小的地址,但是是不是可以顺藤摸瓜我们直接获取其他地址啊,其实不同类型的指针的权限是不同的,这里我们后边说

好了,上边的这个&a其实就是一个指针变量,那么我们P=&a的话,这个P就是指针变量

b 指针变量

那我们通过取地址操作符(&)拿到的地址是⼀个数值,比如:0x006FFD70,这个数值有时候也是需要存储起来,方便后期再使用的,那我们把这样的地址值存放在哪里呢?答案是:指针变量中。

那么指针变量我们怎么表示呢?在c语言里用以下表示

cpp 复制代码
int* pa = &a;

如何拆解指针类型?

OK,下面我们来看看这个该怎么写

cpp 复制代码
char ch = 'm';
pc = &ch;//pc的类型怎么写

好滴,聪明的我已经知道了要用char*了,哈哈哈哈

c 解引用操作符

我们将地址保存起来,未来是要使用的,那怎么使用呢? 在现实生活中,我们可以通过仓库编号直接去拿放东西,C语言中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针)指向的对象,这里必须学习⼀个操作符叫解引用操作符(*)。

cpp 复制代码
#include <stdio.h>
int main()
{
	int a = 10;
	
	int* pa = &a;
	*pa = 0;//解引用符号应用
    
    return 0;
}

上述代码中的*pa就是解引用操作符,它的作用是通过pa的地址来找到对应地址的值,所以说*pa其实就是a,我们可以通过打印a,和*pa来进行验证

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	int a = 10;
	
	int* pa = &a;
	*pa = 0;

	printf("a=%d\n", a);
	printf("*pa=%d\n", *pa);

		

	return 0;
}

从而我们得到

其实取地址操作符&和解引用操作符*在一定程度上是互逆的,我们可以这样写

cpp 复制代码
int a = 10;
*&a = 0;

然后我们可以看到结果

到了这里,有些同学会疑惑,既然我们通过了一个指针变量使a变为0,那为何不直接把a赋值为0,而要绕一圈子里?

其实这里就是将a交给pa来处理的,多一种处理方式。举个例子,就是有些大官看不惯一个人,他不好自己出手,就交给自己的小弟出手来解决,这种感觉,随着指针的学习,会越来越理解。

d 指针变量的大小

说来说去,指针就是内存变量,既然是变量,就会有他的大小,要想知道指针变量的大小,我们还要从内存说起。我们已经知道,32内存位计算器有32条地址总线,每条线有1和0两个状态,那么一个内存的编号就有32条地址线表示,一条地址线占一个比特位,那么32条地址线就是32个比特位,因此就是4个字节。同理,64位计算机的话,就是8个字节。我们可以通过sizeof函数来进行验证,验证代码如下

cpp 复制代码
#define _crt_secure_no_warnings
#include <stdio.h>
int main()
{
	printf("%zd\n", sizeof(char*));
	printf("%zd\n", sizeof(short*));
	printf("%zd\n", sizeof(int*));
	printf("%zd\n", sizeof(float*));
	printf("%zd\n", sizeof(long*));


	return 0;
}

我们首先在x86环境里验证

可以发现无论哪个类型的指针变量的大小都是4。

然后我们在x64环境里进行验证

发现每个指针变量的大小都是8个字节。

上边的验证也很好的说明了指针就是内存,32位系统一个内存是4个字节,因而其指针变量大小也是4个字节。64位系统一个内存是8个字节,因而指针变量大小也是8个字节。

相关推荐
江梦寻1 分钟前
思科模拟器路由器配置实验
开发语言·网络·网络协议·学习·计算机网络
代码小鑫2 分钟前
A034-基于Spring Boot的供应商管理系统的设计与实现
java·开发语言·spring boot·后端·spring·毕业设计
奋飞安全16 分钟前
初试js反混淆
开发语言·javascript·ecmascript
guoruijun_2012_416 分钟前
fastadmin多个表crud连表操作步骤
android·java·开发语言
CoderBob17 分钟前
【EmbeddedGUI】脏矩阵设计说明
c语言·单片机
浪里个浪的102419 分钟前
【C语言】计算3x3矩阵每行的最大值并存入第四列
c语言·开发语言·矩阵
@东辰26 分钟前
【golang-技巧】-自定义k8s-operator-by kubebuilder
开发语言·golang·kubernetes
乐悠小码32 分钟前
数据结构------队列(Java语言描述)
java·开发语言·数据结构·链表·队列
史努比.34 分钟前
Pod控制器
java·开发语言
敲敲敲-敲代码43 分钟前
游戏设计:推箱子【easyx图形界面/c语言】
c语言·开发语言·游戏