在以下代码中:
#include <stdio.h>
int main(int argc,char** argv)
{
char *str = "Hello world";
char *p = &argc+1;
printf("%i \n",(&argc+1));
printf("%i \n",*(&argc+1));
printf("%i \n",&str);
printf("%i \n",*str);
printf("%i \n",p);
printf("%i \n",*p);
return 0;
}
输出结果为:
-541685632
4196028
-541685632
72
-541685632
-68
我的问题是,因为他们都指向同一个地址,他们所指向的是不是同一个值;
答案 0 :(得分:2)
当然这是所有未定义的行为,但鉴于&argc+1
恰好是&str
您的特定实现,这就是您获得在该实现上看到的行为的原因:
首先让我们摆脱&argc+1
,而只使用&str
:
#include <stdio.h>
int main(int argc,char** argv)
{
char *str = "Hello world";
char *p = &str;
printf("%i \n", &str);
printf("%i \n",*(&str)); // (1)
printf("%i \n", &str);
printf("%i \n", *str); // (2)
printf("%i \n", p);
printf("%i \n",*p); // (3)
return 0;
}
开(1)您正在打印*(&str)
,这当然与str
相同。这将打印存储在变量str
中的内存地址。
开(2)您正在打印*str
。因此,您将指针存储在str
中并取消引用它。 *str
的值将为'H'(a.k.a。72),因为这是位于str
指向的地址的字符。
在(3)上打印p
指向的值。 p
指向str
,因此您可能希望{1}}的值打印得像(1)一样。但是,您将str
声明为p
指针,因此取消引用它只会读取一个char。所以你得到的只是char
值的第一个字节。
答案 1 :(得分:0)
&argc+1
指向可能未分配给您的程序的内存。这是不确定的行为,所以如果你的观察与你的期望不同,你不应该感到惊讶。
答案 2 :(得分:0)
区别在于您取消引用的指针类型:
(&argc+1)
是指向int
的指针,取消引用它会将四个字节解释为一个整数。
&str
是指向char
指针的指针,取消引用它会将四个/八个字节解释为一个指向字符的指针。但是,您的代码会将其解除引用两次,因此当您打印*str
时,您会在内存中的其他位置打印一个字节。
p
是指向char
的指针,取消引用它只会将一个字节解释为一个字节。
除此之外,当然,取消引用(&argc+1)
没有C标准的祝福,它允许编译器发出代码,这些代码可能在您进行解除引用时完全执行任何操作。这绝对包括打开互联网连接以静默下载并安装一个漂亮的小程序来记录您的每次击键并将其直接发送给NSA或其他人......所以,尽量避免调用未定义的行为。
答案 3 :(得分:0)
首先,这些并非都指向同一地址......是什么让您认为str
的地址与&argc+1
相同?在任何平台上,我认为这两个在任何C编译器中都不一样!但是这些事情依赖于编译器和平台,所以试图以这种方式访问内存是一个不好的想法,并且非常不便携。
但暂时将所有这些放在一边,即使他们DID指向同一个地址,你在每个实例中以不同的方式使用该地址......在(&argc+1)
的情况下,你打印的是值指针(作为整数)。在*(argc+1)
情况下,您正在通过第一个指针打印int
指向的TO。在&str
的情况下,您正在打印地址str
(与str
的内容无关)。使用*str
,您将char
打印str
指向的p
。使用(&argc+1)
,您将打印指针的值,与第一个案例*p
一样。最后,使用char
打印前一个指针指向的%i
。
此外,您使用printf
格式打印所有这些值,但打印值的实际数据类型各不相同......有些是指针(在大多数实现中通常为32位) ,有些是8位的char。 {{1}}如何处理与相应格式字符串不对齐的数据值因实现而异,这是不好的做法!
仅供参考,当我尝试使用Linux / Fedora下的gcc 4.8.1进行编译时,会出现多个编译时错误。
总而言之,这里有很多丑陋的东西!