📘 Тема 1.6. Необходимый материал#
Шпаргалка по массивам и строкам.
1. Зачем нужны массивы#
До сих пор числа обрабатывались «на лету»: считали — сразу использовали — забыли. Но иногда к элементу нужно вернуться: пройти по данным второй раз, сравнить соседей, отсортировать. Для этого данные нужно хранить.
Массив — набор элементов одного типа, которые лежат в памяти подряд и доступны по номеру.
Итерируемые объекты — структуры, элементы которых можно перебирать в цикле:
| Структура | Пример | Особенность |
|---|---|---|
| массив | int arr[5] = {1, 2, 3, 4, 5}; |
фиксированный размер |
| строка | string s = "Hello"; |
последовательность символов |
| вектор | vector<int> v = {10, 20, 30}; |
размер может меняться |
Термины:
| Термин | Значение |
|---|---|
| элемент | одно значение в массиве |
| индекс | номер элемента, начинается с 0 |
| размер | количество элементов |
| обход | перебор всех элементов циклом |
2. Объявление и инициализация#
тип имя;
int a; // 100 целых чисел, значения не заданы
int b = ;
int c = ; // все элементы равны 0
int d = ; // размер 3 вычисляется сам
bool used = ; // 26 флажков, все false
Важно
Размер массива должен быть константой. В олимпиадных задачах массив обычно объявляют с запасом по максимальному ограничению: если
N ≤ 1000, пишутint a[1000];(или чуть больше), а реально используют первыеnэлементов.
Предупреждение
Локальный массив без инициализации (
int a[100];внутриmain) содержит «мусор». Если массив используется как счётчики, обязательно пишите= {0}.
3. Индексация#
- Первый элемент —
a[0]. - Последний элемент массива из
nэлементов —a[n - 1].
int arr = ;
cout << arr << endl; // 10
cout << arr << endl; // 50
arr = 99; // теперь {10, 20, 99, 40, 50}
| Индекс | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| Значение | 10 | 20 | 30 | 40 | 50 |
Почему с нуля? Индекс — это смещение от начала массива. Первый элемент лежит в самом начале, его смещение равно 0.
Внимание
arr[5]для массива из пяти элементов — выход за границы. Компилятор это не проверяет: программа может выдать мусор, испортить соседние переменные или упасть.
4. Заполнение и вывод#
С клавиатуры#
int n;
cin >> n;
int a;
for
По формуле#
int a;
for
Случайными числами#
; // без этого rand() каждый раз даёт одно и то же
for
Заметка
Случайные числа удобны, чтобы проверить свою программу на большом тесте. В решениях олимпиадных задач они не нужны.
Вывод#
for
cout << endl;
5. Шаблоны обработки массива#
Минимум и максимум#
int mn = a;
int mx = a;
for
Важно
Начинайте с первого элемента массива, а не с нуля. Для массива
{-5, -10, -3}начальноеmx = 0даст ответ 0, хотя максимум равен −3.
Среднее значение#
int sum = 0;
for
double average = sum / n;
Без (double) получится целочисленное деление: 61 / 6 = 10, а не 10.1667.
Сравнение с соседями#
// локальные максимумы: первый и последний элементы не проверяем
int cnt = 0;
for
Самая длинная серия одинаковых#
int best = 1, current = 1;
for
Предупреждение
При обращении к
a[i - 1]цикл начинается сi = 1, при обращении кa[i + 1]— заканчивается наi < n - 1. Иначе будет выход за границы.
6. Массив через указатель#
Имя массива — это адрес его первого элемента. Поэтому a[i] и *(a + i) — одно и то же.
int arr = ;
int* ptr = arr; // указатель на arr[0]
cout << *ptr << endl; // 10
cout << * << endl; // 40
Размер массива, объявленного в той же функции, можно узнать через sizeof:
int arr = ;
int size = sizeof / sizeof; // 6
7. Символы и ASCII#
Каждому символу соответствует числовой код по таблице ASCII.
| Символ | Код |
|---|---|
' ' (пробел) |
32 |
'0' ... '9' |
48 ... 57 |
'A' ... 'Z' |
65 ... 90 |
'a' ... 'z' |
97 ... 122 |
Цифры и буквы идут подряд, поэтому с символами можно работать как с числами:
char ch = 'A';
cout << ch << endl; // 65
cout << 97 << endl; // a
int d = '7' - '0'; // 7 — символ-цифра в число
char c = '0' + 5; // '5' — число в символ-цифру
int idx = 'c' - 'a'; // 2 — номер буквы в алфавите
char letter = 'a' + 3; // 'd'
Подсчёт букв массивом#
int cnt = ;
for
Совет
Приём
c - 'a'превращает букву в индекс от 0 до 25. Так массивcnt[26]становится «таблицей частот» букв, аbool used[26]— набором отметок «буква уже встречалась».
8. Строки string#
string — строка из символов. Нужен #include <string>.
string s;
cin >> s; // одно слово (до пробела)
; // вся строка, вместе с пробелами
| Операция | Что делает | Пример для s = "Hello" |
|---|---|---|
s.size(), s.length() |
длина строки | 5 |
s[i] |
символ с индексом i |
s[1] → 'e' |
s.substr(start, len) |
подстрока длины len с позиции start |
s.substr(1, 3) → "ell" |
s.find(t) |
позиция первого вхождения t |
s.find("l") → 2 |
s.push_back(c), s += c |
добавить символ в конец | "Hello!" |
s.append(t), s += t |
добавить строку в конец | "Hello World" |
s.back() |
последний символ | 'o' |
s.empty() |
пустая ли строка | false |
s == t, s < t |
сравнение строк | s == "Hello" → true |
s.compare(t) |
0, если равны; <0 или >0 иначе |
s.compare("Hello") → 0 |
Перебор символов#
for
Поиск подстроки#
if
Важно
Если подстрока не найдена,
findвозвращает специальное значениеstring::npos. Сравнивайте именно с ним, а не с-1.
Предупреждение
substr(start, len)— второй аргумент это длина, а не конечная позиция.cin >> sчитает только до пробела. Для строки с пробелами нуженgetline(cin, s).- Если перед
getlineбылcin >> n, в потоке остался перевод строки. Пропустите его:cin.ignore();.s.size()возвращает беззнаковое число. Для пустой строкиs.size() - 1— это не −1, а огромное число. Пишитеi + 1 < s.size()или приводите кint.
9. Строки char[]#
Строка в стиле языка C — массив символов, который заканчивается нулевым символом '\0'. Функции для неё лежат в <cstring>.
char s = "Hello"; // H e l l o \0
| Функция | Что делает |
|---|---|
strlen(s) |
длина строки |
strcpy(dest, src) |
копирует src в dest |
strcat(dest, src) |
дописывает src в конец dest |
strcmp(s1, s2) |
сравнивает строки: 0, если равны |
strstr(s1, s2) |
ищет s2 внутри s1 |
Заметка
stringудобнее и безопаснее: он сам знает свою длину и сам выделяет память.char[]нужно знать, чтобы читать чужой код, но в своих решениях используйтеstring.
10. Пример: палиндром#
Два индекса идут навстречу друг другу с краёв строки и сравнивают символы.
bool
const string& s — передача по ссылке: строка не копируется, а const запрещает её менять.
11. Пример: пары соседних символов#
Задача «Инопланетный геном»: сколько пар соседних букв первой строки встречаются во второй строке.
string s1, s2;
cin >> s1 >> s2;
int ans = 0;
for
cout << ans << endl;
Для s1 = "ABBACAB" и s2 = "BCABB": пары первой строки AB, BB, BA, AC, CA, AB, из них во второй встречаются AB, BB, CA, AB — ответ 4.
12. Типичные ошибки#
| ❌ Неправильно | ✅ Правильно |
|---|---|
a[n] — последний элемент |
a[n - 1] |
for (int i = 0; i <= n; i++) для обхода массива |
for (int i = 0; i < n; i++) |
int cnt[26]; и сразу cnt[x]++ |
int cnt[26] = {0}; |
int mx = 0; для максимума массива |
int mx = a[0]; |
a[i] > a[i - 1] при i = 0 |
начинать цикл с i = 1 |
sum / n для среднего |
(double)sum / n |
cin >> s для строки с пробелами |
getline(cin, s) |
s.find(t) == -1 |
s.find(t) == string::npos |
s.substr(2, 5) как «с 2 по 5» |
s.substr(start, len) — второй аргумент длина |
s[i] вместо s[i] - '0' для цифры |
s[i] - '0' |
if (s = "YES") |
if (s == "YES") |
13. Шаблон программы#
using namespace std;
int