Passing an array by reference in C?

271,772

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;

Share:
271,772
Hannoun Yassir
Author by

Hannoun Yassir

Updated on March 04, 2020

Comments

  • Hannoun Yassir
    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
    Hannoun Yassir almost 15 years
    i know but i find problem passing an array with the same method :s
  • JaredPar
    JaredPar almost 15 years
    @Yassir, can you give an example?
  • Ralph Caraveo
    Ralph Caraveo almost 15 years
    This 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
    Ralph Caraveo almost 15 years
    I mean demonstrated properly in dribeas' post! =)
  • JaredPar
    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
    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
    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
    M4rk over 11 years
    use memset( array, 0, sizeof array); instead of for() cycle inside the reset :)
  • David Rodríguez - dribeas
    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
    bobbogo over 8 years
    Another disadvantage of your wrapper formulation is that wrapper is being passed by value. 80 bytes (-ish), and the assignment inside SomeMethod() has no effect on the wrapper declared in main. Looks like a bug.
  • Aka
    Aka about 6 years
    It's good practice not to type cast the return value of malloc. see here
  • David Rodríguez - dribeas
    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
    Elias Hasle about 5 years
    Why sizeof(*array) when the array type is constrained to be int? Why not just sizeof(int)?
  • Duck Dodgers
    Duck Dodgers about 5 years
    Perfect 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.