当我连续编译并执行此代码几次时,它会将cc的地址报告为0x0012FF5C。但是当我尝试在foo中使用第二次调用printf打印出该地址的字符串时,它会打印出垃圾而不是打印出“Hello”?为什么这样??当我知道地址位于应用程序的地址空间内时(至少我不重新启动我的PC,或者启动其他需要大量空间的应用程序并导致其他原因)我直接将地址作为参数进行了论证是错误的我的应用程序被分页了?? ??
void foo(char *cc[])
{
printf("%x\n",cc);
printf("%s\n",(char *)(0x0012FF5C));
}
int main()
{
char *c[] = {"Hello","World"};
foo(c);
}
答案 0 :(得分:12)
因为C或C ++标准中没有任何内容可以保证这一点。这些地址可能可以根据编译器/操作系统进行预测,但不要依赖它。
#include <stdio.h>
int main(void) {
char s[] = "okay";
printf("%p", (void*)s);
return 0;
}
我每次都获得一个不同的地址 (linux上的gcc)。不要使用“地址文字”;)
现代操作系统上的进程地址空间随机化,以确保每次执行的安全性:
http://en.wikipedia.org/wiki/Address_space_layout_randomization
答案 1 :(得分:6)
因为当第二个printf尝试将此char *数组作为字符串打印时,第一个printf为您提供char *数组的地址。
答案 2 :(得分:5)
好的,首先,永远不要假设多次执行会返回相同的地址
现在。让我们说你很幸运并获得相同的地址。请注意,cc
是一个指针数组。并且您正在发送此阵列的基地址。您需要发送数组的第一个元素的值
试试这个,如果幸运的话,
printf("%s\n",*((char**)(0x0012FF5C)));
答案 3 :(得分:4)
如果您在没有virtual memory和memory protection的计算机上运行程序,则很可能会成功。这些技术/功能是它不起作用的原因。
每个进程都有自己的虚拟地址空间,处理器的memory-management unit将其地址转换为硬件地址。
答案 4 :(得分:3)
我不认为你的(0x0012FF5C)代表了poiter。尝试(char *)(0x0012FF5C)。
除此之外,像其他人一样告诉你,这没有实际价值,因为每次运行都没有保证字符串位于该地址。这不是一些嵌入式程序集,您可以将此字符串放在此位置,然后直接使用该地址。
答案 5 :(得分:2)
您的进程的内存位置可能在两次执行之间发生了变化。您不能这样做,您正在尝试阅读未由您的流程分配的地址。此外,我有很多警告:
test.c:在函数'foo'中:test.c:6:警告:格式'%x'需要类型'unsigned int',但参数2的类型为'char **'
test.c:7:警告:格式'%s'需要类型'char *',但参数2的类型为'int'
test.c:9:警告:格式'%x'需要类型'unsigned int',但参数2的类型为'char **'
答案 6 :(得分:2)
当我知道地址
时
嗯,当你对地址进行硬编码时,你真的知道关于地址的任何内容,你在猜测
在同一程序的执行之间,事物的地址可能会发生变化的原因有很多。如果您正在更改代码(正如您在此处所做的那样),地址可能会更改的原因更多。
答案 7 :(得分:2)
如前所述,您在内存中的代码位置可能因执行而异,并且变量的位置也会发生相同的情况。尝试运行此代码。它打印您在内存中指向的变量的实际地址。您将看到多次执行会产生完全不同的地址。永远记住!
#include <stdio.h>
void foo(char *cc[])
{
printf("%x\n",cc);
printf("%s\n",(0x0012FF5C)); //this line will fail, there is no guarantee to that
cc++;
printf("%x\n",cc);
}
int main()
{
char *c[] = {"Hello","World"};
printf("c array location: %p",c); //print location
foo(c);
}
答案 8 :(得分:1)
首先,printf("%x\n",cc);
不会打印cc
的地址。它最好打印cc
的值,但行为未定义,因为您为格式%x
传递了错误的类型参数。它期望unsigned int
,你提供了一个指针。
在实践中最可能的行为是它将打印cc
值的最不重要部分(因此在32位机器上它似乎可以工作,而在64位机器上你不会看到整个地址)。但它可能以不同的方式出错。
第二件事,cc
的类型为char**
,因此cc
的值不是指向字符串第一个字符的指针,它是指向第一个元素的指针来自c
的数组main
。 %s
格式需要指向字符串第一个字符的指针。因此,即使cc
的值确实为0x0012FF5C
,使用printf
格式将该值传递给%s
也是错误的。
您看到的“垃圾”是尝试从该指针数组中打印指针数据,就好像它是属于字符串的字符数据一样。事实并非如此。
答案 9 :(得分:0)
我简化了你的例子。如果您知道字符串的地址,则可以从该地址读取。
#include <stdio.h>
void foo(char cc[])
{
int i;
printf("%p\n",cc);
printf("Type the address you would like to read:");
scanf ("%x",&i);
printf("Character value at your address: %c\n",*((char *)(i)));
}
int main()
{
char c[] = "Hello";
foo(c);
}
这将允许您从命令行中指定的地址进行读取。它将首先打印出字符数组的基址,以便您知道在哪里查找字符串。
示例:
$ ./a.out
0xbfcaaf3a
Type the address you would like to read:bfcaaf3d
Character value at your address: l
正如预期的那样,它会打印Hello
的第四个字母。