2

有一个问题要打印值的地址:

char word[] = "hi there"; //print address of string
int a = 1; // print address of 1

我知道如何打印变量的地址,我认为值在变量地址内?那么值的地址其实就是变量地址呢?

这是一个技巧问题,我是对的吗?

提前致谢

4

6 回答 6

9
char word[]="hi there"; //print address of string

word是一个名为 char 数组的对象的名称。它有一个地址和一个大小。

在这个地址上,有第一个元素,一个值为 的 char 'h'。以下字母在下一个地址之后,直到最后一个'e'。这个后面跟着一个 0 字节,即字符串终止符。所以数组的总大小是 9:8 个给定的字符加上一个 0 字节。

+--+--+--+--+--+--+--+--+--+
|h |i |  |t |h |e |r |e |# | <-- # means NUL byte.
+--+--+--+--+--+--+--+--+--+
+--+--+--+--+--+--+--+--+--+
|68|69|20|74|68|65|72|65|00|
+--+--+--+--+--+--+--+--+--+

这里我们有一个特长:&wordword指向同一个地址,但是它们所代表的大小不同。&word指向整个数组,所以sizeof(*(&word))是 9,而word指向第一个字符,所以sizeof(*word)是 1。

据说“word衰减为指向第一个元素的指针”。

如评论中所问,请注意这与案例略有不同

char * wordptr = "hi there";

因为内存布局相同,但字符串位于只读内存中,而普通数据段包含指向该字符串的指针。所以&wordptr,wordptr*wordptr是完全不同的:&wordptrchar **指向数据存储器,wordptrchar *指向 RO 存储器(即指向真正的字符串 - 准确地说,指向字符串的第一个字符)并且*wordptr只是'h'开头的.

哦,

int a = 1; // print address of 1

a是一个名为 的对象的名称int。它也有一个地址和一个大小。

它的大小取决于实现,它的内存布局也是如此。让我们以最低字节在前的小端机器为例,假设每个 int 有 4 个字节:

+--+--+--+--+
|01|00|00|00|
+--+--+--+--+

您可以使用 and 获取他们两个的地址并将它们&word打印&a出来:

printf("%p %p\n", &word, (void *)&a);

((void *)是必需的,因为在某些实现中,指针的大小可能会有所不同,因此为了安全起见,我们需要转换指针类型。)

术语“地址 1”没有意义;虽然您获得其地址的变量&a保持值 1,但这仅仅是“巧合”:您可以设置a = 3,并且地址保持不变,而存储在那里的值会发生变化。所以说“当前持有 1 的变量的地址”确实更好。

于 2013-10-16T14:38:07.377 回答
4

如果您正在谈论在等号右侧打印值的地址,那么这是一个技巧问题。

等号右边的值称为初始化器。

初始化程序不需要(这意味着它们是否由编译器决定)具有地址,并且在您的情况下,即使它们有地址,您也无权访问它。

如果您在谈论变量的地址,a那么word问题就很简单了,因为如果您引用它,它们就会有一个地址。

于 2013-10-16T14:41:15.330 回答
3

图片可能会有所帮助。我接受了你的声明

char word[] = "hi there";
int a = 1;

并将它们放入一个简单的程序中,然后使用我编写的一个小实用程序来显示这些项目在内存中的布局。我在工作中的系统上得到以下内存映射(SLES 10,gcc 4.1.2):

           项目地址 00 01 02 03
           ---- ------- -- -- -- --
     “你好” 0x400a32 'h' 'i' 20 't'
                      0x400a36 'h' 'e' 'r' 'e'
                      0x400a3a 00 '0' '1' 00

           字 0x7fffb48d2ee0 'h' 'i' 20 't'
                0x7fffb48d2ee4 'h' 'e' 'r' 'e'
                0x7fffb48d2ee8 00 00 00 00

              一个 0x7fffb48d2edc 01 00 00 00

与数字文字不同,为字符串文字预留了存储空间。这种存储在整个程序中都是可见的,并在程序的生命周期内保持(它具有静态存储持续时间)。此存储可能是可写的,也可能不是可写的,具体取决于平台;最好假设它不是。您永远不应该尝试修改字符串文字的内容,并且尝试这样做会调用未定义的行为。

字符串文字"hi there"留出了 9 个字节,从地址开始到地址0x400a32结束(通过0x400a3a的字节不是字符串的一部分,并且包含一些随机值)。 0x400a3b0x400a3d

字符数组word还从 address 开始留出了 9 个字节0x7fffb48d2ee0。字符串文字的内容已被复制到其中。

整数变量a从地址开始留出 4 个字节0x7fffb48d2edc,它包含值1( 0x00000001)。1就像我之前说的,没有为像;这样的数字文字预留存储空间。编译器会简单地生成代码以将值加载到a.

我正在使用的系统是little-endian,这意味着多字节值的最低有效字节 ( 0x01) 存储在低地址(little-endian 系统读取“从右到左”)。在大端系统上,最低有效字节将存储在高地址(大端系统读取“从左到右”)。同样,图片可能会有所帮助 - 如果我们存储二进制值0x12345678,则各个字节将存储在地址A中,如下所示:

大端:A+0 A+1 A+2 A+3
值:0x12 0x34 0x56 0x78
小端:A+3 A+2 A+1 A+0

请注意,在这种情况下,a存储在比 低的地址word,即使它是在源代码中的 word之后声明的。不要假设变量在内存中的排列顺序与它们声明的顺序相同。

于 2013-10-16T15:34:28.140 回答
2

&是“地址”运算符,它生成指向其操作数的指针。

因此,&a是一个有效的指针表达式,它保存变量的地址,a因此该指针的值将使用以下语句打印。

printf("Address of a: %p",(void*)&a);

同样,如果您想要指向整个word[]数组的指针,您可以通过以下方式打印:

printf("Pointer to Whole array: %p",(void*)&word);

如果您想要word[]数组中第一个元素的地址,您可以通过以下方式打印它

printf("Address of first element in the word[]: %p",(void*)word);

好吧,您可能会打印并看到上面的两个printf()语句为您提供了相同的地址,但它们是不同的。读这个

笔记:

如果 的操作数&具有 类型type,则结果为pointer to type

  • 结果&apointer to int

  • 结果&wordpointer to array of 9 char。因为size of (*(&word))是 9

  • 引用word有类型pointer to char

于 2013-10-16T14:40:27.317 回答
2

您是否尝试检查打印指针。我认为这可能会对你有所帮助。

地址是使用%p从规范中打印出来的:-

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

要在指向指针的指针中打印地址,请使用如下:-

printf("%p",x)

在 linux 中,您可以使用普通 gdb 查看内存地址

于 2013-10-16T14:30:47.797 回答
0

您可以使用运算符打印变量的地址&

int a = 1; 
printf("Address of variable a is: %p",&a);
于 2013-10-16T14:31:19.987 回答