在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的数组的指针。
int a[][N]
将在所有其他情况下是未指定数量的N个int数组的数组,但作为函数参数声明符,它被调整为指向N个int数组的指针,即在这种情况下,它与写作int (*a)[N]
相同。
一些例子:
void fun_1D(int*);
void fun_1D(int[]);
void fun_1D(int[10]);
int arr_1D[20];
fun_1D(arr_1D);
fun_1D(&arr_1D[0]);
void fun_2D(int (*)[20]);
void fun_2D(int[][20]);
void fun_2D(int[10][20]);
int arr_2D[20][20];
fun_2D(arr_2D);
fun_2D(&arr_2D[0]);
fun_1D(arr_2D[i]);
fun_1D(&arr_2D[i][0]);
void fun_ptrs(int**);
void fun_ptrs(int*[]);
void fun_ptrs(int*[10]);
int *arr_ptr[20];
fun_ptrs(arr_ptr);
fun_ptrs(&arr_ptr[0]);
fun_1D(arr_ptr[i]);
fun_2D(arr_ptr);
fun_ptrs(arr_2D);
注意,声明为数组的函数参数在左值到右值转换时会被调整为相同的指向数组将要衰变为的指针类型。
一些简单的经验法则:
- 数组不是指针。
- 指针不是数组。
- 一个写作数组的函数参数实际上不是一个数组。它实际上被调整为指向这种数组元素的指针。在此调整之后,函数参数永远不是数组。这不适用于任何其他情况,除了函数参数。
- 并非每种类型都可以是数组的元素类型。未指定长度的数组就是这样的类型。
- 不存在“数组长度未指定”的对象。它们只能用于引用在其他地方定义的数组的extern变量声明中,或在从数组的初始值推断出实际大小的定义中,或在函数参数声明中,其中该数组被调整为指向元素的指针。
如果我在main中声明int a[6][6]并调用期望int** a的函数,它能正常工作吗?
不行,因为int[6][6]
不是int**
,也不能衰变为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*)
相同,因为那就是这个类型。
int**
声明了我的矩阵,但是int **
并不会创建一个二维数组。请参考这篇文章:正确分配多维数组。 - Andrew Henleint **
或int [][]
,这也是C++开始变得有趣的时刻。而且我很高兴我不必使用C ;) - 463035818_is_not_a_number