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.
Related
char* s_ptr = "hello"; // (1)
int* a = 5; // (2)
Why does the first line work and the second doesn't? In the first case, there is no variable that stores "hello", and as I understand it, a "hello" object (char array) is created in memory and a s_ptr points to first element in array. Why is number 5 not created in memory in second case?
If you run printf("%p\n%p\n", s_ptr, a); it will probably be a little bit clearer. "hello" decays to a pointer (which arrays often does) and that pointer is assigned to the pointer s_ptr. On the other hand, the pointer a will simply be assigned to the value 5.
Try it out: https://onlinegdb.com/73pgzVmCJ
Related questions:
String literals: pointer vs. char array
What is array to pointer decay?
char* s_ptr = "hello"; // (1)
int* a = 5; // (2)
Why does the first line work and the second doesn't? In the first case, there is no variable that stores "hello", and as I understand it, a "hello" object (char array) is created in memory and a s_ptr points to first element in array. Why is number 5 not created in memory in second case?
The first line (1) assigns a reference to a string literal (which is an array of characters) to a char * (character pointer) variable. This is perfectly valid, as the string literal expression is of type pointer to char and the variable s_ptr is defined as pointer to char.
The second line (2) assigns the value 5 (integer) to a int * which is an integer pointer, and that's a different type (not possible to convert automatically)
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.
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. :)
OK, I'm having trouble understanding pointers to pointers vs pointers to arrays.
Consider the following code:
char s[] = "Hello, World";
char (*p1)[] = &s;
char **p2 = &s;
printf("%c\n", **p1); /* Works */
printf("%c\n", **p2); /* Segmentation fault */
Why does the first printf work, while the second one doesn't?
From what I understand, 's' is a pointer to the first element of the array (that is, 'H').
So declaring p2 as char** means that it is a pointer to a pointer to a char. Making it point to 's' should be legal, since 's' is a pointer to a char. And thus dereferencing it (i.e. **p2) should give 'H'. But it doesn't!
Your misunderstand lies in what s is. It is not a pointer: it is an array.
Now in most contexts, s evaluates to a pointer to the first element of the array: equivalent to &s[0], a pointer to that 'H'. The important thing here though is that that pointer value you get when evaluating s is a temporary, ephemeral value - just like &s[0].
Because that pointer isn't a permanent object (it's not actually what's stored in s), you can't make a pointer-to-pointer point at it. To use a pointer-to-pointer, you must have a real pointer object to point to - for example, the following is OK:
char *p = s;
char **p2 = &p;
If you evaluate *p2, you're telling the compiler to load the thing that p2 points to and treat it as a pointer-to-char. That's fine when p2 does actually point at a pointer-to-char; but when you do char **p2 = &s;, the thing that p2 points to isn't a pointer at all - it's an array (in this case, it's a block of 13 chars).
From what I understand, 's' is a pointer to the first element of the array
No, s is an array. It can be reduced to a pointer to an array, but until such time, it is an array. A pointer to an array becomes a pointer to the first element of the array. (yeah, it's kinda confusing.)
char (*p1)[] = &s;
This is allowed, it's a pointer to an array, assigned the address of an array. It points to the first element of s.
char **p2 = &s;
That makes a pointer to a pointer and assigns it the address of the array. You assign it a pointer to the first element of s (a char), when it thinks it's a pointer to a pointer to one or more chars. Dereferencing this is undefined behavior. (segfault in your case)
The proof that they are different lies in sizeof(char[1000]) (returns size of 1000 chars, not the size of a pointer), and functions like this:
template<int length>
void function(char (&arr)[length]) {}
which will compile when given an array, but not a pointer.
Here's the sample that works, plus printouts of pointer addresses to make things simple to see:
#include <stdio.h>
char s[] = "Hello, World";
char (*p1)[] = &s;
char *p2 = (char*)&s;
int main(void)
{
printf("%x %x %x\n", s, p2, *p2);
printf("%x\n", &s); // Note that `s` and `&s` give the same value
printf("%x\n", &s[0]);
printf("%c\n", **p1);
printf("%c\n", *p2);
}
I was trying to learn strings in C when I came across this code.
#include <stdio.h>
int main(){
char s[] = "Hello world";
printf("%s" , s);
printf("%s" , &s);
return 0;
}
Both gave Hello World as output. According to my understanding, this output is Ok for First case. How is it working for the second one? Please clarify.
Taking the address of an array is the same as taking the address of it's first element. When the array's name is used, then it also decays to the address of it's first element- so the expressions s and &s yield the same result.
s returns the address of the first item in the array and &s returns the address of the array itself -- these happen to be the same.
In general, if you wish to be more explicit, the expression &s[0] can also be used to return the address of the first item.
s and &s return the same address and hence. This address is the location where "H" from "Hello world" is stored.
Because,
The name of the array decays to the address of the first element in an array &
The address of first element is same as address of the array.
Just for what it may be worth, if you want to get technical, your second version:
printf("%s" , &s);
has undefined behavior, and only works by accident. By explicitly taking the address, you're getting the address of the array (which is fine) but the result has the type "pointer to array of 12 characters", rather than the type "pointer to char", as required for printf's %s conversion. Since the types don't match, the result is undefined behavior.
In reality, however, that's purely a technicality -- the code will work just fine on every implementation of C of which I'm aware.
If you wanted to demonstrate that the difference exists, you could do so pretty easily though. For example:
char string[] = "hello world";
printf("without &: %p, %p\n", (void *)string, (void *)(string+1));
printf("with &: %p, %p\n", (void *)&string, (void *)(&string+1));
In the first case, string decays to a pointer to char, so on the first line, the second pointer will be exactly one greater than the first. On the second line, we're adding one to a pointer to an array of characters, so when we add one, it'll actually add the size of the array. Running this on my machine, I get results like this:
without &: 0038F96C, 0038F96D
with &: 0038F96C, 0038F978
char s[] is similar to char *s that is a charecter pointer that points to the first element of the array (it contains the address of the first element stored).
we can also store strings by storing the address of the first character. during the time of execution, computer start taking characters from that address one by one and make a string until it reaches a null character('\0').
in the above example 's' and '%s' represents the same value (the address of the starting character) hope you will get it.
if you use char s[10] (fixed length array) you will understand everything.
s is equivalent to &s[0] so we are passing address of s[0] not the address of pointer that is pointing to s[0] so it will print Hellow world in second case.
s is name of array not a pointer.