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 thebyval_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 OverflowBecause 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 thebyval_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.
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);
Pass by value possible in C? - Stack Overflow
Passing an array as an argument to a function in C - Stack Overflow
c - Pass an array by value - Stack Overflow
c pass array by value? - 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".
Because this:
void foo(int arr[])
is really just syntax sugar for this:
void foo(int *arr)
So when you call the function, your array decays into a pointer to the first element.
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...
For passing 2D (or higher multidimensional) arrays instead, see my other answers here:
- How to pass a multidimensional [C-style] array to a function in C and C++, and here:
- 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:
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])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])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])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])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:
- My code experimentation online: https://onlinegdb.com/B1RsrBDFD
See also:
- 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*?
- C pointers : pointing to an array of fixed size
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
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).
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:
- Create an local array in
main(). - Fill it with a known pattern
- Print the contents of array
- Pass the array to a function
- Inside function body modify the contents of the array
- Print the array inside the function
- In
main()print the contents of the local array again - If outputs in
6and7match. 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
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"
In idiomatic C++, an array arr of 5 ints is declared std::array<int, 5> arr; or std::vector<int> arr(5);. Swapping of values is std::swap. Functions should either alter their parameters and return void, or alter a copy and return that value.
You also don't loop through every element in your outer loop.
#include <array>
#include <iostream>
void sort(std::array<int, 5> & arr){
for(int i = 0; i < 5; i++){
for(int j = 1; j < 5; j++){
if(arr[i] < arr[j]){
std::swap(arr[i], arr[j]);
}
}
}
}
int main(){
std::array<int, 5> arr = {1,2,3,4,5};
sort(arr);
for(int m=0; m<5; m++){
std::cout<<arr[m];
}
}
However, the easiest way to sort is to use <algorithm>'s std::sort, which takes a range as two Iterator parameters
#include <algorithm>
#include <array>
#include <iostream>
int main(){
std::array<int, 5> arr = {1,2,3,4,5};
std::sort(arr.begin(), arr.end(), std::greater<int>{});
for(int m=0; m<5; m++){
std::cout<<arr[m];
}
}
1) you can use c++ swap function instead using a temp variable
swap(arr[i], arr[j]);
2) your for loops should look like this
for(int i = 0; i < 5; i++) {
for(int j = i; j < 5; j++) {
The outer loop has to iterate through the whole array (from 0 to 4) and the inner has to iterate through the 'right side' of the array, because the left side is already sorted
so we can't pass array by value
https://stackoverflow.com/a/16137997/6521788 https://stackoverflow.com/a/16137995/6521788
You can just copy the values into a new array
You cannot pass an array by value in C: arrays are passed by address. If you want to pass an array by value, wrap it in a struct:
struct with_array {
int b[3][2];
};
void sample(struct with_array s) {
...
}
int main() {
struct with_array arg = {.b = {{2,3},{4,2} ,{5,2}}};
sample(arg);
}
P.S. If you do not need to pass by value, your approach can be fixed, too. You need to follow the right syntax on initialization, and pass the whole array to sample, rather than accessing one of its elements (which is also beyond the bounds of the array).
Use:
sample(d);
instead of:
sample(d[3][2]);
d[3][2] is simply the value of an element of the array and this is not what you want to pass.
Also:
int d[3][2]={(2,3),(4,2),(5,2)};
this is not how you initialize an array.
int d[3][2]={{2, 3}, {4,2}, {5, 2}};
is the correct way.
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.
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;
}