3

In the following code:

char *title = "VP";
printf("Sizeof title: %zd | Sizeof *title: %zd | Strlen: %zd\n", sizeof title, sizeof *title, strlen(title));

Sizeof title: 8 | Sizeof *title: 1 | Strlen: 2

It seems like the sizeof title operates on the pointer to the string (8 bytes for me), and the strlen(title) predictably gives me 2.

Why does the sizeof *title produce 1 when dereferencing the pointer rather than 3 (the byte-length of the string)? For example, why does it do that instead of what it would produce for:

printf("%zd\n", sizeof("VP"));
// 3
samuelbrody1249
  • 4,379
  • 1
  • 15
  • 58
  • 1
    See [How to find the 'sizeof' (a pointer pointing to an array)?](https://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array). – dxiv Jan 16 '21 at 06:34
  • samuelbrody1249, Since `title` is a pointer, not a _string_, why expect `sizeof title` to return the size of something it is not? – chux - Reinstate Monica Jan 16 '21 at 06:50

2 Answers2

3

The size of a pointer is always the size of the pointer itself, not what it points to. That's because sizeof is mostly a compile-time operator (the result is evaluated by the compiler) and the compiler can't know what a pointer might point to at run-time.

As for sizeof *title it's the same as sizeof title[0] which is a single char. And the size of a char is 1 (it's specified to always be 1 by the way, no matter the actual bit-width).

Lastly about sizeof "VP". In C all literal strings are really arrays of characters, including the terminating null character. So the literal string "VP" is an array of three characters, hence its size is 3.


To make the answer a little bit more complete, I say that the sizeof operator is mostly compile-time. That of course can't be true for variable-length arrays, where the compiler must insert code to store the actual size of the array in a way that it can be fetched at run-time. If the array decays to a pointer, then all you have is the pointer and again sizeof returns the size of the pointer itself.

And a note about string literal arrays. While they are technically non-constant arrays, they still can't be modified. Attempting to modify a string literal leads to undefined behavior. Literal strings are thus, in effect, read-only.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • -- thanks for that. What would be the suggested way that you could do the runtime equivalent of `sizeof` for the above to get `3` ? – samuelbrody1249 Jan 16 '21 at 06:34
  • @samuelbrody1249 A variable-length array, as in `size_t length = 3; char array[length]; strcpy(array, "VP");` Then `sizeof array` will be calculated at run-time. However, once the array has decayed to a pointer, then `sizeof` returns the size of the pointer. – Some programmer dude Jan 16 '21 at 06:36
  • thanks. What if the string literal is defined in the global scope (and stored in `.data`) is that still the same or any different? – samuelbrody1249 Jan 16 '21 at 06:38
  • 1
    @samuelbrody1249 All strung literals are "global", the arrays never go out of scope during the life-time of the program. So you can always use pointers to literal strings. – Some programmer dude Jan 16 '21 at 06:39
  • Also worth noting that `%zd` is not the correct specifier, it should have been `%zu`. – Aykhan Hagverdili Jan 16 '21 at 06:52
  • 1
    "they still can't be modified." --> more like "modification should not be attempted." Attempting to modify a _string literal_ might work. It is UB. – chux - Reinstate Monica Jan 16 '21 at 06:53
  • @AyxanHaqverdili ok, but then why are there so many references online that say to use `%zd` ? https://keramida.wordpress.com/2006/04/03/how-big-is-a-size/. – samuelbrody1249 Jan 16 '21 at 06:55
  • @samuelbrody1249 I don't know why they are using the wrong specifier. You can see the table [here](https://en.cppreference.com/w/c/io/fprintf) for correct specifiers. – Aykhan Hagverdili Jan 16 '21 at 06:59
  • 1
    @samuelbrody1249 There *is* a "signed `size_t`" in some operating systems. For example `ssize_t` which is defined in POSIX (operating systems like Linux or macOS). Then `%zd` is valid. But for the normal C-standard `size_t` it needs to be an unsigned specifier (like `%zu`). – Some programmer dude Jan 16 '21 at 07:07
  • @Someprogrammerdude out of curiosity then, why is something like `CHAR_MAX` or other constants in `limits.h` not `%zu` but `%d` ? Oh, I think because the preprocessor substitutions default to integer if I'm not mistaken? – samuelbrody1249 Jan 16 '21 at 07:11
  • @samuelbrody1249 That's correct, those macros expand to plain `int` values (when possible). – Some programmer dude Jan 16 '21 at 07:15
1

The type of title is char *, so the type of *title is char, not char [3]. Thus , sizeof *title is equivalent to sizeof (char), which is 1.

title isn’t the string, it just points to the first element of the string.

John Bode
  • 119,563
  • 19
  • 122
  • 198