内存

谈内存之前,首先了解一下C++的类型在不同编译中的所占字节:

1.字节和字长

字节,八位就是一个字节,是固定概念。字长是指计算机一次能处理的二进制数据的长度,是一个非固定的概念。例如,8位计算机的字长为8bit,即一个字节, 32位计算机的字长位32bit,即4个字节,同理,64位计算机的字长为64bit,即8字节。

2.char类型始终是一个字节,即8bit。

3.int、short int和long int

通常int占4个字节,short占2个字节,long占4个字节或8个字节(在32位机器中为4个字节)。

4.浮点型float、双精度double、和长双精度long double

典型情况下,float 为4个字节,double是8个字节,long double为12个字节或16个字节

C/C++仅仅定义了这些基本数据类型之间的关系,并没有定义严格定义它们的字长。

在不同的平台上,根据编译器不同的实现,它们的字长如下表所示:

数据类型

LP64

ILP64

LLP64

ILP32

LP32

char

8

8

8

8

8

short

16

16

16

16

16

_int32

N/A

32

N/A

N/A

N/A

int

32

64

32

32

16

long

64

64

32

32

32

long long

N/A

N/A

64

N/A

N/A

pointer

64

64

64

32

32

在这张表中,LP64,ILP64,LLP64是64位平台上的字长模型,ILP32和LP32是32位平台上的字长模型。

LP64意思是long和pointer是64位,

ILP64指 int,long,pointer是64位,

LLP指long long和pointer是32-bit的。

ILP32指int,long和pointer是32位的,

LP32指long和pointer是32位的。

32位Windows采用的是ILP32数据模型,64位Windows采用的是LLP64数据模型。

所以,Windows上的32位程序设计和64位程序设计最大的不同(也就是ILP32和LLP64的不同),就在于指针的长度不同??由32位变成了64位。

Win32 API在很多情况下,都需要将整数转换成指针或者相反。在 32 位的硬件上不会有问题,其中指针的大小和整数的大小是相同的,但在 64 位的硬件上却完全不一样。



1.变量在内存中


测试用例:

#include <iostream>
using namespace std;

int main(void)
{
	/*栈空间*/
	int a = 1;
	int b = 2;

	int n1[2] = {1,2};
	int n2[2][2] = {1,2,3,4};

	int *a1 = &a;
	int *n = n1;

	/*堆空间*/
	int *n3 = new int[];
	int *n4 = new int[2];

	return 0;
}


各变量在内存中的地址:



(1) 由内存列表可以看出: 

变量在内存中从高地址向低地址生长,说明存储在栈中

(2) 由红色标志的地址可以看出:

数组本身就是一个地址,所以数组名与取地址的数组名所表示的地址是相同的

(3) 由绿色方框中的地址可以看出:

内存地址是从低地址向高地址生长,说明用new申请的内存是在堆中.


变量及其申请的空间在内存中的具体存储:



每个变量后都有8字节的cc作为间隔.


2.指针在内存中

指针的大小用sizeof可以获取.

指针的大小跟编译器有关,

例如:

用VS2013中的32位编译器编译指针,sizeof(指针)=4

用VS2013中的64位编译器编译指针,sizeof(指针)=8



vs2013编译器调整:




3.复杂指针


复杂指针阅读准则:

①阅读变量时:

右左法则”是一个简单的法则,但能让你准确理解所有的声明。这个法则运用如下:从最内部的括号开始阅读声明,向右看,然后向左看。当你碰到一个括号时就调转阅读的方向。括号内的所有内容都分析完毕就跳出括号的范围。这样继续,直到整个声明都被分析完毕。
 
对上述“右左法则”做一个小小的修正:当你第一次开始阅读声明的时候,你必须从变量名开始,而不是从最内部的括号。



②阅读函数指针时:

右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。

        笔者要对这个法则进行一个小小的修正,应该是从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。





在上述程序中添加如下指针:

        /*指针*/
	//数组指针(本质上是一个指针,而且是一个指向数组的指针)
	int (*n5)[2]=n2; 
	//n5 = n2;
	//n5 = &n1;
	
	//指针数组(本质上是一个数组,里面存放的都是指针)
	int *n6[2];    //int *(n6[2])  //[]的优先级比*高
	n6[0] = n1;
	n6[1] = &a;


内存分布: (由于重新编译程序,内存重新分配,所以地址与上面有所不同,这里不想再重新做图了,偷懒了,知道具体分布就ok了)

 

由此验证指针数组与数组指针的区别.

数组指针:本质上是一个指针,而且是一个指向数组的指针

指针数组:本质上是一个数组,里面存放的都是指针


数组指针:

int (*a)[2]

[2] 用来控制申请内存的长度为2.

(*a)用来控制标识内存的地址,且没有限制.

总结: 相当于限制了申请内存的长度,地址的个数没限制



指针数组:

int *p[4] 相当于int *(p[4]) ,因为[]的优先级比*高.

(p[4]) 相当于限制了申请地址的个数,只能为4.

但是每一个地址所指向的内存是可变的(即内存长度不定).

总结: 相当于限制了申请地址的个数,内存的的长度没有限制


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值