在 C 和 C++ 中作为函数参数的 int **a 和 int a[][] 之间的确切区别是什么?

Mih*_*nea 4 c c++ parameters pointers function

我在用矩阵编写程序时遇到过这个问题,我曾经int** m声明我的矩阵 - 因为我需要动态分配,并且在我使用的函数中int a[][]。我不记得有任何问题。但是当我使用一个简单的m[6][6]矩阵时,f(int**m, int** m2, rest params)我遇到了麻烦。

它编译了,当我运行程序(带有 GCC 的代码块)时,它就崩溃了。我尝试通过添加printf()s 进行调试,但它在一个if()没有意义的块上崩溃了。从int a[][]to修改第一个函数参数int* a[6]并继续,稍后修改第二个参数,我的程序在第一次尝试时运行。通过更仔细地调试我保存的内容int m[i][j]并检查是否是垃圾值,而不是我放入的内容,我只是放入10标记某些东西。

这么多年过去了,除非我在做这样的事情时被 GCC 编译错误,否则我只会写第一个想到的方法。

在所有 4 种组合中使用int**int [][]声明变量/获取函数参数背后的逻辑是什么?我使用的大多数预定义函数都int**在函数头文件中使用。

我知道int [][]不等于int**,它是int* []正确的,但是我缺少什么?int[][]是多维数组意味着数组的数组,所有 3 种编写方式似乎都相同。因为int[][]它几乎总是要求只让第一个参数无效,就像int array[][][][]我需要将 int 数组a[][n1][n2][n3]放在函数参数中一样,对吧?它需要知道除第一个以外的多维数组的维数,因为在声明函数参数时可以毫无问题地使用int*andint[]吗?

eer*_*ika 10

C 和 C++ 中的函数参数int **aint a[][]作为函数参数之间的确切区别是什么?

int *a. 这是一个指向 int 的指针。

int **a. 这是一个指向 int 指针的指针。

int a[]在所有其他上下文中,这是一个未指定数量的 int 数组,但作为函数参数声明符,它被调整为指向 int 的指针,即在这种情况下,它与您编写的int *a.

int a[][]是一个未指定数量的未指定整数数组的数组,但这种类型是格式错误的,因为数组元素不能是未指定大小的数组。

int *a[]在所有其他上下文中,这是一个未指定数量的指向 int 的指针的数组,但作为函数参数声明符,它被调整为指向指向 int 的指针的指针,即在这种情况下,它与您编写的相同int **a

int (*a)[N] 这是一个指向 N 个整数数组的指针。

int a[][N]在所有其他上下文中,这是一个未指定数量的 N int 数组的数组,但作为函数参数声明符,它被调整为指向 N int 数组的指针,即在这种情况下,它与您编写的相同int (*a)[N].


一些例子:

void fun_1D(int*);        // argument is pointer to int
void fun_1D(int[]);       // same as above
void fun_1D(int[10]);     // same as above; note that 10 is ignored

int arr_1D[20];           // array of int
fun_1D(arr_1D);           // implicit conversion
fun_1D(&arr_1D[0]);       // same as above

void fun_2D(int (*)[20]); // note that 20 is not ignored
void fun_2D(int[][20]);   // same as above
void fun_2D(int[10][20]); // same as above; note that 10 is ignored

int arr_2D[20][20];       // array of array of int
fun_2D(arr_2D);           // implicit conversion
fun_2D(&arr_2D[0]);       // same as above

fun_1D(arr_2D[i]);        // implicit conversion
fun_1D(&arr_2D[i][0]);    // same as above

void fun_ptrs(int**);     // argument is pointer to pointer to int
void fun_ptrs(int*[]);    // same as above
void fun_ptrs(int*[10]);  // same as above; note that 10 is ignored

int *arr_ptr[20];         // array of pointers
fun_ptrs(arr_ptr);        // implicit conversion
fun_ptrs(&arr_ptr[0]);    // same as above

fun_1D(arr_ptr[i]);       // no conversion needed


// broken examples
fun_2D(arr_ptr);          // int*[20] is not int(*)[20]
fun_ptrs(arr_2D);         // int[20][20] is not int**
Run Code Online (Sandbox Code Playgroud)

注意声明为数组的函数参数如何调整为与数组在左值到右值转换时衰减到的指针类型相同的指针类型。

要记住的一些简单的经验法则:

  • 数组不是指针。
  • 指针不是数组。
  • 写成数组的函数参数实际上不是数组。它实际上被调整为指向此类数组元素的指针。在此调整之后,函数参数永远不是数组。这不适用于任何其他上下文,函数参数除外。
  • 并非每种类型都可以是数组的元素。未指定长度的数组就是这样的类型。
  • 没有“数组未指定长度”类型的对象。它们只能用在引用别处定义的数组的外部变量声明中,或用于从数组的初始化器推导出实际大小的定义中,或在将数组调整为指向的指针的函数参数声明中使用元素。

如果我在 main 中声明 int a[6][6] 并调用一个需要 int** a 的函数,它会起作用吗?

不,因为int[6][6]不是一个int**,也不会衰变为一。int[6][6]衰减到int(*)[6]我上面解释的那样。int(*)[6]并且int**不能相互转换。一个是指向数组的指针,另一个是指向指针的指针。

反过来

不,因为int[6][6]参数被调整为int(*)[6]. 有关这些不兼容的原因,请参阅上一段。

似乎int a[][]不被接受

正确的。正如我在顶部的第四段中所解释的(不包括引用)。

如果我有函数 f1(int *a) 和 f2(int a[]) 和 f2(int a[6]) 在这些情况下 sizeof (a) 会返回什么?

正如我上面所解释的,所有这些都声明了一个类型为 的参数int*sizeof a将与sizeof(int*)因为那是类型相同。


ali*_*oar 7

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

这是指向 int 指针的指针。

int a[][]
Run Code Online (Sandbox Code Playgroud)

这是 int 数组的数组,但这是无效的,因为在声明时必须知道第二个数组的维数,即第二个数组必须是完整的,因为它之后无法完成,就像那样

int a[][DIM]
Run Code Online (Sandbox Code Playgroud)


Elj*_*jay 5

C++ 继承了 C 的数组衰减为指针的行为。

这种行为真的很有帮助,直到有人突然意识到发生了一些奇怪的事情,然后有人试图弄清楚它做了什么并测试了这种行为并意识到它有点疯狂。

但是请保持冷静,一旦您意识到数组衰减为指针意味着什么,一切都会再次变得有意义。

下面是一个示例来说明差异。

static void func1(int** p) {
    (void)p;
}

static void func2(int (&a)[2][2]) {
    (void)a;
}

int main() {
    // x is a 2-dimensional array of int objects.
    int x[2][2] = {{10, 20}, {30, 40}};
    // x[0][0] is 10, and is at 0x1000 (say, for example)
    // x[0][1] is 20, and is at 0x1004
    // x[1][0] is 30, and is at 0x1008
    // x[1][1] is 40, and is at 0x100C

    // y is a 1-dimensional array of pointers.
    int* y[2] = { &x[0][0], &x[1][0] };
    // y[0] is 0x1000, and is at 0x1010 (say, for example)
    // y[1] is 0x1008, and is at 0x1018

    // x cannot decay into an int**, because it is not an array of pointers.
    // y can decay into an int**, because it is an array of pointers.
    func1(y);

    // x can be used for an int[2][2] reference parameter.
    // y cannot be used for an int[2][2] reference parameter.
    func2(x);
}
Run Code Online (Sandbox Code Playgroud)