操作函数中的多维数组

时间:2022-08-28 21:34:54

I read a lot of stuff in here and tried many but i couldn't find a way to pass a multidimensional array to a function in C, change some of the values and somehow return the new array. It's important to find a way to pass that array further to another function and do the same thing.

我在这里读了很多东西,尝试了很多,但是我找不到方法将多维数组传递给C中的函数,改变一些值,然后以某种方式返回新的数组。找到一种方法将数组进一步传递给另一个函数并做同样的事情是很重要的。

I would like to find a way to pass the array to a function.Then pass it from the first function to a second one,do something there(maybe print,maybe change values),then use it again to the first function and finally use that array in main.

我想找到一种将数组传递给函数的方法。然后将它从第一个函数传递给第二个函数,在那里做一些事情(可能是打印,可能是更改值),然后将它再次用于第一个函数,最后在main中使用这个数组。

My last try is:

我最后一次尝试:

void func(int multarray[][columns]){
    multarray[0][0]=9;
}

int main(){
    int rows;
    int columns;
    int multarray[rows][columns];
    func(multarray);
    return 0;
}

I also tried this:

我也试过这样的:

void func(int multarray[rows][columns]){
    multarray[0][0]=9;
}

int main(){
    int rows;
    int columns;
    int multarray[rows][columns];
    func(multarray);
    return 0;
}

I also tried this:

我也试过这样的:

int
getid(int row, int x, int y) {
          return (row*x+y);
}

void
printMatrix(int*arr, int row, int col) {
     for(int x = 0; x < row ; x++) {
             printf("\n");
             for (int y = 0; y <col ; y++) {
                 printf("%d  ",arr[getid(row, x,y)]);
             }
     }
}

main()
{

    int arr[2][2] = {11,12,21,22};
    int row = 2, col = 2;

    printMatrix((int*)arr, row, col);

}

from here

从这里

I also tried double pointers.I also read that there is a different approach if the compiler does not support VLAs. I am using gnu.

我还尝试了双投。我还读到,如果编译器不支持VLAs,就会有不同的方法。我使用gnu。

4 个解决方案

#1


5  

Not exactly sure, what the problem is but this works (and prints the value "9"):

不确定的是,问题是什么,但这是可行的(并打印值“9”):

#include <stdio.h>

#define ROWS 10
#define COLUMNS 10

void func2(int multarray[][COLUMNS]){
        multarray[1][4]=10;
}

void func1(int multarray[][COLUMNS]){
        multarray[0][3]=9;
        func2(multarray);
}

int main(){

        int multarray[ROWS][COLUMNS];
        func1(multarray);
        printf("%d\n", multarray[0][3]);
        printf("%d\n", multarray[1][4]);
        return 0;
}

Notice, that the array decays to a pointer when passed to a function.

注意,当数组传递给函数时,它会衰减到指针。

#2


9  

Several things to remember:

要记住几件事情:

  1. When you pass an array expression as an argument to a function, it will be converted from an expression of type "N-element array of T" to "pointer to T", and the value of the expression will be the address of the first element of the array. The called function receives a pointer value.

    当您将数组表达式作为参数传递给函数时,它将从“n元素T数组”类型的表达式转换为“指向T的指针”,表达式的值将是数组的第一个元素的地址。被调用的函数接收指针值。

  2. The [] operator can be used with expressions of array or pointer type; IOW, given the declarations int a[10]; int *p = a;, then p[i] and a[i] refer to the same element.

    []运算符可以与数组或指针类型的表达式一起使用;IOW,给定在[10]中的声明;int *p = a;,然后p[i]和a[i]表示相同的元素。

  3. When declaring a function that accepts a VLA as a parameter, you must declare the parameters that specify dimension before you declare the array.

    在声明接受VLA作为参数的函数时,必须在声明数组之前声明指定维度的参数。

So, for a function that manipulates a 2D VLA, you'd write something like

对于一个操作2D VLA的函数,你可以写一些类似的东西。

void foo( size_t rows, size_t cols, int (*multiarray)[cols] ) // or multiarray[][cols]
{
   size_t i, j;

   for ( i = 0; i < rows; i++ )
     for ( j = 0; j < cols; j++ )
       multiarray[i][j] = some_value();
}

What's up with int (*multiarray)[cols]? Remember that in passing the array expression as an argument, the type of the array expression is converted from "N-element array of T" to "pointer to T". In this case, T is "cols-element array of int", so we're going from "rows-element array of cols-element aray of int" to "pointer to cols-element array of int". In the context of a function parameter declaration, T a[N], T a[], and T *a are all identical; in all three cases, a is declared as a pointer to T. So int (*multiarray)[cols] is equivalent to int multiarray[][cols], which is equivalent to int multiarray[rows][cols]. I prefer using the first form because it most accurately represents the situation.

int (*multiarray)[cols]怎么了?请记住,在传递数组表达式作为参数时,数组表达式的类型由“N-element数组of T”转换为“指向T的指针”。在这种情况下,T是“int的cols-element数组”,所以我们从“int的cols-element aray的row -element数组”到“int的cols-element数组指针”。在函数参数声明的上下文中,T a[N]、T a[]、T *a都是相同的;在这三种情况下,a被声明为指向T. So int (*multiarray)[cols]的指针,它等价于int multiarray[][cols],它相当于int multiarray[rows][cols]。我更喜欢用第一种形式,因为它最能准确地反映情况。

If you want to pass this array as an argument to another function, you'd use the same type:

如果要将这个数组传递给另一个函数,则使用相同类型:

void bar( size_t rows, size_t cols, int (*multiarray)[cols] )
{
   foo( rows, cols, multiarray );
}

int main( void )
{
  size_t rows = 0;
  size_t cols = 0;

  // you must assign values to rows and cols before declaring a VLA with them
  rows = ...;
  cols = ...;

  int arr[rows][cols];

  bar( rows, cols, arr );
  ...
}

Any changes to the array contents made in foo will be reflected in bar and main.

对foo中的数组内容的任何更改都将在bar和main中反映出来。

VLAs can be useful, but they have their limitations. They can't be declared static, nor can they be defined outside of a function. They cannot use {}-style initialization syntax. Also, VLA support is now optional as of the 2011 standard, so you can't rely on them being supported everywhere.

VLAs是有用的,但也有其局限性。它们不能声明为静态的,也不能在函数之外定义。它们不能使用{}式的初始化语法。此外,在2011年的标准中,VLA支持现在是可选的,所以您不能指望它们在任何地方都得到支持。

In the event you don't have VLAs available and your array size isn't known until runtime, you'll have to use dynamic memory allocation (malloc or calloc), and the types you pass to your functions will be different:

如果你没有可用的VLAs,而且你的数组大小直到运行时才知道,你必须使用动态内存分配(malloc或calloc),你传递给函数的类型将不同:

void foo( size_t rows, size_t cols, int **multiarray )
{
  size_t i, j;

  for ( i = 0; i < rows; i++ )
    for ( j = 0; j < cols; j++ )
      multiarray[i][j] = some_value();

}

void bar( size_t rows, size_t cols, int **multiarray )
{
  foo( rows, cols, multiarray );
}

int main( void )
{
  size_t rows; 
  size_t cols;
  int **multiarray = NULL;

  ... // get rows and cols

  // allocate memory for pointers to each row
  multiarray = malloc( sizeof *multiarray * rows );
  if ( multiarray )
  {
    size_t i;
    // allocate each row
    for ( i = 0; i < rows; i++ )
    {
      multiarray[i] = malloc( sizeof *multiarray[i] * cols );
      if ( !multiarray[i] )
        break;
    }

    if ( i < rows )
    {
      // malloc failed for one of the multiarray rows; we need to 
      // free whatever memory has already been allocated and exit
      while ( i-- )
        free( multiarray[i] );
      free( multiarray );
      exit(0);
    }
  }

  bar ( rows, cols, multiarray );
  ...

  if ( multiarray )
  {
    size_t i;

    for ( i = 0; i < rows; i++ )
      free( multiarray[i] );
    free( multiarray );
  }
}

One drawback with this approach is that the allocated memory isn't guaranteed to be contiguous (i.e., rows won't be adjacent in memory). If that matters, you'll have to go with yet another approach. Instead of allocating rows and columns separately, you allocate everything in one single block, and manually map array indices:

这种方法的一个缺点是分配的内存不能保证是连续的(例如。,行在内存中不会相邻)。如果这一点很重要,你将不得不采用另一种方法。不同于单独分配行和列,您可以在单个块中分配所有内容,并手动映射数组索引:

void foo( size_t rows, size_t cols, int *fakemultiarray )
{
  size_t i, j;

  for ( i = 0; i < rows; i++ )
    for ( j = 0; j < rows; j++ )
       fakemultiarray[ i * rows + j ] = some_value();
}

void bar( size_t rows, size_t cols, int *fakemultiarray )
{
  foo( rows, cols, fakemultiarray );
}

int main( void )
{
  size_t rows;
  size_t cols;
  int *fakemultiarray = NULL;

  ... // get rows and cols

  fakemultiarray = malloc( sizeof *fakemultiarray * rows * cols );
  if ( fakemultiarray )
    bar( rows, cols, fakemultiarray );

  ...
  free( fakemultiarray );
}

In this case, we've allocated a single buffer large enough for all elements, but we have to index it as a 1D array, computing the index as i * rows + j.

在这种情况下,我们已经为所有元素分配了足够大的一个缓冲区,但是我们必须将它作为一个1D数组进行索引,将索引计算为i * rows + j。

#3


3  

For your 2 dimensional arrays I would define a type for it.

对于二维数组,我会为它定义一个类型。

typedef int my2DArray_t[ROWS][COLUMNS];

You can then declare variables of this type and pointers to them. This makes it easier to pass things around.

然后可以声明这种类型的变量并指向它们。这使得传递信息变得更容易。

void someFuncOther (my2DArray_t *someArray)
    {

    /* Set some values in array */
    (*someArray)[1][1] = 4;

    }

void someFunc (my2DArray_t *someArray)
    {

    /* Set some values in array */
    (*someArray)[1][0] = 7;

    /* Have someFuncOther do some more work */
    someFuncOther (someArray);

    }


int main (void)
    {
    /* This is the actual array */
    my2DArray_t myArray;

    /* Set some values in array */
    myArray[0][2] = 6;

    /* Have someFunc do some work on myArray by passing a pointer to it */
    someFunc (&myArray);

    }

#4


0  

It is helpful to think of arrays as pointers to memory. Then it is easy to think of a 2d array as a pointer to a memory of pointers (kinda)

将数组看作指向内存的指针是有帮助的。然后很容易将2d数组看作指向指针的指针(有点)

This is not going to work

这行不通

 int arr[2][2] = {11,12,21,22}; //not going to work

but this worked just fine for me

但这对我来说很好

 1 #include <stdio.h>
 2 
 3  
 4 main()
 5 {
 6    int arr[2][2] = {{11,1},{2,21}};
 7    int row = 2, col = 2;
 8    int i,j;
 9 
 10    for(i=0;i<row;i++)
 11       for(j=0;j<col;j++)
 12         printf("%d  - ",arr[i][j]);
 13 
 14 
 15  }

#1


5  

Not exactly sure, what the problem is but this works (and prints the value "9"):

不确定的是,问题是什么,但这是可行的(并打印值“9”):

#include <stdio.h>

#define ROWS 10
#define COLUMNS 10

void func2(int multarray[][COLUMNS]){
        multarray[1][4]=10;
}

void func1(int multarray[][COLUMNS]){
        multarray[0][3]=9;
        func2(multarray);
}

int main(){

        int multarray[ROWS][COLUMNS];
        func1(multarray);
        printf("%d\n", multarray[0][3]);
        printf("%d\n", multarray[1][4]);
        return 0;
}

Notice, that the array decays to a pointer when passed to a function.

注意,当数组传递给函数时,它会衰减到指针。

#2


9  

Several things to remember:

要记住几件事情:

  1. When you pass an array expression as an argument to a function, it will be converted from an expression of type "N-element array of T" to "pointer to T", and the value of the expression will be the address of the first element of the array. The called function receives a pointer value.

    当您将数组表达式作为参数传递给函数时,它将从“n元素T数组”类型的表达式转换为“指向T的指针”,表达式的值将是数组的第一个元素的地址。被调用的函数接收指针值。

  2. The [] operator can be used with expressions of array or pointer type; IOW, given the declarations int a[10]; int *p = a;, then p[i] and a[i] refer to the same element.

    []运算符可以与数组或指针类型的表达式一起使用;IOW,给定在[10]中的声明;int *p = a;,然后p[i]和a[i]表示相同的元素。

  3. When declaring a function that accepts a VLA as a parameter, you must declare the parameters that specify dimension before you declare the array.

    在声明接受VLA作为参数的函数时,必须在声明数组之前声明指定维度的参数。

So, for a function that manipulates a 2D VLA, you'd write something like

对于一个操作2D VLA的函数,你可以写一些类似的东西。

void foo( size_t rows, size_t cols, int (*multiarray)[cols] ) // or multiarray[][cols]
{
   size_t i, j;

   for ( i = 0; i < rows; i++ )
     for ( j = 0; j < cols; j++ )
       multiarray[i][j] = some_value();
}

What's up with int (*multiarray)[cols]? Remember that in passing the array expression as an argument, the type of the array expression is converted from "N-element array of T" to "pointer to T". In this case, T is "cols-element array of int", so we're going from "rows-element array of cols-element aray of int" to "pointer to cols-element array of int". In the context of a function parameter declaration, T a[N], T a[], and T *a are all identical; in all three cases, a is declared as a pointer to T. So int (*multiarray)[cols] is equivalent to int multiarray[][cols], which is equivalent to int multiarray[rows][cols]. I prefer using the first form because it most accurately represents the situation.

int (*multiarray)[cols]怎么了?请记住,在传递数组表达式作为参数时,数组表达式的类型由“N-element数组of T”转换为“指向T的指针”。在这种情况下,T是“int的cols-element数组”,所以我们从“int的cols-element aray的row -element数组”到“int的cols-element数组指针”。在函数参数声明的上下文中,T a[N]、T a[]、T *a都是相同的;在这三种情况下,a被声明为指向T. So int (*multiarray)[cols]的指针,它等价于int multiarray[][cols],它相当于int multiarray[rows][cols]。我更喜欢用第一种形式,因为它最能准确地反映情况。

If you want to pass this array as an argument to another function, you'd use the same type:

如果要将这个数组传递给另一个函数,则使用相同类型:

void bar( size_t rows, size_t cols, int (*multiarray)[cols] )
{
   foo( rows, cols, multiarray );
}

int main( void )
{
  size_t rows = 0;
  size_t cols = 0;

  // you must assign values to rows and cols before declaring a VLA with them
  rows = ...;
  cols = ...;

  int arr[rows][cols];

  bar( rows, cols, arr );
  ...
}

Any changes to the array contents made in foo will be reflected in bar and main.

对foo中的数组内容的任何更改都将在bar和main中反映出来。

VLAs can be useful, but they have their limitations. They can't be declared static, nor can they be defined outside of a function. They cannot use {}-style initialization syntax. Also, VLA support is now optional as of the 2011 standard, so you can't rely on them being supported everywhere.

VLAs是有用的,但也有其局限性。它们不能声明为静态的,也不能在函数之外定义。它们不能使用{}式的初始化语法。此外,在2011年的标准中,VLA支持现在是可选的,所以您不能指望它们在任何地方都得到支持。

In the event you don't have VLAs available and your array size isn't known until runtime, you'll have to use dynamic memory allocation (malloc or calloc), and the types you pass to your functions will be different:

如果你没有可用的VLAs,而且你的数组大小直到运行时才知道,你必须使用动态内存分配(malloc或calloc),你传递给函数的类型将不同:

void foo( size_t rows, size_t cols, int **multiarray )
{
  size_t i, j;

  for ( i = 0; i < rows; i++ )
    for ( j = 0; j < cols; j++ )
      multiarray[i][j] = some_value();

}

void bar( size_t rows, size_t cols, int **multiarray )
{
  foo( rows, cols, multiarray );
}

int main( void )
{
  size_t rows; 
  size_t cols;
  int **multiarray = NULL;

  ... // get rows and cols

  // allocate memory for pointers to each row
  multiarray = malloc( sizeof *multiarray * rows );
  if ( multiarray )
  {
    size_t i;
    // allocate each row
    for ( i = 0; i < rows; i++ )
    {
      multiarray[i] = malloc( sizeof *multiarray[i] * cols );
      if ( !multiarray[i] )
        break;
    }

    if ( i < rows )
    {
      // malloc failed for one of the multiarray rows; we need to 
      // free whatever memory has already been allocated and exit
      while ( i-- )
        free( multiarray[i] );
      free( multiarray );
      exit(0);
    }
  }

  bar ( rows, cols, multiarray );
  ...

  if ( multiarray )
  {
    size_t i;

    for ( i = 0; i < rows; i++ )
      free( multiarray[i] );
    free( multiarray );
  }
}

One drawback with this approach is that the allocated memory isn't guaranteed to be contiguous (i.e., rows won't be adjacent in memory). If that matters, you'll have to go with yet another approach. Instead of allocating rows and columns separately, you allocate everything in one single block, and manually map array indices:

这种方法的一个缺点是分配的内存不能保证是连续的(例如。,行在内存中不会相邻)。如果这一点很重要,你将不得不采用另一种方法。不同于单独分配行和列,您可以在单个块中分配所有内容,并手动映射数组索引:

void foo( size_t rows, size_t cols, int *fakemultiarray )
{
  size_t i, j;

  for ( i = 0; i < rows; i++ )
    for ( j = 0; j < rows; j++ )
       fakemultiarray[ i * rows + j ] = some_value();
}

void bar( size_t rows, size_t cols, int *fakemultiarray )
{
  foo( rows, cols, fakemultiarray );
}

int main( void )
{
  size_t rows;
  size_t cols;
  int *fakemultiarray = NULL;

  ... // get rows and cols

  fakemultiarray = malloc( sizeof *fakemultiarray * rows * cols );
  if ( fakemultiarray )
    bar( rows, cols, fakemultiarray );

  ...
  free( fakemultiarray );
}

In this case, we've allocated a single buffer large enough for all elements, but we have to index it as a 1D array, computing the index as i * rows + j.

在这种情况下,我们已经为所有元素分配了足够大的一个缓冲区,但是我们必须将它作为一个1D数组进行索引,将索引计算为i * rows + j。

#3


3  

For your 2 dimensional arrays I would define a type for it.

对于二维数组,我会为它定义一个类型。

typedef int my2DArray_t[ROWS][COLUMNS];

You can then declare variables of this type and pointers to them. This makes it easier to pass things around.

然后可以声明这种类型的变量并指向它们。这使得传递信息变得更容易。

void someFuncOther (my2DArray_t *someArray)
    {

    /* Set some values in array */
    (*someArray)[1][1] = 4;

    }

void someFunc (my2DArray_t *someArray)
    {

    /* Set some values in array */
    (*someArray)[1][0] = 7;

    /* Have someFuncOther do some more work */
    someFuncOther (someArray);

    }


int main (void)
    {
    /* This is the actual array */
    my2DArray_t myArray;

    /* Set some values in array */
    myArray[0][2] = 6;

    /* Have someFunc do some work on myArray by passing a pointer to it */
    someFunc (&myArray);

    }

#4


0  

It is helpful to think of arrays as pointers to memory. Then it is easy to think of a 2d array as a pointer to a memory of pointers (kinda)

将数组看作指向内存的指针是有帮助的。然后很容易将2d数组看作指向指针的指针(有点)

This is not going to work

这行不通

 int arr[2][2] = {11,12,21,22}; //not going to work

but this worked just fine for me

但这对我来说很好

 1 #include <stdio.h>
 2 
 3  
 4 main()
 5 {
 6    int arr[2][2] = {{11,1},{2,21}};
 7    int row = 2, col = 2;
 8    int i,j;
 9 
 10    for(i=0;i<row;i++)
 11       for(j=0;j<col;j++)
 12         printf("%d  - ",arr[i][j]);
 13 
 14 
 15  }