【问题标题】:Confused about Pointers to Pointers and Dynamic Memory Allocation对指针指针和动态内存分配感到困惑
【发布时间】:2013-12-25 21:11:39
【问题描述】:

我很难完全理解发生了什么。

这就是我阅读底部代码的方式。

  1. 将 A 定义为指向一个指针地址的指针,该指针指向 双地址。

  2. 在堆上分配 4 个内存块,每个内存块可以容纳一个 地址为双。返回分配的第一个块的地址 到 A.

  3. 在堆上分配 6 个内存块,每个内存块可以容纳一个 double 数据类型并返回 4 个中每一个的第一个块的地址 较早分配的块。

  4. 变量 A 仍然包含四个块中第一个块的地址 假设 A[0] 改变了指向地址的值的指针 由 A 而不是 A 本身。

现在这是连接在底部的图表的来源。假设我想访问存储在红色块中的数据。我该怎么做?

下面的代码可以工作吗?

double data = *(*(A + 3) + 2);

我的逻辑是 A 是一个指针,递增 3 应该将地址增加大小为 (double *) 的字节数。取消引用地址(A + 3),我将获得第一个块的地址(假设它没有重新分配)。通过将结果地址增加 2 并取消引用该地址,我应该获得红色块处的值。

所以如果我理解正确的话,1 + M 指针被存储在内存中。为什么?如果目标是存储 MxN 数据,为什么我需要 1 + M 指针来这样做?如果我想定义不同大小的行,额外的指针似乎会有所帮助,但目标是定义一个矩形数据数组。

const int M = 4;
const int N = 6;
double **A;

A = malloc(M*sizeof(double *));

for (i = 0; i < N; i++) {
    A[i]= malloc(N*sizeof(double));
}

图表:

旁注: 我是电气工程专业的学生,​​在某种程度上不熟悉 C 语言和正式的编程实践。我知道我对这么简单的代码行很迂腐,但我想确保我正确理解指针和内存分配。乍一看,它们很难理解。这是我的教授给我的矩阵乘法代码的一部分,我想将指针传递给一个函数并让它访问和修改内存中的正确值。个人希望看到此代码的二维数组,但我认为这是有充分理由的。

【问题讨论】:

    标签: c pointers memory memory-management


    【解决方案1】:

    您也可以将它连续存储,然后只做数学运算,而不是让编译器为您做它

    所以:

    double * A = malloc (M * N * sizeof(double));
    
    double get(double * what, cur_x, cur_y, max_x, max_y)
    {
        return *(what+cur_x*max_y+cur_y);
    }
    

    这将保存所有间接,因为您知道大小

    如果您不需要动态分配大小,这就是

    double A[17][14] 会在堆栈上为你做的

    【讨论】:

      【解决方案2】:

      是的,double data = *(*(A + 3) + 2); 可以工作,并且可以访问“红色”替身。

      我猜你的教授很快就会告诉你A[3][2] 也很有效,更容易阅读,比*(*(A + 3) + 2); 更可取

      吸取的教训(还没有,但是你的教授试图教给你的东西):在 C 中,多维数组不是类似于 C 中的“具有 N 列和 M 行的表” ,所有的数组都是真正的指针,而多维数组是作为指针的指针来实现的。每当您写A[3][2]*(*(A + 3) + 2) 时,这就是内部真正发生的事情。这反过来又解释了为什么不能在一个语句中分配 N*M 矩阵;您必须先分配“行指针”,然后为每个行指针分配“列”。

      【讨论】:

      • “C,所有数组都是真正的指针” 不。数组将衰减为指针,数组下标适用于指针,但它们是not the same“你不能在一个语句中分配 NM 矩阵”* 是的,你可以:double A[M][N];,尽管对于大矩阵,你不想在堆栈上分配它。使用 VLA 你可以使用double (*A)[N] = malloc(M * sizeof *A);
      • 我想我只是epimone,我在主帖中所说的是一个链表,对吗?所有数组都是链表?
      • 不,数组是可以连续寻址的内存块:int arr[10] = {...}; 然后您可以访问arr[0]arr[1] 直到arr[9]。这些语句相当于:*(&amp;arr[0] + 0)*(&amp;arr[0] + 1) 等(&amp;arr[0] 是第一个元素的地址,如果我写了*(arr + 1),它会超过数组末尾的 1,你也可以这样做:@ 987654337@ 然后使用 *(ptr + 0), *(ptr + 1) 由于数组到指针的衰减)。双指针看起来像一个链表,但与真正的 LL 不同的是,除了它指向的地址之外,指针本身没有(其他)数据。
      • @Altermeris 更正我上一条评论:*(arr + 1) 等同于*(&amp;arr[0] + 1),因此不需要获取第一个元素的地址。我不知道为什么我不这么认为。
      【解决方案3】:

      malloc(M*sizeof(double *)) 说:“给我一个指向 M 双指针的指针。” malloc(N*sizeof(double)) 说:“给我一个指向 N 双打的指针。” 现在注意这个错误:

      for (i = 0; i < N; i++) {
          A[i]= ...;
      }
      

      A 指向 M 双指针数组,但您正在向其中写入 N 个条目(其中每个条目都是指向 N 双打)。如果M &gt; N 你浪费空间,如果M &lt; N 你使用了你没有请求写入权限的空间。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-03-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-12
        • 2015-02-05
        相关资源
        最近更新 更多