首页 > 解决方案 > int **a 和 int a[][] 作为 C 和 C++ 中的函数参数之间的确切区别是什么?

问题描述

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

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

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

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

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

标签: c++cfunctionpointersparameters

解决方案


C 和 C++ 中的函数参数int **a和函数参数之间的确切区别是什么?int 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**

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

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

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

如果我在 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) 会返回什么?

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


推荐阅读