为什么有指向指针的指针(int ** a)?

时间:2010-02-01 05:45:15

标签: c++ pointers

int **a = malloc2d(M, N) // dynamically allocates a 2D array

拥有 int ** a 副int * a的目的是什么?我知道动态分配需要指针,但为什么有一个指向指针的指针?

对于三维数组,它将是:

int ***a

7 个答案:

答案 0 :(得分:8)

由于多种原因,您需要一个指向指针的指针。

在您给出的示例中,双指针用于存储2D数组。

C中的2D数组被视为1D数组,其元素为1D 数组(行)。

例如,T的4x3数组(其中“T”是某种数据类型)可以 声明:“T mat [4] [3]”,并由以下描述 计划:

                       +-----+-----+-----+
  mat == mat[0]   ---> | a00 | a01 | a02 |
                       +-----+-----+-----+
                       +-----+-----+-----+
         mat[1]   ---> | a10 | a11 | a12 |
                       +-----+-----+-----+
                       +-----+-----+-----+
         mat[2]   ---> | a20 | a21 | a22 |
                       +-----+-----+-----+
                       +-----+-----+-----+
         mat[3]   ---> | a30 | a31 | a32 |
                       +-----+-----+-----+

另一种情况是,当你传递一个指向函数的指针时,你希望该函数分配该指针。为此,您必须指向变量的地址,因此指向指针

void make_foofoo(int** change) {
    *change = malloc(4);
}

答案 1 :(得分:7)

在C中,指向类型T的指针指向存储类型T的某些数据的位置。为了使事情具体化,我将在下面讨论T = int

指针的最简单用法可能是指向一个值:

int a = 42;
int *pa = &a;

现在,*paa都是相同的,等于42。此外,*papa[0]都是等效的:例如,您可以这样做:

*pa += 1; /* a is 43 */
pa[0] += 1; /* a is 44 */
a += 1; /* a is 45 */

实际上,C编译器会自动将pa[0]转换为*(pa+0)

指针可以指向数据序列中的位置:

int arr[] = { 1, 2, 3 }; /* 3 ints */
int *parr = arr; /* points to 1 */

现在,我们的记忆如下:

            +---+---+---+
       arr: | 1 | 2 | 3 |
            +---+---+---+
 +------+     |
 | parr | ----+
 +------+

parr是一个指针,指向上图中arr的第一个元素。顺便说一下,parr周围也有一个框,因为我们需要将对象parr存储在内存中的某个位置。 parr的值是arr的第一个元素的地址。

现在,我们可以使用parr来访问arr

的元素
arr[0] == parr[0]; /* true */
parr[1]++; /* make arr[1] equal to 3 */

因此,指针可用于表示“我指向某些对象的连续存储中的n个元素中的第一个”。当然,人们必须知道这个方案有多少对象可以工作:但是一旦我们记得这样做,这是一种非常方便的方式来访问C中的内存。

指针也可以指向动态分配的内存:

#include <stdlib.h>
size_t n;
/* now, obtain a value in n at runtime */
int *p = malloc(n * sizeof *p);

如果malloc()调用成功,p现在指向分配给10 int的连续区域中的第一个。我们现在可以在我们的计划中使用p[0]p[n-1]

你可能知道上面的大部分或全部内容:-),但是,上述内容有助于理解我接下来要说的内容。

还记得我们说指针可以指向相同类型的连续对象序列吗? “相同类型”也可以是另一种指针类型。

#include <stdlib.h>
int **pp;
pp = malloc(3 * sizeof *pp);

现在,pp指向int *。回到我们之前的图片:

            +------+------+------+
            |      |      |      |
            +------+------+------+
 +------+     |
 |  pp  | ----+
 +------+

并且3个框中的每一个都是int *,它可以指向int s的连续序列的第一个元素:

for (i=0; i < 3; ++i)
    pp[i] = malloc((i + 1) * sizeof *ppi[i]);

在这里,我们为pp[0]中的一个int,pp[1]中的2个和pp[3]中的3个分配了空间:

             +------+         +---+
 pp -------->|      |-------->|   |
             +------+         +---+---+
             |      |-------->|   |   |
             +------+         +---+---+---+
             |      |-------->|   |   |   |
             +------+         +---+---+---+

因此,pp[0]是指向一个int的指针,int是动态分配的int块中唯一的int。换句话说,pp[0][0]int,并指向上方最顶部的“width-3”框。同样,pp[1][0]pp[1][1]都有效,是pp[0][0]框下方的两个框。

指向指针的最常见用法是在运行时创建一个二维“数组”:

int **data;
size_t i;
data = malloc(n * sizeof *data);
for (i=0; i < n; ++i)
    data[i] = malloc(m * sizeof *data[i]);

现在,假设所有malloc()成功,data[0] ... data[n-1]是有效int *值,每个值都指向一个单独的m个连续长度int个对象。

但是,正如我在上面所示,指向指针的指针不需要在每个“行”中具有相同的“元素数”。最明显的例子是argv in main()

到目前为止,你可以猜到,一个“3级深度”指针,例如int ***p;是可以的,可以在C中使用。

答案 2 :(得分:2)

为了好玩,这是一个*****示例:

  1. 我们有一个3d纹理(体积纹理) - 3个维度,因此***
  2. 纹理中的每个体素都有一个颜色(*
  3. 纹理是动画的,有时间帧数(*
  4. 因此我们有tex [2] [3] [10] [2] [10] ....这是:

    1. 在3D中协调2,3,10
    2. 颜色2(绿色)
    3. 第10帧
    4. 要传递具有修改权限的数据,您需要传递int****** ...有趣!的xD

      (这就是我喜欢struct和类的原因....)

答案 3 :(得分:1)

帮助绘制图片。想象一个一维数组,其中每个元素都包含一个指针。这些指针中的每一个都指向另一个一维数组。 malloc2d不是标准的库函数,但我猜它返回了一个以这种方式构造的二维数组。

答案 4 :(得分:1)

您可以使用它来创建2维数组, 有点像数学矩阵或棋盘。 因此,您几乎可以存储数据表。

答案 5 :(得分:1)

普通C数组是指向内存块的指针。

2D数组是指向数组每一行指针列表的指针。

所以,指向指针的指针。

答案 6 :(得分:0)

你只传递指针的大小(通常是32位或64位),而不是整个对象。