将动态分配的数组作为参数传递给C语言

时间:2013-08-29 23:11:18

标签: c arrays matrix

所以...我在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, ...);

...

4 个答案:

答案 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))也是如此。