50-1 指针是什么
内存空间如何管理?
答:切割成内存单元,每一个单元是1byte(字节)。
为了迅速定位到内存单元,对内存单元进行编号。内存单元的编号称为地址(地址也叫指针);
指针其实就是地址;
地址就是编号;
指针就是内存单元的编号。
指针理解的2个要点:
1、指针是内存中一个最小单元的编号,也就是地址
2、平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
总结1:指针就是地址,口语中说的指针通常指的是指针变量。
int main()
{
int a = 10; //a是整型变量,占用4个字节的内存空间
int* pa = &a;
//pa是一个指针变量,用来存放地址
//我们经常口语化地说pa是一个指针,其实就是指针变量,指针变量就是一个变量,用来存放地址
//指针变量里边存的是地址,而通过这个地址,就可以找到一个内存单元
//本质上指针就是地址
return 0;
}
我们可以通过&(取地址操作符)取出变量的内存起始地址,把地址可以存放到一个变量中,这变量
就是指针变量
int main()
{
int a = 10; //在内存中开辟一块空间
int* pa = &a;
//这里我们对变量a,取出它的地址,可以使用&操作符
//a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量中,p就是一个指针变量
return 0;
}
指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
那这里的问题是:
一个小的单元到底是多大?
如何编址?
经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。
对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0);
那么32根地址线产生的地址就会是:
00000000000000000000000000000000
00000000000000000000000000000001
......
11111111111111111111111111111111
这里就有2的32次方个地址。
每个地址标识一个字节,那我们就可以给(2^32Byte == 2^32/1024KB ==2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB)4G的空闲进行编址。
同样的方法,那64位机器,如果给64根地址线,能编址(2^64Byte == 2^64/1024KB ==2^64/1024/1024MB==2^64/1024/1024/1024GB == 2^34GB)2^34G的空间。
在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节(32/8)。
那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节(64/8),才能存放一个地址。
总结3:
指针变量是用来存放地址的,地址是唯一标示—块地址空间的。
指针的大小在32位平台是4个字节,在64位平台是8个字节。(X86是32位的环境,X64是64位的环境)
以X64为例:
代码:
int main()
{
char* pc = NULL;
short* ps = NULL;
int* pi = NULL;
double* pd = NULL;
//
printf("%zu\n", sizeof(pc));
printf("%zu\n", sizeof(ps));
printf("%zu\n", sizeof(pi));
printf("%zu\n", sizeof(pd));
return 0;
}
结果:
50-2 指针和指针类型
指针类型的意义
代码1 查看存储的数据
int main()
{
int a = 0x11223344;
return 0;
}
在调试-窗口-内存中,查看&a
可查看到存的是11223344(从右往左看)
代码2 解引用改变值
int main()
{
int a = 0x11223344;
int* pa = &a;
*pa = 0;
return 0;
}
原本存放11223344:
地址相同:
现在存放:00000000
代码3 强制类型转换
int main()
{
int a = 0x11223344;
char* pa = (char*) & a;
return 0;
}
调试:
char*依然可以存放整型,因为对于指针变量来说,大家都是4byte。
但是你会发现,解引用后结果是00332211,而int*解引用后是44332211。
结论1
这就说明了虽然指针变量都是4byte,但依然要存在不同类型的指针变量。不同指针变量解引用效果不同,如上述char*解引用只有1个字节解引用,而int*有四个字节解引用
代码4 指针+/-1的效果
int main()
{
int a = 0x11223344;
int* pa = (int*)&a;
char* pc = (char*)&a;
printf("%p\n", pa);
printf("%p\n", pa+1);
printf("%p\n", pc);
printf("%p\n", pc+1);
return 0;
}
结果:
结论2:
指针的类型决定了指针+-1操作的时候,跳过几个字节 ,决定了指针的步长
代码5.1
int main()
{
int a = 0x11223344;
int* pi = (int*)&a;
float* pf = (char*)&a;
*pi = 100;
return 0;
}
调试:
&a,为0x64,即100
代码5.2 int*与float*
int main()
{
int a = 0x11223344;
int* pi = (int*)&a;
float* pf = (char*)&a;
*pf = 100;
return 0;
}
调试:
结果发生变化
结论3
虽然pi解引用访问4个字节,pi+1跳过4个字节;pf解引用访问4个字节,pi+1跳过4个字节
但是int*与float*同样不能通用,因为浮点数和整数在内存中存储的方式是不同的,存的数据也完全
不同
以上内容主要是要表明指针类型的作用,每一个指针类型都有存在的重要意义。