【问题标题】:How does malloc know how much memory space is treated for an index?malloc 如何知道索引处理了多少内存空间?
【发布时间】:2021-11-26 04:33:27
【问题描述】:

当我们使用malloc 时,它返回一个指针,指向传递给malloc 的固定大小内存地址的开头。例如,malloc(40) 会抛出一些 40 字节长的未初始化内存。问题是,我已经看到人们对这段内存进行索引的代码示例。我的问题是,malloc 如何定义索引的大小?

以这段代码为例,

#include <stdio.h>
#include <stdlib.h>

int main()
{   
    char **array;
    array = malloc(3 * sizeof(char *));

    for (int i=0; i < 3; i++) {
        array[i] = malloc(10);
    }
    
    for (int i=0; i<10; i++) {
        free(array[i]);
    }
    free(array);
    return 0;
}

我首先想解释一下我认为正在发生的事情,并希望有人能纠正我的任何错误想法。

char **array 创建变量“array”,它将成为一个指向字符指针的指针。这意味着,如果我们取消引用该值,它将为我们提供存储 char 的内存地址位置。

array = malloc(3 * sizeof(char *)) 。让我们在这里假设sizeof(char *) 将始终返回 8。继续下去,这将创建一个 32 字节长的未初始化内存。他们这里的关键点是它是 32 字节长,它如何处理可索引的大小?

array[i] = malloc(10) 是我在这里感到困惑的一部分。我们有一块 32 字节长的未初始化内存,我们如何索引它?

我有一个想法想提一下,希望有人能纠正我的任何误解。

      0x02                     0x0A                 0x12
[     0x90             |       0x91           |     0x92           ]
 <-- sizeof(char*)  ->  <-- sizeof(char*)  ->  <-- sizeof(char*)  ->
       ^
       |  
       |
    0x01 (memory address of variable array) (array - points to 0x02)

-- Random memory locations

0x90 -- | Starting from the memory address location 0x90, the next sizeof(char) bytes will representing the value in this memory address location.
['c']

0x91
['a']

0x92
['t']

根据我的理解,malloc 将知道我们对初始指针所做的转换的可索引大小,即char** array 内部的char*。这意味着,我们从malloc(40) 返回的指针将指向,在本例中,位于0x02(数组的开头)的内存地址空间。

每次我们执行array[i] 操作时,我们实际上是在执行0x02 + sizeof(char*) * i,这会将指针推到新位置的开头。这意味着例如,当我们执行array[1] 时,我们实际上正在执行0x02 + sizeof(char*) * 1,这会将我们推向0x02 + 8 (0x0A)。这意味着从内存地址位置0x0A 开始,下一个sizeof(char *) 字节将作为索引 存储在内存中的这个位置。在这个例子中它是一个char *,在我的例子中我写了0x90,这意味着内存中的某个其他位置0x90下一个sizeof(char),即1个字节将具有实际值。表示“c”的实际值(例如),但这可能位于内存中的其他位置,与 malloc 无关。

使用这个公式,我们可以得到一个从 malloc 返回的整数数组,例如 int* ten_int_array = malloc(10 *sizeof(10))。现在公式将调整为ten_int_array + sizeof(int) * i。这将使 malloc 不是固定大小的可索引。

感谢您的任何回复,我正在尝试在这里验证我的假设。

【问题讨论】:

  • malloc无关。进行索引的不是malloc。它是编译器。当代码进行索引时,编译器将根据指针的类型生成正确的偏移量。 malloc 所做的只是分配您告诉它的内存大小(可能更多用于簿记和对齐)。所以不完全清楚你的问题是什么。
  • 当你有一个T * 并从中索引时,你访问内存位置就好像它包含T 的连续元素数组一样。
  • 指针的大小并不重要。指针只是一个内存地址。重要的是编译器在计算数组的偏移量时会做什么。它通过将数组索引乘以数组的元素大小来做到这一点。结果数字是从存储在指针中的内存地址到数组中的索引元素的偏移量(以字节为单位)。
  • 所有 malloc 所做的就是分配一块您请求的大小的内存块,然后将内存地址返回到该块的第一个字节。
  • 阅读这些 cmets,如果我要在一个公式中将其隔开,它将是 T* example = malloc(10 * sizeof(T)),那么 T[i] 实际上就是 example + sizeof(T) * i

标签: c malloc


【解决方案1】:

这就是正在发生的事情。假设您在 64 位系统上运行它,其中内存地址需要 8 个字节(64 位)。

char *str; 声明了一个由* 表示的指针变量,它可以指向内存中的某个位置。按照上述约定,它应该是 8 个字节大。编译器知道它应该指向的对象是char。它完全不知道在这个位置之后或之前是否应该有其他字符,只有程序员才知道。

所以,str = malloc(10); 分配了足够的内存空间来保存 10 个字符,包括以“0”结尾的字符。内存地址赋值给指针变量str

char **array; 将指针 * 声明到指针 *。这又是一个 8 字节变量,正如编译器所知,它指向另一个本身指向 char 的指针。与上一个类似,它不知道是否有更多的指针与它应该指向的指针相邻。

array = malloc(3 * sizeof(char*)); 在内存中分配了足够的空间来保留 3 个指向 char 的指针。分配结果将分配给array

在“c”运算符中,[] 应用于指针类似于应用于数组变量。所以array[1] 从上面分配的内存中返回一个指针#2。

array[i] = malloc(10); 为 10 个字符的字符串分配内存,并将结果分配给 array[i] 指向的指针。 free(array[i]) 释放此内存。

因此,您有一个两级动态结构。

           |-malloc(3 * sizeof (char*)) == 24 bytes
           |
           V
array --> [0] --> malloc(10) == 10 bytes
          [1] --> malloc(10)
          [2] --> malloc(10)

所以,当你释放的时候,你需要先free(array[i]) //0..2 然后free(array) 因为释放数组后,它指向的内存也会失效,你不能使用它。

【讨论】:

    猜你喜欢
    • 2014-12-13
    • 1970-01-01
    • 2015-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-27
    • 2012-05-10
    • 2016-10-06
    相关资源
    最近更新 更多