Passing an array by reference in C?
Solution 1
In C arrays are passed as a pointer to the first element. They are the only element that is not really passed by value (the pointer is passed by value, but the array is not copied). That allows the called function to modify the contents.
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
}
Now, if what you want is changing the array itself (number of elements...) you cannot do it with stack or global arrays, only with dynamically allocated memory in the heap. In that case, if you want to change the pointer you must pass a pointer to it:
void resize( int **p, int size ) {
free( *p );
*p = malloc( size * sizeof(int) );
}
int main() {
int *p = malloc( 10 * sizeof(int) );
resize( &p, 20 );
}
In the question edit you ask specifically about passing an array of structs. You have two solutions there: declare a typedef, or make explicit that you are passing an struct:
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
You can typedef the type as you declare it (and it is a common idiom in C):
typedef struct Coordinate {
int x;
int y;
} Coordinate;
Solution 2
To expand a little bit on some of the answers here...
In C, when an array identifier appears in a context other than as an operand to either & or sizeof, the type of the identifier is implicitly converted from "N-element array of T" to "pointer to T", and its value is implicitly set to the address of the first element in the array (which is the same as the address of the array itself). That's why when you just pass the array identifier as an argument to a function, the function receives a pointer to the base type, rather than an array. Since you can't tell how big an array is just by looking at the pointer to the first element, you have to pass the size in as a separate parameter.
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);
...
}
There are a couple of alternate ways of passing arrays to functions.
There is such a thing as a pointer to an array of T, as opposed to a pointer to T. You would declare such a pointer as
T (*p)[N];
In this case, p is a pointer to an N-element array of T (as opposed to T *p[N], where p is an N-element array of pointer to T). So you could pass a pointer to the array as opposed to a pointer to the first element:
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);
...
}
The disadvantage of this method is that the array size is fixed, since a pointer to a 10-element array of T is a different type from a pointer to a 20-element array of T.
A third method is to wrap the array in a struct:
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);
...
}
The advantage of this method is that you aren't mucking around with pointers. The disadvantage is that the array size is fixed (again, a 10-element array of T is a different type from a 20-element array of T).
Solution 3
The C language does not support pass by reference of any type. The closest equivalent is to pass a pointer to the type.
Here is a contrived example in both languages
C++ style API
void UpdateValue(int& i) {
i = 42;
}
Closest C equivalent
void UpdateValue(int *i) {
*i = 42;
}
Solution 4
also be aware that if you are creating a array within a method, you cannot return it. If you return a pointer to it, it would have been removed from the stack when the function returns. you must allocate memory onto the heap and return a pointer to that. eg.
//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)
}
Solution 5
Arrays are effectively passed by reference by default. Actually the value of the pointer to the first element is passed. Therefore the function or method receiving this can modify the values in the array.
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);
}
The two calls are equivalent, and the exit value should be 0;
Hannoun Yassir
Updated on March 04, 2020Comments
-
Hannoun Yassir about 4 years
How can I pass an array of structs by reference in C?
As an example:
struct Coordinate { int X; int Y; }; SomeMethod(Coordinate *Coordinates[]){ //Do Something with the array } int main(){ Coordinate Coordinates[10]; SomeMethod(&Coordinates); }
-
Hannoun Yassir almost 15 yearsi know but i find problem passing an array with the same method :s
-
JaredPar almost 15 years@Yassir, can you give an example?
-
Ralph Caraveo almost 15 yearsThis example demonstrates passing a primitive type by reference (using a pointer which is passed by value) but doesn't demonstrate passing an array of structs by reference as demonstrated properly in the post below.
-
Ralph Caraveo almost 15 yearsI mean demonstrated properly in dribeas' post! =)
-
JaredPar almost 15 years@Ralph, and you believe it was worth a -1? The OP asked a question which has no valid answer and I provided a simple "closest feature is ..." answer. Maybe not a +1 answer but certainly not a -1
-
Johannes Schaub - litb almost 15 years@Ralph, and certainly, dribeas didn't pass it by reference either (as you see when you read his answer, he says that he passes the pointer by value). Btw, functions behave the same way. They are like arrays passed by a pointer to them.
-
Ralph Caraveo almost 15 years@litb, I understand that which is why I acknowledged that it was passed by ref (using a pointer which is passed by value). It's just simulated. @JaredPar, i didn't down-vote you at all...it was someone else my friend.
-
M4rk over 11 yearsuse memset( array, 0, sizeof array); instead of for() cycle inside the reset :)
-
David Rodríguez - dribeas over 11 years@rodi: That is an interesting point, considering that you introduced a bug :) I have updated the code to use
memset
as it should be used:memset(array,0,size * sizeof *array)
--sizeof(array)
in this case is the size of a pointer, not the pointed data. -
bobbogo over 8 yearsAnother disadvantage of your wrapper formulation is that
wrapper
is being passed by value. 80 bytes (-ish), and the assignment insideSomeMethod()
has no effect on thewrapper
declared inmain
. Looks like a bug. -
Aka about 6 yearsIt's good practice not to type cast the return value of malloc. see here
-
David Rodríguez - dribeas about 6 years@Aka: You are absolutely right, and I have learned that since I wrote this some 9 years ago :) [I have edited to remove the casts, thanks for bringing this up]
-
Elias Hasle about 5 yearsWhy sizeof(*array) when the array type is constrained to be int? Why not just sizeof(int)?
-
Duck Dodgers about 5 yearsPerfect answer. Just as info for some n00b like me, who might try to repeat the first code snippet from this answer on a char array, with the modification that instead of nullifying, he might try to assign some non-null value to the pointer inside the function, ought to know, like I just realized now, that that code snippet would not work as it is. Need to use "size - 1" to keep space for null termination.