char *p = "String";
This is legal, but it really should be:
const char *p = "String";
so you don't accidentally try to modify the array.
What array, you ask? Any string literal corresponds to a statically allocated array of size LEN+1
, where LEN
is the length of the literal. So in this case, there's an anonymous array of type char[7]
that exists during the entire execution of your program, containing the values
`{ 'S', 't', 'r', 'i', 'n', 'g', '\0' }`.
The initializer for p
causes it to point to the first element of that array, which contains the 'S'
. And since the array was not allocated by a call to malloc()
(or calloc()
, or realloc()
), you must not attempt to free()
it.
Given p
, you can't directly determine the size of the array (since p
points to its first element, not to the array as a whole). You can compute strlen(p) + 1
, which is probably the same as the allocated size -- but if the string literal were "foo\0bar"
, then it would be 8 bytes long, but strlen
would stop at the first null character and return 3
. So if you need to be able to determine the size of the array, don't discard that information by assigning its address to a pointer.
Now if you had instead written:
char arr[] = "String";
the initializer would copy the contents of the string literal into the array arr
, and the size of arr
would be determined by the compiler from the size of the initializer. Again, you must not attempt to call free()
on this array (or rather, on a pointer to its first element), since it wasn't allocated with malloc()
. But you can easily determine its size via sizeof arr
, which will yield 7
. (sizeof p
would give you the size of a pointer, not of the array it points to.)
Finally, if you used malloc()
to allocate an array:
#define message "String"
char *p = malloc(sizeof message + 1);
if (p == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
strcpy(p, message);
you still can't use p
(which is just a pointer to a single character) to determine the size of the allocated array -- but free()
is able to figure it out. How? The language doesn't say, but any implementation will keep extra bookkeeping information behind the scenes to let free()
do the right thing.
Note that the implementation doesn't necessarily remember the size you requested. A call to malloc(7)
might actually allocate, say, 16 bytes, and the only information free
needs is the base address and the actual allocated size.
But since you wrote the call to malloc
, if you need to remember the allocated size, just save it somewhere:
// ...
const size_t allocated_bytes = sizeof message + 1;
char *p = malloc(allocated_bytes);
// ...
If you have a declared array object, you can use sizeof
to determine its size. Arrays are usually manipulated using pointers, which do not retain the size of the array; you have to keep track of that yourself. malloc()
and friends do maintain some size information behind the scenes, but only for the purpose of letting free()
work correctly; you (probably) can't access that information yourself. If you need to keep track of the size of an allocated array, you have to do it yourself.