Strings and the Null Terminator
What a C string actually is in memory, string literals, and the difference between length and size.
C Has No String Type
Most languages hand you a string type; C hands you a convention. A string in C is a char array whose meaningful characters are followed by '\0', the null terminator, the character with code zero you met in chapter 2. Every string function, every %s, every text-processing program is built on that single agreement, and so is a whole museum of bugs for when it breaks. Get the convention exact and chapter 8 is easy.
The Convention in Memory
char word[6] = "hello";
The literal "hello" initializes six bytes: 'h' 'e' 'l' 'l' 'o' '\0'. Count again: five visible letters, six bytes, because the terminator is real storage. Declaring char word[5] = "hello" in ANSI C silently drops the terminator, leaving a char array that is not a string; the size mismatch is legal and the resulting bug is not. Letting the compiler count, char word[] = "hello", always gets it right.
The distinction that follows: the array's size (six here) is its capacity, while the string's length (five) is how many characters precede the terminator. Size is fixed at declaration; length is whatever the data says, discovered by walking to '\0'.
The Other Initializer, and Spare Room
A string literal is the convenient way to fill a char array, not the only way. Chapter 7's brace-list initializer works too, one character at a time, and it comes with an obligation:
listed: hello
roomy: hi, and its remaining bytes are: 0 0 0 0 0 0 0 0
listed and "hello" produce identical bytes, but notice what had to be typed: in the brace-list form you supply the terminator yourself. Write {'h', 'e', 'l', 'l', 'o'} and you have a five-byte char array that is not a string, and %s on it walks off the end. The literal form adds '\0' for you; the list form does exactly what you wrote and nothing more. Exam papers put both side by side and ask which one is a string.
roomy shows the reverse case, an array larger than its initializer. The two characters land in bytes 0 and 1, byte 2 gets the terminator, and every byte after it is zero-filled, because a partially initialized array has its remainder set to zero. So the spare capacity is not garbage, it is '\0' all the way to the end, which is why char roomy[10] = "hi" is a perfectly good ten-byte buffer holding a two-character string.
Walking to the Terminator
Everything you know about arrays applies, plus one idiom: loops over strings end at the terminator, not at a count.
That while is the length function every exam asks you to hand-write, and %s is doing the same walk internally: print characters until the terminator. Which exposes the convention's sharp edge: %s on a char array with no terminator walks into undefined behaviour, reading whatever bytes follow until a zero happens to appear. A char array becomes a string only when the terminator is in place, and every function trusts you on it.
Because the terminator is '\0', code zero, and zero is false, the loop condition can be written while (word[length]), and much real code does. This course keeps the explicit != '\0' for one chapter more; read both fluently.
Building a String by Hand
Reading characters into an array and then placing the terminator yourself makes the convention muscle memory, and previews how every input function works underneath:
Type a word and press enter. Three conditions guard the loop, and each carries a rule: EOF ends input, '\n' ends the line, and length < CAPACITY - 1 stops one short of the capacity, reserving the terminator's byte. Write the - 1 wrong and the buffer[length] = '\0' after a full read is the out-of-bounds write from last chapter. This is the bounds discipline of chapter 7 meeting the terminator convention, the two rules that together make C strings safe.
'\0', '0', and "0"
Chapter 2's distinction returns with one addition. '\0' is the terminator, code zero. '0' is the digit character, code 48. "0" is a two-byte string: the digit and a terminator. And an empty string, "", is one byte, just the terminator, with length zero and the %s output of nothing. Exam papers rotate these four endlessly; the byte counts are the answers.
The gap between '7' and 7 is the same gap, and it has a one-expression fix that every text-processing program uses:
the character 7 has code 55
its numeric value is 7
digit - '0' works because the standard guarantees the ten digit characters occupy consecutive codes in order, so subtracting the code of '0' from the code of any digit character leaves its value: 55 minus 48 is 7. Character arithmetic like this is ordinary integer arithmetic, since a char in an expression is promoted to int as chapter 3 described. This is how you convert digits found inside a string, one at a time, and it is the building block under the library's whole-string converters, which arrive with command-line arguments in chapter 12.
Key Takeaways
- A C string is a char array plus the convention: characters, then
'\0'; the terminator occupies a real byte. "hello"needs six bytes;char w[] = "hello"counts them for you; a too-small explicit size silently drops the terminator in ANSI C.- Size is capacity, length is the distance to
'\0', discovered by the hand-written walk every exam requires. %sand every string function walk to the terminator; an unterminated array makes that walk undefined behaviour.- Building strings by hand: stop filling at capacity minus one, then place
'\0'yourself. - The brace-list initializer makes you supply
'\0'yourself:{'h','e','l','l','o'}is a char array, not a string, while"hello"adds the terminator for you. - An array larger than its initializer is zero-filled to the end, so
char roomy[10] = "hi"holds a two-character string in a clean ten-byte buffer. '\0'(code 0),'0'(code 48),"0"(two bytes),""(one byte): know all four.- Digit characters have consecutive codes, so
c - '0'converts one digit character to its numeric value.
How did you find this lesson?
Your rating helps us improve the content.
Create an account to track your progress and access interactive exercises. Already have one? Sign in.
Strings and the Null Terminator - Quiz
Test your understanding of the lesson.
Practice Exercises
Build a String by Hand
Read one line of input character by character with getchar, store it in a buffer, place the null terminator yourself, and report the string and its length (computed with your own terminator walk, no library calls). Stop filling at capacity minus one so the terminator always has its byte.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!