所以...我在main上有一个动态分配的数组:
int main()
{
int *array;
int len;
array = (int *) malloc(len * sizeof(int));
...
return EXIT_SUCCESS;
}
我还想构建一个对这个动态分配的数组做一些事情的函数。 到目前为止,我的职能是:
void myFunction(int array[], ...)
{
array[position] = value;
}
如果我将其声明为:
void myFunction(int *array, ...);
我还能做到:
array[position] = value;
或者我必须这样做:
*array[position] = value;
...
另外,如果我正在使用动态分配的矩阵,哪一个是声明函数原型的正确方法:
void myFunction(int matrix[][], ...);
或者
void myFunction(int **matrix, ...);
...
答案 0 :(得分:6)
如果我将其声明为:
void myFunction(int *array, ...);
我还能做到:
array[position] = value;
是的 - 这是合法的语法。
另外,如果我正在使用动态分配的矩阵,那么哪一个 声明函数原型是正确的:
void myFunction(int matrix[][], ...);
或者
void myFunction(int **matrix, ...);
...
如果您正在使用多个维度,则必须声明函数声明中除第一个维度之外的所有维度的大小,如下所示:
void myFunction(int matrix[][100], ...);
此语法不会按您的意图执行:
void myFunction(int **matrix, ...);
matrix[i][j] = ...
这声明了一个名为matrix
的参数,它是指向int的指针;尝试使用matrix[i][j]
取消引用可能会导致分段错误。
这是在C中使用多维数组的许多困难之一。
以下是解决此主题的有用SO问题: Define a matrix and pass it to a function in C
答案 1 :(得分:1)
我还能做到:
array[position] = value;
是的,因为索引运算符p[i]
与*(ptr + i)
完全相同。实际上,您可以写5[array]
而不是array[5]
,它仍然有效。在C数组中实际上只是指针。使数组定义与指针不同的唯一因素是,如果你使用sizeof
的“true”数组标识符,它会为你提供实际的存储大小分配,同时取sizeof
指针只会给你指针的大小,这通常是系统的整数大小(虽然可以是不同的)。
另外,如果我正在使用动态分配的矩阵,哪一个是声明函数原型的正确方法:(...)
它们都不是因为那些是指向数组的指针数组,这些数组可能是非连续的。出于性能原因,您希望矩阵是连续的。所以你要写
void foo(int matrix[])
并在内部计算正确的偏移量,如
matrix[width*j + i]
请注意,使用括号语法编写此内容看起来很奇怪。另请注意,如果您使用指针的sizeof
或“未指定长度的数组”函数参数,您将获得指针的大小。
答案 2 :(得分:1)
不,你只是继续使用array[position] = value
。
最后,无论您是将参数声明为int *something
还是int something[]
,都没有什么区别。两者都可以工作,因为数组定义只是一些隐藏的指针数学。
然而,关于如何理解代码存在一个区别:
int array[]
总是表示一个数组(虽然它可能只是一个元素)。int *pointer
但是可以是指向单个整数或整个整数数组的指针。就寻址/表示而言:pointer == array == &array[0]
如果您正在使用多个维度,那么事情会有所不同,因为如果您明确定义多维数组,C会强制您声明最后一个维度:
int **myStuff1; // valid
int *myStuff2[]; // valid
int myStuff3[][]; // invalid
int myStuff4[][5]; // valid
答案 3 :(得分:1)
是的,请使用array[position]
,即使参数类型为int *array
。您提供的替代方法(*array[position]
)在这种情况下实际上无效,因为[]
运算符优先于*
运算符,使其等同于*(array[position])
,它试图取消引用a[position]
的价值,而不是它的地址。
对于多维数组来说会有点复杂,但你可以这样做:
int m = 10, n = 5;
int matrixOnStack[m][n];
matrixOnStack[0][0] = 0; // OK
matrixOnStack[m-1][n-1] = 0; // OK
// matrixOnStack[10][5] = 0; // Not OK. Compiler may not complain
// but nearby data structures might.
int (*matrixInHeap)[n] = malloc(sizeof(int[m][n]));
matrixInHeap[0][0] = 0; // OK
matrixInHeap[m-1][n-1] = 0; // OK
// matrixInHeap[10][5] = 0; // Not OK. coloring outside the lines again.
应该解释matrixInHeap
声明的方式是'' matrixInHeap
指向的是n
int
值的数组,因此sizeof(*matrixInHeap) == n * sizeof(int)
或矩阵中整行的大小。 matrixInHeap[2][4]
有效,因为matrixInHeap[2]
正在通过matrixInHeap
推进地址2 * sizeof(*matrixInHeap)
,跳过两整行的n
整数,从而产生第3行的地址,然后最后的[4]
选择第三行的第五个元素。 (记住,数组索引从0开始而不是1)
指向普通的多维c阵列时,可以使用相同的类型(假设你已经知道了大小):
int (*matrixPointer)[n] = matrixOnStack || matrixInHeap;
现在假设您想要一个将这些可变大小矩阵中的一个作为参数的函数。当先前声明变量时,类型具有关于大小的一些信息(堆栈示例中的两个维度以及堆示例中的最后一个维度n
)。所以函数定义中的参数类型将需要n
值,我们实际上可以这样做,只要我们将它作为一个单独的参数包含在内,定义如下函数:
void fillWithZeros(int m, int n, int (*matrix)[n]) {
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
matrix[i][j] = 0;
}
如果我们在函数内部不需要m
值,我们可以将其完全删除,只要我们保留n
:
bool isZeroAtLocation(int n, int (*matrix)[n], int i, int j) {
return matrix[i][j] == 0;
}
然后我们只需在调用函数时包含大小:
fillWithZeros(m, n, matrixPointer);
assert(isZeroAtLocation(n, matrixPointer, 0, 0));
可能感觉有点像我们正在为编译器工作,特别是在我们根本不在函数体内使用n
的情况下(或仅作为参数)类似的功能),但至少它是有效的。
关于可读性的最后一点:使用malloc(sizeof(int[len]))
等同于malloc(len * sizeof(int))
(并且任何告诉你的人都不理解c中的结构填充)但是第一种写入它的方法使它成为可能对于读者来说,我们谈论的是数组。 malloc(sizeof(int[m][n]))
和malloc(m * n * sizeof(int))
也是如此。