Below is a snippet from the book C Programming Just the FAQs. Isn't this wrong as Arrays can never be passed by value?

VIII.6: How can you pass an array to a function by value?

Answer: An array can be passed to a function by value by declaring in the called function the array name with square brackets ([ and ]) attached to the end. When calling the function, simply pass the address of the array (that is, the array’s name) to the called function. For instance, the following program passes the array x[] to the function named byval_func() by value:

The int[] parameter tells the compiler that the byval_func() function will take one argument—an array of integers. When the byval_func() function is called, you pass the address of the array to byval_func():

byval_func(x);

Because the array is being passed by value, an exact copy of the array is made and placed on the stack. The called function then receives this copy of the array and can print it. Because the array passed to byval_func() is a copy of the original array, modifying the array within the byval_func() function has no effect on the original array.


Solution 1:

Because the array is being passed by value, an exact copy of the array is made and placed on the stack.

This is incorrect: the array itself is not being copied, only a copy of the pointer to its address is passed to the callee (placed on the stack). (Regardless of whether you declare the parameter as int[] or int*, it decays into a pointer.) This allows you to modify the contents of the array from within the called function. Thus, this

Because the array passed to byval_func() is a copy of the original array, modifying the array within the byval_func() function has no effect on the original array.

is plain wrong (kudos to @Jonathan Leffler for his comment below). However, reassigning the pointer inside the function will not change the pointer to the original array outside the function.

Solution 2:

Burn that book. If you want a real C FAQ that wasn't written by a beginner programmer, use this one: http://c-faq.com/aryptr/index.html.

Syntax-wise, strictly speaking you cannot pass an array by value in C.

void func (int* x); /* this is a pointer */

void func (int x[]); /* this is a pointer */

void func (int x[10]); /* this is a pointer */

However, for the record there is a dirty trick in C that does allow you to pass an array by value in C. Don't try this at home! Because despite this trick, there is still never a reason to pass an array by value.

typedef struct
{
  int my_array[10];
} Array_by_val;

void func (Array_by_val x);

Solution 3:

Isn't this wrong as arrays can never be passed by value?

Exactly. You cannot pass an array by value in C.

I took a look at the quoted part of the book and the source of this confusion or mistake is pretty fast found.

The author did not know about that *i is equivalent to i[] when provided as a parameter to a function. The latter form was invented to explicitly illustrate the reader of the code, that i points to an array, which is a great source of confusion, as well-shown by this question.

What I think is funny, that the author of the particular part of the book or at least one of the other parts (because the book has 5 authors in total) or one of the 7 proofreaders did not mentioned at least the sentence:

"When the byval_func() function is called, you pass the address of the array to byval_func():"

With at least that, they should had noticed that there is a conflict. Since you passing an address, it is only an address. There is nothing magically happen which turns an address into a whole new array.


But back to the question itself:

You can not pass an array as it is by value in C, as you already seem to know yourself. But you can do three (there might be more, but that is my acutal status of it) things, which might be an alternative depending on the unique case, so let´s start.

  1. Encapsulate an array in a structure (as mentioned by other answers):
#include <stdio.h>

struct a_s {
   int a[20];
};

void foo (struct a_s a)
{
   size_t length = sizeof a.a / sizeof *a.a;

   for(size_t i = 0; i < length; i++)
   {
       printf("%d\n",a.a[i]);
   }
}

int main()
{
   struct a_s array;

   size_t length = sizeof array.a / sizeof *array.a;

   for(size_t i = 0; i < length; i++)
   {
       array.a[i] = 15;
   } 

   foo(array);
}
  1. Pass by pointer but also add a parameter for determine the size of the array. In the called function there is made a new array with that size information and assigned with the values from the array in the caller:
#include <stdio.h>

void foo (int *array, size_t length)
{
   int b[length];

   for(size_t i = 0; i < length; i++)
   {
       b[i] = array[i];
       printf("%d\n",b[i]);
   }
}

int main()
{
   int a[10] = {0,1,2,3,4,5,6,7,8,9};

   foo(a,(sizeof a / sizeof *a));
}
  1. Avoid to define local arrays and just use one array with global scope:
#include <stdio.h>

int a[10];
size_t length = sizeof a / sizeof *a;

void foo (void)
{
   for(size_t i = 0; i < length; i++)
   {
       printf("%d\n",a[i]);
   }
}

int main()
{   
   for(size_t i = 0; i < length; i++)
   {
       a[i] = 25;
   } 

   foo();
}

Solution 4:

In C and C++ it is NOT possible to pass a complete block of memory by value as a parameter to a function, but we are allowed to pass its address. In practice this has almost the same effect and it is a much faster and more efficient operation.

To be safe, you can pass the array size or put const qualifier before the pointer to make sure the callee won't change it.