Lesson 5 of 8
char looks like the "text type," but it isn't. It's a one-byte integer that streams happen to
print as a symbol.
A char is a number
#include <iostream>
int main() {
char letter = 'A';
std::cout << letter << "\n";
std::cout << static_cast<int>(letter) << "\n";
std::cout << static_cast<char>(letter + 1) << "\n";
std::cout << ('z' - 'a') << "\n";
return 0;
}
A
65
B
25
'A' is 65. Printing it as char shows the symbol; casting to int shows the number; adding 1
and casting back gives 'B'. And 'z' - 'a' is a perfectly ordinary subtraction giving 25 —
which tells you the letters occupy consecutive codes.
The mapping is ASCII, and the parts worth remembering are:
| Characters | Codes |
| --- | --- |
| '0'–'9' | 48–57 |
| 'A'–'Z' | 65–90 |
| 'a'–'z' | 97–122 |
You don't need to memorise the numbers, but two consequences are genuinely useful:
#include <iostream>
int main() {
char digit = '7';
int value = digit - '0';
std::cout << value * 2 << "\n";
char lower = 'q';
char upper = static_cast<char>(lower - ('a' - 'A'));
std::cout << upper << "\n";
return 0;
}
14
Q
Subtracting '0' converts a digit character into its numeric value — '7' is 55, '0' is
48, and 55 − 48 = 7. And since uppercase sits exactly 32 below lowercase, subtracting that gap
changes case.
In real code prefer <cctype>'s std::toupper and std::isdigit, which handle edge cases
properly. But knowing why the arithmetic works stops these from being magic.
'a' versus "a"
This is the distinction the lesson title promises, and it trips up everyone once:
#include <iostream>
int main() {
std::cout << sizeof('a') << "\n";
std::cout << sizeof("a") << "\n";
return 0;
}
1
2
'a'— single quotes — is onechar. One byte."a"— double quotes — is a string literal: an array of characters ending with a hidden null terminator'\0'. Two bytes: theaand the terminator.
That trailing '\0' is how C-style strings mark their end, and it's why "a" is bigger than it
looks. std::string (lesson 6.4) manages all this for you; raw string literals are the older C
mechanism underneath.
Getting the quotes wrong produces confusing errors:
// WILL NOT COMPILE
int main() {
char c = "A"; // double quotes: a 2-byte array, not a char
return 0;
}
error: invalid conversion from 'const char*' to 'char'
The message names both types, which — as lesson 2.5 noted — usually tells you exactly what went wrong.
Escape sequences
Some characters can't be typed directly, so they're written with a backslash:
#include <iostream>
int main() {
std::cout << "Tab:\there\n";
std::cout << "Quote:\"quoted\"\n";
std::cout << "Backslash:\\\n";
std::cout << 'X' << '\n';
return 0;
}
Tab: here
Quote:"quoted"
Backslash:\
X
\n newline, \t tab, \\ backslash, \" quote, \0 null. Note the last line: '\n' in
single quotes is a single char, and it's marginally more efficient than "\n" when you're
printing nothing else.
The limit: char is one byte
Here's where char runs out, and it matters a great deal for this site's audience:
#include <iostream>
#include <string>
int main() {
std::string english = "Hello";
std::string khmer = "សួស្តី";
std::cout << english.size() << "\n";
std::cout << khmer.size() << "\n";
return 0;
}
5
18
"Hello" is 5 characters and 5 bytes. "សួស្តី" is 6 characters a reader would count — and 18 bytes.
A single byte holds 256 possible values, nowhere near enough for every writing system on Earth. Modern text uses UTF-8, which encodes each character in one to four bytes: ASCII characters stay one byte (which is why UTF-8 is backward compatible), while Khmer, Chinese, and emoji take three or four.
The consequences for you:
.size()on astd::stringreturns bytes, not characters.- Indexing
khmer[0]gives you one byte — a fragment of a character, not the character. - Reversing a UTF-8 string byte by byte produces garbage.
C++ has no good built-in answer here; correct Unicode handling means a library like ICU. For this course, be aware of the distinction: as long as you treat strings as opaque units — store them, compare them, print them whole — UTF-8 just works. It's indexing and counting that breaks.
Try it
Write a program that takes the character '5' and prints: the character itself, its ASCII code,
and the result of multiplying its numeric value by 3.
Checkpoint
charis a one-byte integer; ASCII maps codes to symbols.digit - '0'converts a digit character to its numeric value.'a'is onechar;"a"is a two-byte array including a hidden'\0'.- Escape sequences (
\n,\t,\\,\") write characters you can't type directly. - UTF-8 uses one to four bytes per character, so
std::string::size()counts bytes, not characters — indexing non-ASCII text by byte will break it.
Questions about this lesson
Log in to ask a question.