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
Related
Hello everyone so I have been learning C and I came across this example and I don't really find the logic behind. this is not a technical question regarding code I was looking more for an explanation.
this is the 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;
}
the output is 10 22
basically my question is why does the 22 that is passed from the set_array function rewrites the 0 on the b array and actually prints but the 22 that is passed from the set_int function doesn't get passed nor printed.
Thank you all!
In C passing by reference means passing an object indirectly through a pointer to it. If you will pass an object directly to a function then the function will deal with a copy of the value of the object.
Compare two function calls in this demonstrative program.
#include <stdio.h>
void f( int x )
{
x = 10;
}
void g( int *x )
{
*x = 10;
}
int main(void)
{
int x = 0;
printf( "Before call f: x = %d\n", x );
f( x );
printf( "After call f: x = %d\n", x );
putchar( '\n' );
printf( "Before call g: x = %d\n", x );
g( &x );
printf( "After call g: x = %d\n", x );
return 0;
}
The program output is
Before call f: x = 0
After call f: x = 0
Before call g: x = 0
After call g: x = 10
That is we passed to the function f the object x directly. So the function deals with a copy of the object x. Changing the copy does not influence on the original object x declared in main.
As for the function g then it got an access to the object x indirectly through a pointer to it. So changing the pointed object we changed the object x declared in main.
As for arrays then when an array is passed to a function it is implicitly converted to pointer to its first element. So the function in fact gets elements of the array by reference through this pointer. Using the pointer and the pointer arithmetic we can change any element of the array.
This function declaration
void set_array(int array[4]);
is equivalent to the following declaration
void set_array(int array[]);
and the both declarations are adjusted by the compiler to the declaration
void set_array(int *array);
So the function deals with a pointer - the pointer to the first element of the array used as an argument of the function call.
The call of the function set_array in your program
set_array(b);
is equivalent to the following call
set_array( &b[0] );
because arrays used in expressions as for example as a function argument expression are implicitly converted to pointers to their first elements.
C functions, when receiving parameters other than arrays and pointers (arryays are actually translated to pointers) don't update the source value because they created a copy of the value passed by the parameter.
Should your function be:
void set_int(int *x)
{
x = 22;
}
Then you're working with the source variable. But since you didn't declare a pointer, but a variable, you'd have to call it like this:
set_int(&a);
To ensure you're passing a's memory reference, rather than it's content.
Before I start I want to tell you I am learning to program.
What is the difference between Passing the variable to function and passing an array to the function in C?
When we pass a variable to function we are just passing the value of function. But when we pass an array we are passing somehow a pointer because when we do some changes on an array inside a function, actual array gets changed.
In order to make my question clear I am attaching code which will explain what I am asking-
Code 1:
//Passing variable to function
#include<stdio.h>
void swap(int x, int y);
int main(void)
{
//Nothing is happening to real values of variables
int x, y;
x = 1;
y = 2;
swap(x, y);
printf("%d = x \n %d = y", x, y);
}
void swap(int x, int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
Code 2:
//Here you can see the values of arrays are swapped.
#include<stdio.h>
void swap(int arr[]);
int main(void)
{
int idx, array[2];
for(idx = 0; idx < 2; idx++ )
{
scanf("%d", &array[idx]);
}
swap(array);
for(idx = 0; idx < 2; idx++, printf("\n"))
{
printf("%d", array[idx]);
}
}
void swap(int arr[])
{
int temp;
temp = arr[0];
arr[0] = arr[1];
arr[1] = temp;
}
Maybe my question is still unclear but I just want to know why the values of the array gets changed in main function as when we call the function we are just passing a function value of that variable.
In the both cases when a variable as you are saying is passed to a function or an array is passed to a function there is passed a value.
But in the first case there is passed the value of the variable while in the second case there is passed the value of the pointer to first element of an array.
Arrays used in expressions with rare exceptions are converted to pointers to their first elements.
From the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
So having a pointer to an object you can change the pointed object.
Let's assume that you have two functions.
void f( int x )
{
x = 10;
}
and
void g( int *px )
{
*px = 10;
}
and their calls
int n = 0;
f( n );
g( &n );
You can imagine the function definitions and their calls the following way
int n = 0;
f( n );
g( &n );
//...
void f( /* int x */ )
{
int x = n;
x = 10;
}
void g( /* int *px */ )
{
int *px = &n;
*px = 10;
}
That is the both functions deal with copies of values of the expressions used as function arguments. But in case of the function g as the function gets the value of the address of the pointed object n you can change the pointed object n using the pointer (address).
In the terms of C passing an object to a function indirectly through a pointer to the object is called passing by reference.
From the C Standard
— A pointer type may be derived from a function type or an object
type, called the referenced type. A pointer type describes an object
whose value provides a reference to an entity of the referenced
type. A pointer type derived from the referenced type T is sometimes
called ‘‘pointer to T’’. The construction of a pointer type from a
referenced type is called ‘‘pointer type derivation’’. A pointer type
is a complete object type.
Pay attention to that a function declaration like this
void f( int a[], size_t n );
is equivalent to the following declaration
void f( int *a, size_t n );
And the both declare the same one function.
If you have an array as for example
#define N 10
//...
int a[N];
then it is passed to the function like
f( a, N );
then as it is followed form the first quote from the C Standard the array designator is converted to pointer to its first element. And having this pointer in the function you can change any element of the array because each element of the array in fact is passed by reference. Using the pointer arithmetic you can change any element of the pointed array. For example
void f( int *a, size_t n )
{
for ( int i = 0; i < n; i++ )
{
a[i] = i;
// that is the same as
// *( a + i ) = i;
}
}
When you pass an array, you are actually passing the base address of the same, which is a pointer to the first array element in the memory. It is inherently a call by reference, so you don't need to explicitly use a reference or & while passing into your swap function. arr decays to &(arr[0]).
On the other hand, variables are not by default passed by value, and you need to explicitly use a & to pass them by reference to get their values swapped in their memory locations and not just specific to the scope of the swap function.
What is the difference between Passing the variable to function and passing an array to the function in C?
You cannot pass an array as it is to a function. The C syntax does not allow that. When you provide the identifier of an array as argument it decays to a pointer to the first element of the array - so you pass the array by reference to its first element.
If the relative parameter of the function is of the matching pointer type, here int * or int a[], this is permissible.
Instead when providing a variable as argument you pass it by value. Means you do not access the variable provided as argument in the function itself. Rather the value is copied into a local variable of the function.
If you want to change the value of the variable passed itself, you need to use the & ampersand operator to gather the address of the variable itself. This is only permissible if the relative parameter is of matching pointer type as above.
Thus, In the first example you do not swap the values of x and y in main(). You only change x and y inside of swap() which is pretty useless.
If you want to swap xand y in main you need to define swap() as:
void swap(int* x, int* y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
and call swap() like:
swap(&x, &y);
I suggest you to learn more about pointers.
You are not passing the array as copy. It is only a pointer pointing to the address where the first element is in memory.
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. However in C function arguments are always passed by value. In case of an array (variable), while passed as a function argument, it decays to the pointer to the first element of the array. The pointer is then passed-by-value, as usual.
An array is a special variable. When you pass a regular variable to a function as an argument, its value is copied to a local variable pertaining to the function.
When you pass an array to a function as an argument, the address of the first element of the array is copied to a local variable pertaining to the function.
That is basically the difference between passing a regular variable and passing an array to a function.
There is one issue with your perception though. If you want to modify a regular variable to be passed to a function, then you need to pass its address to the function, thus the function should take a pointer type. So just use the pointer notation, i.e int *p as opposed to int p[], even though, they are equivalent as function parameters.
Your code should look like this:
#include<stdio.h>
void swap(int *x, int *y);
int main(void)
{
int x, y;
x = 1;
y = 2;
swap(&x, &y);
printf("%d = x \n %d = y", x, y);
}
void swap(int *x, int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
This question already has answers here:
Passing an array as an argument to a function in C
(11 answers)
Closed 1 year ago.
An element of an array can be changed like this.
#include <stdio.h>
void func(int a[]){
a[0] = 56;
}
int main()
{
int a[1]={34};
func(a);
printf("%d" ,a[0]);
return 0;
}
But when the array is replaced by just 'int a'; it remains unchanged. Or in other words, to change value of 'int a' from outside main(), pointers are required. What is the reasoning behind this? Why can an array be changed from a function without pointers but a simple 'int a' requires a pointer for modification?
To change an object in a function you need to pass it by reference. Otherwise the function will deal with a copy of the value of the passed object.
In C passing by reference means passing an object indirectly through a pointer to it.
This function declaration
void func(int a[]){
a[0] = 56;
}
is equivalent to
void func(int *a){
a[0] = 56;
}
due to adjusting by the compiler a parameter having an array type to pointer type to the array element type.
So in the above function elements of the array are passed in fact by reference. That is having a pointer to the first element of an array and the pointer arithmetic you can change any element of the array.
To change the same way a scalar object you need to pass it through a pointer to it.
To make the difference visible then if you have for example a function like
void func( int value )
{
value = 56;
}
And in main you have
int x;
func( x );
then the function call may be imagined the following way
void func( /*int value */ )
{
int value = x;
value = 56;
}
As you can see it is the local variable value initialized by the value of the variable x that is changed.
On the other have if you have a function like
void func( int value[] )
{
value[0] = 56;
}
and in main you have
int a[1];
func( a );
then the function call may be imagined the following way
func( &a[0] );
void func( /* int value[] */ )
{
int *value = &a[0];
value[0] = 56;
}
Im relatively knew to C, i am used to program in Java so i find C a little bit difficult in what concerns arrays. I still cofuse myself with this cases:
int a [];
int* a;
int *a;
In java, i would do something like this to return an array in a function:
int [] returnArr(int [] a){
... modify a ...
return a;
}
int [] a = {...};
int [] b = returnArr(a); ##
How can i do the same in C, specially the parts with ##.
EDITED:
I have this function:
float *normalizeValues(float *v, float maxY){
int size = sizeof(v) / sizeof(float);
float max = findMax(v);
float ratio = maxY / max;
int i;
for(i = 0; i < size ; ++i){
v[i] = v[i] * ratio;
}
return v;
}
And im doing the following:
float vert [] = {306, 319, 360, 357, 375, 374, 387, 391, 391, 70, 82, 94, 91, 108, 114, 125, 127, 131};
int i = 0;
float *vert2;
vert2 = normalizeValues(vert, 0.7);
for(i = 0; i < sizeof(vert2) / sizeof(float); ++i){
fprintf(stdout,": %f\n",vert2[i]);
}
And the output is only 1 element.
EDIT: To directly answer your updated question: you have to pass in the size of the array. C has no mechanism to store the size of arrays like Java does. If the compiler knows about the size of the array because the array is a global or local variable, not dynamically allocated, then you can use the sizeof() operator. Otherwise, you have to know the size separately, or use sentinel values in your array (such as a 0.0 at the end, or a NULL).
As for arrays, pointers and arguments in general, see below:
You will be returning a pointer to the array, which is indicated with the '*' syntax:
int *returnArr(int[] a) {
// modify a...
return a;
}
int a[] = { ... };
int *b;
b = returnArr(a);
A few things to note:
You can't do assignments in variable declarations that involve non-constant expressions (e.g., function calls). This might have changed in C99, though.
The brackets go after the variable name, unlike in Java where they are part of the type. Even though Java's syntax is more consistent, it doesn't quite make sense in C where you often give the array size in the brackets in the variable declaration:
int a[3] = { ... };
There's no way to specify that a function returns an array as opposed to a plain pointer. In C, array references decay to pointers (though pointers and arrays are NOT the same thing, as is commonly claimed). That means that whenever you pass an array around, C only provides a means to a pass a pointer to the array. The whole array isn't actually copied. As it happens, the name of the array is also a pointer to the first element of the array.
Please also take note of what user268396 says in their answer. If you are planning to create a new array and return it, you'll need to either allocate the array dynamically, or have a pointer to an already allocated array be passed in (which is what it seems like you are kind of doing anyway).
You can't. When the function returns the stack frame will be wiped out (typically) and your generated array will be clobbered by that. You can however edit the function prototype to accept a pointer to the array to modify. That kind of function argument is known as an "output parameter". Example:
void function func(int a, int b, int[2] to_modify)
{
to_modify[0] = a;
to_modify[1] = b;
}
int main()
{
int foo[2];
func(1, 2, foo);
printf("Result: foo[0] = %d, foo[1] = %d\n", foo[0], foo[1]);
return 0;
}
This will print "Result: foo[0] = 1, foo[1] = 2".
Hope this helps
#include<stdio.h>
void change(int *c)/*Pointer c now has the first location of the array a[]*/
{
*(c+0) = 0;/*assign values to the array by adding step-size to the first array position*/
*(c+1) = 1;
*(c+2) = 2;
*(c+3) = 3;
*(c+4) = 4;
}
main()
{
int a[5]={10,20,30,40,50}; /* Declare and Assign an array a[] of size 5.*/
int *b = a; /*Declare and assign a Pointer to the location of the array.*/
change(b); /*pass the pointer(which is now pointing to first position of array) to the change() function.*/
printf("%d,%d,%d,%d,%d,",a[0],a[1],a[2],a[3],a[4]);/*Print the changed value.*/
}
Output: 0,1,2,3,4,
From Java point of view, Pointers are simply like(not exactly) Object references.
Object O;
O = New SomeClassName();
Like Object Reference O is pointing to some Actual Object of type SomeClassName, so does pointers in C:
int *b;
b = &a;
Variable b is simply pointing to the address location to a.
Taking a deep dive into array concepts:
int a[5];
int *b = a;
Here we are just saying like Mr.*b point to the first location of group a i.e. a[0].
Now the power pointer in C is that from now on, here after:
*b means a[0]
*(b+1) means a[1]
*(b+2) means a[2]
*(b+3) means a[3]
*(b+4) means a[4]
This means you change in *(b+4), you're changing a[4].
int* returnArr(int a[]){
//modify a
return a;
}
One need mention is when you use an array in the parameter list of a function, it will be converted into a pointer. So in main(...)'s declaration, char *argv[] and char **argv are actually same. In this case, int a[] and int* a are same. But array and pointer is not the same thing.
Take the following code as an example:
int a[10];
int main(){
int *p = a;
p[5] = 4;
return p[5];
}
p is a pointer, when we access p[i], note that the address of p is not the address of a, the content of p is the address of a. Then the code will:
access the memory to get the content of p, i.e. the address of a.
compute the offset based on i and type of the pointer(int).
access the memory to get the result.
a is an array of int, if we access a[i], the address of a is just the address of a[0], the code will:
Compute the offset based on i and the type int.
Access the memory.
Pointer and array are different types. So if you declare int *p in one file and use it in that file, but define the p as an array in another file, that will cause problem.
You may also wonder about int *p = a, in ANSI, if you use an array(its name) as an expression, the compiler will convert it into a pointer, pointing to the very first element of the array.
Update based on Jim Balter's comments:
If you use an array(its name) as an expression, the compiler will not always convert it into a pointer, pointing to the very first element of the array. For instance, in sizeof(p->q->a), p->q->a is an expression but if a is an array it isn't converted into a pointer.
"Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object.
In C, you can only return a pointer of an array in a function.
For example, if you want to return a string(array of char) in a function, you can return a pointer to a null-ended string. If you want to return an array of some other type(int, user-defined struct, etc), you can alloc some memory to store the array, and return the pointer of the array, return the size of the array in the parameter.
example:
int *function(int *size)
{
*size = 10;
int *intP = (int *)malloc((*size)*sizeof(int));
return intP;
}
I would just like to confirm that when I have a function of the sort
int subtract(int a, int b)
{
return a-b;
}
I am passing values when i call subtract(3,2) rather than pointers.
Thanks,
Yes you are
a parameter of type int a means pass an integer by value to the function
a parameter of type int* a means pass a a pointer to some integer to the function.
so for this
int subtract(int a, int b)
{
// even if I change a or b in here - the caller will never know about it....
return a-b;
}
you call like this:
int result = substract(2, 1); // note passing values
for pointers
int subtract(int *a, int *b)
{
// if I change the contents of where a or b point the - the caller will know about it....
// if I say *a = 99; then x becomes 99 in the caller (*a means the contents of what 'a' points to)
return *a - *b;
}
you call like this:
int x = 2;
int y = 1;
int result = substract(&x, &y); // '&x means the address of x' or 'a pointer to x'
Yes, C always pass function parameters by value . To pass a pointer you have to specify the star (asterisk) that identify the pointer type.
Bear in mind that C always pass by value function parameters even in the case of a pointer, in that case the address of the pointer is actually copied .
Yes, you are passing values. A pointer would be denoted by an asterisk after the type name and before the variable name.