如何在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元素阵列不同).
在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;
在这里扩展一些答案......
在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元素阵列不同).
C语言不支持任何类型的引用传递.最接近的等价物是传递指向该类型的指针.
这是两种语言的人为例子
C++风格的API
void UpdateValue(int& i) { i = 42; }
最接近的C等价物
void UpdateValue(int *i) { *i = 42; }
另请注意,如果要在方法中创建数组,则无法返回.如果返回指向它的指针,则在函数返回时它将从堆栈中删除.您必须将内存分配到堆上并返回指向该内存的指针.例如.
//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) }
在普通的C中,您可以在API中使用指针/大小组合.
void doSomething(MyStruct* mystruct, size_t numElements) { for (size_t i = 0; i < numElements; ++i) { MyStruct current = mystruct[i]; handleElement(current); } }
使用指针最接近C中可用的引用调用.
默认情况下,数组通过引用有效传递.实际上传递了指向第一个元素的指针的值.因此,接收它的函数或方法可以修改数组中的值.
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;