av[1] and av[1][0] Not the same address? - c

What's up ?
I can't understand this issue...
I know that the first element of an array stock the address of the entire array. But in this situation i can't figure it out.
#include <stdio.h>
int main(int ac, char **av)
{
printf("&av[1]= %p\n", &av[1]);
printf("&av[1][0]= %p\n", &av[1][0]);
return(0);
}
Input
./a.out "Hello"
Output
&av[1]= 0x7ffee0ffe4f0
&av[1][0]= 0x7ffee0ffe778

If somebody told you that char **av declares a two-dimensional array, they did you a disservice. In char **av, av is a pointer to a char *, possibly the first char * of several. So av[1] is a char *—it is a pointer to a char, and &av[1] is the address of that pointer.
av[1][0] is the char that av[1] points to, and &av[1][0] is the address of that char.
The pointer to the char and the char are of course not in the same place, so &av[1] and &av[1][0] are different.
In contrast, if you had an array, such as char av[3][4], then av is an array of 3 arrays of 4 char. In that case, av[1] is an array of 4 char, and &av[1] would be the address of (the start of) that array. &av[1][0] would be the address of the first char in that array. Since the char is at the beginning of the array, the address of the array and the address of the char are the same.
(However, they are not necessarily represented the same way in a C implementation, and printing them with %p can show different results even though they refer to the same place in memory.)

av isn't a two-dimensional array here. It's an array of pointers.
Whereas with a two dimensional array, &av[1][0] would have the same address as &av[1]; in an array of pointers , &av[1][0] means take the second (index=1) pointer, dereference it, and give me the address of the first element of what the dereferenced pointer target points at (the target of av[1] is also a pointer).
&av[1] is the address of the second char*, &av[1][0] is the address of the first character that the second char* points at. Different things.

av is an array of pointers where each element of this array points to a char array (of type char *) in which each character you are passing as input to the program is stored.
As you can see by the following variation of your program, av[0] stores the address of av[0][0] (i.e. points to the first position of the string stored in av[0][0]) which contains the character . and av[1] stores the address of av[1][0] (i.e. points to the first position of the string stored in av[1][0]) which contains the character H.
#include <stdio.h>
int main(int ac, char **av)
{
printf("&av[0]= %p\n", &av[0]);
printf("&av[1]= %p\n", &av[1]);
printf("av[0]= %p\n", av[0]);
printf("av[1]= %p\n", av[1]);
printf("av[0][0]= %c\n", av[0][0]);
printf("av[0][1]= %c\n", av[0][1]);
printf("av[0][0]= %p\n", &av[0][0]);
printf("av[0][1]= %p\n", &av[0][1]);
printf("av[1][0]= %c\n", av[1][0]);
printf("av[1][1]= %c\n", av[1][1]);
printf("av[1][0]= %p\n", &av[1][0]);
printf("av[1][1]= %p\n", &av[1][1]);
return(0);
}
which provides the following output:
$ ./a.out "Hello"
&av[0]= 0x7fff53625cf8
&av[1]= 0x7fff53625d00
av[0]= 0x7fff53626ee9
av[1]= 0x7fff53626ef1
av[0][0]= .
av[0][1]= /
&av[0][0]= 0x7fff53626ee9
&av[0][1]= 0x7fff53626eea
av[1][0]= H
av[1][1]= e
&av[1][0]= 0x7fff53626ef1
&av[1][1]= 0x7fff53626ef2
Graphically it is something like (significant part of addresses were removed for simplification purposes):
av: | 26ee9 | 26ef1 |
| |
av[0] av[1]
address: 25cf8 25d00
av[0]: | . | / | ...
| |
av[0][0] av[0][1]
address: 26ee9 26eea
av[1]: | H | e | ...
| |
av[1][0] av[1][1]
address: 26ef1 26ef2
I hope this clarifies your doubt.

av is a pointer to an array of pointers to chars. So its second element (the second element of the array) is, indeed a pointer. &av[1] is it's address (the address of a pointer, not the address of a character).
On the other side, av[1][0] is the first character of that second string. Its address is a char address, where the first character is stored.
Both addresses are addresses of different things, so it's normal they point to different places.
av[1] and &av[1][0] are, respectively, the pointer value (that points to the first char) and the address of the first char of the second string, so they must be pointers showing the same value. The same happens to *av[1] and av[1][0], they represent the same pointed to character.

Related

Why p and *p giving the same address when p points to an array?

I was writing this program -
#include<stdio.h>
void main()
{
int arr[20];
arr[0]=22;
arr[1]=23;
int (*p)[20]=&arr;
printf("address in p :%u:\n",p);
printf("address in *p:%u:\n",*p);
}
The Output of this code is same for p and *p ! So far as I know *p is holding the base address of arr which is nothing but arr[0]!!!
So *p should have give the output 22 ! But it's showing the same memory address like p is showing. Please tell me why this is happened? What is the reason behind it.
Codepad Site Link : http://codepad.org/LK7qXaqt
p is a pointer to an array of 20 integers. Address of first byte of array is said to be the address of the array. Dereferencing it will give the entire array itself. Therefore *p represents the array arr, so you can think of *p as an array name.
As array names are converted to pointers to its first element when passed to a function, *p is decayed to pointer to first element of arr. Therefore
printf("address in *p: %p:\n", (void*)*p);
will print the address of first element of array arr while
printf("address in p: %p:\n", (void*)p);
will print the address of the entire array (i.e first byte of the array). Since value of first byte and first element is same, that's why both are printing the same address.
For detailed explanation: What exactly is the array name in c?
Because p and *p points to same memory location only there types are different
+-+-+-+-+-+-+-+-+-+-+-+-+
| | | | | | | | | | | | |
+-+-+-+-+-+-+-+-+-+-+-+-+
arr [ ]
p [ ]
(*p)[ ]
If you print p+1 and *p + 1 you should see the difference
int (*p)[20] declare p as pointer to array of size 20 of type int so at the same time *p is the pointer to the first element of the array.
Address of first element and of whole array would be same.
Yes it is possible to apply the address operator to an array, although it seems redundant. The result p is a pointer to array. Such a thing is under normal circumstances rarely encountered. As #Mohit pointed out correctly, the object it points to is the whole array, which implies that sizeof(*p) should be the size of the array (not of its first element).
*p logically is the array then; as usual it decays to a pointer to its first element (which is an int) when passed as an argument, e.g. to printf. Since it's the first element its location in memory is the location of (the beginning of) the whole array.

Creates two pointers? char *name[] = {"xxx", "yyy"}

Somebody told me as an answer to my last question that
char *name[] = {"xxx", "yyy"}
is changed by the compiler to
char *name[] = {Some_Pointer, Some_Other_Pointer};
I tried the following for understanding:
printf("%p\n", &name);
printf("%p\n", name);
printf("%s\n", *name);
printf("%c\n", **name);
So as an output it gives me:
0xfff0000f0
0xfff0000f0
xxx
x
Can you explain to me how the address of the pointer "name" is the same as the address where the pointer "name" is pointing to?
From my understanding the pointer "name" itself occupies 8 bytes. How can the first string "xxx" which occupies 4 bytes in memory be at the same location as the pointer?
First of all, when you have any array like name in C, the value of the array is the address of its first element. Note that this value is not stored in some variable. It is used as an immediate value in the compiled assembly code. So it doesn't makes sense to think about its address.
Second, since an array is stored in memory as a bunch of consecutive location, the address of the array is defined the address of the first element. So for any array A you have the following equality of addresses
&(A[0]) == A == &A
It doesn't change anything to that if you have array of pointer or whatever.
To view the address of "xxx" you should print printf("%p\n", name[0]); like this. Surely address of name and address of "xxx" wont be the same. Here name is array of pointer which holds the address of "xxx and yyy".
printf("%p\n", &name);
printf("%p\n", name);
printf("%p\n", name[0]); address of "xxx"
printf("%p\n", name[1]); address of "yyy"
Can you explain to me how the address of the pointer "name" is the same as the address where the pointer "name" is pointing to?
&name give you the address of the entire array of pointers (which holds the pointers to the strings XXX and YYY) and name will give you the pointer to its first element, i.e, XXX (after decay). Since the address of the first byte is said to be the address of the variable (array), the value of &name is same as that of name but both of &name and name are of different type.
The type of name decays from array of char* to pointer to char* and its value is the address of the first element of the array. The expression &name is of type pointer to char* [2] and its value is the address of the array which is the same as the address of the array's first element.
It seems that you misunderstood the representation of array in C. There isn't a "meta" object representing an array in C. An array in C consists only its elements in sequence. Thus applying operator & to the array name simply gets you the address of the array's first element (value-wise, not type-wise).
If you try writing:
char (*p)[2] = &name;
printf("%p", &p);
This prints out the address of a pointer to an array, and it will certainly be a different value than name and &name.
From my understanding the pointer "name" itself occupies 8 bytes. How
can the first string "xxx" which occupies 4 bytes in memory be at the
same location as the pointer?
That's because name is an array, not a pointer. A pointer is a variable which stores the address of another variable of the same type but an array is a contiguous blocks of memory bound to (referenced by) a single identifier. Basically, it's a different type. Please note that arrays are not first class objects in C - you can't pass an array to or return an array from a function.
The confusion arises because an array in many situations decays (implicitly converted) into a pointer to its first element. Some case where this happens are:
void f(char p[]); // p is a pointer, not an array
// This is exactly the same as
void f(char *p);
char s[] = {'h', 'e', 'l', 'l', 'o'};
f(s); // here s decays to a pointer to its first element
// another example
char t = "hello"[1]; // the string literal decays to a pointer to its first element
Here are some cases where an array stays an array(does not decay into a pointer):
char s[] = "hello";
char *t = "hello"; // string literal decays into a pointer
printf("%d", sizeof s); // prints 5
printf("%d", sizeof t); // prints 4 or 8 depending on the pointer size on the machine
printf("%d", sizeof *t); // prints 1
// taking your example
char *name[] = {"xxxx", "yyyy"}; // yet another case where string literals decay to a pointer
printf("%p", name); // name is an array but here decays to a pointer
printf("%p", &name); // &name is a pointer to an array of 2 pointers to characters
Though name, &name evaluate to the same value in the printf call, they are not the same type. To see the difference do this:
printf("%p", name + 1);
printf("%p", &name + 1);
printf("%d", *(&name + 1) - name); // prints the length of the array
To sum up, arrays and pointers are different types. Pointers store addresses, arrays store values of type they are defined to store. In some situations arrays evaluate to the address of its first element. That's where the similarity ends between arrays and pointers.

Referencing char array pointers in C

I ran into a pointer dereferencing problem.
In C, &a means the address of a. If a is a pointer ,then &a simply means the address of that pointer.
So if we have:
char ptr [] = "abcd"
ptr should be a pointer pointing to the first character, which is 'a'. therefore,
&ptr
should be the address of ptr, which is different than the address of 'a'. However, when I tried the following code I got really confused:
int main()
{
char a [] = "abcd";
printf("0x%X 0x%X", a, &a);
}
Output: 0xBF7E62AB 0xBF7E62AB
Can someone explain why a and &a have the same value? Based on my understanding they should be different. thanks in advance
So if we have: char ptr [] = "abcd", ptr should be a pointer pointing to the first character.
No. Not at all.
ptr is an array. And an array is not a pointer.
Indeed, if you declared ptr as a real pointer, then you would get the expected behavior:
const char *ptr = "abcd";
printf("ptr = %p, &ptr = %p\n", (void *)ptr, (void *)&ptr);
As to why the address of the array is the same as the address of its first element: it's quite logical. The array represents a contiguous sequence of elements. The address of the array is where the array begins in memory. It begins where its first element begins. So, the address of the first element is (rather "can be" -- the standard does not mandate this behavior) the same as the address of the array itself.
+-----------+-----------+- - - -
| element 1 | element 2 |
+-----------+-----------+- - - -
^ start of array
^ start of first element
Can someone explain why a and &a have the same value? Based on my understanding they should be different.
In the statement
printf("0x%X 0x%X", a, &a);
Both a and &a are of different types. a is of char * type (after decay) while &a is of char (*)[5] type.
a decays to a pointer to the first element, therefore a is the address of first element of the string. While &a is the address of the string "abcd" and it is equal to the address of first element.
An array is not a pointer. That's right when you said &p is the address of the pointer, if p is definied like this:
char *p;
An array is different and don't has exactly the same behavior.
With the arrays:
char a[] = "abc";, &a[0] is the address of the first element in your array, which is the same as a.
char a[] = "abcd" does not declare a pointer a to "abcd" but an array. Even if an array can decay to a pointer, it is a different type for which &a and a yield the same address.
Basically a yields the address to the first element of the array, so it is equivalent to &a (and to &a[0]).
Arrays will always reference the location where it is stored in memory, that's why when you print a, it gives you the address where it is, which is equal to getting the pointer pointing at the array (&a)
To get the behaveour you seek change
char a [] = "abcd";
to
char *a = strdup("abcd");
or for a readonly string
const char *a = "abcd";
You will then get a different address for a and &a.
When passing an array to a function, the array gets converted to a pointer.
With your original program try
printf("%d %d\n",sizeof(a),sizof(&a));
The first will vary with the size of the string, the second will be based on the pointer size on your machine.

Array to pointer decay and passing multidimensional arrays to functions

I know that an array decays to a pointer, such that if one declared
char things[8];
and then later on used things somewhere else, things is a pointer to the first element in the array.
Also, from my understanding, if one declares
char moreThings[8][8];
then moreThings is not of type pointer to char but of type "array of pointers to char," because the decay only occurs once.
When moreThings is passed to a function (say with prototype void doThings(char thingsGoHere[8][8]) what is actually going on with the stack?
If moreThings is not of pointer type, then is this really still a pass-by-reference? I guess I always thought that moreThings still represented the base address of the multidimensional array. What if doThings took input thingsGoHere and itself passed it to another function?
Is the rule pretty much that unless one specifies an array input as const then the array will always be modifiable?
I know that the type checking stuff only happens at compile time, but I'm still confused about what technically counts as a pass by reference (i.e. is it only when arguments of type pointer are passed, or would array of pointers be a pass-by-reference as well?)
Sorry to be a little all over the place with this question, but because of my difficulty in understanding this it is hard to articulate a precise inquiry.
You got it slightly wrong: moreThings also decays to a pointer to the first element, but since it is an array of an array of chars, the first element is an "array of 8 chars". So the decayed pointer is of this type:
char (*p)[8] = moreThings;
The value of the pointer is of course the same as the value of &moreThings[0][0], i.e. of the first element of the first element, and also the same of &a, but the type is a different one in each case.
Here's an example if char a[N][3]:
+===========================+===========================+====
|+--------+--------+-------+|+--------+--------+-------+|
|| a[0,0] | a[0,1] | a[0,2]||| a[1,0] | a[1,1] | a[1,2]|| ...
|+--------+--------+-------+++--------+--------+-------++ ...
| a[0] | a[1] |
+===========================+===========================+====
a
^^^
||+-- &a[0,0]
|+-----&a[0]
+-------&a
&a: address of the entire array of arrays of chars, which is a char[N][3]
&a[0], same as a: address of the first element, which is itself a char[3]
&a[0][0]: address of the first element of the first element, which is a char
This demonstrates that different objects may have the same address, but if two objects have the same address and the same type, then they are the same object.
"ARRAY ADDRESS AND POINTERS TO MULTIDIMENSIONAL ARRAYS"
Lets we start with 1-D array first:
Declaration char a[8]; creates an array of 8 elements.
And here a is address of fist element but not address of array.
char* ptr = a; is correct expression as ptr is pointer to char and can address first element.
But the expression ptr = &a is wrong! Because ptr can't address an array.
&a means address of array. Really Value of a and &a are same but semantically both are different, One is address of char other is address of array of 8 chars.
char (*ptr2)[8]; Here ptr2 is pointer to an array of 8 chars, And this time
ptr2=&a is a valid expression.
Data-type of &a is char(*)[8] and type of a is char[8] that simply decays into char* in most operation e.g. char* ptr = a;
To understand better read: Difference between char *str and char str[] and how both stores in memory?
Second case,
Declaration char aa[8][8]; creates a 2-D array of 8x8 size.
Any 2-D array can also be viewed as 1-D array in which each array element is a 1-D array.
aa is address of first element that is an array of 8 chars. Expression ptr2 = aa is valid and correct.
If we declare as follows:
char (*ptr3)[8][8];
char ptr3 = &aa; //is a correct expression
Similarly,
moreThings in your declaration char moreThings[8][8]; contain address of fist element that is char array of 8 elements.
To understand better read: Difference between char* str[] and char str[][] and how both stores in memory?
It would be interesting to know:
morething is an address of 8 char array .
*morething is an address of first element that is &morething[0][0].
&morething is an address of 2-D array of 8 x 8.
And address values of all above three are same but semantically all different.
**morething is value of first element that is morething[0][0].
To understand better read: Difference between &str and str, when str is declared as char str[10]?
Further more,
void doThings(char thingsGoHere[8][8]) is nothing but void doThings(char (*thingsGoHere)[8]) and thus accepts any array that is two dimensional with the second dimension being 8.
About type of variables in C and C++: (I would like to add in answer)
Nothing is pass by reference in C its C++ concept. If its used in C that means author talking about pointer variable.
C supports pass by Address and pass by value.
C++ supports Pass by address, pass by value and also pass by Reference.
Read: pointer variables and reference variables
At the end,
Name Of an array is constant identifier not variable.
Nicely explained by Kerrek,
In addition to that, we can prove it by the following example:
#include <stdio.h>
int main ()
{
int a[10][10];
printf (".. %p %p\n", &a, &a+1);
printf (".. %p %p \n ", &a[0], &a[0]+1);
printf (".. %p %p \n ", &a[0][0], &a[0][0] +1);
}
The Output is :
.. 0x7fff6ae2ca5c 0x7fff6ae2cbec = 400 bytes difference
.. 0x7fff6ae2ca5c 0x7fff6ae2ca84 = 40 bytes difference
.. 0x7fff6ae2ca5c 0x7fff6ae2ca60 = 4 bytes difference.
&a +1 -> Moves the pointer by adding whole array size. ie: 400 bytes
&a[0] + 1 -> Moves the pointer by adding the size of column. ie: 40 bytes.
&a[0][0] +1 -> Moves the pointer by adding the size of element ie: 4 bytes.
[ int size is 4 bytes ]
Hope this helps. :)

Pointer to Pointer with argv

Based on my understanding of pointer to pointer to an array of characters,
% ./pointer one two
argv
+----+ +----+
| . | ---> | . | ---> "./pointer\0"
+----+ +----+
| . | ---> "one\0"
+----+
| . | ---> "two\0"
+----+
From the code:
int main(int argc, char **argv) {
printf("Value of argv[1]: %s", argv[1]);
}
My question is, Why is argv[1] acceptable? Why is it not something like (*argv)[1]?
My understanding steps:
Take argv, dereference it.
It should return the address of the array of pointers to characters.
Using pointer arithmetics to access elements of the array.
It's more convenient to think of [] as an operator for pointers rather than arrays; it's used with both, but since arrays decay to pointers array indexing still makes sense if it's looked at this way. So essentially it offsets, then dereferences, a pointer.
So with argv[1], what you've really got is *(argv + 1) expressed with more convenient syntax. This gives you the second char * in the block of memory pointed at by argv, since char * is the type argv points to, and [1] offsets argv by sizeof(char *) bytes then dereferences the result.
(*argv)[1] would dereference argv first with * to get the first pointer to char, then offset that by 1 * sizeof(char) bytes, then dereferences that to get a char. This gives the second character in the first string of the group of strings pointed at by argv, which is obviously not the same thing as argv[1].
So think of an indexed array variable as a pointer being operated on by an "offset then dereference a pointer" operator.
Because argv is a pointer to pointer to char, it follows that argv[1] is a pointer to char. The printf() format %s expects a pointer to char argument and prints the null-terminated array of characters that the argument points to. Since argv[1] is not a null pointer, there is no problem.
(*argv)[1] is also valid C, but (*argv) is equivalent to argv[0] and is a pointer to char, so (*argv)[1] is the second character of argv[0], which is / in your example.
Indexing a pointer as an array implicitly dereferences it. p[0] is *p, p[1] is *(p + 1), etc.

Resources