代码之家  ›  专栏  ›  技术社区  ›  Hannoun Yassir

在C中通过引用传递数组?

  •  60
  • Hannoun Yassir  · 技术社区  · 15 年前

    如何在C中通过引用传递结构数组?

    举个例子:

    struct Coordinate {
       int X;
       int Y;
    };
    SomeMethod(Coordinate *Coordinates[]){
       //Do Something with the array
    }
    int main(){ 
       Coordinate Coordinates[10];
       SomeMethod(&Coordinates);
    }
    
    7 回复  |  直到 6 年前
        1
  •  121
  •   David Rodríguez - dribeas    6 年前

    在C中,数组作为指向第一个元素的指针传递。它们是唯一不按值传递的元素(指针按值传递,但不复制数组)。允许被调用函数修改内容。

    void reset( int *array, int size) {
       memset(array,0,size * sizeof(*array));
    }
    int main()
    {
       int array[10];
       reset( array, 10 ); // sets all elements to 0
    }
    

    现在,如果您想要的是更改数组本身(元素数…),那么就不能使用堆栈或全局数组,只能使用堆中动态分配的内存。在这种情况下,如果要更改指针,必须向其传递指针:

    void resize( int **p, int size ) {
       free( *p );
       *p = malloc( size * sizeof(int) );
    }
    int main() {
       int *p = malloc( 10 * sizeof(int) );
       resize( &p, 20 );
    }
    

    在问题edit中,您特别询问有关传递结构数组的问题。这里有两个解决方案:声明typedef,或显式地表示正在传递结构:

    struct Coordinate {
       int x;
       int y;
    };
    void f( struct Coordinate coordinates[], int size );
    typedef struct Coordinate Coordinate;  // generate a type alias 'Coordinate' that is equivalent to struct Coordinate
    void g( Coordinate coordinates[], int size ); // uses typedef'ed Coordinate
    

    您可以在声明类型时对其进行typedef(这是C语言中的常见习惯用法):

    typedef struct Coordinate {
       int x;
       int y;
    } Coordinate;
    
        2
  •  11
  •   John Bode    15 年前

    在这里展开一些答案…

    在C语言中,当数组标识符出现在上下文中而不是作为操作数出现在&或sizeof中时,该标识符的类型将从“n元素数组t”隐式转换为“指向t的指针”,其值将隐式设置为数组中第一个元素的地址(与数组本身的地址相同)。这就是为什么当您将数组标识符作为参数传递给函数时,该函数接收到指向基类型的指针,而不是数组。由于不能通过查看指向第一个元素的指针来判断数组有多大,因此必须将大小作为单独的参数传入。

    struct Coordinate { int x; int y; };
    void SomeMethod(struct Coordinate *coordinates, size_t numCoordinates)
    {
        ...
        coordinates[i].x = ...;
        coordinates[i].y = ...; 
        ...
    }
    int main (void)
    {
        struct Coordinate coordinates[10];
        ...
        SomeMethod (coordinates, sizeof coordinates / sizeof *coordinates);
        ...
    }
    

    有两种将数组传递给函数的可选方法。

    存在一个指向t数组的指针,而不是指向t的指针。

    T (*p)[N];
    

    在这种情况下,p是指向t的n元素数组的指针(与t*p[n]相反,p是指向t的n元素数组)。因此,您可以向数组传递一个指针,而不是向第一个元素传递一个指针:

    struct Coordinate { int x; int y };
    
    void SomeMethod(struct Coordinate (*coordinates)[10])
    {
        ...
        (*coordinates)[i].x = ...;
        (*coordinates)[i].y = ...;
        ...
    }
    
    int main(void)
    {
        struct Coordinate coordinates[10];
        ...
        SomeMethod(&coordinates);
        ...
    }
    

    这种方法的缺点是数组大小是固定的,因为指向t的10元素数组的指针与指向t的20元素数组的指针的类型不同。

    第三种方法是将数组包装在结构中:

    struct Coordinate { int x; int y; };
    struct CoordinateWrapper { struct Coordinate coordinates[10]; };
    void SomeMethod(struct CoordinateWrapper wrapper)
    {
        ...
        wrapper.coordinates[i].x = ...;
        wrapper.coordinates[i].y = ...;
        ...
    }
    int main(void)
    {
        struct CoordinateWrapper wrapper;
        ...
        SomeMethod(wrapper);
        ...
    }
    

    这种方法的优点是你不需要用指针。缺点是数组的大小是固定的(同样,T的10元素数组与T的20元素数组是不同的类型)。

        3
  •  8
  •   JaredPar    15 年前

    C语言不支持任何类型的传递引用。最接近的等价物是向类型传递指针。

    这两种语言都有一个人为的例子

    C++风格的API

    void UpdateValue(int& i) {
      i = 42;
    }
    

    最接近的C当量

    void UpdateValue(int *i) {
      *i = 42;
    }
    
        4
  •  7
  •   user128026    15 年前

    另外,请注意,如果要在方法中创建数组,则不能返回该数组。如果返回指向它的指针,则当函数返回时,它将从堆栈中移除。 必须将内存分配到堆上并返回指向该堆的指针。 如。

    //this is bad
    char* getname()
    {
      char name[100];
      return name;
    }
    
    //this is better
    char* getname()
    {
      char *name = malloc(100);
      return name;
      //remember to free(name)
    }
    
        5
  •  6
  •   haffax    15 年前

    在纯C语言中,您可以在API中使用指针/大小组合。

    void doSomething(MyStruct* mystruct, size_t numElements)
    {
        for (size_t i = 0; i < numElements; ++i)
        {
            MyStruct current = mystruct[i];
            handleElement(current);
        }
    }
    

    使用指针最接近C中可用的引用调用。

        6
  •  6
  •   dlamblin    15 年前

    默认情况下,数组通过引用有效传递。实际上,将传递指向第一个元素的指针的值。因此,接收该命令的函数或方法可以修改数组中的值。

    void SomeMethod(Coordinate Coordinates[]){Coordinates[0].x++;};
    int main(){
      Coordinate tenCoordinates[10];
      tenCoordinates[0].x=0;
      SomeMethod(tenCoordinates[]);
      SomeMethod(&tenCoordinates[0]);
      if(0==tenCoordinates[0].x - 2;){
        exit(0);
      }
      exit(-1);
    }
    

    两个调用相等,退出值应为0;

        7
  •  2
  •   Jeff M    13 年前

    嘿,伙计们,这里有一个简单的测试程序,演示如何使用new或malloc分配和传递数组。只需剪切、粘贴并运行即可。玩得高兴!

    struct Coordinate
    {
        int x,y;
    };
    
    void resize( int **p, int size )
    {
       free( *p );
       *p = (int*) malloc( size * sizeof(int) );
    }
    
    void resizeCoord( struct Coordinate **p, int size )
    {
       free( *p );
       *p = (Coordinate*) malloc( size * sizeof(Coordinate) );
    }
    
    void resizeCoordWithNew( struct Coordinate **p, int size )
    {
       delete [] *p;
       *p = (struct Coordinate*) new struct Coordinate[size];
    }
    
    void SomeMethod(Coordinate Coordinates[])
    {
        Coordinates[0].x++;
        Coordinates[0].y = 6;
    }
    
    void SomeOtherMethod(Coordinate Coordinates[], int size)
    {
        for (int i=0; i<size; i++)
        {
            Coordinates[i].x = i;
            Coordinates[i].y = i*2;
        }
    }
    
    int main()
    {
        //static array
        Coordinate tenCoordinates[10];
        tenCoordinates[0].x=0;
        SomeMethod(tenCoordinates);
        SomeMethod(&(tenCoordinates[0]));
        if(tenCoordinates[0].x - 2  == 0)
        {
            printf("test1 coord change successful\n");
        }
        else
        {
            printf("test1 coord change unsuccessful\n");
        }
    
    
       //dynamic int
       int *p = (int*) malloc( 10 * sizeof(int) );
       resize( &p, 20 );
    
       //dynamic struct with malloc
       int myresize = 20;
       int initSize = 10;
       struct Coordinate *pcoord = (struct Coordinate*) malloc (initSize * sizeof(struct Coordinate));
       resizeCoord(&pcoord, myresize); 
       SomeOtherMethod(pcoord, myresize);
       bool pass = true;
       for (int i=0; i<myresize; i++)
       {
           if (! ((pcoord[i].x == i) && (pcoord[i].y == i*2)))
           {        
               printf("Error dynamic Coord struct [%d] failed with (%d,%d)\n",i,pcoord[i].x,pcoord[i].y);
               pass = false;
           }
       }
       if (pass)
       {
           printf("test2 coords for dynamic struct allocated with malloc worked correctly\n");
       }
    
    
       //dynamic struct with new
       myresize = 20;
       initSize = 10;
       struct Coordinate *pcoord2 = (struct Coordinate*) new struct Coordinate[initSize];
       resizeCoordWithNew(&pcoord2, myresize); 
       SomeOtherMethod(pcoord2, myresize);
       pass = true;
       for (int i=0; i<myresize; i++)
       {
           if (! ((pcoord2[i].x == i) && (pcoord2[i].y == i*2)))
           {        
               printf("Error dynamic Coord struct [%d] failed with (%d,%d)\n",i,pcoord2[i].x,pcoord2[i].y);
               pass = false;
           }
       }
       if (pass)
       {
           printf("test3 coords for dynamic struct with new worked correctly\n");
       }
    
    
       return 0;
    }