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.

Answer from Péter Török on Stack Overflow
🌐
GeeksforGeeks
geeksforgeeks.org › c language › pass-array-value-c
How to pass an array by value in C ? - GeeksforGeeks
July 23, 2025 - There are no direct ways to pass the array by value. However, there is trick that allows you to simulate the passing of array by value by enclosing it inside a structure and then passing that structure by value.
Discussions

Pass by value possible in C? - Stack Overflow
Arrays automatically decay into pointers in certain contexts in C. Function calls are one of those places. That said, you are passing the pointer by value - C has no other way to pass parameters than "by value". More on stackoverflow.com
🌐 stackoverflow.com
Passing an array as an argument to a function in C - Stack Overflow
For historical reasons, arrays are not first class citizens and cannot be passed by value. Originally, C didn't have any pass by value, except for single values. It wasn't until struct was added to the language that this was changed. And then it was considered too late to change the rules for ... More on stackoverflow.com
🌐 stackoverflow.com
c - Pass an array by value - Stack Overflow
Bring the best of human thought and AI automation together at your work. Explore Stack Internal ... Generally when we pass array by its name, it’s call by address. That means if we change any value of array outside main() it will be reflected in main(). More on stackoverflow.com
🌐 stackoverflow.com
c pass array by value? - Stack Overflow
Write a C program that tests whether or not the following data types are passed by reference or by value, and prints what it discovers out to the terminal: ... Hypothetically, if your program discovers that an int is passed by value and an array of ints is passed by value, then it should produce ... More on stackoverflow.com
🌐 stackoverflow.com
June 22, 2012
🌐
TutorialsPoint
tutorialspoint.com › pass-an-array-by-value-in-c
Pass an array by value in C
In C programming, when you pass an array by value, you are not sending the entire array. Instead of this, it passes a pointer to the first element. So, this shows functions directly work with an original array but do not copy. Note: If we make any ch
🌐
SkillVertex
skillvertex.com › blog › how-to-pass-an-array-by-value-in-c
How To Pass An Array By Value In C ?
May 10, 2024 - In 'modify()', before modification 10 10 10 10 10 In 'modify()', after modification 100 100 100 100 100 In 'Main', after calling modify() 10 10 10 10 10 · Ans. To pass an entire array to a function in C, you only need to provide the array’s name as an argument.
🌐
Techie Delight
techiedelight.com › home › pass an array by value to a function in c/c++
Pass an array by value to a function in C/C++ | Techie Delight
3 weeks ago - We know that arguments to the function are passed by value in C by default. However, arrays in C cannot be passed by value to a function, and we can modify the contents of the array from within the callee function.
Top answer
1 of 11
232

When passing an array as a parameter, this

void arraytest(int a[])

means exactly the same as

void arraytest(int *a)

so you are modifying the values in main.

Personally, I would use the second option, as it seems less confusing and better indicates that you don't get a copy of the array.

For historical reasons, arrays are not first class citizens and cannot be passed by value. Originally, C didn't have any pass by value, except for single values. It wasn't until struct was added to the language that this was changed. And then it was considered too late to change the rules for arrays. There were already 10's of users...

2 of 11
62

For passing 2D (or higher multidimensional) arrays instead, see my other answers here:

  1. How to pass a multidimensional [C-style] array to a function in C and C++, and here:
  2. How to pass a multidimensional array to a function in C++ only, via std::vector<std::vector<int>>&

Passing 1D arrays as function parameters in C (and C++)

1. Standard array usage in C with natural type decay (adjustment) from array to ptr

@Bo Persson correctly states in his great answer here:

When passing an array as a parameter, this

void arraytest(int a[])

means exactly the same as

void arraytest(int *a)

Let me add some comments to add clarity to those two code snippets:

// param is array of ints; the arg passed automatically "adjusts" (frequently said
// informally as "decays") from `int []` (array of ints) to `int *` 
// (ptr to int)
void arraytest(int a[])

// ptr to int
void arraytest(int *a)

However, let me add also that the above two forms also:

  1. mean exactly the same as

     // array of 0 ints; automatically adjusts (decays) from `int [0]`
     // (array of zero ints) to `int *` (ptr to int)
     void arraytest(int a[0])
    
  2. which means exactly the same as

     // array of 1 int; automatically adjusts (decays) from `int [1]`
     // (array of 1 int) to `int *` (ptr to int)
     void arraytest(int a[1])
    
  3. which means exactly the same as

     // array of 2 ints; automatically adjusts (decays) from `int [2]`
     // (array of 2 ints) to `int *` (ptr to int)
     void arraytest(int a[2])
    
  4. which means exactly the same as

     // array of 1000 ints; automatically adjusts (decays) from `int [1000]`
     // (array of 1000 ints) to `int *` (ptr to int)
     void arraytest(int a[1000])
    
  5. etc.

In every single one of the array examples above, and as shown in the example calls in the code just below, the input parameter type adjusts (decays) to an int *, and can be called with no warnings and no errors, even with build options -Wall -Wextra -Werror turned on (see my repo here for details on these 3 build options), like this:

int array1[2];
int * array2 = array1;

// works fine because `array1` automatically decays from an array type
// to a pointer type: `int *`
arraytest(array1);
// works fine because `array2` is already an `int *` 
arraytest(array2);

As a matter of fact, the "size" value ([0], [1], [2], [1000], etc.) inside the array parameter here is apparently just for aesthetic/self-documentation purposes, and can be any positive integer (size_t type I think) you want!

In practice, however, you should use it to specify the minimum size of the array you expect the function to receive, so that when writing code it's easy for you to track and verify. The MISRA-C-2012 standard (buy/download the 236-pg 2012-version PDF of the standard for £15.00 here) goes so far as to state (emphasis added):

Rule 17.5 The function argument corresponding to a parameter declared to have an array type shall have an appropriate number of elements.

...

If a parameter is declared as an array with a specified size, the corresponding argument in each function call should point into an object that has at least as many elements as the array.

...

The use of an array declarator for a function parameter specifies the function interface more clearly than using a pointer. The minimum number of elements expected by the function is explicitly stated, whereas this is not possible with a pointer.

In other words, they recommend using the explicit size format, even though the C standard technically doesn't enforce it--it at least helps clarify to you as a developer, and to others using the code, what size array the function is expecting you to pass in.


2. Forcing type safety on arrays in C

(Not recommended (correction: sometimes recommended, especially for fixed-size multi-dimensional arrays), but possible. See my brief argument against doing this at the end. Also, for my multi-dimensional-array [ex: 2D array] version of this, see my answer here.)

As @Winger Sendon points out in a comment below my answer, we can force C to treat an array type to be different based on the array size!

Quick summary

// `a_p` is a pointer to an array of 2 integers
int (*a_p)[2]; 

// Now, assuming you have this array of 2 integers:
int my_array[2];

// ...you can make `a_p` point to `my_array` like this:
a_p = &my_array;

// This, however, would be **illegal**, since `my_array2` is the wrong size
int my_array2[3]; // Ok: array of 3 `int`s
a_p = &my_array2; // ERROR! `a_p` is a ptr to an array of 2 ints, not 3 ints, 
                  //        so this assignment is not allowed!

Details

First, you must recognize that in my example just above, using the int array1[2]; like this: arraytest(array1); causes array1 to automatically decay into an int *. HOWEVER, if you take the address of array1 instead and call arraytest(&array1), you get completely different behavior! Now, it does NOT decay into an int *! This is because if you take the address of an array then you already have a pointer type, and pointer types do NOT adjust to other pointer types. Only array types adjust to pointer types. So instead, the type of &array1 is int (*)[2], which means "pointer to an array of size 2 of int", or "pointer to an array of size 2 of type int", or said also as "pointer to an array of 2 ints". So, you can FORCE C to check for type safety on an array by passing explicit pointers to arrays, like this:

// `a` is of type `int (*)[2]`, which means "pointer to array of 2 ints"; 
// since it is already a ptr, it can NOT automatically decay further
// to any other type of ptr 
void arraytest(int (*a)[2])
{
    // my function here
}

This syntax is hard to read, but similar to that of a function pointer. The online tool, cdecl, tells us that int (*a)[2] means: "declare a as pointer to array 2 of int" (pointer to array of 2 ints). Do NOT confuse this with the version withOUT parenthesis: int * a[2], which means: "declare a as array 2 of pointer to int" (AKA: array of 2 pointers to int, AKA: array of 2 int*s).

Now, this function REQUIRES you to call it with the address operator (&) like this, using as an input parameter a POINTER TO AN ARRAY OF THE CORRECT SIZE!:

int array1[2];

// ok, since the type of `array1` is `int (*)[2]` (ptr to array of 
// 2 ints)
arraytest(&array1); // you must use the & operator here to prevent
                    // `array1` from otherwise automatically decaying
                    // into `int *`, which is the WRONG input type here!

This, however, will produce a warning:

int array1[2];

// WARNING! Wrong type since the type of `array1` decays to `int *`:
//      main.c:32:15: warning: passing argument 1 of ‘arraytest’ from 
//      incompatible pointer type [-Wincompatible-pointer-types]                                                            
//      main.c:22:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
arraytest(array1); // (missing & operator)

You may test this code here.

To force the C compiler to turn this warning into an error, so that you MUST always call arraytest(&array1); using only an input array of the corrrect size and type (int array1[2]; in this case), add -Werror to your build options. If running the test code above on onlinegdb.com, do this by clicking the gear icon in the top-right and click on "Extra Compiler Flags" to type this option in. Now, this warning:

main.c:34:15: warning: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Wincompatible-pointer-types]                                                            
main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’    

will turn into this build error:

main.c: In function ‘main’:
main.c:34:15: error: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Werror=incompatible-pointer-types]
     arraytest(array1); // warning!
               ^~~~~~
main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
 void arraytest(int (*a)[2])
      ^~~~~~~~~
cc1: all warnings being treated as errors

Note that you can also create "type safe" pointers to arrays of a given size, like this:

int array[2]; // variable `array` is of type `int [2]`, or "array of 2 ints"

// `array_p` is a "type safe" ptr to array of size 2 of int; ie: its type
// is `int (*)[2]`, which can also be stated: "ptr to array of 2 ints"
int (*array_p)[2] = &array;

...but I do NOT necessarily recommend this (using these "type safe" arrays in C), as it reminds me a lot of the C++ antics used to force type safety everywhere, at the exceptionally high cost of language syntax complexity, verbosity, and difficulty architecting code, and which I dislike and have ranted about many times before (ex: see "My Thoughts on C++" here).


For additional tests and experimentation, see also the link just below.

References

See links above. Also:

  1. My code experimentation online: https://onlinegdb.com/B1RsrBDFD

See also:

  1. My answer on multi-dimensional arrays (ex: 2D arrays) which expounds upon the above, and uses the "type safety" approach for multi-dimensional arrays where it makes sense: Why can't I pass a C-style multidimensional array to a function taking an array of int*?
  2. C pointers : pointing to an array of fixed size
Find elsewhere
Top answer
1 of 3
15

It is possible to do this by wrapping the array in a struct. You can include a field for the size of the array so that you don't need to pass this parameter explicitly. This approach has the virtue of avoiding extra memory allocations that must later be freed.

C already passes arguments to functions by value, but array identifiers decay to pointers in most expressions, and in function calls in particular. Yet structs do not decay to pointers, and are passed by value to a function, meaning that a copy of the original structure and all of its contents is visible in the scope of the function. If the struct contains an array, this is copied too. Note that if instead the struct contains, say, a pointer to int for a dynamic array, then the pointer is copied when the struct is passed to the function, but the same memory is referenced by both the copy and the original pointer. This approach relies on the struct containing an actual array.

Also note that a struct can not contain a member with an incomplete type, and so can not contain a VLA. Here I have defined the global constant MAX_ARR to be 100 to provide some space for handling differently sized arrays with the same struct type.

You can also return a struct from a function. I have included an example which modifies the Array struct which is passed into a function, and returns the modified struct to be assigned to a different Array struct in the calling function. This results in the caller having access to both the original and the transformed arrays.

#include <stdio.h>

#define MAX_ARR  100

struct Array {
    size_t size;
    int array[MAX_ARR];
};

void print_array(struct Array local_arr);
void func(struct Array local_arr);
struct Array triple(struct Array local_arr);

int main(void)
{
    struct Array data = {
        .size = 10,
        .array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
    };
    struct Array transformed_data;

    func(data);
    transformed_data = triple(data);

    printf("Original\n");
    print_array(data);

    printf("Transformed\n");
    print_array(transformed_data);

    return 0;
}

void print_array(struct Array local_arr)
{
    for (size_t i = 0; i < local_arr.size; i++) {
        printf("%5d", local_arr.array[i]);
    }
    putchar('\n');
}

void func(struct Array local_arr)
{
    for (size_t i = 0; i < local_arr.size; i++) {
        local_arr.array[i] *= 2;
    }
    printf("Modified\n");
    print_array(local_arr);
}

struct Array triple(struct Array local_arr)
{
    for (size_t i = 0; i < local_arr.size; i++) {
        local_arr.array[i] *= 3;
    }
    return local_arr;
}

Program output:

Modified
    2    4    6    8   10   12   14   16   18   20
Original
    1    2    3    4    5    6    7    8    9   10
Transformed
    3    6    9   12   15   18   21   24   27   30
2 of 3
5

In general, you can't.

The caller can do something like this;

int main()
{
    int abc[]={5,1,2,9};

    {
         int temp[sizeof (abc)/sizeof (*abc)];
         memcpy(temp, abc, sizeof(abc));
         Foo(temp);
    }
}

Bear in mind that Foo() does not receive any information about the number of elements in the array passed.

If you want Foo() to do a similar thing, so the caller doesn't need to, it is necessary to pass the number of elements as a separate argument.

void Foo(int arr[], size_t size)    /*  C99 or later */
{
       int temp[size];   //   VLA
       memcpy(temp, arr, size*sizeof(int));
         /* whatever */
}

or (before C99).

void Foo(int arr[], size_t size)    /*  Before C99 */
{
       int *temp = malloc(size * sizeof (int));
       memcpy(temp, arr, size*sizeof(int));
         /* whatever */
       free(temp);
}

To avoid a memory leak, it is necessary to ensure, in the second case, that the function does not return before calling free(temp).

In both versions of Foo() above, additional error checking may be needed (e.g. to detect null pointer or zero sizes being passed, that malloc() succeeds, etc).

Top answer
1 of 2
4

Does this count as passing by value or passing by reference?

When you say "passing an array to a function", Actually a pointer to the first element is passed to the function. This allows the called function to modify the contents of the array. Since there is no copy of the array being made it makes sense to say that arrays are passed by reference.

Hints on how I can do this?

The test should be:

  1. Create an local array in main().
  2. Fill it with a known pattern
  3. Print the contents of array
  4. Pass the array to a function
  5. Inside function body modify the contents of the array
  6. Print the array inside the function
  7. In main() print the contents of the local array again
  8. If outputs in 6 and 7 match. You have a proof.

How do you pass an array by value?

Only possible way of passing an array by value is by wrapping it in a structure.
Online Sample:

#include <iostream>

struct myArrayWrapper 
{
    int m_array[5];
};

void doSomething(myArrayWrapper a) 
{
    int* A = a.m_array;

    //Display array contents
    std::cout<<"\nIn Function Before Modification\n";
    for (size_t j = 0; j < 5; ++j)
       std::cout << ' ' << A[j];
    std::cout << std::endl;

     //Modify the array
     for (size_t j = 0; j < 5; ++j)
       A[j] = 100;

    std::cout<<"\nIn Function After Modification\n";
    //Display array contents
    for (size_t j = 0; j < 5; ++j)
       std::cout << ' ' << A[j];
    std::cout << std::endl;

}

int main()
{
    myArrayWrapper obj;
    obj.m_array[0] = 0;
    obj.m_array[1] = 1;
    obj.m_array[2] = 2;
    obj.m_array[3] = 3;
    obj.m_array[4] = 4;
    doSomething(obj);

    //Display array contents
    std::cout<<"\nIn Main\n";
    for (size_t j = 0; j < 5; ++j)
       std::cout << ' ' << obj.m_array[j];
    std::cout << std::endl;

    return 0; 
}

Output:

In Function Before Modification
 0 1 2 3 4

In Function After Modification
 100 100 100 100 100

In Main
 0 1 2 3 4
2 of 2
2

C only pass arguments to functions by value.

From the mighty Kernighan & Ritchie, 2nd edition:

(1.8, Call by value) "In C all function arguments are passed by "value"

🌐
TutorialsPoint
tutorialspoint.com › cprogramming › c_passing_arrays_to_functions.htm
Passing Arrays as Function Arguments in C
If you want to pass an array to a function, you can use either call by value or call by reference method. In call by value method, the argument to the function should be an initialized array, or an array of fixed size equal to the size of the ...
🌐
Study.com
study.com › courses › computer science courses › computer science 111: programming in c
Passing & Using Array Addresses in C Programming | Study.com
These examples highlight pass by value and pass by reference processes, respectively. In the first case, a copy of the pay rate variable is passed to the function. In the second example, we pass a copy of the address (a pointer) to the function. Now the function can update the underlying structure or variable. Since a batting roster is a good example of an array...
🌐
BeginnersBook
beginnersbook.com › 2014 › 01 › c-passing-array-to-function-example
Passing array to function in C programming with example
September 24, 2017 - For example if array name is arr then you can say that arr is equivalent to the &arr[0]. #include <stdio.h> void myfuncn( int *var1, int var2) { /* The pointer var1 is pointing to the first element of * the array and the var2 is the size of the array. In the * loop we are incrementing pointer so that it points to * the next element of the array on each increment. * */ for(int x=0; x<var2; x++) { printf("Value of var_arr[%d] is: %d \n", x, *var1); /*increment pointer for next element fetch*/ var1++; } } int main() { int var_arr[] = {11, 22, 33, 44, 55, 66, 77}; myfuncn(var_arr, 7); return 0; }
🌐
Quora
quora.com › How-do-you-pass-an-array-by-value-in-C
How to pass an array by value in C++ - Quora
Answer: The only way I’m aware of that you can pass an array by value is to include it in a struct and pass the struct by value. [code]struct foo { int data[5]; }; void some_func(foo f) { // function body } [/code]
Top answer
1 of 5
31

This is caused by the fact that arrays tend to decay into pointers.

int a[] = { 1, 2, 3 };
int* p = a; // valid: p is now the address of a[0]
a = p;  // NOT valid.

printf("a = %p\n", a);
printf("p = %p\n", p); // prints same address as a

a and p will print the same value.

Contrary to what others have said, a is not a pointer, it can simply decay to one. http://c-faq.com/aryptr/aryptrequiv.html

In your first function() what gets passed is the address of the array's first element, and the function body dereferences that. Infact, the compiler is treating the function prototype as this:

void function(int* array /*you wrote int array[]*/){
    array[0] = 4;
    array[1] = 5;
    array[2] = 6;   
}

function(&array[0]);

This has to happen because you said "array of unknown size" (int array[]). The compiler could not guarantee to deduce the amount of stack required to pass by value, so it decays to a pointer.

---- Edit ----

Lets combine both your examples and use more distinctive names to make things clearer.

#include <stdio.h>

void func1(int dynArray[]) {
    printf("func1: dynArray = %p, &dynArray[0] = %p, dynArray[0] = %d\n",
             dynArray, &dynArray[0], dynArray[0]);
}

void func2(int* intPtr) {
    printf("func2: intPtr = %p, &intPtr[0] = %p, intPtr[0] = %d\n",
             intPtr, &intPtr[0], intPtr[0]);
}

void func3(int intVal) {
    printf("func3: intVal = %d, &intValue = %p\n",
             intVal, &intVal);
}

int main() {
    int mainArray[3] = { 1, 2, 3 };
    int mainInt = 10;

    printf("mainArray = %p, &mainArray[0] = %p, mainArray[0] = %d\n",
             mainArray, &mainArray, mainArray[0]);
    func1(mainArray);
    func2(mainArray);

    printf("mainInt = %d, &mainInt = %p\n",
             mainInt, &mainInt);
    func3(mainInt);

    return 0;
}

Live demo at ideone: http://ideone.com/P8C1f4

mainArray = 0xbf806ad4, &mainArray[0] = 0xbf806ad4, mainArray[0] = 1
func1: dynArray = 0xbf806ad4, &dynArray[0] = 0xbf806ad4, dynArray[0] = 1
func2: intPtr = 0xbf806ad4, &intPtr[0] = 0xbf806ad4, intPtr[0] = 1

mainInt = 10, &mainInt = 0xbf806acc
func3: intVal = 10, &intValue = 0xbf806ad0

In func1 and func2 "dynArray" and "intPtr" are local variables, but they are pointer variables into which they receive the address of "mainArray" from main.

This behavior is specific to arrays. If you were to put the array inside a struct, then you would be able to pass it by value.

2 of 5
3

An array passed to a function is converted to a pointer. When you pass a pointer as argument to a function, you simply give the address of the variable in the memory. So when you modify the value of the cell of the array, you edit the value under the address given to the function.

When you pass a simple integer to a function, the integer is copied in the stack, when you modify the integer within the function, you modify the copy of the integer, not the original.

Reminder of the different kinds of memory in C

In C, we can use three types of memory :

  • the stack, used for local variables and functions calls: when we create a variable in main(), we use the stack to store the variable, and when a function is called, the parameters given to the method are register in the stack. When we exit a function, we "pop" these parameters to return to the original state, with the used variable before the call of the function. (anecdote: a stackoverflow is when we hack the stack to use previous variables in a function without passing it as parameters)
  • the heap which corresponds to the dynamicly allocated memory: when we need large amount of data, we use this heap because the stack is limited to a few megabytes.
  • the code where the program instructions are stored

In the case of this array passed by a function, which is a pointer (address to an other variable), it is stored in the stack, when we call the function, we copy the pointer in the stack.

In the case of the integer, it is also stored in the stack, when we call the function, we copy the integer.

If we want to modify the integer, we can pass the address of the integer to modify the value under the pointer, like this:

void function(int *integer)
{
    *integer = 2;
}

int main()
{
    int integer = 1;
    function(&integer);

    printf("%d", integer);

    return 0;
}
🌐
guvi.in
studytonight.com › c › array-in-function-in-c.php
Passing Arrays to Functions in C
September 17, 2024 - But how can we pass an array as argument to a function? Let's see how its done. There are two possible ways to do so, one by using call by value and other by using call by reference.