首先,事实证明你已经打印的地址并不意味着在该地址被分配内存。您只需添加数字并生成其他数字。
其次,你通过加2得到的数字的原因是比基地址大8,而不是比基地址大2,这是因为,当你在C中增加指针的整数时,算法是根据指向元素,而不是内存中的字节(除非指向的元素是字节)。假设你有一个int数组,例如int x[8]
,并且你有一个指向x[3]
的指针。向该指针添加两个会生成一个指向x[5]
的指针,而不是指向x[3]
开头以外的两个字节的指针。记住C是抽象是很重要的,C标准指定了抽象内部发生的事情。在C抽象内部,指针运算对元素的数量起作用,而不是原始内存地址。 C实现(编译器和将C代码转化为程序执行的工具)需要对原始内存地址执行任何操作,以便实现由C标准指定的抽象。通常,这意味着编译器在将元素添加到指针时将整数乘以元素的大小。所以两个乘以四(在一台机器上,其中int
是四个字节),并且八个结果被添加到基地址。
三,你不能依赖这种行为。 C标准只针对指向数组内对象的指针定义指针运算,包括数组末尾的一个虚构对象。另外,指向单个对象的指针就像一个元素的数组一样。因此,如果您有一个指向p
的指向int的指针,则允许您计算p+0
或p+1
,因为它们指向数组中唯一的对象(p+0
),而虚拟对象指向数组中最后一个元素之外的一个对象(p+1
)。你是而不是允许计算p-1
或p+2
,因为这些都在数组之外。请注意,这不是取消引用指针(尝试读取或写入计算出的地址处的内存)的问题:即使仅仅计算,该地址也会导致C标准未定义的行为:您的程序可能会崩溃,它可能会崩溃给你“正确”的结果,或者它可以删除你帐户中的所有文件,所有这些行为都符合C标准。
单纯计算出界限地址不会产生这种奇怪的行为。但是,该标准允许它,因为一些计算机处理器具有不寻常的地址方案,这需要比简单算术更多的工作。也许在平坦地址空间之后的第二常用地址方案是基地址和偏移方案。在这种方案中,四字节指针的高16位可能包含基地址,低16位可能包含偏移量。对于给定的基地址b和偏移量o,相应的虚拟地址可能是4096 * b + o。 (这种方案仅能够寻址字节,许多不同的基址和偏移值可以指相同的地址,例如,基址0和偏移量4096是指与基址1和偏移量0相同的地址。 )使用base-and-offset方案时,编译器可以通过仅添加到偏移量并忽略基数来实现指针算术。 (这样的C实现可以支持高达65536字节的数组,只能通过偏移量寻址的范围)。在这种实现中,如果您有指向int p
且编码为0x0000fffc(基址0,偏移量65532)的指针,并且int
是四个字节,则p+2
将具有值0x00000004,而不是八个更大的值(0x00010004)。
这是一个例子,其中指针算术产生的值不会在平地址机器上产生。很难想象一个实现,其中根据C标准无效的指针运算会导致崩溃。但是,考虑一个实现,必须由进程手动交换内存,因为处理器没有硬件来支持虚拟内存。在这种实现中,指针可能包含内存中用于描述磁盘位置和用于管理内存交换的其他信息的结构地址。在这样的实现中,执行指针运算可能需要读取内存中的结构,因此执行无效指针运算可能会读取无效地址。
在C中,你永远不会通过像这样的测试获得很远的学习;由于*未定义的行为*你会发现很多不一致 - 你都不应该指望它们。 – Dave 2012-07-31 05:05:51
请首先使用SO搜索工具:[我可以使用更多的内存,而不是使用malloc()分配多少内存,为什么?](http://stackoverflow.com/questions/3509714/i-can-使用多内存而不是使用多少分配与malloc-why) – 2012-07-31 09:56:53