5

当我连续编译并执行此代码几次时,它报告 cc 的地址为 0x0012FF5C。但是,当我尝试使用 foo 中对 printf 的第二次调用来打印该地址处的字符串时,它会打印垃圾而不是打印出“Hello”?为什么这样??当我知道地址位于应用程序的地址空间内时,如果我直接将地址作为参数传递会有什么问题(至少直到我不重新启动我的电脑,或者启动其他需要大量空间的应用程序,这会导致我的申请将被分页)??

void foo(char *cc[])
{
    printf("%x\n",cc);
    printf("%s\n",(char *)(0x0012FF5C));
}

int main()
{
    char *c[] = {"Hello","World"};
    foo(c);
}
4

10 回答 10

12

Because there is nothing in the C or C++ standard to guarantee that. Those addresses may be predictable depending your compiler/OS, but don't count on it.

#include <stdio.h>

int main(void) {
    char s[] = "okay";
    printf("%p", (void*)s);
    return 0;
}  

I get a different address every time (gcc on linux). Don't use "address literals" ;)

Process address space on modern OS's is randomized for security on each execution:

http://en.wikipedia.org/wiki/Address_space_layout_randomization

于 2012-04-26T12:37:49.500 回答
6

因为当第二个 printf 尝试将此 char* 数组打印为字符串时,第一个 printf 会为您提供 char* 数组的地址。

于 2012-04-26T12:43:08.033 回答
5

好的,第一件事是,永远不要假设多次执行会返回相同的地址

现在。假设您很幸运并获得了相同的地址。请注意,这cc是一个指针数组。你正在发送这个数组的基地址。您需要发送数组第一个元素的值

试试这个,如果你幸运的话,

printf("%s\n",*((char**)(0x0012FF5C)));
于 2012-04-26T12:40:09.333 回答
4

如果你在没有虚拟内存内存保护的机器上运行你的程序,你很可能会成功。这些技术/功能是它不起作用的原因。

每个进程都有自己的虚拟地址空间,其地址由处理器的内存管理单元转换为硬件地址。

于 2012-04-26T12:40:56.150 回答
3

I don't think your (0x0012FF5C) represents poiter. Try (char*)(0x0012FF5C).

Besides that, like other tell you, this has no practical value, as there is no guarantee string will be located at that address every run. This is not some embedded assembly where you say put this string at this location and later use the address directly.

于 2012-04-26T12:38:27.907 回答
2

The memory location of your process may have changed between the both executions. You can't do that, you are trying to read an adress who isn't alloced by your process. Moreover I have many warnings :

test.c: In function ‘foo’: test.c:6: warning: format ‘%x’ expects type ‘unsigned int’, but argument 2 has type ‘char **’</p>

test.c:7: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’</p>

test.c:9: warning: format ‘%x’ expects type ‘unsigned int’, but argument 2 has type ‘char **’</p>

于 2012-04-26T12:36:31.730 回答
2

when I know that the address

Well, you don't really know anything about the address when you're hard-coding it, you're guessing at it.

There are lots of reasons why the address of a thing could change between executions of the same program. There are even more reasons why the address could change if you're changing the code (as you appear to be doing here).

于 2012-04-26T12:38:37.907 回答
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);
}
于 2012-04-26T12:39:35.177 回答
1

首先,printf("%x\n",cc);不打印cc. 充其量它会打印 的值cc,但行为是未定义的,因为您为 format 传递了错误的类型参数%x。它期望unsigned int,你已经提供了一个指针。

实践中最可能的行为是它会打印值的最低有效部分cc(因此在 32 位机器上它似乎可以工作,而在 64 位机器上你不会看到整个地址)。但它可能会以不同的方式出错。

第二件事,cc有 type char**,因此 的值cc不是指向字符串第一个字符的指针,而是指向数组第一个元素的指针cfrom main。该%s格式需要一个指向字符串第一个字符的指针。因此,即使cc真的是的值0x0012FF5C,将该值传递给printf格式%s也是错误的。

您看到的“垃圾”是试图从该指针数组中打印指针数据,就好像它是属于字符串的字符数据一样。它不是。

于 2012-04-26T12:59:43.457 回答
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

于 2012-04-26T13:17:17.763 回答