The
Separate a stored byte from EOF
For the portable narrow-character interface, pass EOF or a value representable as unsigned char. A char read from a string can be negative on a signed-char implementation. Convert that stored char to unsigned char before calling isspace, isalpha, isdigit or tolower. The later integer promotion is safe.
fgetc has a different role: keep its int result intact while checking EOF. Converting it to char or unsigned char first can erase the sentinel distinction. After excluding EOF, you have a real byte value. Classification returns an arbitrary nonzero int for true, so test != 0 rather than == 1.
Follow one complete example
Run this program, then change one boundary while keeping the API preconditions valid. Predict its output before pressing Run.
#include <cctype>
#include <cstdio>
#include <string>
int main() {
std::string text="MiXeD";
for(char& c:text) c=static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
std::printf("%s %d\n",text.c_str(),std::isspace(static_cast<unsigned char>('\n'))!=0);
}Declare a locale and text policy
The initial "C" locale gives this exercise a repeatable byte-text policy. The caller keeps it stable; the normalization utility does not change global locale. Calling setlocale inside a generally shared helper does not create isolated per-call configuration.
A UTF-8 character can occupy multiple bytes, and case folding can change length or require language-specific rules. Bytewise tolower does not decode that sequence or normalize it. For a machine protocol with exact ASCII grammar, use the protocol definition directly; for international text, use an appropriate Unicode text library. Do not claim either behavior from this small field adapter.
Trim a half-open range, then transform it
Use [first,last) bounds. Advance first over leading whitespace while first < last; retreat last while the same condition holds. C-locale whitespace includes tab, newline, carriage return, form feed and vertical tab in addition to space. An all-whitespace field becomes an empty range without a last-1 underflow.
Copy that remaining range once and lowercase its bytes. Interior spaces, NUL and high-bit bytes are not automatically deleted. The build tests embedded binary bytes so an accidental strlen-based conversion cannot silently shorten the field. The unsigned-char precondition is also a code-review obligation: a particular libc may tolerate negative inputs without making them portable.
Read the return value
Predict this smaller case. The check item later changes the values, so explain the rule as well as the output.
#include <cctype>
#include <cstdio>
int main(){unsigned char a='A', b='\t'; std::printf("%d %c\n",std::isspace(b)!=0,std::tolower(a));}Complete the faded example
State the missing precondition or result check before filling the code. The fill exercise supplies the rest of the implementation.
while (first < last && /* classify input[first] safely */) ++first;
while (last > first && /* classify input[last-1] safely */) --last;
// Fill: convert the copied range without deleting interior bytes.Check your model
Why is converting EOF to unsigned char different from converting a stored negative char to unsigned char?
Practice the boundary
Implement std::string normalize_field(std::string_view input) using the C character interface.
The caller keeps LC_CTYPE at the initial "C" locale for the whole call. Trim all leading/trailing characters recognized by isspace, then lowercase using tolower. Preserve every interior byte except for that case conversion. Embedded NUL is an ordinary byte here. Empty and all-whitespace inputs return an empty string. Do not mutate the input or change global locale.
Convert each char to unsigned char before passing it to cctype. This is byte-oriented C-locale normalization, not Unicode case folding or a UTF-8 validator.
Read → six checks → two bug hunts → fill → build. A successful graded submission is evidence; reading or watching alone does not grant mastery. Review cards reinforce API choices separately.
Watch and verify
The Watch & read panel links a free lecture for the relevant background and primary API references. The lecture notes say which parts are background; the tested contract here supplies the exact wrapper policy.
C standard-library course · C library review cards · Unix/Linux systems