Isr*_*ael 2 c pointers function multidimensional-array pointer-to-pointer
我有这样的功能:
void myfunc(int** arr, int n) {
int i, j;
for(i=0; i<n; ++i) {
for(j=0; j<n; ++j) {
printf("%d,", *(arr + i*n + j) ); // Print numbers with commas
}
printf("\n"); // Just breakline
}
}
Run Code Online (Sandbox Code Playgroud)
在其他函数中我有一个二维数组,如下所示:
int main() {
int seqs[8][8] = {
{0, 32, 36, 52, 48, 16, 20, 4},
{0, 16, 20, 52, 48, 32, 36, 4},
{0, 32, 36, 44, 40, 8, 12, 4},
{0, 8, 12, 44, 40, 32, 36, 4},
{0, 32, 36, 38, 34, 2, 6, 4},
{0, 2, 6, 38, 34, 32, 36, 4},
{0, 32, 36, 37, 33, 1, 5, 4},
{0, 1, 5, 37, 33, 32, 36, 4}
};
// Call to myfunc
myfunc(seqs, 8); // This is the idea
}
Run Code Online (Sandbox Code Playgroud)
但编译器抛出这个错误:
lab.c: In function 'main':
lab.c:75:5: warning: passing argument 1 of 'myfunc' from incompatible pointer type [enabled by default]
lab.c:4:6: note: expected 'int **' but argument is of type 'int (*)[8]'
Run Code Online (Sandbox Code Playgroud)
将此array(seqs)传递给function(myfunc)的正确方法是什么?
在C99或C11中,你会这样做:
void myfunc(int n, int arr[n][n])
{
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
printf("%d,", arr[i][j]);
printf("\n");
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,大小在数组之前,而不是在数组之后.此功能可以正常使用:
int main(void)
{
int seqs[8][8] =
{
{ 0, 32, 36, 52, 48, 16, 20, 4 },
{ 0, 16, 20, 52, 48, 32, 36, 4 },
{ 0, 32, 36, 44, 40, 8, 12, 4 },
{ 0, 8, 12, 44, 40, 32, 36, 4 },
{ 0, 32, 36, 38, 34, 2, 6, 4 },
{ 0, 2, 6, 38, 34, 32, 36, 4 },
{ 0, 32, 36, 37, 33, 1, 5, 4 },
{ 0, 1, 5, 37, 33, 32, 36, 4 },
};
myfunc(8, seqs);
int matrix3x3[3][3] = { { 1, 2, 3 }, { 2, 4, 6 }, { 3, 6, 9 } };
myfunc(3, matrix3x3);
}
Run Code Online (Sandbox Code Playgroud)
有人问我:
你的例子确实看起来确实好多了,但它是否定义明确?难道
n真的保证之前进行评估int arr[n][n]?功能参数的评估顺序不是未指定的行为吗?
旧标准(ISO/IEC 9899:1999)在§6.7.5.2*数组声明符*中说:
5 如果size是一个不是整数常量表达式的表达式:如果它出现在函数原型范围的声明中,则将其视为替换为
*; 否则,每次评估它时,其值应大于零.可变长度数组类型的每个实例的大小在其生命周期中不会改变.如果size表达式是运算sizeof符操作数的一部分,并且更改size表达式的值不会影响运算符的结果,则无法指定是否计算size表达式.
它给出了一个例子(它是非规范性文本,因为它是一个例子,但强烈表明了预期的内容):
示例4可变修改(VM)类型的所有声明必须处于块范围或函数原型范围.使用
static或extern存储类说明符声明的数组对象不能具有可变长度数组(VLA)类型.但是,使用static存储类说明符声明的对象可以具有VM类型(即指向VLA类型的指针).最后,使用VM类型声明的所有标识符必须是普通标识符,因此不能是结构或联合的成员.Run Code Online (Sandbox Code Playgroud)extern int n; int A[n]; // invalid: file scope VLA extern int (*p2)[n]; // invalid: file scope VM int B[100]; // valid: file scope but not VM void fvla(int m, int C[m][m]); // valid: VLA with prototype scope void fvla(int m, int C[m][m]) // valid: adjusted to auto pointer to VLA { typedef int VLA[m][m]; // valid: block scope typedef VLA struct tag { int (*y)[n]; // invalid: y not ordinary identifier int z[n]; // invalid: z not ordinary identifier }; int D[m]; // valid: auto VLA static int E[m]; // invalid: static block scope VLA extern int F[m]; // invalid: F has linkage and is VLA int (*s)[m]; // valid: auto pointer to VLA extern int (*r)[m]; // invalid: r has linkage and points to VLA static int (*q)[m] = &B; // valid: q is a static block pointer to VLA }
还有其他示例显示可变修改的功能参数.
另外,在§6.9.10 函数定义中,它说:
10进入函数时,将评估每个可变修改参数的大小表达式,并将每个参数表达式的值转换为相应参数的类型,就像通过赋值一样.(数组表达式和函数指示符作为参数在调用之前转换为指针.)