在C语言中,**代表什么意思?

5

我有一个样例的 C 程序,我正在试图理解它。下面是源代码中的一个函数摘录:

double** Make2DDoubleArray(int arraySizeX, int arraySizeY)
{
  double** theArray;
  theArray = (double**) malloc(arraySizeX*sizeof(double*));
  int i = 0;

  for (i = 0; i < arraySizeX; i++)
    theArray[i] = (double*) malloc(arraySizeY*sizeof(double));

  return theArray;
}

我的问题是在返回类型中的**有什么意义。我知道*通常用作指针。我知道它也可以用来解除指针引用。
这让我想到double**是一个双精度值,因为它本质上是引用的解引用。我的想法正确吗?如果不是,请有人解释一下在这个例子中使用**的用法。

5
指向指针的指针 - advocateofnone
3
首先,您需要了解什么是“指针”,并停止将其与“引用”混淆,然后您将扩展您的知识到“指向指针”的内容。 - Iłya Bursov
1
从右向左阅读类型。double ** 是“指向指针的指针”。你所写的 **double 没有意义:是“双重指向指针”,因此 **double 是无效的语法。 - yellowantphil
1
也许是因为这个问题可以通过阅读 C 书中关于指针的章节来回答。不过我没有投反对票。 - yellowantphil
3
所有问题都可以通过阅读正确的书解决。这是否导致这个网站不再需要?我认为不是这样的... - Support Ukraine
显示剩余6条评论
6个回答

5
在这种情况下,double 表示类型为 double 的变量。 double* 表示指向 double 变量的指针。 double** 表示指向指向 double 变量的指针的指针。
在您发布的函数中,它用于创建一种双重指针的 double 二维数组。也就是说,它是指向 double 指针数组的指针,每个指针都指向指针数组。

1
@Jonathan 谢谢。您能详细说明为什么在这个例子的上下文中指向指针的指针是有用/必要的吗? - Brian
5
@StenSoft:不,指针不是数组。请阅读comp.lang.c FAQ的第6节。我请求您删除您的评论,因为它可能会误导其他人。认为数组实际上是指针的想法是一个普遍存在的误解,请不要帮助传播它。 - Keith Thompson
3
一个二维数组是由若干个一维数组组成的,在内存中是连续的。使用指向指针的指针可以实现类似的数据结构,每一行都是独立分配的,但称其为二维数组是有误导性的。 - Keith Thompson
这是一种旧式的“快捷方式”,它利用了C语言将数组引用简化为指向第一个元素的指针的特性来混淆代码意图。当您将C语言视为结构化的PDP-11汇编语言时,这样做是很有道理的。但是现在活跃的程序员中很少有人曾经编写过PDP-11汇编代码。 - pojo-guy
C语言最初是作为B语言(它本身是BCPL的子集)的扩展而构建的,可利用PDP-11指令集的功能,例如字节寻址能力。它最初并不打算成为可移植的。PDP-11汇编语言(像大多数汇编语言一样)不直接支持数组。您需要使用指针加寄存器偏移量。 - pojo-guy
显示剩余6条评论

4
some_type*

是指向some_type的指针。因此,

some_type**

这是一个指向某种类型的指针的指针。

通常用于模拟二维数组。

在您的情况下,第一个malloc为指向双精度数组的指针保留内存。第二个malloc为双精度数组保留内存。通过这种方式,您已经分配了可用作二维数组的内存。


4
这里有一个更为通用的答案:螺旋规则。对于这个特定的例子:
      +-----------+
      |+--------+ |
      ||  +---+ | |
      ||  ^   | | |
double** foo; | | |
   ^  |^      | | |
   |  |+------+ | |
   |  +---------+ |
   +--------------+

将其阅读为 "\"foo\" 是指向 double 指针的指针。"

在这种情况下,每个指针在语义上都是一个数组,因此表示了一个类型为double 的二维数组。


2
作者使用了一种在 C 语言中创建双精度二维数组的方法(不是唯一的方法),即创建 Y 个双精度一维数组和一个包含 X 个指向这些数组的指针的单个数组。每个 Y 数组都通过类型为 double * 的变量进行访问。然后,他创建了一个指向每个这些数组的指针的单个一维数组,并将这些指针存储在类型为 double ** 或指向指针的指针的数组中。
使用这种方法制作 2D 数组有几个优点。首先,您需要做更少的数学计算才能到达元素,甚至可以将这样的数组传递给不必知道其确切尺寸就能工作的函数。此外,您可以创建诸如三角形数组或其他子数组不必全部相同大小的形状。
唯一的缺点是它们会占用更多的内存。

更少的数学运算来访问一个元素 - 为了澄清,这意味着使用类似 theArray[x_index][y_index] 的语法来访问一个元素。 - anatolyg
另一个可能的缺点是内存不连续,这可能会减慢读取速度,具体取决于您读取元素的顺序。 - yellowantphil
更少的数学,当然可以。但是更多的间接引用和严重降低了引用局部性,这是更为重要的。现在,如果数组应该是不规则的,那可能是一个可以接受的(也许是不可避免的)决定... - Deduplicator
当我说“少一些数学计算”时,我的意思是在机器代码中像这样访问一个数组只需要两个乘以8的操作,而连续的数组则需要乘以8和内部数组大小的乘积,这可能更昂贵(尽管现在前者的额外内存访问可能已经弥补了这一点)。 - Lee Daniel Crocker

1
在您的情况下,"**" 表示指向指针的指针。我想这是不言自明的。 "**" 指向一个指针,该指针又指向一个内存位置。如果您想节省内存并且需要声明一个具有r行和c列的二维数组,而它们是可变的,则使用它非常有用。因此,以下是您需要做的:
      void create_matrix(int r,int c)
      {
           double ** matrix;
           matrix = (double **)malloc(sizeof(double *)*r);
           for(int i=0;i<r;i++ )
               matrix[i] = (double *)malloc(sizeof(double)*c);
           /* do operations on matrix */
           return ;
       }

1

*有多个含义:

  1. 指定类型中的指针。
  2. 解引用运算符。
  3. 乘法运算符。

您的示例仅在类型中使用**来定义自动变量:
double **,表示指向指针的指针-至-double


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接