当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《在C中通过引用传递数组?》经验,为你挑选了6个好方法。

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

举个例子:

struct Coordinate {
   int X;
   int Y;
};
SomeMethod(Coordinate *Coordinates[]){
   //Do Something with the array
}
int main(){ 
   Coordinate Coordinates[10];
   SomeMethod(&Coordinates);
}

David Rodríg.. 126

在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 );
}

在问题编辑中,你特别要求传递一组结构.你有两个解决方案:声明一个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

您可以在声明时键入dede类型(这是C中常见的习语):

typedef struct Coordinate {
   int x;
   int y;
} Coordinate;

@rodi:这是一个有趣的点,考虑到你引入了一个bug :)我已经更新了代码以使用`memset`,因为它应该被使用:`memset(array,0,size*sizeof*array)` - ` sizeof(array)`在这种情况下是*指针*的大小,而不是指向的数据. (5认同)

使用memset(array,0,sizeof array); 而不是for()循环内重置:) (2认同)

@Aka:你是完全正确的,而且我已经了解到,自从我9年前写这篇文章以后:) [我已经编辑删除演员表,谢谢你提出这个问题] (2认同)


John Bode.. 11

在这里扩展一些答案......

在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元素阵列不同).



1> David Rodríg..:

在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 );
}

在问题编辑中,你特别要求传递一组结构.你有两个解决方案:声明一个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

您可以在声明时键入dede类型(这是C中常见的习语):

typedef struct Coordinate {
   int x;
   int y;
} Coordinate;


@rodi:这是一个有趣的点,考虑到你引入了一个bug :)我已经更新了代码以使用`memset`,因为它应该被使用:`memset(array,0,size*sizeof*array)` - ` sizeof(array)`在这种情况下是*指针*的大小,而不是指向的数据.
使用memset(array,0,sizeof array); 而不是for()循环内重置:)
@Aka:你是完全正确的,而且我已经了解到,自从我9年前写这篇文章以后:) [我已经编辑删除演员表,谢谢你提出这个问题]

2> John Bode..:

在这里扩展一些答案......

在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> JaredPar..:

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

这是两种语言的人为例子

C++风格的API

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

最接近的C等价物

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


@Yassir,你能举个例子吗?

4> user128026..:

另请注意,如果要在方法中创建数组,则无法返回.如果返回指向它的指针,则在函数返回时它将从堆栈中删除.您必须将内存分配到堆上并返回指向该内存的指针.例如.

//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> haffax..:

在普通的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> dlamblin..:

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

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;

推荐阅读
爱唱歌的郭少文_
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有