In a previous post about using sizeof() on string literals, there was an interesting comment by S. Enevoldsen:
To better remember this realize that arrays are not pointers, and string literals are arrays (that can decay to pointers).
const char arrayVersion[] = “1.0.42-beta”;
const char* pointerString = “1.0.42-beta”;
printf (“sizeof(arrayVersion) = %d\n”, sizeof(arrayVersion));
printf (“sizeof(pointerString) = %d\n”, sizeof(pointerString));Outputs
sizeof(arrayVersion) = 12
– S. Enevoldsen
sizeof(pointerString) = 4
If I knew this, I have long forgotten it. Over the years at my “day jobs” I have gotten used to making string pointers like this:
const char *versionStringPtr = "1.0.42-beta";
I generally add the “Ptr” at the end to remind me (or other programmers) that it is a pointer to a string. In my mind, I knew I could have done “char *string” or “char string[]” and gotten the same use from normal code, but I do not recall if I knew they were treated differently.
What do you expect the output of this to be?
#include <stdio.h>
#include <stdlib.h> // for EXIT_SUCCESS
#include <string.h> // for strlen()
int main()
{
const char *stringPtr = "hello";
printf ("sizeof(stringPtr) = %ld\n", sizeof(stringPtr));
printf ("strlen(stringPtr) = %ld\n", strlen(stringPtr));
printf ("\n");
const char string[] = "hello";
printf ("sizeof(string) = %ld\n", sizeof(string));
printf ("strlen(string) = %ld\n", strlen(string));
return EXIT_SUCCESS;
}
Output would show … what?
sizeof(stringPtr) = ???
strlen(stringPtr) = ???
sizeof(string) = ???
strlen(string) = ???
To be continued…
I would expect the following:
sizeof(stringPtr) = 8; /* or 4 or 2, depending upon the pointer size */
strlen(stringPtr) = 5;
sizeof(string) = 6; /* because of the NUL byte at the end */
strlen(string) = 5;
Also, when you want to print a
size_t
value, using%zu
.What the heck is %z??? When did that get added?
Wild. I use cplusplus.com for reference and I has a whole block with % things I am completely unaware of. Sadly, my programming on embedded systems usually doesn’t support C99 and other new things. I’ll try to add this to my memory. I only recently learned about %p (PC compiler handles it, but the one I use at work does not.)
%zu
was added in C99, but%p
was added in C89. C99 also added<inttypes.h>
for formatting a bunch of different integer types (annoying to use, but at least it exists now).My first “real job” in the mid 1990s used a compiler that was ANSI, but before stdint.h, and we had our own types.h that defined them. A lot changed between that time, and me returning to programming in 2012. Being in an embedded world means I am often using weird compilers and tools (IAR, Renesys, CCS, etc.) that are “C in name only.” It seems.
You see more clearly than I. I was immediately puzzled by the output and had to think about it. Had I chosen a much longer string, it would have been more obvious. (Actually, it should have been obvious anyway, but my brain is old and lazy.)
I learned pretty quickly how fast C arrays decay into pointers, and how a misdeclaration (like
extern int *array;
in a header, andint array[100]
in a C file) can be deadly. I also learned that a barechar
is neither signed nor unsigned, but its own thing (as it’s implementation dependent ifchar
is signed or unsigned by default).Char was, in K&R, a signed value, which never made sense to me. Once uint8_t came to exist, that seemed to take care of it. But I still see chars used for non character binary data, everywhere.
My deal was seeing how buffer[80] could have a known size, but once it was passed in to a function by address you lost that ability. It’s no wonder buffer overruns remain a problem even in 2024.
I got in a weird habit of always passing in stuff like…
&buffer[0]
I picked that up at a job, and thought it was weird, but it makes it abundantly clear that you are passing in the location of the start of some amount of data.
And I think it’s weird you can pass in “buffer” or “&buffer” and they both work…