Reputation: 12905
I thought that an array variable cannot be changed in C, i.e. the base address of an array is unchangeable, but the following code contradicts my assumption :
#include <stdlib.h>
#include <stdio.h>
void changeArray(int **a)
{
*a = malloc(sizeof(int));
}
int main()
{
int a[10];
a[0] = 1;
printf("%d\n",a[0]);
changeArray(&a);
printf("%d\n",a[0]);
}
This code prints :
1
6750576(some random value)
So clearly the base address of an array has been changed. How is it possible?
Upvotes: 2
Views: 1589
Reputation: 1
void changeArray(int **a)
{
printf("\n *a=%p",*a);
*a = malloc(sizeof(int));
printf("\n *a=%p",*a);
}
int main(){
int a[10];
a[0] = 1;
printf("\n..correct...Array Address=%p",a);
printf("\nbefore.....%d",a[0]);
changeArray(&a);
printf("\nafter....%d",a[0]);
printf("\n Array address=%p",a);
return 0;
}
Array Address = 0x7fff287e6130
Before :
1
*a=0x1
*a=0x13a3e010
After :
329506832
Array address=0x7fff287e6130
329506832 is the decimal value of 0x13a3e010
You can see it in your Windows programmer calculator.
The array address is a const pointer, so it will never change.
Here *a means First value of array... not the address of array. For cross-checking... after changeArray Function iterate over the array, you get to know it's first element that gets changing not the array adress which is const poiter....
What you are doing is using malloc system call you are requesting 4 bytes of memory and then that address will get stored in first array element....
Take pen and paper, then you'll get it easily.
Upvotes: 0
Reputation: 506975
The code is playing evil pointer games, without luck. You are passing a pointer having type int(*)[10]
to a function that wants a pointer having type int**
. The pointer you pass has as value the "base address" of the array.
So, when you dereference the int**
, it thinks at that address it gets an int*
, even though what it looks at is an int
object. And it writes the address returned from malloc
into that memory cell.
Back in main, you print out that cell. Note that it is the value of the array's first element, not the address of the array's first element. So what is printed is the integer value interpretation of the address you wrote in the called function.
What you do is undefined behavior: The function wants a int**
, so you have to give it an int**
,
Here is how i think you view the matter
- You hear someone say that an array name is a constant pointer to its first element
- You take the address of that pointer, cast away any const
- You happily write some other address into the pointer, and hope that it doesn't crash
- You use the array again, expecting it "overlays" now the uninitialized memory region that malloc created.
But that view is flawed. The first point is flawed the most, because an array name is not a constant pointer. If the first point were correct, your snippet would make a lot more sense, actually. But an array name will generate an address value that refers to its first element when you use it in an expression, except in very few cases (sizeof, address-of).
Because that address value is not generated when you use address-of, you will get a pointer to that array instead (which was exactly what you wrote with the address-of operator). Since it makes sense that an array and the first element of it has the same address, the address of an array happens to equal to the address of its first element. So what you actually did was writing into the first element, instead of writing into some pointer (that in reality isn't there).
Response to Comment
Consider what happens when the type of the array matters in practice (out of these experiments). You have an array whose elements are arrays themselves.
// array of 3 "array of 10 int"
int a[3][10];
So, by using a
in an expression other than &
and sizeof
, you will get a pointer to the first element, int(*)[10]
. This is crucial, because the following writes into an integer that's offset 2*sizeof(int)*10
bytes
a[2][0] = 1;
// (a + 2) refers to a offset by 2*sizeof(int)*10 bytes
If a
in that expression would give you an int**
, then the compiler would have no idea where it should store the integer 1
correctly into, because any size information about the element type is lost. It could surely store the size somewhere in memory, but where? In the array, there is no space for that. And in addition, sizeof
couldn't be able to give you a compile time result anymore.
Upvotes: 14
Reputation: 340208
The expression &a
returns the address of the array a
. That address gets passed into the chageArray()
function as if it were a **int
.
Inside the changeArray()
function, the expression *a
dereferences the pointer a single time, so the result of the expression is an lvalue correpsonding to the int variable at that address.
Outside of the changeArray() function you can think of the expression &a
is the same as &a[0]
.
So what you've done in the changeArray() function is
*(&a[0]) = malloc(sizeof(int));
which is equivalent to
a[0] = malloc(sizeof(int));
Upvotes: 0
Reputation: 16701
&a
does not result in int **
as you think it does. It evaluates to int *[10]
just like a
does in the following code snippet:
#include <stdio.h>
int main(void)
{
int a[10];
printf("%p %p\n", a, &a);
return 0;
}
This prints for me:
0xbffff058 0xbffff058
So your changearray
function is assigning the pointer being returned by your malloc
to the first element of the array a
in main
.
Further, if you compiled with -Wall
, you will see the a warning (as you should):
bad.c:14: warning: passing argument 1 of ‘changeArray’ from incompatible pointer type
Upvotes: 1
Reputation: 1253
Which compiler did you use to compile the code? I tried using VC++ 2005, the code is illegal, which says "cannot convert parameter 1 from 'int (*__w64 )[10]' to 'int **'"
I am interested in how you compile the code and get the weired result.
Upvotes: 0
Reputation: 754725
In this code you have not changed the base address of the array. You have changed the value of the first element in the array.
Upvotes: 2