[c] Passing an array by reference in C?

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

This question is related to c arrays pass-by-reference

The answer is


In plain C you can use a pointer/size combination in your API.

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

Using pointers is the closest to call-by-reference available in C.


Hey guys here is a simple test program that shows how to allocate and pass an array using new or malloc. Just cut, paste and run it. Have fun!

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

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).


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

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

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;


Examples related to c

conflicting types for 'outchar' Can't compile C program on a Mac after upgrade to Mojave Program to find largest and second largest number in array Prime numbers between 1 to 100 in C Programming Language In c, in bool, true == 1 and false == 0? How I can print to stderr in C? Visual Studio Code includePath "error: assignment to expression with array type error" when I assign a struct field (C) Compiling an application for use in highly radioactive environments How can you print multiple variables inside a string using printf?

Examples related to arrays

PHP array value passes to next row Use NSInteger as array index How do I show a message in the foreach loop? Objects are not valid as a React child. If you meant to render a collection of children, use an array instead Iterating over arrays in Python 3 Best way to "push" into C# array Sort Array of object by object field in Angular 6 Checking for duplicate strings in JavaScript array what does numpy ndarray shape do? How to round a numpy array?

Examples related to pass-by-reference

Passing an integer by reference in Python Does JavaScript pass by reference? Object passed as parameter to another class, by value or reference? change values in array when doing foreach Call-time pass-by-reference has been removed C++ pass an array by reference Passing Objects By Reference or Value in C# Pass variables by reference in JavaScript JavaScript by reference vs. by value How to do the equivalent of pass by reference for primitives in Java