1

Update:
I consider this question to be distinctly different from the questions marked as possible duplicates because of my use of the keyword "const." The answers marked as duplicate do not adequately explain the implications of const in these cases. It seems to me that const should force the compiler to treat these two cases the same, even though without const they are different. See my comment below my question for more details.

What's the difference between const char myStr[] = "hello" and const char* myStr = "hello"?

When I compile the former, the compiled program size is 20 bytes more than the latter, though the two cases take the same amount of space for global variables. Compiler optimization is set to "-Os".


Update:
-As far as compiled program size goes, static const char myStr[] = "hello" is identical to const char* myStr = "hello", which is identical to getting rid of the variable and just passing in the string literal "hello" directly to the function as a parameter. const char myStr[] = "hello" takes 20 bytes more than the other cases just mentioned. char myStr[] = "hello" is identical in program size to its "const" counterpart.


I am passing this string to a function I wrote which requires const char str[] as an input parameter.

Part 2: is the function requiring const char str[] as an input parameter identical to one requiring const char* str as an input parameter?

Related (but not the same) questions

Community
  • 1
  • 1
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
  • 2
    Part 2: http://stackoverflow.com/questions/6567742/passing-an-array-as-an-argument-to-a-function-in-c – user253751 Oct 12 '15 at 02:39
  • 2
    Part 1: you already linked to several answers that answer it... – user253751 Oct 12 '15 at 02:39
  • Part 1: my links don't seem to answer it quite right. They basically say the latter (char*) is a pointer to a string literal which cannot be modified, whereas the former (char str[]) is a char array which *can* be modified. But this doesn't make sense. If I make them both "const" I don't understand why the compiler wouldn't consider them *both* NOT able to be modified, and treat the `const char str[]` version identically to the `const char* str` version. – Gabriel Staples Oct 12 '15 at 02:45
  • const char myStr[] = "hello". myStr is a type of 6-size of array of char. For const char* myStr = "hello", myStr is a type of pointer of char (size may be 4bytes or 8bytes). Check http://cpp.sh/4gzr – Chen OT Oct 12 '15 at 02:46
  • 1
    `const char *myStr = "Hello";` basically means `static const char Hello_string[] = "Hello"; const char *myStr = &Hello_string[0];` – user253751 Oct 12 '15 at 02:50
  • Thanks @immibis, this makes sense and clarifies some things. Programming is tough. So many nuances. – Gabriel Staples Oct 12 '15 at 03:10

8 Answers8

3
const char myStr[] = "hello";

You defined a const char array containing 6 elements (including '\0'), i.e. {'h', 'e', 'l', 'l', 'o'. '\0'}, which is copied from the c-style string literal "hello".

const char* myStr = "hello";  

You defined a pointer of type const char*, pointing to the c-style string literal "hello".

You can see the difference by using sizeof, LIVE on ideone.com gave the result that the former's size is 6, the latter's size is 4.

is the function requiring const char str[] as an input parameter identical to one requiring const char* str as an input parameter?

As function parameter, they're same because array will decay to pointer when you passing it to the function. But using const char str[] make it more clear that the function is expecting an array, not just a pointer (pointing to single object, etc). Note if you pass the array by reference (i.e. const char(&)[size]), it will not be decayed to pointer, and the size of array will be reserved.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
3

It's actually very simple.

const char myStr[] = "Hello, world!\n";

In this case, sizeof(myStr) == 14, because the whole string is located in the stack! It's effectively the same as...

const char myStr[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n', '\0' };

Now, something like...

char myStr[] = "Hello, world!\n";

Is perfectly fine, and allows you to modify the array's contents later on.

Now, this...

const char *myStr = "Hello, world!\n";

Will reserve memory for constant array of characters, namely "Hello, world!\n" somewhere, usually in read-only memory, and assign that array's address to myStr. Thus, sizeof(myStr) == sizeof(const char*).

Now, this is the tricky one...

char *myStr = "Hello, world!\n";

Once in a (long) while, there used to be no const keyword in the C language. As such, programmers remembered what can be modified and what not. In this example, the memory pointed to by myStr is modifiable, according to the type system, but it's not, according to the rules of string literals. Thus, modifying *myStr involves undefined behaviour.

Now, there's just one little additional detail. According to the rules of array-to-pointer degradation, declaring a parameter of type const char* is the same as declaring one of type const char[].

3442
  • 8,248
  • 2
  • 19
  • 41
1
const char* myStr = "hello";  

defines a string constant with the value "hello".

char* myStr = "hello";  

defines a (read-only) constant too, even without const, changing it is undefined behaviour. Some compilers (in some configurations) will warn because of the missing const.

const char myStr[] = "hello";  

defines a string constant with the value "hello", same as above.

char myStr[] = "hello";  

defines an array which can be changed later, with initial value "hello"
(array size = length of hello + terminating 0)

Yes, it's a nasty thing that the * variant is always constant.

When making a function parameter, const char str[] and const char *str are the same. The difference is only when defining new variables, not when specifying a parameter type etc.

deviantfan
  • 11,268
  • 3
  • 32
  • 49
1

const char myStr[] = "hello" copies the string into a buffer. If it's a local variable, it will be pushed onto the stack each time, which is possibly less efficient unless you make it static, but then you might as well just use const char* myStr = "hello". You can pass either to a const char str[] parameter.

Some compilers perform a string-pooling optimization for string literals. If you explicitly request it to be stored in a buffer, I suspect the compiler may not use a string-pooling optimization on the buffer.

Therefore I recommend const char* myStr = "hello" or better const char* const myStr = "hello" (as it may allow the compiler to optimize out the pointer variable in memory, as it knows it cannot be changed).

Neil Kirk
  • 21,327
  • 9
  • 53
  • 91
1

In the first case, the variable is an array, which uses 6 bytes and is initalized to a string. If the variable is local, the space will get allocated upon entry into the function with the contents of the string.

In the second case, the variable is a pointer to an array, while array is located somewhere else. If you define two such pointers, they may point to the same location. If the variable is local, the pointer gets initialized upon entry into the function to point to the string. If you wish, you can assign a different value to the pointer later and make it point somewhere else.

I suggest you look at the disassembly. Although the compiler is free to optimise it as it pleases.

It doesn't make any differemce when passing to a function.

PineForestRanch
  • 473
  • 2
  • 11
  • If you're interested in "const" then in the first case it refers to the array, but in the second case, it refers to the contents pointed to by the pointer. You can make the pointer constant too if you wish - const char * const = "something"; – PineForestRanch Oct 12 '15 at 02:56
0

Another difference: You can re-assign the (const) char* myStr to a different char * (or even 0), but you cannot re-assign the (const) char myStr[] - that will generate a compiler error.

franji1
  • 3,088
  • 2
  • 23
  • 43
0

The two look similar from the outside, but are actually quite different in terms of how they're implemented. In this case, I think the old line about a picture being worth 1000 words is pretty accurate, so let's start with a pair pictures:

enter image description here

The first represents something like char const *myStr = "hello";. We have a local pointer name myStr that points to some constant data that holds the string hello. The dotted line represents the fact the what happens here isn't data movement--myStr just points to the string literal itself.

The second represents something like char const mystr[] = "hello";. This still has a copy of the string in the constant data. Upon (for example) entry into the function where myStr was defined, that constant data is used to initialize the local storage allocated for myStr itself. In this case, the solid line indicates that there really is data movement involved--at least in theory, every time the function containing myStr is entered (assuming it's defined inside a function) that same data is copied into a newly allocated local variable.

It is, of course, possible that in a case like you've shown where myStr is const array that the compiler could actually optimize the code so the copy doesn't take place upon every entry to the routine. Nonetheless, it must act like an array, not a pointer.

For example, in the first case (char const *myStr = ...;), if you use sizeof(myStr), the result must be the same as sizeof(char const *) (typically 4 or 8). In the second case (regardless of any optimization) sizeof(myStr) must give the size of the array itself, so hello will give six (the size includes the terminating NUL). If you used a different string (e.g., "hello there, how are you today?") the first case would be unaffected--you'd still get the size of a pointer. The second case would change completely--myStr is the array of characters itself, so changing the number of characters it contains will change its size (to 32 in this case, if I've counted correctly).

As far as the const goes, it doesn't change much of anything. In the case of a pointer to a literal (char const *myStr = "hello";) you're no longer (as of C++11) allowed to create the pointer without the const qualifier. Before that, you could create a non-const pointer, but you still had to basically act as if it were const--any attempt at modification via that pointer (or any other pointer to the string literal) resulted in undefined behavior.

With the array (char myStr[] = "...";) the const prevents you from modifying the content of the array. As noted above, the compiler might theoretically be able to optimize things so it didn't really create a local upon every entry to a containing function, and initialize that local from the constant storage. In reality, it's pretty much irrelevant, and fairly difficult to even detect with any certainty (which is most of the reason it would be allowed to start with).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
0

In my view: static const char myStr[] = "hello"; Stores the array 'myStr' {sizeof(myStr) = strlen("hello") + 1}in the Data Segment, which means this is a runtime thing. Also it compiles the "hello" word in the program's Code Segment(text). static const char *myStr = "hello"; Stores just a pointer 'myStr' {sizeof(myStr) = } in the Data Segment. And the same with word "hello" in the program's Code Segment.

While you try to use these two in a function's stack: const char myStr[] = "hello"; Means that you explicitly allocate sizeof(myStr) memory from the function's stack, and then do the string copy thing, and the string copy thing is expensive. const char *myStr = "hello"; Just allocate a pointer and then assign it with the right address.

Lea
  • 46
  • 5