有一个问题要打印值的地址:
char word[] = "hi there"; //print address of string
int a = 1; // print address of 1
我知道如何打印变量的地址,我认为值在变量地址内?那么值的地址其实就是变量地址呢?
这是一个技巧问题,我是对的吗?
提前致谢
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|
+--+--+--+--+--+--+--+--+--+
这里我们有一个特长:&word
和word
指向同一个地址,但是它们所代表的大小不同。&word
指向整个数组,所以sizeof(*(&word))
是 9,而word
指向第一个字符,所以sizeof(*word)
是 1。
据说“word
衰减为指向第一个元素的指针”。
如评论中所问,请注意这与案例略有不同
char * wordptr = "hi there";
因为内存布局相同,但字符串位于只读内存中,而普通数据段包含指向该字符串的指针。所以&wordptr
,wordptr
和*wordptr
是完全不同的:&wordptr
是char **
指向数据存储器,wordptr
是char *
指向 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 的变量的地址”确实更好。
如果您正在谈论在等号右侧打印值的地址,那么这是一个技巧问题。
等号右边的值称为初始化器。
初始化程序不需要(这意味着它们是否由编译器决定)具有地址,并且在您的情况下,即使它们有地址,您也无权访问它。
如果您在谈论变量的地址,a
那么word
问题就很简单了,因为如果您引用它,它们就会有一个地址。
图片可能会有所帮助。我接受了你的声明
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
的字节不是字符串的一部分,并且包含一些随机值)。 0x400a3b
0x400a3d
字符数组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之后声明的。不要假设变量在内存中的排列顺序与它们声明的顺序相同。
&
是“地址”运算符,它生成指向其操作数的指针。
因此,&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
。
结果&a
是pointer to int
结果&word
是pointer to array of 9 char
。因为size of (*(&word))
是 9
引用word
有类型pointer to char
。
您是否尝试检查打印指针。我认为这可能会对你有所帮助。
地址是使用%p从规范中打印出来的:-
p参数应该是一个指向 void 的指针。指针的值以实现定义的方式转换为打印字符序列。
要在指向指针的指针中打印地址,请使用如下:-
printf("%p",x)
在 linux 中,您可以使用普通 gdb 查看内存地址
您可以使用运算符打印变量的地址&
:
int a = 1;
printf("Address of variable a is: %p",&a);