Когда мы работаем с текстом, нам кажется, что компьютер «видит» буквы, цифры и знаки препинания так же, как и человек. На самом деле это не так.
Текст для компьютера — это нечто абстрактное, а символ — это прежде всего графический образ, который мы видим на экране или на бумаге. Такой графический образ неудобно напрямую хранить и обрабатывать внутри компьютера.
Компьютер умеет работать только с числами. Поэтому возникает идея:
каждому символу поставить в соответствие некоторое число.
Такой процесс называется кодированием символов.
Например, мы можем договориться, что буква A будет храниться как число 65,
буква B — как 66 и так далее.
Важно понимать, что символ и его внешний вид — это разные вещи. То, как символ выглядит, определяется шрифтом. Шрифт отвечает за форму буквы, толщину линий, наклон и другие визуальные детали.
Компьютер не хранит шрифт внутри текста — он хранит только числовые коды символов, а шрифт применяется уже при отображении текста на экране.
Также важно, что одинаково выглядящие символы могут иметь разный смысл. Например:
AАВыглядят они одинаково, но относятся к разным алфавитам и имеют разное значение. Поэтому в памяти компьютера они обязаны иметь разные числовые коды, даже если визуально их нельзя отличить.
Одной из самых старых и известных систем кодирования символов является ASCII (от англ. American Standard Code for Information Interchange).
В ASCII каждому символу сопоставляется число от 0 до 127. Это означает, что для хранения одного символа достаточно 7 бит информации. Однако на практике символы обычно хранили в 1 байте (8 бит), потому что это было удобнее для компьютеров.
Char Dec Oct Hex | Char Dec Oct Hex | Char Dec Oct Hex | Char Dec Oct Hex
-------------------------------------------------------------------------------------
(nul) 0 0000 0x00 | (sp) 32 0040 0x20 | @ 64 0100 0x40 | ` 96 0140 0x60
(soh) 1 0001 0x01 | ! 33 0041 0x21 | A 65 0101 0x41 | a 97 0141 0x61
(stx) 2 0002 0x02 | " 34 0042 0x22 | B 66 0102 0x42 | b 98 0142 0x62
(etx) 3 0003 0x03 | # 35 0043 0x23 | C 67 0103 0x43 | c 99 0143 0x63
(eot) 4 0004 0x04 | $ 36 0044 0x24 | D 68 0104 0x44 | d 100 0144 0x64
(enq) 5 0005 0x05 | % 37 0045 0x25 | E 69 0105 0x45 | e 101 0145 0x65
(ack) 6 0006 0x06 | & 38 0046 0x26 | F 70 0106 0x46 | f 102 0146 0x66
(bel) 7 0007 0x07 | ' 39 0047 0x27 | G 71 0107 0x47 | g 103 0147 0x67
(bs) 8 0010 0x08 | ( 40 0050 0x28 | H 72 0110 0x48 | h 104 0150 0x68
(ht) 9 0011 0x09 | ) 41 0051 0x29 | I 73 0111 0x49 | i 105 0151 0x69
(nl) 10 0012 0x0a | * 42 0052 0x2a | J 74 0112 0x4a | j 106 0152 0x6a
(vt) 11 0013 0x0b | + 43 0053 0x2b | K 75 0113 0x4b | k 107 0153 0x6b
(np) 12 0014 0x0c | , 44 0054 0x2c | L 76 0114 0x4c | l 108 0154 0x6c
(cr) 13 0015 0x0d | - 45 0055 0x2d | M 77 0115 0x4d | m 109 0155 0x6d
(so) 14 0016 0x0e | . 46 0056 0x2e | N 78 0116 0x4e | n 110 0156 0x6e
(si) 15 0017 0x0f | / 47 0057 0x2f | O 79 0117 0x4f | o 111 0157 0x6f
(dle) 16 0020 0x10 | 0 48 0060 0x30 | P 80 0120 0x50 | p 112 0160 0x70
(dc1) 17 0021 0x11 | 1 49 0061 0x31 | Q 81 0121 0x51 | q 113 0161 0x71
(dc2) 18 0022 0x12 | 2 50 0062 0x32 | R 82 0122 0x52 | r 114 0162 0x72
(dc3) 19 0023 0x13 | 3 51 0063 0x33 | S 83 0123 0x53 | s 115 0163 0x73
(dc4) 20 0024 0x14 | 4 52 0064 0x34 | T 84 0124 0x54 | t 116 0164 0x74
(nak) 21 0025 0x15 | 5 53 0065 0x35 | U 85 0125 0x55 | u 117 0165 0x75
(syn) 22 0026 0x16 | 6 54 0066 0x36 | V 86 0126 0x56 | v 118 0166 0x76
(etb) 23 0027 0x17 | 7 55 0067 0x37 | W 87 0127 0x57 | w 119 0167 0x77
(can) 24 0030 0x18 | 8 56 0070 0x38 | X 88 0130 0x58 | x 120 0170 0x78
(em) 25 0031 0x19 | 9 57 0071 0x39 | Y 89 0131 0x59 | y 121 0171 0x79
(sub) 26 0032 0x1a | : 58 0072 0x3a | Z 90 0132 0x5a | z 122 0172 0x7a
(esc) 27 0033 0x1b | ; 59 0073 0x3b | [ 91 0133 0x5b | { 123 0173 0x7b
(fs) 28 0034 0x1c | < 60 0074 0x3c | \ 92 0134 0x5c | | 124 0174 0x7c
(gs) 29 0035 0x1d | = 61 0075 0x3d | ] 93 0135 0x5d | } 125 0175 0x7d
(rs) 30 0036 0x1e | > 62 0076 0x3e | ^ 94 0136 0x5e | ~ 126 0176 0x7e
(us) 31 0037 0x1f | ? 63 0077 0x3f | _ 95 0137 0x5f | (del) 127 0177 0x7f
В таблице ASCII есть чёткая логика:
0–9A–Za–zЭто сделано очень удобно: например, разница между заглавной и строчной буквой — ровно 32.
Первые 32 символа (коды 0–31) не имеют графического изображения. Это служебные (управляющие) символы, которые используются для технических целей.
Несколько примеров:
0 — NUL9 — TAB10 — LF (Line Feed)13 — CR (Carriage Return)Эти символы не отображаются как буквы или знаки, но играют важную роль при работе с текстом.
У ASCII есть серьёзное ограничение: в нём нет русских букв и вообще нет поддержки большинства языков мира.
Исторически люди пытались решить эту проблему так:
Так появились разные кодировки:
Но у этого подхода было много проблем:
Кроме того, такой подход принципиально не масштабируется:
Для решения всех этих проблем была создана система Unicode.
Unicode — это единая таблица, в которой каждому символу всех письменных языков мира сопоставлен уникальный номер (кодовая точка).
На сегодняшний день стандарт Unicode включает более 150 000 символов (точное число постоянно растёт).
В Unicode входят:
Например:
эмодзи 😀 имеет код U+1F600
Так как количество символов очень большое, на один символ требуется больше одного байта памяти. Существует несколько способов хранения Unicode-символов в памяти (UTF-8, UTF-16, UTF-32), но все они используют больше информации, чем ASCII.
char в C++char и какие у него значенияВ языке C++ для хранения однобайтового символа используется тип char.
Один байт — это 8 бит, поэтому в памяти char хранит некоторое число от 0 до 255, но вопрос в том, как именно это число трактуется.
Чаще всего char рассматривают как знаковый тип, тогда его значения обычно лежат в диапазоне:
Однако в C++ есть три разных «варианта» символьного байта:
signed char — знаковый (обычно от -128 до 127)unsigned char — беззнаковый (обычно от 0 до 255)char — может быть либо signed, либо unsigned, это зависит от компилятора и системыТо есть запись char x; не гарантирует, будет ли это знаковый или беззнаковый тип.
Поэтому строго говоря, использование char для хранения чисел может быть небезопасным: на разных системах один и тот же код может вести себя по-разному.
Но в задачах и при изучении строк мы обычно работаем с обычными символами ASCII, поэтому для простоты дальше будем писать просто char.
char и как его выводитьПеременной типа char можно присвоить:
#include <iostream>
using namespace std;
int main() {
char c = 'A';
cout << c << "\n"; // выведется символ A
}
Если вывести переменную char напрямую, то на экран обычно выводится символ, соответствующий коду внутри char.
#include <iostream>
using namespace std;
int main() {
char c = 65;
cout << c << "\n"; // выведется A
}
charЕсли привести char к типу int, то мы увидим число, которое хранится в этом байте (то есть код символа).
#include <iostream>
using namespace std;
int main() {
char c = 'A';
cout << (int)c << "\n"; // выведется 65
}
charТип char — это целочисленный тип, значит с ним можно делать:
+, -, *, …<, >, ==, …'A' + 1 даёт 'B'Если код 'A' равен 65, то код 'A' + 1 равен 66, то есть это 'B'.
#include <iostream>
using namespace std;
int main() {
char a = 'A';
char b = a + 1;
cout << b << "\n"; // выведется B
}
Можно проверить и числом:
#include <iostream>
using namespace std;
int main() {
cout << (int)('A' + 1) << "\n"; // выведется 66
}
Сравнение идёт по их числовым кодам:
#include <iostream>
using namespace std;
int main() {
cout << ('A' < 'B') << "\n"; // выведется 1 (истина)
}
charС помощью cin можно считать один символ и записать его в переменную char.
#include <iostream>
using namespace std;
int main() {
char c;
cin >> c; // считывает один символ (пропуская пробелы и переводы строк)
cout << c << "\n";
}
Важно: оператор >> для char пропускает пробелы, табуляции и переводы строк.
То есть если вы хотите считать именно пробел, для этого понадобится другой способ (мы разберём позже при изучении строк и функций ввода).
string в C++string и как создавать строки
В C++ тип string — это удобный тип для хранения текста.
Его можно понимать как аналог vector<char>,
то есть динамический массив символов, который сам умеет увеличивать размер,
хранить длину и поддерживать операции добавления и удаления.
Чтобы пользоваться строками, нужно подключить заголовок:
#include <string>
#include <iostream>
#include <string>
using namespace std;
int main() {
string a; // пустая строка
string b = "Hello"; // инициализация строковым литералом
string c("World"); // другой способ инициализации
}
Можно создать строку из нескольких одинаковых символов (как у vector):
string s(5, 'x'); // "xxxxx"
Главная операция со строками — конкатенация, то есть «склеивание».
+ создаёт новую строку+= дописывает к существующей#include <iostream>
#include <string>
using namespace std;
int main() {
string a = "Hello";
string b = "World";
string c = a + ", " + b + "!";
cout << c << "\n"; // Hello, World!
a += "!!!";
cout << a << "\n"; // Hello!!!
}
К строке можно обращаться как к массиву: s[i].
Индексация начинается с нуля.
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "abcd";
cout << s[0] << "\n"; // a
cout << s[3] << "\n"; // d
}
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "cat";
s[0] = 'b';
cout << s << "\n"; // bat
}
resize и size у строк
Метод resize(n) изменяет длину строки.
resize(n, ch)#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "hello";
s.resize(3);
cout << s << "\n"; // hel
s.resize(6, '!');
cout << s << "\n"; // hel!!!
}
Если второй аргумент не указан, строка дополняется нулевыми символами '\0'.
Метод s.size() возвращает длину строки.
cin >> s и getlinecin >> s
При вводе через cin >> s строка считывается
до первого разделяющего символа
(пробела, табуляции или перевода строки).
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
cin >> s;
cout << s << "\n";
}
Если ввести:
Hello world
то в строку попадёт только "Hello".
getline
Если нужно считать всю строку до нажатия Enter,
используется функция getline.
#include <iostream>
#include <string>
using namespace std;
int main() {
string line;
getline(cin, line);
cout << line << "\n";
}
Тип string содержит многие методы, знакомые по vector, например:
push_back(), pop_back()insert — вставка#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "I like tea";
s.insert(7, "green ");
cout << s << "\n"; // I like green tea
}
erase — удаление#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "I like green tea";
s.erase(7, 6);
cout << s << "\n"; // I like tea
}
substr — подстрока#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "programming";
string t = s.substr(3, 4);
cout << t << "\n"; // gram
}