Why does int* ptr_arr_int = {1,2};
gives a compiler error, but whereas char* ptr_arr_char = "amruth";
compiles fine?
int* ptr_arr_int = {1,2}; // ->ERROR
char* ptr_arr_char = "amruth"; // ->OK
Why does int* ptr_arr_int = {1,2};
gives a compiler error, but whereas char* ptr_arr_char = "amruth";
compiles fine?
int* ptr_arr_int = {1,2}; // ->ERROR
char* ptr_arr_char = "amruth"; // ->OK
"amruth"
is a const char[7]
type in C++, and a char[7]
type in C (although the behaviour on attempting to modify the string is undefined).
This can decay to a const char*
or char*
type respectively in some circumstances, such as yours.
Although an int[2]
will similarly decay to an int*
in some circumstances, {1, 2}
is neither an int[2]
nor a const int[2]
type; rather it is a brace-initialiser.
As said, the string is an const char[7]
array and while that can decay to a char*
, {1, 2}
cannot decay to int*
(it's an brace initializer list, similarly: std::initializer_list
). But note there is also the array []
declaration which allows you to automatically declare arrays. Combine that with the list-initialization since C++11 and you are able to initialize both via []
:
int ptr_arr_int[] = { 1,2 }; //OK
char ptr_arr_char[] = "amruth"; //OK
A string by itself already implies a storage class -- it's a static
(+effectively const
) char
array declared using special syntax.
In contrast to that, it's not clear how {1, 2}
in int *ptr_arr_int = {1, 2}
should be stored. Should it be static
or auto
?
If you want it auto
when in a local scope or static
when in file scope, then in C>=99 you can explicitly do int *ptr_arr_int = &(int[]){1,2}[0];
(the &[0]
is optional).
You could conceivably make this implicit, but how far would you take this?int ****x = {1,2};
initialized by creating an array, a pointer to it, a pointer to that etc., could result int quite a bit of code/data and hiding a lot of code/data under a simple construct isn't quite the C way. It would also not be clear when the brace syntax should be initializing the ultimate target basic type or some of the intermediate pointer(s).
It is simply because the language syntax says so. Regarding arrays:
{...}
, containing no more items that what will fit inside the array.char
arrays can be initialized with a string literal, "..."
.However, you have no arrays in your code, you only have pointers.
A char*
can always be set to point at a string literal (in C) so char* ptr_arr_char = "amruth";
is valid. However, it is fishy style, because the string literal cannot be modified. Correct style is to use const char*
.
C++ is more strict and string literals in C++ have type const char[]
. and a C++ compiler will likely give a warning along the lines of "deprecated conversion" if you don't use const char*
.
As for int* ptr_arr_int = {1,2};
, it has two problems.
{1,2}
is an initializer list, but ptr_arr_int
is a single item, so it doesn't make any sense. There is a special, odd rule that actually allows us to use {}
when initializing a single variable, but then you must only have one single initializer inside.If you meant to have the pointer point at a temporary array, only existing in the local scope, then you could have used the C feature called compound literal:
int* ptr_arr_int = (int[]){1,2};
This is AFAIK not possible to do in C++ though, unless you rely on non-standard extensions. But in either language you could of course simply do this instead:
int arr[2] = {1,2};
int* ptr_arr_int = arr;
You are declaring an array of pointers to int
(int*
). But the values you initialize the array with (1
and 2
) are not pointers to integers, they are plain int
egers.
You cannot, because int *
is not a structure that could be initialized with two values like you did with = {1,2};
.
You could have initialized it this way:
int * ptr_arr_int = nullptr;
The other way could have been using an object that expects two values for construction:
struct Point
{
int a;
int b;
};
then you could have written:
Point p = {1,2};
No... that's not correct... that initialiser is only valid for arrays. Had you written:
int array[] = {1, 2};
it would be valid.... but you are trying to initialise a pointer variable, so this would be valid (despite of the warning, because 0xf45
is not an address):
int *pointer = { 0xf45 };
(because you put only a single entry, and it is considered a single value) but:
int *pointer = { 0xf45, 0 };
(You will get another warning about excess elements in scalar initializer
) This means that for a single variable you tried to use two initializers. The braces notation was born to be able to initialise arrays, but also is permitted to be used with scalar types. This means that the two notations:
{ 0 }; /* a single value between braces */
and
0;
are equivalent.
The solution to your problem is to do an extra step, declaring an array and then pointing to it from the pointer:
int array[] = {1, 2};
int *pointer = array;
but think that you can make pointer to point to a different place than the beginning of array, and you cannot array to be magically moved elsewhere. And &array
means the address of array array
while &pointer
means the address of the pointer variable pointer
. pointer
points to the address of array
, but array
is a constant pointer pointing to the address of array[0]
.
Pointers and arrays are somewhat confusing, but never think they are the same thing. Just compare sizeof(char[120])
with sizeof(char *)
and you'll see.