我正在学习C,我想访问(只是想看看地址里有什么,实际上是为了好玩。)C中特定地址的内容,比如:
char *p = (char *)0x7ffeefad7be8;
printf("%s",*p);
但是它显示出分割错误。我知道记忆的一部分是保留的并且不能访问的,kernal的空间,例如g。但我认为这个地址是可以访问的,因为它是我从这个代码中得到的地址:
int *p,a;
p = &a;
printf("%p",p);
所以假设它在[heap]和[stack]的范围内。(它用第一个代码分隔,刚刚证明地址是可访问的)
但错误一直在报告!我做了很多尝试和研究,尽管它仍然不起作用。
以下是$cat /proc/self/maps
:的输出
00400000-0040c000 r-xp 00000000 08:09 3942120/usr/bin/cat
0060b000-0060c000 r--p 0000b000 08:09 3942120/usr/bin/cat
0060c000-0060d000 rw-p 0000c000 08:09 3942120/usr/bin/cat
01a4f000-01a70000 rw-p 00000000 00:00 0[堆]
7f960e06f000-7f960e23b000 r--p 00000000 08:09 3969887/usr/lib/loce/loce-archive
7f960e23bk0-7f960e3d2000 r-xp 00000000 08:09 3935387/usr/lib/libc-2.23.so
7f960e3d2000-7f960e5d2000--p 00197000 08:09 3935387/usr/lib/libc-2.23 so
7f960e55d2000-7f960e 5d6000 r--p 00197000 08:09 3935387/usr/lib/libc-2.23.so
7f960e5d6000-7f960e5d8000 rw-p 0019b000 08:09 3935387/usr/lib/libc-2.23 so
7f960e5d8000-7f960e5dc000 rw-p 00000000 00:00 07f960e55dc000-7f960e 55ff000 r-xp 00000000 08:09 3935386/usr/lib/ld-2.23so
7f960e7ba000-7f960e 7bd000 rw-p 00000000 00:00 07f960e7dd000-7f960e 7ff000 rw-p 00000000 00:00 07f960e7ff000-7f960e 800000 r--p 00023000 08:09 3935386/usr/lib/ld-2.23so
7f960e800000-7f960e 801000 rw-p 00024000 08:09 3935386/usr/lib/ld-2.23so
7f960e801000-7f960e 802000 rw-p 00000000 00:00 07fff58c4c000-7fff58 c6d000 rw-p 00000000 00:00 0[堆栈]
7fff584.1.1.7fff585d11000 r--p 00000000 00:00 0[vvar]
7fff58d11000-7fff585d13000 r-xp 00000000 00:00 0[vdso]
ffffffffff 600000
我真的很想弄清楚为什么它不起作用,因为我已经花了几个小时的时间尝试了。谢谢
我想问题不在于直接访问p
点添加的地址。相反,您希望打印p
指向的ASCIIZ字符串,这意味着printf
将(尝试)从那里访问内存,直到遇到第一个NUL字节。很可能直到允许的数据段结束时才出现NUL。如果您首先指定a=0
,那么位于的第一个点p
应该已经是NUL,并且不应该触发任何故障。
变量p
的类型为char *
,这意味着它是一个被认为指向char
的指针。
在printf()
的第二个参数中,可以取消引用p
。因此,printf()
的第二个自变量实际上是某个单字节值。由于所使用的格式说明符是%s
,因此printf()
的第二个自变量应为char *
,并用于读取从该位置开始的字符串。
因此,从解引用p
获得的单字节值被视为地址并被解引用。因此,分段故障的发生是因为试图访问受限的内存地址,可能是0x0,即null。
另外,我认为(* char)
的演员阵容无效。若要强制转换为char *
,应使用(char *)
。在这种情况下,没有必要显式强制转换为char *
,并且强制转换是可选的。
我想访问特定地址中的[…]内容,如:
char *p = (* char)0x7ffeefad7be8; printf("%s",*p);
但是它显示出分割错误。
正如其他答案已经观察到的那样,与%s
字段描述符相对应的printf()
自变量预计为char *
。这将是p
,而不是*p
。后者是CCD_ 27所指向的CCD_。
但这几乎是一个小的语法错误,而且代码中存在更大的语义问题。C规定,整数可以转换为任何指针类型,但除了在少数情况下的外,结果是由实现定义的。特别是,C决不要求转换机器地址(无论是物理地址还是虚拟地址)的数值会产生指向该地址的指针。
即使您的实现在整数到指针转换方面的行为与您预期的一样,您随后的注释仍然显示出误解:
但我认为该地址是可访问的,因为它是我从代码[…]中获得的地址。因此,假设它在[heap]和[stack]的范围内。
仅仅因为地址在一个程序的一次运行期间是可访问的,并不意味着即使在同一程序的不同运行期间也可以访问,更不用说在完全不同的程序运行期间了。现代操作系统不允许进程随意访问内存。每个进程都有分配给它的特定虚拟地址范围,并且不能保证从一个运行到另一个运行或从一个程序到另一程序都是相同的。
底线:您试图做的事情本质上依赖于实现,通常不太可能产生任何有用的结果。您无法安全地检查内存中的随机位置。