22
 printf("%lu \n", sizeof(*"327")); 

I always thought that size of a pointer was 8 bytes on a 64 bit system but this call keeps returning 1. Can someone provide an explanation?

11
  • 30
    sizeof(*"327") is sizeof(char) since * dereferences the first char of your literal string. just try sizeof(char *) Commented Oct 12, 2017 at 8:51
  • 8
    I also recommend you read e.g. this printf (and family) reference, because "%lu" is the wrong format for sizeof arguments. Commented Oct 12, 2017 at 8:58
  • 8
    Sidenote: sizeof is no function that could be called. Commented Oct 12, 2017 at 10:34
  • 7
    you can't call sizeof Commented Oct 12, 2017 at 15:20
  • 4
    You may have been thinking of sizeof(&"327"). Commented Oct 12, 2017 at 16:49

4 Answers 4

61

Putting * before a string literal will dereference the literal (as string literal are array of characters and will decay to pointer to its first element in this context). The statement

printf("%zu \n", sizeof(*"327")); 

is equivalent to

printf("%zu \n", sizeof("327"[0])); 

"327"[0] will give the first element of the string literal "327", which is character '3'. Type of "327", after decay, is of char * and after dereferencing it will give a value of type char and ultimately sizeof(char) is 1.

Sign up to request clarification or add additional context in comments.

14 Comments

@dwilliss; In C, '3' an integer constant. As per C standard an integer character constant has type int.
@Wilson You misunderstand. All character constants have always been of type int in C. Only in C++ is '3' (or 'm') of type char. Don't believe it? int main() { printf("%zu\n", sizeof 'm');}
It's not really dereferencing to '3' (i.e. a character literal). It is dereferencing a string literal (char*) to the first element which will be a char and hence a single byte (*(char*) = (char)). It just happens that the value of the dereferenced string literal is (char)'3' because that is the first character in the string.
@dwilliss sizeof('3') has always been the same as sizeof(int). Likewise, sizeof(*"3") has always been the same as sizeof(char). As illogical as it may sound, a character literal is not of type char. In fact, all literals in C are at least the size of int. To get something of type char, you need an expression with something other than a literal in it.
|
18

The statement:

printf("%lu \n", sizeof(*"327")); 

actually prints the size of a char, as using * dereferences the first character of string 327. Change it to:

char* str = "327"; printf("%zu \n", sizeof(str)); 

Note that we need to use %zu here, instead of %lu, because we are printing a size_t value.

Comments

4

The string literal is an anonymous, static array of chars, which decays to a pointer to its first character -- that is, a pointer value of type char *.

As a result expression like *"abc" is equivalent to *someArrayOfCharName, which in turn is equivalent to *&firstCharInArray which results in firstCharInArray. And sizeof(firstCharInArray) is sizeof(char) which is 1.

2 Comments

Almost correct. Even while the array is read-only (can't be modified), it's not const. So it decays to a plain non-const char *. This is one of the things that makes C and C++ different.
Technically it doesn't decay unless used in a decay context . This is why sizeof "abcd" is 5. Applying the dereference operator is a decay context of course
0

Good answer by haccks.

Also, the behaviour of your code is undefined, because you have used the wrong format specifier.

So, use %zu instead of %lu because sizeof() returns size_t and size_t is unsigned.

C11 Standard: §7.21.6.1: Paragraph 9:

If a conversion specification is invalid, the behavior is undefined.225) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

5 Comments

While this is true, this should be a comment. There is no UB in case size_t is of smaller or equal size as unsigned long.
@Lundin No matter what type size_t is, either it doesn't promote, or it promotes to signed int/unsigned int, so the only way you'll get an unsigned long passed to printf is if size_t already is an unsigned long. I don't see how you can say, then, that the behaviour is defined if size_t is anything else.
@hvd Fine, but this isn't a real-world problem and it doesn't answer the question. In the real world, either both long and size_t are of the same size and there is no problem. Or long is 32 bit while size_t is larger, in which case you might end up reading part of the size_t but you don't invoke any UB by that.
@Lundin "but you don't invoke any UB by that" -- This answer already explains why you're wrong. The standard explicitly states the behaviour is undefined, and it has to be undefined, because there's no sensible way to define it that works for all calling conventions. Agreed that it doesn't answer the question, but it's entirely accurate and would have been worth posting as a comment.
It might be undefined; it's a common implementation choice for size_t to be a typedef for unsigned long

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.