In your first case, ...
char* p1 = "some string";
... p
is a variable of pointer type, char*
. It's initialized to point to the first char
in a sequence of char
values somewhere. That somewhere might be in read-only memory, so you should NEVER DO THIS :-).
Instead,at least add a const
for the pointee type, like ...
char const* p2 = "some string";
This way you've asked the compiler to not accept modification attempts, which would send you to Undefined Behavior land. C++ accepts the declaration of p1
only for backward compatibility with C. If you turn up your C++ compiler's warning level you will most likely get a warning about it, while the declaration of p2
is perfectly fine.
Since p2
isn't const
itself, you can modify it, e.g. increment it so that it points to the second char
, or whatever.
Anyway, the pointer is not very large, typically 4 or 8 bytes.
In your second case, ...
char a[] = "some string";
... a
is an array that is initialized with the specified characters, plus a terminating null-byte. Each char
is one byte, per definition. sizeof(a)
will therefore report that a
is 12 bytes, namely the 11 bytes of the specified characters, plus the null-byte.
In both C and C++, when you use a
where a pointer is expected, you get an automatic conversion to pointer to the first array element, and we say informally that the array decays into pointer type. In C this happens in all cases of passing the array as argument. In C++ you can, however, pass an array by reference, avoiding the type decay.
Using the decay to advantage, you can find the number of elements of the array via ...
sizeof(a)/sizeof(*a)
where the division is unnecessary for an array of bytes, as a
is, but is necessary in general for arrays of other types.
If you do that with the pointer then you just get the size of the pointer measured in units of the size of the pointee, which is seldom meaningful.
In C there's no other reasonable way to find the number of elements of an array, so the expression above is typically packaged in a macro, and one just accepts the risk of inadvertently using the macro with a pointer argument (meaningless result).
In C++ you can use the possibility of passing an array by reference to define a function that returns the number of elements of an array, like ...
typedef ptrdiff_t Size;
template< class T, Size N >
Size countOf( T const (&)[N] ) { return N; }
Calling countOf
with a pointer as actual argument you just get a compilation error instead of a meaningless result.
For C++ work it's also generally convenient to define startOf
and endOf
functions, especially for working with algorithms from the standard library. As far as I know the first to recognize the importance of this triad of functions was Dietmar Kuhl. You can find a general implementation at my Wordpress blog, but unfortunately, as I recall, I didn't mention Dietmar there (and I'm far too lazy to fix up things! :-) ).
C++ also has some other support for arrays that C doesn't have.
In particular, as a novice you will generally be better off using std::vector
from the standard library, instead of directly using "raw arrays".
Using std::vector
you're much less likely to encounter the many pitfalls that are associated with raw arrays, such as e.g. the number-of-elements computation.
Cheers & hth.,
– Alf