C中内存中的指针布局

时间:2017-04-15 21:57:32

标签: 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吗?

感谢您抽出宝贵时间阅读我的问题,并帮助我了解内存布局。

2 个答案:

答案 0 :(得分:1)

指针刷新

指针只是一个数值,用于保存类型T的值的地址。这意味着T也可以是一个指针类型,从而创建指针指针,指针到指针指针,以及像char**********这样的疯狂事物 - 它只是一个指针({ {1}})其中T*是指向其他内容的指针(T),其中T = E*是指向其他内容的指针(依此类推......)。

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

例如,6502处理器(常见于旧游戏机,如NES和Atari,以及Apple II等)只能处理16位内存,因此它的指针和# 34;是16位大小。

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

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

阵列刷新

数组只是连续可寻址内存中的一系列E元素。事实上,它是一个双指针&#34; (或指向指针的指针)是无害的 - 它仍然是一个常规指针。

例如,分配3 T的数组将导致一个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*要记住的两件事:

  1. 它没有使用任何特定值初始化内存(使用calloc
  2. 内存不能保证(甚至不常见)内存与前一次调用malloc(...)所返回的内存相邻或相邻
  3. 因此,当您使用malloc的后续调用填充先前创建的指针数组时,它们可能位于内存中的任意随机位置。

    您在第一次malloc()调用时所做的只是创建存储malloc()指针所需的内存块。那就是它。

    回答你的问题......

      

    如果我们取消引用n,那么我们可以通过pointer得到什么?我们得到*pointer吗?

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

      

    如果是,那么pointer[0]是什么?

    同样,由于pointer[0]pointer类型,因此int**将返回值pointer[0]的值,其中包含第一个int*字节的数字内容在sizeof(int*)指向的内存块中。

      

    如果我要打印pointer的内容,它会显示pointer吗?

    如果通过&#34;打印内容&#34;你的意思是0x0010,然后是。

    由于printf("%p\n", (void*) pointer)指向malloc()指向的内存块,pointer 本身只是一个大小为{{{1}的值1}},因此将保存您pointer所居住的内存块所在的地址(作为数值)。

    因此,上述sizeof(int**)调用只会打印出该值。

      

    malloc()怎么样?

    再假设您的意思是printf(),那么您的输出会略有不同。

    由于pointer[0]相当于printf("%p\n", (void*) pointer[0]),因此导致pointer[0]被取消引用,您将获得*pointer的值,从而获得指针值存储在第一个元素中。

    您需要进一步取消引用该指针以获取存储在您分配的第一个整数中的数值;例如:

    pointer

答案 1 :(得分:0)

  

如果我取消引用pointer,通过*pointer我会得到什么? pointer[0]

  

如果是,那么pointer[0]是什么?

使用您的定义:0x0020

  

在您看到的图片中,如果正确

对我来说似乎是正确的。

  

pointer[0]是指其中包含地址0x0020的框吗?

仍然是。

  

pointer[1]怎么样?

此时,我想您可以猜到它会显示:0x002c

进一步

如果要检查内存的管理方式以及指针的外观,可以使用gdb。它允许逐步运行程序并执行各种操作,例如显示变量的内容。这是GNU gdb的主页。快速的互联网搜索应该可以找到许多gdb教程。

您还可以使用printf行显示c中指针的地址:

int *plop = NULL;
fprintf(stdout, "%p\n", (void *)pointer);

注意:不要忘记包含<stdio.h>