我的一个朋友给了我这个问题,并要求我帮助它:在运行这段代码后,指针p中存储的地址是什么?
unsigned * p = (unsigned*)1000;
p += 10;
我刚刚在CodeBlocks上添加了printf("%u", p);
,结果是1040。(unsigned*)1000
是什么,它是什么意思?printf("%u", p)
是打印记忆地址的正确方法吗?还是需要使用另一种语法/另一种格式说明符?为什么答案是1040,而不是1010?
主要的问题是,给出的唯一的几行是:
unsigned * p = (unsigned*)1000;
p += 10;
基于这些,我做了一点google的研究,我认为正确的获取地址的方法是printf("%u", p);
,即使这是正确的,这是正确的语法,我仍然不能理解这个添加背后的过程。
4条答案
按热度按时间w3nuxt5m1#
指针本身不像整数值那样是“有符号”或“无符号”的。
对于
p
的定义,您要做的是定义一个名为p
的指针变量,它指向一个unsigned int
值,并且您说它将指向地址1000
(这对于大多数系统来说没有意义)。对于
p += 10
,使p
指向离其原始位置更远的10个unsigned int
元素,假设公共sizeof(unsigned int) == 4
,则在增量之后p
将指向地址1040
(1000 + (10 * sizeof(unsigned int))
)。(unsigned*)1000
是一个普通的强制转换,它告诉编译器值1000
是一个指向unsigned int
的指针,如上所述,这在大多数系统上没有意义。tsm1rwdh2#
unsigned * p = (unsigned*)1000
这是一个由实现定义的从整数到指针的转换。它是否工作以及如何工作取决于目标系统和编译器端口。您将得到地址1000
=0x3E8
。按照惯例,地址总是以十六进制书写。p += 10;
这可能会调用未定义的行为。严格地说p
必须指向一个已分配的数组,否则您无法在其上执行指针运算。实际上,大多数编译器都为此类运算提供了定义良好的编译器扩展,否则编写低级C代码会变得很麻烦。至于它做什么,它是 * 指针算术 *(在初级学习材料中查找该术语),基本上整个代码等价于
unsigned* p = (unsigned*)(1000 + 10*sizeof(int));
。不,这是错误的和未定义的行为。请注意,
unsigned
等于unsigned int
,但您并没有打印指针指向的内容,您打印的是指针地址本身。你需要打印这样的指针地址:
printf("%p", (void*)p)
。始终使用%p
,始终强制转换为void*
。您应该获得0x410作为输出。piztneat3#
关于指针算术,已经有很好的答案了,所以我将集中讨论您问题的另一部分。
printf(" % u",p)是否是打印记忆地址的正确方式
或者是否存在需要使用的另一语法/另一格式说明符?
%p
,并且指针必须强制转换为void *
。p
参数应该是一个指向void的指针。指针的值以一种实现定义的方式转换为一个打印字符序列。
由于
%p
需要一个void
指针,因此向它传递指向任何其他类型的指针都会调用未定义的行为。7.21.6.1 The fprintf function
如果转换规范无效,则行为未定义。如果任何参数不是对应转换规范的正确类型,则行为未定义。
mrfwxfqh4#
创建类型为“指针指向
unsigned int
“的指针变量p
,并将值1000
(0x03E8
)赋给它。由于不能直接将整型常量赋给指针类型,因此必须执行(unsigned *)
强制转换。这相当于
p = p + 10
。当你把一个整数i
加到指针p
上时,结果值是一个指针,指向p
所指向的对象之后的被指向类型的第i
个 * 对象 *。在大多数现代系统中,unsigned int
是4字节宽。因此,p
之后的下一个unsigned int
对象将在地址1004
(0x03EC
)处开始,其后的对象将在1008
(0x03F0
)处开始,等等:因此第10个
unsigned int
对象将开始于地址0x0410
(1040
)。指针的正确格式说明符是
%p
,而不是%u
;可以使用%u
打印p
指向的无符号值:现在,在这个特定的例子中,
p
和p+10
都是 invalid 指针(它们在对象的生命周期中不指向对象),所以试图通过它们读写会导致未定义的行为。下面是一个完整的程序,应该说明以上几点: