%s formatter
The %s
formatter allows printing a c-string using printf. For example:
const char my_c_string[] = "mytext";
printf("printing string: %s", my_c_string);
Result:
> printing string: mytext
The contents of my_c_string
get inserted into the printed text where %s
is located.
C-string length and the nul terminating character
The above example makes use of a string literal. String literals are constructed using text inside double quotes (e.g. "any text"
). String literals implicitly include an additional nul character at the end of the string which is used to indicate the end of the string, without it printf and other functions reading c-strings will not know the length of the string.
This additional nul terminator character takes the value 0 in memory and makes the length of the string 1 character longer. sizeof(my_c_string)
will return a length of 7 instead of 6. In memory my_c_string
will look like this:
(relative) Byte position | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
character | m | y | t | e | x | t | \0 |
raw value | 109 | 121 | 116 | 101 | 120 | 116 | 0 |
const char my_c_string[] = "mytext"
in memoryWhy is printf outputting additional garbage text?
Because the nul character is implicit and there is no indication from reading the code that it exists, it is a common programmer's error to forget to add the nul terminating character to non-literal strings constructed programatically. Failing to include the nul terminator will result in functions like printf continuing to use memory beyond the end of the string. It will only stop reading from memory when is encounters the value 0 in memory. Aside from printing extra data erroneously this, can cause all kinds of issues including crashing the entire application.
Combined example
A quick example of %s, %d and %c combined. Below is similar to a real-world example for printing a log or debug statement for messages sent to an exernal device.
const char msg_string[] = "Complete";
int msg_id = 12839;
char rw_mode = 'R';
printf("Message status: %s, id = %d, R/W mode = %c", msg_string, msg_id, rw_mode);
Result:
> Message status: Complete, id = 12839, R/W mode = R