c - C中内存中的指针布局

标签 c memory memory-management

我最近一直在搞乱指针,我想了解更多关于它们的信息,例如在使用 malloc 之后它们是如何在内存中组织的。
所以这是我目前对它的理解。

int **pointer = NULL;

由于我们明确地将指针设置为 NULL它现在指向地址 0x00 .

现在让我们说我们做
pointer = malloc(4*sizeof(int*));

现在我们有 pointer指向内存中的地址 - 比如说 pointer指向地址 0x0010 .

假设我们然后运行一个循环:
for (i = 0; i<4; i++) pointer[i] = malloc(3*sizeof(int));

现在,这就是我开始感到困惑的地方。如果我们取消引用 pointer , 通过执行 *pointer我们得到什么?我们得到 pointer[0] ?如果是这样,pointer[0] 是什么? ?

继续,现在应该是 pointer[i]包含存储在其中的地址。这才是真正让我感到困惑的地方,我将使用图像来更好地描述我认为正在发生的事情。



在您看到的图像中,如果正确,是 pointer[0]指的是地址为 0x0020 的框在里面? pointer[1] 呢? ?

如果我要打印 pointer 的内容它会告诉我0x0010 ? pointer[0] 呢? ?它会告诉我0x0020 ?

感谢您花时间阅读我的问题并帮助我了解内存布局。

最佳答案

指针复习

指针只是一个数值,它保存 T 类型值的地址。 .这意味着 T也可以是指针类型,从而创建指向指针的指针、指向指针的指针以及像 char********** 这样的疯狂事物- 这只是一个指针(T*),其中 T是指向其他东西 (T = E*) 的指针,其中 E是指向其他东西的指针(等等......)。

这里要记住的是,指针本身就是一个值,因此会占用空间。更具体地说,它(通常)是 CPU 支持的可寻址空间的大小。

例如,6502 处理器(常见于旧游戏机,如 NES 和 Atari,以及 Apple II 等)只能寻址 16 位内存,因此它的“指针”大小为 16 位.

因此,无论底层类型如何,指针都会 (usually)与可寻址空间一样大。

请记住,指针并不能保证它指向有效的内存——它只是一个恰好指定内存位置的数值。

数组刷新器

数组只是一系列 T连续可寻址内存中的元素。它是一个“双指针”(或指向指针的指针)这一事实是无害的——它仍然是一个常规指针。

例如,分配 3 个数组 T将产生一个内存块 3 * sizeof(T)字节长。

当你malloc(...)那个内存,返回的指针只是指向第一个元素。

T *array = malloc(3 * sizeof(T));
printf("%d\n", (&array[0] == &(*array))); // 1 (true)

请记住,下标运算符([...])基本上只是语法糖:
(*(array + sizeof(*array) * n)) // array[n]

指针数组

总而言之,当你这样做时
E **array = malloc(3 * sizeof(E*));

你正在做同样的事情
T *array = malloc(3 * sizeof(T));

在哪里 T真的是E* .

关于 malloc(...) 要记住两件事:
  • 它不会使用任何特定值初始化内存(使用 calloc )
  • 不能保证(甚至不常见)内存与上一次调用 malloc 返回的内存是连续的或相邻的。

  • 因此,当您使用对 malloc() 的后续调用填充先前创建的指针数组时,它们可能在内存中任意随机的位置。

    你用你的第一个 malloc() 所做的一切调用只是创建存储 n 所需的内存块。指针。而已。

    为了回答你的问题...

    If we dereference pointer, by doing *pointer what do we get? Do we get pointer[0]?



    由于pointer只是一个 int** ,并记住 malloc(...)返回您分配的内存块中第一个字节的地址,*pointer确实会评估为 pointer[0] .

    And if so, what is pointer[0]?



    同样,由于 pointer作为类型int** ,然后 pointer[0]将返回 int* 的值类型第一个 sizeof(int*) 的数字内容pointer 指向的内存块中的字节数.

    If I were to print the contents of pointer would it show me 0x0010?



    如果“打印内容”是指printf("%p\n", (void*) pointer) , 那就不要。

    既然你malloc() 'd 内存块 pointer指向,pointer本身只是一个大小为 sizeof(int**) 的值,因此将保存您的内存块地址(作为数值)malloc() 'd 居住。

    所以以上printf() call 将简单地打印该值。

    What about pointer[0]?



    再次假设您的意思是 printf("%p\n", (void*) pointer[0]) ,那么你会得到一个稍微不同的输出。

    由于pointer[0]相当于*pointer , 从而导致 pointer要取消引用,您将获得 int* 的值因此存储在第一个元素中的指针值。

    您需要进一步取消引用该指针以获取存储在您分配的第一个整数中的数值;例如:
    printf("%d\n", **pointer);
    // or
    printf("%d\n", *pointer[0]);
    // or even
    printf("%d\n", pointer[0][0]); // though this isn't recommended
                                   // for readability's sake since
                                   // `pointer[0]` isn't an array but
                                   // instead a pointer to a single `int`.
    

    关于c - C中内存中的指针布局,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43431675/

    相关文章:

    c++ - 读-处理-写的最佳缓冲区大小

    c - fork() - 多进程和系统调用

    c++ - 为什么这段 C++ 代码有效?栈内存和指针

    c - 解除分配多个内存指针的最方便的方法?

    c - 如何实现以下算法以在 c 中对动态数组进行排序?

    c - 数组返回类型

    python - 提高运行大文件的性能

    php - 什么是吃内存的 PHP 脚本

    c# - 局部变量实际上在 CLR 中分配在哪里?

    ios - @try-@finally 保证在处理 ARC 未跟踪的对象时消除内存泄漏