The nul terminator is what tells you what spaces are filled. Everything up to and including the nul terminator has been filled. Everything after it has not.
There is no general notion of which elements of an array have been filled. An array holds some number of elements; its size is determined when it is created. All of its elements have some value initially; there's no way, in general, to determine which ones have been assigned a value and which ones have not from looking at the values of the elements.
Strings are arrays of char
and a coding convention that the "end" of the string is marked by a nul character. Most of the string manipulation functions rely on this convention.
A string literal, such as "John"
, is an array of char
. "John"
has 5 elements in the array: 'J'
, 'o'
, 'h'
, 'n'
, '\0'
. The function strcpy
, for example, copies characters until it sees that nul terminator:
char result[100]; // no meaningful values here
strcpy(result, "John");
After the call to strcpy
, the first five elements of result
are 'J'
, 'o'
, 'h'
, 'n'
, and '\0'
. The rest of the array elements have no meaningful values.
I would be remiss if I didn't mention that this style of string comes from C, and is often referred to as C-style strings. C++ supports all of the C string stuff, but it also has a more sophisticated notion of a string, std::string
, which is completely different. In general, you should be using C++-style strings and not C-style strings.