多维数组作为函数参数的形式
今天在看CSAPP的时候,直接敲入了书中的代码片段(P582),没有多加思考,却出现了段错误coredump,然后再纠结:被调用函数是否可以访问到主函数中的数据,函数中的自动变量存在栈中?最后才知道是函数声明的问题。所以通过这篇文章理清了数组作为参数时如何实践,同时不要忽略编译器给我们的警告。
在main中调用matvec1出现问题:
$vi 2.c
$ gcc 2.c csapp.o -lpthread
2.c: In function ‘main’:
2.c:49:2: warning: passing argument 1 of ‘matvec1’ from incompatible pointer type [enabled by default]
2.c:3:6: note: expected ‘int **’ but argument is of type ‘int (*)[3]’
$ ./a.out
Segmentation fault (core dumped)
int *matvec1(int **A, int *x, int n){
int i,j;
int *y = Malloc(n * sizeof(int));
for(i=0; i<n ;i++)
y[i] = 0;
for(i=0; i<n; i++)
for(j=0; j<n; j++){
y[i] += A[i][j] * x[j];
}
return y;
}
在一维数组作为函数参数时,既可以写成数组形式也可以写成指针形式,但是对于多维数组上述形式是错误的,只有第一维可以搞成指针形式,要特别注意。
可以选的形式有:
void func(int (*A)[10])
void func(int A[][10])
此时的程序可以正确执行。
int *matvec2(int A[][3], int *x, int n){
int i,j;
int *y = Malloc(n * sizeof(int));
for(i=0; i<n ;i++)
y[i] = 0;
for(i=0; i<n; i++)
for(j=0; j<n; j++){
y[i] += A[i][j] * x[j];
}
return y;
}
int *matvec3(int (*A)[3], int *x, int n){
int i,j;
int *y = Malloc(n * sizeof(int));
for(i=0; i<n ;i++)
y[i] = 0;
for(i=0; i<n; i++)
for(j=0; j<n; j++){
y[i] += A[i][j] * x[j];
}
return y;
}
但是,这样的情况就限制了这个函数只能处理的数组的类型,没有弹性,所以最优雅的做法是转为一维数组的逻辑来思考(理解行优先存储)。
func(&A[0][0][0], ....);
void func(int *p, int X, int Y, int Z){
int i, j, k;
// todo
p[i*Y+j*Z+k] = AAA;
//todo
}
所以修改后的用例如下:
int *matvec4(int *A, int *x, int n){
int i,j;
int *y = Malloc(n * sizeof(int));
for(i=0; i<n ;i++)
y[i] = 0;
for(i=0; i<n; i++)
for(j=0; j<n; j++){
y[i] += A[i*n + j] * x[j];
}
return y;
}
int main(){
int A[3][3] = {{1,2,3}, {4,5,6}, {7,8,9}};
int x[3] = {2,3,4};
int i, n = 3;
int *y = NULL;
//y = matvec3(A, x, n);
y = matvec4(&A[0][0], x, 3);
printf("Ax = [");
for(i=0; i<n ;i++)
printf("%d," , y[i]);
printf("]\n");
free(y);
return 0;
}