简体   繁体   中英

Initializing char* vs int*

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.

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;

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 (ie {1, 2, 3} ) is not an array, and therefore can't be used to initialize the pointer.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM