如何在C语言中获取地址?

3

这个问题可能有一个非常简单的答案,但我无法看到它。

#include <stdio.h>

int main(void) {
int x = 0;
printf("\n%d\n%d\n",x,&x);
}

好的,printf输出了0(x)和2293752(&x)。我正在尝试找出一种方法,可以查看任何地址(&)并查看已存储在那里的内容。这只是为了进行实验。有帮助吗?


我建议您使用%p而不是%d,它会给您十六进制地址。 - Stefano Borini
1
%p 用于 void*,因此需要进行转换。顺便说一下,标准不能保证它会以十六进制形式打印输出。 - Bastien Léonard
不,它并没有,但我还没有遇到一个没有这个功能的实现。当然,一款现代的本地PDP-11 C编译器可能会选择八进制,因为在PDP-11上,这是所有内容的自然表示方式。但是,我使用的PDP的最后一个本地C编译器(DECUS C)太旧了,无法使用%p。 - RBerteig
6个回答

4
void* memAddr = (void*)0xAABBCCDD; //put your memory address here
printf("int value at memory address %p is %i", memAddr, *((int*)memAddr));

你可能会发现检查任意内存地址只会导致崩溃。

测试了一下,结果就是崩溃了。其实我也不是真的需要知道到底发生了什么,只是好奇罢了。 - akway
你正在假设memAddr包含一个int,它是4个字节。你应该至少使用无符号整数,因为你同样有可能使它看起来是负数。将char转换为一些可读的格式,如十六进制,更为合理。 - groundhog
1
地址可以包含任何内容并转换为任何类型。例如:您假设memAddr包含一个无符号字符,即一个字节。您应该至少使用有符号字符,因为它实际上可能是负数。将int转换为一些可读格式,如十进制,更为合理。 - Tom Dalling

2
那就是指针解引用,用的是 * 运算符。但是,对于随机地址存储的数据类型,你无法确定其类型。
#include <stdio.h>

int main(void) {
int x = 0;
printf("\n%d\n%d\n%d\n",x,&x,*(&x));
}

/* resulting output will be 0, some memory address, and 0 again */

不是我想要的。如果2293752是x的地址,那么我想检查0000000..99999999地址上的内容。 - akway
1
请注意,*(&x) 实际上是将 * 运算符应用于值 (&x)。您可以选择将其应用于不涉及 & 运算符的其他内容 - 例如,一个常量地址。 - Amber
1
你可能会发现GCC在运行时中止程序。在这些情况下,它非常严格,因此最好先使用适当的%p并转换为void * - Johannes Schaub - litb
同意 - 随意地玩弄内存通常不是很有效的。 - Amber
再次假设内存为整数。 - groundhog

2
尝试这样做存在许多问题,首先,正如Wilson所提到的,您实际上不会知道存储在那里的内容。
但是,Wilson有点偏差,您应该将其转换为char而不是int,因为使用int会看到4个字节,而不是像使用char一样只看到一个字节。
此外,除非您能够读取8位ASCII字符并将它们映射到您的头脑中的某些有意义的东西,否则您可能希望将其转换为其他形式,例如base2、base8或base16。
您可以用几种方法来实现这一点 - 可能最好的方法是使用位运算符和二进制移位运算符,在调度表中查找以将其映射到可查看的ASCII。
然而,您仍然不会知道存储在那里的内容,您只能看到一些原始二进制数据的编码形式。原因是C仅针对指向该内存地址的变量进行了类型化。对该内存的裸视图只会给你二进制值,而无法查找该内存绑定的变量或这些变量的类型。
第二个问题是您需要小心地只查看您有权访问的内存部分。除非您小心地访问它,否则无法查看代码段内存。如果您随意探索,您会很幸运地避免分段错误。
然而,最有效的查看进程内存的方法可能是将其段转储到磁盘中。在UNIX中,可以通过核心转储来完成此操作。然后,您可以将其加载到调试器中并随意探索,甚至可以根据堆栈的足够知识将其映射到正确的类型。您还可以使用二进制编辑器以未类型化的方式检查它 - 通常可以识别字符串。
祝你好运!

1
如果你想探索内存,我建议使用低级调试器,例如OllyDbg

0
假设您想查看“原始”数据,并且知道进程地址空间内的地址,您可以执行以下操作:
long x=<address>
printf("%x", *(int *)x);

你能解释一下这部分代码吗:*(int *)x - akway
1
在C语言中,整数和指针确实是不同的类型:据我所知,long不能保证能够保存一个地址,而且使用指针更加明确。 - Bastien Léonard
Bastien: 确实,那段代码非常依赖于硬件。实际上,没有一种可移植(且安全/可靠)的方法来实现原帖中想要的功能。akway: *(int *)x 将变量 x 强制转换为指向整数的指针,然后检索该指针指向的位置存储的(整数)值。它有效地将 x 的值视为指向整数的内存地址,并读取该整数。如果该地址超出了进程的地址空间,则会以与环境相关的方式失败。 - Wilson

0

要查看地址,您可以使用%p

printf("%p",&x);

我建议您开始阅读关于指针的知识,指针是一个存储内存地址的变量。
int x=10;
int *p; //this is a pointer to int
p=&x; //now p has the memory location of x
printf("%d\n",*p); //this will print 10

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接