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

Bra*_*don 6 c++ pointers

int **a = malloc2d(M, N) // dynamically allocates a 2D array
Run Code Online (Sandbox Code Playgroud)

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

对于三维数组,它将是:

int ***a
Run Code Online (Sandbox Code Playgroud)

Ami*_*shk 8

出于几个原因,您需要指向指针的指针.

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

C中的2D数组被视为一维数组,其元素是一维数组(行).

例如,Tx的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 |
                       +-----+-----+-----+
Run Code Online (Sandbox Code Playgroud)

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

void make_foofoo(int** change) {
    *change = malloc(4);
}
Run Code Online (Sandbox Code Playgroud)


Alo*_*hal 7

在C中,指向类型的指针指向存储T某些类型数据的位置T.为了保持具体,我将在T = int下面讨论.

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

int a = 42;
int *pa = &a;
Run Code Online (Sandbox Code Playgroud)

现在,*paa都是相同的,等于42.此外,*papa[0]都是相同的:因此,举例来说,你可以这样做:

*pa += 1; /* a is 43 */
pa[0] += 1; /* a is 44 */
a += 1; /* a is 45 */
Run Code Online (Sandbox Code Playgroud)

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

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

int arr[] = { 1, 2, 3 }; /* 3 ints */
int *parr = arr; /* points to 1 */
Run Code Online (Sandbox Code Playgroud)

现在,我们的记忆如下:

            +---+---+---+
       arr: | 1 | 2 | 3 |
            +---+---+---+
 +------+     |
 | parr | ----+
 +------+
Run Code Online (Sandbox Code Playgroud)

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

现在,我们可以parr用来访问以下元素arr:

arr[0] == parr[0]; /* true */
parr[1]++; /* make arr[1] equal to 3 */
Run Code Online (Sandbox Code Playgroud)

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

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

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

如果malloc()呼叫成功,则p现在指向分配10 int秒的连续区域中的第一个.我们可以使用p[0]通过p[n-1]现在在我们的节目.

你可能知道上面的大部分或全部:-),但是,上面的内容有助于理解我接下来会说些什么.

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

#include <stdlib.h>
int **pp;
pp = malloc(3 * sizeof *pp);
Run Code Online (Sandbox Code Playgroud)

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

            +------+------+------+
            |      |      |      |
            +------+------+------+
 +------+     |
 |  pp  | ----+
 +------+
Run Code Online (Sandbox Code Playgroud)

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

for (i=0; i < 3; ++i)
    pp[i] = malloc((i + 1) * sizeof *ppi[i]);
Run Code Online (Sandbox Code Playgroud)

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

             +------+         +---+
 pp -------->|      |-------->|   |
             +------+         +---+---+
             |      |-------->|   |   |
             +------+         +---+---+---+
             |      |-------->|   |   |   |
             +------+         +---+---+---+
Run Code Online (Sandbox Code Playgroud)

所以,pp[0]是指向一个的指针int,这intint动态分配的ints 块中的唯一指针.换句话说,pp[0][0]是一个int,并指向上面最顶部的"宽度-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]);
Run Code Online (Sandbox Code Playgroud)

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

但是,正如我在上面所示,指向指针的指针不需要在每个"行"中具有相同的"元素数量".最明显的例子是argvmain().

到目前为止,你可以猜到,一个"3级深度"指针,如int ***p;可以,可以在C中使用.