Passing of arrays to function in c - c

If I only pass an element of an integer array (not the whole array) to a function , is it passed by value or by reference by default ?
for example-
arr[]={2,3,4,5,6}
ans=fun(arr[2])
and fun is some function which multiplies any value by 2 , then will i get the ans as 8 or 4 if i print arr[2] in the main function afterwards? Any help would be appreciated.

C has no references.
int fun(int a) {
a = 0;
}
int main() {
int arr[5] = {2, 3, 4, 5, 6};
fun(arr[2]);
printf("%d\n", arr[2]); //prints 4
return 0;
}
You can pass a pointer (still passes to the function by value, but that value is the address of the value you are interested in).
int fun(int *a) {
*a = 0;
}
int main() {
int arr[5] = {2, 3, 4, 5, 6};
fun(&arr[2]);
printf("%d\n", arr[2]); //prints 0
return 0;
}
I have a suspicion you meant C++. In that case, the function's signature determines whether it is passed by reference.
int fun(int &a) { //by reference, because of &
*a = 0;
}
int main() {
int arr[5] = {2, 3, 4, 5, 6};
fun(arr[2]);
printf("%d\n", arr[2]); //prints 0
return 0;
}

You question is tagged with c so I will answer in that context:
In the C language, there is no pass-by-reference. We can achieve a similar result as pass-by-reference by passing pointers.
That being said, if you're not passing a pointer to a function, then you're not changing the value within the calling scope.
void func(int a)
{
a = a * 2; // value of a within the calling scope does not change (pass-by-value)
}
void func2(int *a)
{
*a = (*a) * 2; // value pointed to by a is changed within the calling scope
}

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.
When we pass any array as an argument what matters is how we are handling it in the called function. If you are getting the address of the passed value(*val) then it will behave as Pass by reference and if you are getting the value directly in a variable as (val) then it will behave like a pass by value.

Related

Should I pass an int array to a function by reference?

A basic idea of what I'm talking about is below.
#include <stdio.h>
void someFunction(int arr[], int n)
{
for (int i = 0; i < n; ++i)
arr[i] *= 2;
}
void someFunctionByReference(int *arr, int n)
{
for (int i = 0; i < n; ++i)
arr[i] *= 2;
}
int main()
{
int arr[] = {5, 3, 2, 4, 5, 7, 0};
int n = sizeof(arr) / sizeof(arr[0]);
someFunction(arr, n);
int arr2[] = {5, 3, 2, 4, 5, 7, 0};
int n2 = sizeof(arr2) / sizeof(arr2[0]);
someFunctionByReference(arr2, n2);
return 0;
}
Both of these functions (as I see it) do the same thing. They even contain the same code. However, I would like to understand what the differences between the two are, and if there is a proper and improper way of doing this in certain scenarios.
Both function invocations and definitions are identical. Under most circumstances, an expression of array type will “decay” to an expression of pointer type and the value of the expression will be the address of the first element. In the context of a function parameter declaration, T a[N] and T a[] are interpreted as T *a - the parameter is a pointer, not an array object. This is because when you pass an array expression as a function argument, the function will actually receive a pointer value, not an array.
This behavior is unique to array expressions - other aggregate types like struct and union types do not “decay” in this manner. If you pass a struct type with an array member, the contents of the array member will be copied over.
And this is not an example of “pass by reference”, either. C passes all function parameters by value, no exceptions. Sometimes those values are pointers. This particular quirk is simply fallout from how C treats arrays.

Arrays & Passing By Reference in C

I am learning some of the basics of C, and am currently stepping my way through arrays and more specifically how passing by reference works. When the below code is run it returns 10 22. When I read through the code however, based on the last command it seems as though the variable a should return 22 instead of 10 (meaning the full output would be 22 22 instead of 10 22). Why would the variable a not update to 22 in this code?
#include <stdio.h>
void set_array(int array[4]);
void set_int(int x);
int main(void)
{
int a = 10;
int b[4] = { 0, 1, 2, 3 };
set_int(a);
set_array(b);
printf("%d %d\n", a, b[0]);
}
void set_array(int array[4])
{
array[0] = 22;
}
void set_int(int x)
{
x = 22;
}
Arrays are [loosely] "pass by reference". Actually, the array "decays" into an int *.
But, scalars are "pass by value".
In set_int, you set the function scoped copy of x but do not return it to the caller.
Here's the refactored code, with a "call by reference" example:
#include <stdio.h>
void
set_array(int array[4])
{
array[0] = 22;
}
int
set_int(int x)
{
x = 22;
return x;
}
void
set_int_byptr(int *x)
{
*x = 37;
}
int
main(void)
{
int a = 10;
int b[4] = { 0, 1, 2, 3 };
int c = 4;
#if 0
set_int(a);
#else
a = set_int(a);
#endif
set_array(b);
set_int_byptr(&c);
printf("a=%d b=%d c=%d\n", a, b[0], c);
return 0;
}
In C if you want to modify variable passed to function you need to pass the pointer to it:
examples:
int setval(int *obj, int value)
{
*obj = val;
return val;
}
void usage()
{
int x;
setval(&x, 22);
}
void *setpointer(void **ptr, size_t size)
{
*ptr = malloc(size);
return *ptr;
}
void usage1()
{
int *array;
setpointer(&array, 200*sizeof(*array));
}
First we need to get this out of the way, because I honestly believe it will make things less confusing - C does not pass any function arguments by reference, ever. C passes all function arguments by value. Sometimes, those values are pointers. This is not the same thing as pass-by-reference.
Among other things, pass-by-value means that any changes to a formal parameter are not reflected in the actual parameter. In your set_int function, x is a distinct object from a, and any changes to x do not affect a.
If we want a function to modify the value in a parameter, we must pass a pointer to that parameter:
void set_int( int *x )
{
*x = 22; // writes a new value to the thing x points to
}
int main( void )
{
int a = 10;
set_int( &a ); // foo writes a new value to a
return 0;
}
In the above code, we want the function set_int to update the variable a, so we must pass a pointer to a to the function.
x == &a // int * == int *
*x == a // int == int
Thus, writing a new value to the expression *x in set_int is the same as writing a new value to a in main. Any change to x itself is local to set_int.
Things get confusing when we add arrays to the mix. An array is not a pointer; however, unless it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element.
When you call set_array(b), the expression b "decays" from type "4-element array of int" (int [4]) to type "pointer to int" (int *), and the value of the expression is the same as &b[0].
Here's another confusing thing - in a function parameter declaration, array declarations of type T a[N] and T a[] are interpreted as T *a - a is a pointer to T, not an array of T. So your prototype
void set_array(int b[4])
is interpreted as
void set_array(int *b)
and what it receives is a pointer to the first element. As a practical matter, this means that any changes to array[i] in set_array are reflected in b, but this is fallout from how C specifically treats array expressions, not a difference in parameter passing mechanisms. The argument is still being passed by value, it's just that the argument is a pointer value that's the result of a well-defined conversion operation on array expressions.
You are doing 2 things over here:
1) Pass by value:
the function set_int(), its parameter is passed simply, without any address, which means it is pass by value, and any change made by this function set_int() will not be reflected in the calling function.
2) Pass by reference:
However, in the case of set_array(b), you are passing the array to the called function, and its base address will be passed (Means address of first element of b, that is &b[0]), hence this is pass by reference and any change is made to this value will be reflected in the calling function
which is the reason 22 is updated for b, but 22 didn't get update for a

How to pass by value function loop using array address parameter in C

I am currently experimenting with the fun ways you can loop with C.
I declared an array locally, and printed that out using a pointer to the address &array for loop.
I was trying out two different approaches:
Passing an array to this for within the same scope.
Passing an array by value to a function to loop.
The output should be the same, but the latter seems to print exactly 4 more value:address elements out of bounds from the array.
N.B : No this is not 'industry' standard way of doing things, i'm just curious about accessing memory here.
1st approach:
int main()
{
int T[] = {1, 2, 3, 8}; // declare and init.
for(int * p = T; p < *(&T+1); p++)
{
printf("%d \t: %x\n", *p, p);
}
}
Output:
1 : eda32920
2 : eda32924
3 : eda32928
8 : eda3292c
2nd approach: (different output than expected)
void loop(int T[])
{
for(int * p = T; p < *(&T+1); p++)
{
printf("%d \t: %x\n", *p, p);
}
}
int main()
{
int T[] = {1, 2, 3, 8}; // declare and init.
loop(T);
}
Output:
1 : e3929920
2 : e3929924
3 : e3929928
8 : e392992c
-476931752 : e3929930
32766 : e3929934
-1358561188 : e3929938
2041695417 : e392993c
How and why does passing by affect the condition statement of this for loop, and print out exactly 4 more elements?
In the second code snippet that is when an array is passed to a function you are dealing with a pointer instead of the array, because when an array is passed by value it is implicitly converted to pointer to its first element. And the compiler adjusts a parameter having an array type to pointer to the element type.
So the function declaration in fact looks the following way
void loop(int *T )
{
for(int * p = T; p < *(&T+1); p++)
{
printf("%d \t: %x\n", *p, p);
}
}
So as the sizeof( int * ) is equal to either 4 or 8 (depending on used system) then the expression
*(&T+1)
does not points to the memory after the last element of the array pointed to by the expression &T.
When you pass an array as an argument in C function what's really passed is pointer to the beginning of that array so the function doesn't know the actual size of that array that's why those extra garbage values are getting printed. You need to pass an extra argument "size" along with the array argument you are passing.

Is array as an argument in c really reference type?

#include <stdio.h>
#include <stdlib.h>
void fun(int *arr)
{
arr=(int *)malloc(2*sizeof(int));
arr[0]=5;
arr[1]=4;
printf("in fun {%d, %d}",arr[0],arr[1]);
}
void anotherFunction(int *arr)
{
arr[0]=4;
arr[1]=5;
printf("in fun {%d, %d}",arr[0],arr[1]);
}
int main(void)
{
int *arr,*emptyInMain;
int arr2[]={99,99};
arr=(int *)malloc(2*sizeof(int));
arr[0]=99;
arr[1]=99;
printf("arr ");
fun(arr);
printf("\narr in main {%d, %d}\n",arr[0],arr[1]);
printf("emptyInMain");
fun(emptyInMain);
//printf("\narr in main {%d, %d}\n",emptyInMain[0],emptyInMain[1]); // WILL GIVE RUNTIME ERROR
printf("\n\--commented the line in the code because emptyInMain[0],emptyInMain[1] will give RUNTIME ERROR--");
printf("\narr2");
fun(arr2);
printf("\narr2 in main {%d, %d}\n",arr2[0],arr2[1]);
printf("\nfollowing output shows expected behaviour\n");
printf("\narr2");
anotherFunction(arr2);
printf("\narr2 in main {%d, %d}\n",arr2[0],arr2[1]);
return 0;
}
We all know that passing array as argument is a call by reference. As if I send an array arr={99,99} to a function which makes arr[0]=4 and arr[1]=5, the values get changed to 4 and 5 in the calling function also. The same should be applicable if I send the address of the variable and some manipulation is done in other function.
The following output of the above code confused me. I want to be assured if what I am thinking is correct or not.
arr in fun {5, 4}
arr in main {99, 99}
emptyInMainin fun {5, 4}
--commented the line in the code because emptyInMain[0],emptyInMain[1] will give RUNTIME ERROR--
arr2in fun {5, 4}
arr2 in main {99, 99}
following output shows expected behaviour
arr2in fun {4, 5}
arr2 in main {4, 5}
Only the last output shows the change.
Why I think arr did not get changed in first three cases is we are sending address of arr which is stored in local variable of fun(). This local variable starts pointing to some other address after the statement:
arr=(int *)malloc(2*sizeof(int));
anotherFunction() is the only function that doesn't change the allocation of its own local variable and manipulates the value stored in its (local variable's) address.
Please let me know if following assumptions of mine are wrong. Also please let me know what best change can I make to make values in the array change in all the cases. What could I do to make the variable point to location by means of malloc inside the called function (I guess double pointer but not sure).
To answer the question in your title, C parameters are always passed by value, never by reference. What makes arrays different is that when you pass an array as a parameter, it's automatically converted to a pointer to the first element of the array, and this is the value that's passed. All other types of parameters are passed by making a copy of the value.
In either case, assigning to the parameter variable in the function has no effect on the caller's variable. When the parameter is a pointer, you can indirect through it to access the caller's data. And if it's a pointer to an array element, you can index it to access the caller's array. That's what happens in your anotherfunction() function.
If you want to allocate the array in the function and have this affect the caller, there are two ways to do it.
First is to have the function return the pointer:
int *fun() {
int *localarr = malloc(2 * sizeof(int));
localarr[0] = 4;
localarr[1] = 5;
return localarr;
}
Then the caller would do:
arr = fun();
The second way is to pass a pointer to a pointer.
void fun(int **arrparam) {
int *localarr = malloc(2 * sizeof(int));
localarr[0] = 4;
localarr[1] = 5;
*arrparam = localarr;
}
Then the caller does:
fun(&arr);
What could I do to make the variable point to location by means of malloc inside the called function so that variable in main also starts pointing to the new location (I guess double pointer but not sure).
In order to do that, you have pass a pointer to a pointer (that's your double pointer).
foo(int** ptr)
{
*ptr = malloc(sizeof(int)*2);
(*ptr)[0] = 10;
(*ptr)[1] = 20;
}
int main()
{
int* ptr;
foo(&ptr); // Use the & operator to pass a pointer to the pointer.
// Check to make sure that the values are as expected.
assert(ptr[0] == 10);
assert(ptr[1] == 20);
// deallocate the memory
free(ptr);
}

Passing a constant matrix

Referring to this question and especially the accepted answer of litb, I wonder why the gcc complain about this:
void func(const int (*ip)[3]) {
printf("Value: %d\n", ip[1][1]);
}
int main() {
int i[3][3] = { {0, 1, 2} , {3, 4, 5}, {6, 7, 8} };
func(i);
return 0;
}
If I eliminate the const the compiler keeps still. Did I something misunderstand? I wanted to be sure that func don't modify my array.
EDIT: The same thing happens if I define a data type for my matrix:
typedef int Array[3][3];
void func(const Array *p) {
printf("Value: %d\n", (*p)[1][1]);
}
int main() {
Array a = { {0, 1, 2}, {3, 4, 5}, {6, 7, 8} };
func(&a);
return 0;
}
I accept, this kind of code isn't very C style, more like C++. In C++ indeed there would be no problem if I define Array as a class containing all the matrix behavior.
class Array {...};
I suppose, I didn't understand very well the concept of arrays and arrays of arrays in C and passing them to functions. Any enlightenment?
Thank you in advance.
EDIT2: Meanwhile I chewed a bit on this problem and it seems to converge to the following question: C/C++ implicitly converts a pointer to an int to a pointer to an const int. Thus the following works:
func(const int a[]) // aquivalent: func(const int *a)
{ ... }
int main()
{
int b[10];
func(b);
return 0;
}
But C/C++ don't implicitly converts a pointer to an array of n ints to a pointer to an array of n const ints. Even though an array of n ints is implicitly converted to an array of n const ints. This level of indirection in the implicit conversion isn't supported. The following will be rejected (at least with a warning in C):
func(const int a[][n]) // aquivalent: func(const int (*a)[n])
{ ... }
int main()
{
int b[m][n];
func(b);
return 0;
}
It's similar to the problem that C++ doesn't implicitly convert a template for the type A into a template of type B even if A can be implicitly converted to B. The two templates are of completely different types.
Is this the right answer?
Your i variable is an array with 3 elements.
When you pass it to a function, inside the function, it becomes a pointer to the first element. The compiler can add const either to the pointer or to the thing pointed to: an array of 3 ints. It cannot however change the thing pointed to from an array of 3 ints to an array of 3 constants.
I think you need to do the cast yourself.
#include <stdio.h>
typedef const int array_of_3_constants[3];
void func(int (* const i)[3]) {
++i[0][0];
printf("Value: %d\n", i[1][1]);
}
void gunc(array_of_3_constants *i) {
++i[0][0]; /* error */
printf("Value: %d\n", i[1][1]);
}
int main(void) {
int i[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
func(i);
func((array_of_3_constants*)i); /* warning */
gunc(i); /* warning */
gunc((array_of_3_constants*)i);
return 0;
}
You don't need to eliminate const, just pass a compatible value by casting the argument in the call to func:
func( (void *)i );
If possible, it would be preferrable to declare i as const, but this hack should work.

Resources