如何在C程序中打印指针地址?

我正在尝试学习如何(使用)C程序中的指针; 我的例子如下:

#include  #include  int main(int argc, char *argv[]) { int * tab = (int*)malloc(sizeof(int)*5); int a =10; int *p; p = &a; printf("the adress of a is%d \n",&a); printf("the adress of a using the pointer is%p \n",p); printf("the adress of tab is%d \n",tab); } 

我正在尝试打印a的地址, p的地址以及tab的第一个字节开始的位置。

使用"%p"时我可以获得hex值,但我愿意使用地址的十进制值。

编辑:在这个video 图像上 ,有人使用"%d"打印指针地址的十进制值,这让我很困惑。

要打印对象指针的十进制版本,首先将指针转换为整数。 最好使用可选类型uintptr_t

以下类型( uintptr_t )指定一个无符号整数类型,其属性是任何有效的void指针都可以转换为此类型( uintptr_t )…C11dr§7.20.1.41

 #include  uintptr_t d = (uintptr_t)(void *) &a; 

然后打印出来。
有关PRIuPTR的一些信息

 printf("%" PRIuPTR "\n", d); 

对于C99之前的代码,请考虑直接转换为unsigned long 。 @Barmar


OP后来评论道

“…我将尝试操纵tab变量,我将测试选项卡中的每个单元格是否为4字节,因此我可能会使用tab + 8字节来获取特定单元格的值,这里它很简单例如,带小数对我来说很容易。“

这是一个值得怀疑的方法,因为指针的十进制化可能无法提供预期的连续数字模型。 这篇文章可能对学习有好处,但是OP在另一篇文章中提供了更多细节,甚至可以为更高层次的问题提供更好的想法。

首先,请注意地址通常是“类似数字”但可能不是(例如,记住1980年代16位x86 PC上远程地址的段+偏移概念)。

然后,与指针最相似的整数类型是intptr_t (signed)或uintptr_t (unsigned) – 都来自

您可能会将其强制转换为long long (希望它们不小于指针),例如

  printf("address of a in decimal is %lld\n", (long long) (intptr_t) (&a)); 

但实际上,你为什么要以这种方式展示地址? 我认为不需要它(例如,调试器或链接器通常显示hexa中的地址,这可能是%p所做的)。

请注意,C11标准(参见n1570 ,§7.21.6.2,p315)对打印指针的%p没有太多说明:

参数应该是指向void的指针。 指针的值以实现定义的方式转换为打印字符序列。

我正在理解上述内容,其中任何指针的打印Hello ⭔都是可接受的标准符合行为。 在实践中,实现以类似于链接器和调试器的方式打印指针,并且不以愚蠢的方式行事(但我理解他们可以)。

最后,指针的实际具体“数值”值并不重要,并且从一次执行到下一次执行可能会有很大差异(例如,由于ASLR )。

对于打印“地址”(实际上是指针), "%p"是最常用的方法(注意必要的转换为void* )。 如果需要十进制而不是hex的地址,可以将指针转换为整数值; 这在C中有明确定义(参见此在线C标准草案):

6.3.2.3指针

(6)任何指针类型都可以转换为整数类型。 除了之前指定的以外,结果是实现定义的。 如果结果无法以整数类型表示,则行为未定义。 结果不必在任何整数类型的值范围内。

所以代码可能如下所示:

 int main(int argc, char *argv[]) { int a =10; int *p = &a; p = &a; unsigned long long addrAsInt = (unsigned long long)p; printf("the adress of a is %llu \n",addrAsInt); printf("the adress of a using the pointer is %p \n",(void*)p); } 

如果要将指针视为十进制整数,请将其%lu转换为unsigned long并以%lu格式打印。 虽然标准不能保证这一点,但它应该适用于大多数实现。

 printf("the address of a is %lu\n", (unsigned long)&a); 

p是打印指针的转换说明符。 用这个。

 int a = 42; printf("%p\n", (void *) &a); 

请记住,省略强制转换是未定义的行为,而使用p转换说明符的打印是以实现定义的方式完成的。