Justin Wyllie Justin Wyllie - 2 months ago 21
C Question

Declaring variable length strings in c - apparently dynamic?

I am trying to understand something basic about how 'strings' are defined in c.

char s[2];
scanf("%s", s);
printf("%s", s);
printf("sizeof s %d", sizeof(s));

I'm not a c programmer. I'm aware that there are problems with using scanf to get user input and that I'm not even checking its return value etc. This is just to understand something basic about declaring strings.

Given the above code what it does if I enter say 'helloworld' is print 'helloworld'. Good. But I thought by saying char s[2] I was saying something like 's is an array of length two where each element is of type char'.

Thus I was expecting to see 'he' printed. Not 'helloworld'. Because my s array only has room for 2 chars.

The sizeof still returns 2. But it looks like my array has grown to the size of the user input.

What is happening?


Two issues:

  • C does not do any bounds checking on array accesses;
  • Under most circumstances, an expression of array type will be converted to an expression of pointer type, and the value of the expression will be the address of the first element of the array. This includes array expressions passed as arguments to functions.

The %s conversion specification tells printf to print the sequence of characters starting at the specified address until it sees the 0 terminator at the end of the string. Similarly, it tells scanf to store a sequence of characters starting at the specified address until it sees a whitespace character or EOF.

When you pass the expression s as an argument to scanf or printf, the expression is converted from type "2-element array of char" to "pointer to char", and the value of the expression is the address of the first element of the array (it's equivalent to passing the expression &s[0]).

All scanf receives is a pointer value - it has no idea how big the array starting at that address is. So it doesn't know that s is only large enough to contain two characters. Instead, it happily writes those extra characters past the end of the array. Similarly, printf doesn't know that the array is only 2 characters wide - it just keeps printing until it sees that 0 terminator.

You can specify a field width as part of the conversion:

scanf( "%1s", s ); 

This will read at most 1 character from standard input and store it to s. Remember that a string is a sequence of characters followed by a 0 terminator, so to store an N-character string, you need to set aside an N+1-element array to store it.