First, check this rule - from C11 Standard#6.3.2.1p3 [emphasis added]:
3 Except when it is the operand of the sizeof operator, the _Alignof 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.
From String literals [emphasis added]:
Constructs an unnamed object of specified character array type in-place, used when a character string needs to be embedded in source code.
Lets decode this first:
char * stringa = "a";
printf("***stringa[0] = %c\n", (*(char **)(void *)&stringa)[0]);
In this statement char * stringa = "a";
, string "a"
will convert to pointer to type char
that points to the initial element of the string "a"
. So, after initialisation, stringa
will point to first element of string literal "a"
.
&stringa
is of type char **
. Dereferencing it will give char *
type which is nothing but string "a"
and applying [0]
to it will give character 'a'
.
Now, lets decode this:
printf("***a[0] = %c\n", (*(char **)(void *)&"a")[0]);
Since, here you are giving unary operator &
so, in this expression, (*(char **)(void *)&"a")[0]
, string "a"
will not convert to pointer to its initial element and &"a"
will give the pointer of type const char (*)[2]
and that pointer will be type casted to char **
type.
Dereferencing this pointer will give value at address which is nothing but string "a"
, which it will think of as a pointer of type char
(because of type casting char **
) and applying [0]
to it. That means, it's trying to do something like this ((char *)0x0000000000000061)[0]
(0x61
is hex value of character 'a'
) which is resulting in the error EXC_BAD_ACCESS.
Instead, you should do
printf("***a[0] = %c\n", (*(const char (*)[2])(void *)&"a")[0]);
EDIT:
OP is still confused. This edit is an attempt to explain the expressions (above in the post) in a different way.
From comments:
OP: But you wrote ((const char ()[2])(void )&"a")[0] works! There are two dereferencing operations ( and [0]) going on here!
Not sure if you aware of it or not but, I think, it's good to share definition of []
operator, from C11 Standard#6.5.2.1p2:
The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))).
Expression (*(char **)(void *)&stringa)[0]
:
(*(char **)(void *)&stringa)[0]
| | |
| +----------------------+
| |
| this will result in
| type casting a pointer
| of type char ** to char **
|
|
This dereferencing
will be applied on result of &stringa
i.e. ( * ( &stringa ) )
and result in stringa
i.e. this
|
|
| &stringa (its type is char **)
| +-------+
| | 800 |---+
| +-------+ |
| |
+-------> stringa |
/ +-------+ (pointer stringa pointing to first char of string "a"
/ | 200 |---+ (type of stringa is char *)
| +-------+ |
now apply [0] 800 |
to it |
i.e. stringa[0]. +-------+
stringa[0] is +-> | a | 0 | (string literal - "a")
equivalent to | +-------+
*((stringa) + (0)) | 200 ---> address of "a"
i.e. |
*(200 + 0), |
add 0 to address 200 |
and dereference it. |
*(200 + 0) => *(200) |
dereferencing address |
200 will result in |
value at that address |
which is character |
'a', that means, |
*(200) result in -------+
Expression (*(char **)(void *)&"a")[0]
:
(*(char **)(void *)&"a")[0]
| | |
| +------------------+
| |
| this will result in
| type casting a pointer
| of type const char (*)[2] to char **
|
|
this dereferencing will be
applied to pointer of type
char ** which is actually a
pointer of type char (*)[2]
i.e. *(&"a").
It will result in value at address 200
which is nothing but string "a"
but since we are type casting
&"a" with double pointer (char **)
so single dereference result
will be considered as pointer of
type char i.e. char *.
*(char **)(void *)&"a"
|
|
| &"a" (its type is const char (*)[2] because type of "a" is
| +-------+ const char [2] i.e. array of 2 characters)
| | 200 |---+
| +-------+ |
| |
| |
| |
| +-------+
+------------------> | a | 0 | (string literal - "a")
/ +-------+
/ 200 ---> address of "a"
|
|
The content at this location will be
treated as pointer (of type char *)
i.e. the hex of "a" (0x0061) [because the string has character `a` followed by null character]
will be treated as pointer.
Applying [0] to this pointer
i.e. (0x0061)[0], which is
equivalent to (* ((0x0061) + 0)).
(* ((0x0061) + 0)) => *(0x0061)
i.e. trying to dereference 0x0061
Hence, resulting in bad access error.
Expression (*(const char (*)[2])(void *)&"a")[0]
:
(*(const char (*)[2])(void *)&"a")[0]
| | |
| +----------------------------+
| |
| this will result in
| type casting a pointer
| of type const char (*)[2] to const char (*)[2]
|
|
this dereferencing will be
applied to pointer of type
const char (*)[2]
i.e. *(&"a")
and result string "a"
whose type is const char [2]
|
|
| &"a" (its type is const char (*)[2] because type of "a" is
| +-------+ const char [2] i.e. array of 2 characters)
| | 200 |---+
| +-------+ |
| |
| |
| |
| +-------+
+------------------> | a | 0 | (string literal - "a")
/ +-------+
/ 200 ---> address of "a"
|
|
Apply [0] to "a"
i.e. "a"[0].
Now, scroll to the top of my post
and check string literal definition -
string literal constructs unnamed object of character array type.....
also, read rule 6.3.2.1p3
(which is applicable for an array of type) -
....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. ....
So, "a" (in expression "a"[0]) will be converted to pointer
to initial element i.e. pointer to character `a` which is
nothing but address 200.
"a"[0] -> (* ((a) + (0))) -> (* ((200) + (0)))
-> (* (200)) -> 'a'
From comments:
OP: there is no such thing as an object in C ....
Don't confuse word object with objects in C++
or other object oriented languages.
This is how C standard defines an object:
From C11 Standard#3.15p1
1 object
region of data storage in the execution environment, the contents of which can represent values
E.g. - int x;
--> x
is an object of type int
.
Let me know, if you have any more question.