19

This is possible in C++:

const char* ch = "hello";

But something like this is not possible:

int* i = { 1, 2, 3 };

Both char *ch and int* i are plain pointers. Why can char* be assigned with multiple chars while int* can not be assigned with multiple ints?

I know we can use

int x[] = {1, 2, 3};

but that is not the question.

Peeyush Kushwaha
  • 3,453
  • 8
  • 35
  • 69
codekiddy
  • 5,897
  • 9
  • 50
  • 80
  • 8
    Character literals (`"hello"`) are special beasts in c and c++. – πάντα ῥεῖ Aug 16 '14 at 10:56
  • 2
    You shouldn't initialize `char *` with a string literal. `const char *`. – Robert Allan Hennigan Leahy Aug 16 '14 at 10:57
  • `char* ch = "hello";` is valid C, but invalid C++ (though it used to be valid there too). Please tag your question appropriately. –  Aug 16 '14 at 10:58
  • 1
    @WhozCraig That's valid C, and invalid C++. It's unclear what language the OP is interested in. –  Aug 16 '14 at 11:03
  • thank you for all your valuable inputs, I edited my post to reflect both C and C++ – codekiddy Aug 16 '14 at 11:03
  • @codekiddy The point is that there are good answers for C that are completely useless for C++, and there are good answers for C++ that are completely useless for C. Do you really only want to get answers that are correct for both languages, which will neither be the best answer for C, nor the best answer for C++? –  Aug 16 '14 at 11:05
  • @hvd yeah, I see that, and still not sure what the real question is. And they're different constructs anyway. The synonymous construct for `char*` would be `char * ch = {'a', 'b', 'c'};` which is just as wrong as the `int*` version. – WhozCraig Aug 16 '14 at 11:07
  • sorry for mess, I removed the C tag, I just want to know the background why const char* x = "something" is possible. – codekiddy Aug 16 '14 at 11:09
  • 1
    You're confusing `char` and `char*`. – Lightness Races in Orbit Aug 16 '14 at 14:03
  • @LightnessRacesinOrbit I don't think he is. It's clear that the man wants to know why a `char` pointer can point to a sequence of `char`s rather than just to a single `char`. – async Aug 16 '14 at 22:16
  • `char *ch = "hello";` is valid C++, although deprecated. – M.M Aug 21 '14 at 08:29
  • C will find its duplicate [here](http://stackoverflow.com/questions/24805673/declare-and-initialize-pointer-concisely-i-e-pointer-to-int). – Quentin Aug 21 '14 at 08:36

3 Answers3

15
const char* ch = "hello";

is sort of like

static const char string_literal[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
const char* ch = &string_literal[0];

except that each identical string literal does not necessarily point to a distinct location in memory.

The same is also possible for any other type:

static int integer_list[] = { 1, 2, 3 };
int* i = &integer_list[0];
// or equivalently, just int* i = integer_list;

Now, i[0] is 1, i[1] is 2, and i[2] is 3.

There is a special syntax for string literals, because they are so frequently used, and so frequently in contexts where it is not desirable to clutter the code with dummy variables.

If you've got a lot of code that uses statically allocated read-only arrays of integer type, you may be able to hide the boilerplate using templates:

template <int a, int b, int c>
struct int_array { static const int values[3]; };
template <int a, int b, int c>
const int int_array<a, b, c>::values[] = { a, b, c };

You only need to define the template once, and then each different user can use that template for the specific values that user is interested in.

const int* i = int_array<1, 5, 6>::values;

Often, it will be easier to simply define a separate array variable, but there are cases where such a template helps.

As noted in the comments, it's possible to define the template more generically, so that it works for arrays of arbitrary type and arbitrary length, but it requires an up-to-date compiler with good support for the current version of C++ (for GCC and clang, current versions are fine, but make sure to pass the -std=c++11 or -std=gnu++11 option to enable C++11 features):

template <typename T, T... v>
struct static_array {
  static const T values[sizeof...(v)];
};

template <typename T, T... v>
const T static_array<T, v...>::values[sizeof...(v)] = { v... };

Now, the syntax for a user of this array is

const int* i = static_array<int, 1, 2, 3, 4>::values;
const unsigned* j = static_array<unsigned, 1, 2, 3, 4, 5>::values;
T.C.
  • 133,968
  • 17
  • 288
  • 421
  • is it possible to write a variadic version of the template? – Karoly Horvath Aug 16 '14 at 11:20
  • "There is a special syntax for string literals, because they are so frequently used, and so frequently in contexts where it is not desirable to clutter the code with dummy variables." Thanks! – async Aug 16 '14 at 22:13
4

A string literal is an array of characters. Note that ch is just a pointer to a single character so it really doesn't point to the string as a whole but just its base address (the address of the first character). An initializer-list (i.e {1, 2, 3}) is not an array, and therefore can't be used to initialize the pointer.

David G
  • 94,763
  • 41
  • 167
  • 253
  • Oh, I see now, so basicaly the quotes can be imagined as "initializer list" or an array for chars. – codekiddy Aug 16 '14 at 11:15
  • @codekiddy "hello" is type `const char[6]`. The expression assignment does what assigning any "array" does to a proper-typed pointer; express as the address of the first element. It isn't some initializer list. its an *array*, and you're saving off its first element address. The only initialization going on is the initialization of the pointer with said-address. – WhozCraig Aug 16 '14 at 11:18
3

The character literal is compiled to a piece of initialized storage in the data segment of your binary. The const char * is a pointer to that storage.

As a matter of fact, it should be possible to do the same for an const int *, if only you had the address of a memory block. You could do this using inline assembler (but I never tried) specifying a .data segment.

xtofl
  • 40,723
  • 12
  • 105
  • 192
  • In C99 and later you can have array literals of other types; not exactly sure why C++ didn't do something similar – M.M Aug 21 '14 at 08:31