Difference between char* and char[]

Recently I came across something that puzzled me, an array had been declared using char *sent = "This is a sentence";. I know that arrays are very similar to pointers but the code confused me as usually an array has a fixed size and the above does not have any size limit and unless the memory block after the last character is used up.

My question I guess is what exactly is the above code? and can it be treated like a normal 1D array?
The code above is a pointer to a string of characters. It can be treated like a normal array though. The index just has to be real.
The only difference is in what the compiler remembers about the array for you.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <limits>
#include <string>
using namespace std;

// This little function is the same thing as the <cstring> function of the same
// name, but just does it the C++ way...
inline int strlen( const char* s )
  {
  return char_traits <char> ::length( s );
  }

// This is where the plot gets hot...
int main()
  {
  const char  ptr_to_array[] = "Hello world!";
  const char* ptr_to_chars   = "Hello world!";

  // What is the size of each string?

  // The compiler knows the answer for you
  cout << "The size of the array is: "
       << sizeof( ptr_to_array )
       << " chars (including null)\n";

  // You have to count to the terminating null (and hope that is the last char in the array)
  cout << "The size of the chars is: "
       << strlen( ptr_to_chars ) + 1
       << " chars (including null)\n";

  // If you know the answer already (as you do with the array pointer)
  // then the answer is compiled-into the program -- meaning it does not take
  // any time to find it.

  // Otherwise, you must take time to count through the array to learn the
  // answer, or simply keep track of the answer in another variable.

  // Of course, you can downgrade the treatment of the array as a pointer to
  // characters at any time.
  cout << "Both answers should read: "
       << strlen( ptr_to_array ) + 1
       << " chars (including null)\n";

  cout << "Press ENTER to quit.\n";
  cin.ignore( numeric_limits <streamsize> ::max(), '\n' );

  return 0;
  }

Hope this helps.
Last edited on
I think that the pointer is a pointer to the string literal, and that string cannot be changed, while an array would copy the string literal to the stack, and you are free to modify it. So when I want to use a string I don't plan on changing, I use the pointer to avoid the small extra copying and memory use
Last edited on
The only difference is in what the compiler remembers about the array for you


This is not true. Your example doesn't check the size of the buffer (if any), it only checks the length of the string. Try using a different test string:

1
2
3
4
5
6
7
8
9
10
11
char[] blah = "\0\0\0\0\0\0\0\0";

strlen(blah); // will return 0 (string is empty)
sizeof(blah); // will return 9*sizeof(char) (buffer is 9 chars long)

char* ptr = "\0\0\0\0\0\0\0\0";
strlen(ptr); // will return 0 (string is empty)
sizeof(ptr); // will return sizeof(void*) (probably 4, possibly 8)
     // sizeof() is not calculating the size of the buffer, but is calculating
     // the size of the -pointer-.  Since it's a pointer the exact size of
     // the buffer is impossible to determine. 



eker676 and Gumbercules have the right idea... to explain further:

char* ptr = "A string"; makes a pointer which points to a globaly allocated string (which may or may not be pooled with other identical strings by the compiler). No string copy takes place with this code, but editing the string data is not safe, as changes to it may change some strings that it's pooled with.

char str[] = "A string"; actually allocates a new buffer and copies the string to it. This requires the whole string to be copied (as well as requiring a new buffer to be allocated), but editing the string is safe.

1
2
3
4
char str[] = "Blah";  // this line is equivilent to:

char str[5];
strcpy(str,"Blah");


Empty brackets with an initializer are just a shortcut which makes it so the programmer doesn't need to know the exact size of the buffer (it can be determined by the initialization data).

HOWEVER

When used as function parameters, char[] and char* are synonymous:
1
2
void somefunc(char p[]) {}  // is exactly the same as:
void somefunc(char* p) {}  // both treat 'p' as a pointer 
Disch, perhaps you ought to read more carefully before running your mouth and making blanket statements. Had you, you would have known that the whole point of my post is that you cannot know the length of an array unless you (1) use the type foo[] syntax, (2) explicitly track it with an integer variable, or (3) use some sort of terminating semaphore (such as a null).

Gumbercules is not correct at all; he is extrapolating based on apparent behavior, which is not sufficient to state fact.

Further, you are wrong to attack me with bad logic. My statement remains true regardless of your quibbles about my example. The example wasn't about the length of variable data. It was about the ways to know the length of a static buffer, which are: (1) have the compiler do it for you with array syntax, (2) track it yourself, or (3) use a semaphore value.

As for storage, in all cases the "string data" is statically allocated. Whether or not the array[] actually makes a copy of the static data, and where that data is stored (affecting its mutability), is implementation defined. While true that the usual case is to make a copy, that need not be. OK, so I'm not a language lawyer, but it is both hysterically raisinable and a good optimization in const-correct code.

Save for that nit-pick, you are correct in your explanation, and your post is better aimed at the young mind. Further, your brain was awake enough to make the point about how [] is a handy shortcut. Thank you.


In C and C++, declaring an array as:
char a[] = "foo";
is semantically equivalent to:
char a[ 4 ] = { 'f', 'o', 'o', '\0' };

In use, the variable a is a pointer with attached compile-time metadata (the length of the array). So if you ask the size of a you are asking for the size of the array itself (in bytes), not the pointer to the array.

In all other use the two are identical. (C and C++ typically have no runtime bounds checking -- though I imagine there are compilers, like Borland's, that can add it for you.) Hence, saying:
a[ 1 ] = 'm';
is identical to saying:
*(a + 1) = 'm';

Oh, one last thing. Make sure your compilers are set to complain about things like:
char* message = "I am not an idiot.";
since it is not const-correct. Say instead:
const char* message = "I know what I am doing.";

Please forgive my rant. Just don't be arrogant at me, please.
Sorry. I didn't mean to offend. My post wasn't really directed at you -- I just wanted to point out a possibility for misunderstanding. I didn't mean to sound arrogant, though I know I do sometimes (which is especially bad when you're wrong, which I often am).
Heh, I know I can be a little arrogant at times too... and even a little too sensitive. Sorry about that.
Topic archived. No new replies allowed.