读写内存位置

10

在Google上进行了大量的研究后,我找到了这个程序:

#include <stdio.h>

int main()
{
    int val;
    char *a = (char*) 0x1000;
    *a = 20;
    val = *a;
    printf("%d", val);
}

但它会在*a = 20处抛出运行时错误。

那么我该怎么样才能写入和读取特定的内存位置呢?


你确定可以写入 0x1000 吗?这是哪个平台? - Piotr Praszmo
@Banthar:Windows中的代码块 - Rasmi Ranjan Nayak
9个回答

19

你正在进行某项操作,但在你的系统上,你无法将数据写入到该内存中,导致出现了一个分段错误。

分段错误(通常缩写为 Segmentation Fault)、总线错误或访问违例,一般意味着试图访问 CPU 无法物理寻址的内存。当硬件发现有内存访问违规时,它会向操作系统发出信号。然后操作系统内核向导致异常的进程发送信号。默认情况下,接收信号的进程会转储核心并终止。也可以覆盖默认的信号处理程序,以自定义如何处理信号。

如果您想了解更多,请查阅维基百科上的 MMU 词条。

以下是从堆中合法请求内存的方法。函数 malloc() 接受要分配的字节数作为参数。请注意,每个 malloc() 应该和相应的 free() 调用进行匹配,在使用完内存后释放它。free() 调用通常应该在调用 malloc() 的同一个函数中。

#include <stdio.h>
int main()
{
    int val;
    char *a;

    a = (char*)malloc(sizeof(char) * 1);

    *a = 20;
    val = (int)*a;
    printf("%d", val);

    free(a);

    return 0;
}

你也可以通过以下简单的方式在堆栈上分配内存:

#include <stdio.h>
int main()
{
    int val;
    char *a;
    char b;

    a = &b;
    *a = 20;
    val = (int)*a;

    printf("%d", val);

    return 0;
}

我可以问一下,为什么您不只是堆栈分配一个char并获取其地址呢?对于一个简单的示例来说,这似乎过于复杂了。 - Richard J. Ross III
一个堆分配的例子几乎是必要的。这里的目标显然是理解正确的内存分配,而不是修复一个破损的程序。 - Eric des Courtis

10

这会抛出一个段错误 (SEGFAULT),因为你不知道在那个地址里放了什么东西。很可能那是内核空间,而托管环境不希望你胡乱地编写另一个应用程序的内存。你只应该编写你所知道的程序可以访问的内存,否则你的程序将在运行时出现难以解释的崩溃。


7
用户代码无法访问内核空间(环),这是现代操作系统、虚拟内存和MMU的基础。否则,你是正确的。 - Vinicius Kamakura

5
如果你在用户空间运行代码(这是你正在做的),那么你得到的所有地址都是虚拟地址,而不是物理地址。你不能仅仅假设并写入任何虚拟地址。
实际上,在虚拟内存模型中,你不能假定任何地址都是有效的地址。它取决于内存管理器向编译器实现返回有效地址,然后处理你的用户程序,而不是反过来。
为了使你的程序能够写入一个地址:
  1. 它应该是一个有效的虚拟地址
  2. 它应该对你的程序的地址空间可访问

3

你不能随意写入任何地址。你只能修改程序可以写入的内存内容。

如果您需要修改某个变量的内容,那么指针就派上用场了。

char a = 'x';
char* ptr = &a; // stored at some 0x....
*ptr = 'b'; // you just wrote at 0x....

2

权限问题,操作系统会保护内存空间防止随意访问。

您没有指定确切的错误,但我猜测您遇到了“segmentation fault”,这清楚地表明出现了内存访问违规。


1

您可以写入特定的内存位置。

但前提是您有写入该位置的权限。

您所遇到的问题是操作系统禁止您写入0x1000


我正在code::blocks中运行它。在调试时,它会出现分段错误SIGSEGV - Rasmi Ranjan Nayak
@RasmiRanjanNayak 那个信息并没有真正改变我的答案 :-) - Šimon Tóth
@RasmiRanjanNayak 不是的,它给你的是SIGSEGV(请注意拼写),这是POSIX术语,表示程序正在访问无效的内存位置,也就是分段错误。 - Lundin

1

这是将数据写入内存位置0x1000的正确方法。但在虚拟内存时代,你几乎从不知道要提前写入的实际内存位置,因此这种类型的操作很少使用。

如果您能告诉我们您试图解决的实际问题,也许我们可以提供帮助。


我是说,你为什么要尝试写入特定的内存地址?你编写的程序应该做什么? - Graeme Perrow
我参加了一次面试,他们问了我同样的问题。这就是为什么。 - Rasmi Ranjan Nayak

1

你不能随意选择一个内存位置并进行写入。该内存位置必须分配给你,并且必须可写。

一般来说,你可以使用&获取变量的引用/地址并在其上写入数据。或者你可以使用malloc()在堆上请求空间以写入数据。

这个答案只涵盖了如何在内存中写入和读取数据。但我没有涵盖如何以正确的方式执行它,以使程序正常运行。其他答案可能比我的更好地涵盖了这一点。


我知道malloc会有帮助。但是不使用malloc,怎么做呢? - Rasmi Ranjan Nayak
@RasmiRanjanNayak:这取决于应用程序。但是为了仅仅进行写入和读取(甚至崩溃程序),您可以声明局部变量或全局变量,然后获取对其的引用并将数据写入其中。 - nhahtdh
1
@RasmiRanjanNayak,你不能仅仅因为不想使用malloc就决定不使用它。如果你需要在声明变量的作用域之外访问变量,你需要使用malloc。对于局部作用域,你可以按照其他答案建议的方式在堆栈上分配。但你不能随意选择一些内存地址并写入其中。你无法控制那些地址。 - Daniel

-1

首先,您需要确定要写入的内存位置。 然后,检查您是否具有足够的权限进行写入。


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