1

I was testing the use of sizeof() for the same String content "abc". my function is like this:

int main(void){
    char* pass1 = "abc";
    char pass2[] = "abc";
    char pass3[4] = "abc";
    char pass4[] = "";

    scanf("%s", pass4);

    printf("sizeof(pass1) is: %lu\n", sizeof(pass1));
    printf("sizeof(pass2) is: %lu\n", sizeof(pass2));
    printf("sizeof(pass3) is: %lu\n", sizeof(pass3));
    printf("sizeof(pass4) is: %lu\n", sizeof(pass4));

    return 0;
}

I input "abc" for pass4, the output is like this:

sizeof(pass1) is: 8
sizeof(pass2) is: 4
sizeof(pass3) is: 4
sizeof(pass4) is: 1

I was expecting all 4s. I thought the 4 above string definitions are the same.

why sizeof(pass1) returns 8? Why sizeof(pass4) is 1?

Di Wang
  • 471
  • 1
  • 8
  • 22

3 Answers3

3

When you take sizeof on a pointer type, you'll get the size in bytes of the memory address. In this case 8 is the size of the address (in bytes). sizeof on statically allocated read only strings in C will return the actual size in bytes of the string including the null byte.

Ryan
  • 14,392
  • 8
  • 62
  • 102
  • I thought the pointer pass1 is pointing to the 8 bit character type memory address.I never defined a 8 bytes memory address for that string. – Di Wang Feb 06 '17 at 02:26
  • @DiWang That depend on compiler and platform, maybe you use 64-bit compiler in x64 platform. You can check sizeof(void*), sizeof(char*), sizeof(double*) or any pointer type, they shoule be same. – khôi nguyễn Feb 06 '17 at 02:42
  • Thanks, sizeof(char*) is 8. tested on my computer. – Di Wang Feb 06 '17 at 02:48
  • then you should read again about pointer. It stores the address to some position in memory. The size of the pointer is 8 bytes and size of the memory region it points to in this case is 1 byte. Note that [`char` isn't necessarily 8 bits](http://stackoverflow.com/q/2098149/995714) – phuclv Feb 06 '17 at 02:49
  • Well I added a command, now the sizeof(pass4) is 1. I am totally confused – Di Wang Feb 06 '17 at 07:27
2

sizeof gives the size of its operand. To understand the results you are seeing, you need to understand what pass1, pass2, pass3, and pass4 actually are.

pass1 is a pointer to char (i.e. a char *) so sizeof pass1 gives the size of a pointer (a variable which contains a memory address, not an array). That is 8 with your compiler. The size of a pointer is implementation defined, so this may give different results with different compilers. The fact you have initialised pass1 so it points at the first character of a string literal "abc" does not change the fact that pass1 is declared as a pointer, not an array.

pass2 is an array initialised using the literal "abc" which - by convention - is represented in C using an array of four characters (the three letters 'a' to 'c', plus an additional character with value zero ('\0').

pass3 is also an array of four char, since it is declared that way char pass3[4] = <etc>. If you had done char pass3[4] = "abcdef", you would still find that sizeof pass3 is 4 (and the 4 elements of pass3 will be 'a' to 'd' (with other character 'e', 'f', and '\0' in the string literal "abcdef" not used to initialise pass3).

Since both pass2 and pass3 are arrays of four characters, their size is 4 (in general, the size of an array is the size of the array element multiplied by number of elements). The standard defines sizeof char to be 1, and 1*4 has a value 4.

pass4 is initialised using the literal "". That string literal is represented using a single char with value '\0' (and no characters before it, since none are between the double quotes). So pass4 has size 1 for the same reason that pass2 has size 4.

Peter
  • 35,646
  • 4
  • 32
  • 74
  • But pass4 has been replaced by "abc", \0 is over written. how can the size be 1 again? I have tested strlen(pass4), it returns 3, but sizeof(pass4) returns 1. – Di Wang Feb 06 '17 at 18:48
  • The `scanf("%s", pass4)` (which I'll point out you inserted AFTER I gave this answer) gives undefined behaviour, unless the user enters no characters before the newline. That means anything is allowed to happen. In practice, if you enter `abc` it will overwrite whatever memory is located immediately after `pass4`. That doesn't change the size of `pass4` - it simply means your code overwrites memory past the end of `pass4`. Since `strlen()` keeps walking through memory until it finds a `'\0'`, it will report `4`, but that is happenstance. – Peter Feb 07 '17 at 07:30
0

In this declaration

char* pass1 = "abc";

in the right side used as an initializer there is a character array that has size equal to 4. String literals have types of character arrays. Take into account that string literals include the terminating zero. You can check this the following way

printf("sizeof( \"abc\") is: %zu\n", sizeof( "abc"));

In the declaration the array is used to initialize a pointer. Used as initializer of a pointer the array is implicitly converted to the pointer to its first element.

Thus the pointer pass1 points to the first element of the string literal "abc". The size of the pointer itself in your system is equal to 8 bytes.

In these declerations

char pass2[] = "abc";
char pass3[4] = "abc";

the string literal is used to initialize arrays. In this case each element of the arrays is initialized by the corresponding element of the string literal. All other elements of the arrays are zero initialized. If the size of an array is not specified then it is calculated from the number of initializers.

So in this declaration

char pass2[] = "abc";

the array pass2 will have 4 elements because the sgtring literal provides four initializers.

In this declaration

char pass3[4] = "abc";

there is explicitly specified that the array has 4 elements.

Thus the both arrays has size equal to 4 and the pointer declared first has size of 8 bytes.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335