I'm trying understand how to pass a parameter by reference in C language.
So I wrote this code to test the behavior of parameters passing:
#include <stdio.h>
#include <stdlib.h>
void alocar(int* n){
n = (int*) malloc( sizeof(int));
if( n == NULL )
exit(-1);
*n = 12;
printf("%d.\n", *n);
}
int main()
{
int* n;
alocar( n );
printf("%d.\n", *n);
return 0;
}
Here is printed:
12.
0.
Example 2:
#include <stdio.h>
#include <stdlib.h>
void alocar(int* n){
*n = 12;
printf("%d.\n", *n);
}
int main()
{
int* n;
n = (int*) malloc(sizeof(int));
if( n == NULL )
exit(-1);
alocar( n );
printf("%d.\n", *n);
return 0;
}
It printed:
12.
12.
What's the difference of this two programs?
C is pass-by-value, it doesn't provide pass-by-reference.
In your case, the pointer (not what it points to) is copied to the function paramer (the pointer is passed by value - the value of a pointer is an address)
void alocar(int* n){
//n is just a local variable here.
n = (int*) malloc( sizeof(int));
//assigning to n just assigns to the local
//n variable, the caller is not affected.
You'd want something like:
int *alocar(void){
int *n = malloc( sizeof(int));
if( n == NULL )
exit(-1);
*n = 12;
printf("%d.\n", *n);
return n;
}
int main()
{
int* n;
n = alocar();
printf("%d.\n", *n);
return 0;
}
Or:
void alocar(int** n){
*n = malloc( sizeof(int));
if( *n == NULL )
exit(-1);
**n = 12;
printf("%d.\n", **n);
}
int main()
{
int* n;
alocar( &n );
printf("%d.\n", *n);
return 0;
}
Actually not really much a difference, except the first one is broken. :) (Well, both are, but the first is broken more).
Let me explain what happens in the second case:
- variable
n
of type pointer-to-int
is allocated on the stack
- a new variable of type
int
is allocated to the stack, it's address is stored in variable n
- function
alocar
is called, being passed the copy of variable n
, which is the copy of the address of our variable of type int
- the function sets the
int
variable being pointed by n
to 12
- the function prints the value of the variable being pointed by
n
(12)
- the function returns
The first case:
- variable
n
of type pointer-to-int
is allocated on the stack
- the function
alocar
is called with a copy of the variable n
(which is still uninitialized - contains an unknown value)
- a new variable of type
int
is created in memory and the local copy of variable n
in function alocar
is set to point to that new variable
- the variable (pointed by the function's local copy of
n
) is set to 12 and printed
- the function returns, again in the main() function:
- since the original
n
variable in main is still uninitialized, it points to a random place in memory. So the value in random place in memory is printed (which is likely to crash your program).
Also, both programs are broken because they don't free the memory allocated by malloc().
You want to modify the value of n
in main
, not what n
points to, so you need to pass a pointer to it. Since the type of n
in main
is int *
, the parameter to alocar
needs to be of type int **
:
void alocar(int **n)
{
*n = malloc(sizeof **n); // note no cast, operand of sizeof
if (!*n)
exit(-1);
**n = 12;
printf("%d\n", **n);
}
int main(void)
{
int *n;
alocar(&n);
printf("%d\n", *n); // we've already tested against n being NULL in alocar
free(n); // always clean up after yourself
return 0;
}
The answer posted by nos is correct.
Also note that the first of the two posted programs will actually crash on many systems, when the printf line in main() tries to dereference main's pointer n
, which was never set:
printf("%d.\n", *n);
See, what's happened in first program.
Before call to alocar we have just variable n in main, pointing to some undefined place:
main()::n [ X--]--->(?)
(there's value in square brackets, which is undefined, marked as X). Then we call alocar, and we have another variable in alocar's scope, which have a copy of origianl var.
main()::n [ X--]--->(?)
alocar()::n [ X--]-----^
Now, allocate some memory:
main()::n [ X--]--->(?)
alocar()::n [ *--]--->[ Y ]
Assign value to allocated var:
main()::n [ X--]--->(?)
alocar()::n [ *--]--->[ 12 ]
Return. alocar()::n is removed as it live only while alocar() is executed.
main()::n [ X--]--->(?)
[ 12 ]
main()::n is still pointing to some undefined place... (Which possibly stores value 0) And no one points to allocated place.