指针的深入理解1

1.如何理解指针

假设有一栋宿舍楼,把你放在楼里,楼上有100个房间,但是房间没有编号,你的一个朋友来找你玩,
如果想找到你,就得挨个房子去找,这样效率很低,但是我们如果根据楼层和楼层的房间的情况,给每个房间编上号,如:
⼀楼:101,102,103...
⼆楼:201,202,203....

有了房间号,如果你的朋友得到房间号,就可以快速的找房间,找到你。

生活中,每个房间有了房间号,就能提高效率,能快速的找到房间。
如果把上面的例子对照到计算中,又是怎么样呢?
我们知道计算上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,那我们买电脑的时候,电脑上内存是8GB/16GB/32GB等,那这些内存空间如何高效的管理呢?
其实也是把内存划分为一个个的内存单元,每个内存单元的大小取1个字节。

生活中我们把门牌号也叫地址,在计算机中我们
把内存单元的编号也称为地址。C语言中给地址起
了新的名字叫:指针。
所以我们可以理解为:内存单元的编号==地址==指针

2. 指针变量和地址

       其实在c语言中,创建一个变量就是向内存申请空间。

指针的深入理解1_第1张图片

我们可以看到int a的每个字节都有一个地址。 

那我们怎样拿到它的地址并打印呢?那我们就要用到&取地址操作符和*解引用操作符。

int main()
{
	int a = 15;
	int* pt = &a;
	printf("%d", *pt);
	return 0;
}

在上述代码中我们用&a操作拿到了地址,那么int *pt是啥呢?

其实int *pt 表示整型指针,pt为指针变量。在这里*告诉我们pt是指针,去掉名字就是类型,在这里int *就是指针类型。*pt就是通过地址找到a,在这里*pt=a;所以我们将其打印出来。

我们也可以将a的地址打印出来。

int main()
{
	int a = 15;
	int* pt = &a;
	printf("%d\n", *pt);
	printf("%p", pt);
	return 0;
}

 结果为:

指针的深入理解1_第2张图片

我们在一开始看到a的每一个字节都有地址,在这里其实我们取地址操作只是拿到了第一个字节的地址,但是它们在内存中是连续存放的,所以我们通过*解引用操作符就可以找到其他字节。

3.指针变量的大小 

前面的内容我们了解到,32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后是1或者0,那我们把32根地址线产生的2进制序列当做一个地址,那么一个地址就是32个bit位,需要4个字节才能存储。如果指针变量是用来存放地址的,那么指针变的大小就得是4个字节的空间才可以。同理64位机器,假设有64根地址线,一个地址就是64个二进制位组成的二进制序列,存储起来就需要8个字节的空间,指针变的大小就是8个字节。

我们来看一下代码演示:

#include
int main()
{
	printf("%zd\n", sizeof(char*));
	printf("%zd\n", sizeof(short*));
	printf("%zd\n", sizeof(int*));
	printf("%zd\n", sizeof(double*));
	return 0;
}

分别用x86和x64的环境运行:

x86:

指针的深入理解1_第3张图片

x64:

指针的深入理解1_第4张图片 

结论:
• 32位平台下地址是32个bit位,指针变量大小是4个字节。
• 64位平台下地址是64个bit位,指针变量大小是8个字节。
• 注意指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的。 

4.指针变量类型的意义

指针变量的大小和类型无关,只要是指针变量,在同一个平台下,大小都是一样的,为什么还要有各种各样的指针类型呢?

我们来观察一个例子:

#include 
int main()
{
int n = 0x11223344;
int *pi = &n;
*pi = 0;
return 0;
}

这是代码1.运行结果是:

指针的深入理解1_第5张图片

指针的深入理解1_第6张图片 

int  n中的所有字节都变为0.

我们再来看看代码2:

#include 
int main()
{
	int n = 0x11223344;
	char* pc = (char*)&n;
	*pc = 0;
	return 0;
}

 运行结果:

指针的深入理解1_第7张图片

指针的深入理解1_第8张图片 

代码2中只改变了一个字节。

对比我们可以得出一个结论:指针的类型决定了,对指针解引用的时候有多大的权限(一次能操作几个字节)。例如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。 

当我们使用指针加减时,如int *pt;pt+1其实就是跳过一个整型,char *pt;pt+1其实就是跳过一个字节。

5.void*指针

在指针类型中有一种特殊的类型是 void* 类型的,可以理解为无具体类型的指针(或者叫泛型指
针),这种类型的指针可以用来接受任意类型地址。但是也有局限性,void* 类型的指针不能直接进行指针的+-整数和解引用的运算。

我们来看一串代码:

#include 
int main()
{
	int a = 10;
	int* pa = &a;
	char* pc = &a;
	return 0;
}

如果我们写出这样的代码,编译器就会报警告

指针的深入理解1_第9张图片

如果要避免这种警告,在不同类型的指针赋值时进行强制类型转换即可。其实我们在使用void*的指针也不会出现这种问题。viod*的指针可以接收任意类型的指针。void*的指针无法直接进行指针运算,这个我们后期会讲的。

谢谢

 

你可能感兴趣的:(c语言,开发语言)