char *ch = "delhi"; // valid
int *arr = {1, 2, 3}; // invalid
int *arr = (int[3]){1, 2, 3}; // valid
Why some of the above statements are valid while others are invalid?
It's because array is treated as a constant pointer in the function it is declared. There is a reason for it. Array variable is supposed to point to the first element of the array or first memory instance of the block of the contiguous memory locations in which it is stored.
To declare a pointer to an array type, you must use parentheses, as the following example illustrates: int (* arrPtr)[10] = NULL; // A pointer to an array of // ten elements with type int. Without the parentheses, the declaration int * arrPtr[10]; would define arrPtr as an array of 10 pointers to int.
You can only add or subtract integers to pointers. When you add (or subtract) an integer (say n) to a pointer, you are not actually adding (or subtracting) n bytes to the pointer value. You are actually adding (or subtracting) n-times the size of the data type of the variable being pointed bytes.
Here is a list of the differences present between Pointer to an Array and Array of Pointers. A user creates a pointer for storing the address of any given array. A user creates an array of pointers that basically acts as an array of multiple pointer variables. It is alternatively known as an array pointer.
Disclaimer too: I'm answering the question for C++, and I think the answer won't apply to C, in many aspects.
In short, pointer and array are different things.
In c++,
int *arr = {1, 2, 3};
is invalid because pointer couldn't be initialized via list initialization.
int *arr = (int[3]){1, 2, 3};
is valid because array could be initialized via list initialization, and aggregate initialization will be appied for array actually. For this case, a temporary array will be constructed and then decayed to int*
and assigned to arr
. Note that the temporary variable will be destroyed after the statement so arr
will be dangled after that.
char *ch = "delhi";
is not valid from c++11, const char* ch = "delhi"
is valid. "delhi" is a string literal with type const char[6]
, and then decayed to const char*
and assigned to ch
. Because string literal has static storage duration and ch
won't be dangled.
Note that it's not the special rule for int
pointer, it's same for char
pointer too. const char* ch1 = { 'd', 'e', 'l', 'h', 'i', '\0'};
will fail too.
char *ch = "delhi"; // valid
This uses a string literal. The compiler generates a static c-string and assigns its starting address to ch
. This syntax is special for strings, and has been introduced for the convenience of avoiding typing something like char ch[] = {'d', 'e', 'l', 'h', 'i', '\0'};
every time.
int *arr = {1, 2, 3}; // invalid
{1, 2, 3}
is an array initializer, or a std::initializer_list
starting from c++ 11. In the first case, the array initializer is not an 'array literal' but a special convenience syntax that is understood by the compiler and applies to arrays only (int*
and int[]
are slightly different types). In the c++ 11 case you simply don't have conversion from std::initializer_list<T>
to T*
.
int *arr = (int[3]){1, 2, 3}; // valid
In this case you are telling the compiler to generate a temporary int[3]
array, initialize it with the list, and assign its address to arr
. Valid, but you should get a warning that you are taking the address of a temporary object or something like that.
EDIT (errata corrige):
The first part of the answer seems to imply that a string literal and a char[]
are the same thing. This was unintended, hopefully the part "The compiler generates a static c-string..." and the remark on the second paragraph avoided this misunderstanding in most cases.
The statement "{1, 2, 3} is a std::initializer_list in c++ 11" is not correct. "{1, 2, 3}" is a braced-list-initializer, which is not a type per se. It is a syntactical element that can initialize certain types depending on the context.
Disclaimer: I'm answering the question for C++ - some of the reasoning might also apply to C, but I haven't checked the latter.
String literals (the right side of your first example) are (in c++) const char
arrays with static storage duration. This means the compiler puts them somewhere in a fixed position in memory that remains valid during the whole execution of your program. As a result, you can assign them to a pointer just like any other array (storing the address of the first element).
Your particular example won't work in c++11 and later, because ch
would actually have to be of type const char*
. In C-however - and to the best of my knowledge - string literals are arrays of type char
(non const), so you can also assign them to a normal char
ptr and c++ versions prior to c++11 allowed this assignment for campatibility reasons.
The second line is invalid C++ code for multiple reasons: Contrary to the first line, the right side is not an array, so array to pointer decay doesn't work here. Now you can initialize a pointer with and initializer list, but only if
nullptr
)however, the meaning would be totally different compared to the first example: you wouldn't initialize the pointer with the address of an element in the initializer list but just with a copy
Now in the third example (which will be rejected by a c++ compiler by the way, but is OK for const int*
and const int[]
) I believe you are creating a temporary array that is initialized by copying the contents of the initializer list (the integer literals) and then assigning it to a pointer. Imho this should produce a dangling pointer as soon as the end of the statment is reached, but I'm not 100% sure of it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With