10.22 Строки
TODO Не дошли до malloc(), требуется пересмотр объёма + inplace документация
Что мы знаем про строки из лекций?
Где хранится длина строки?
Чем это опасно?
Ввод и вывод строк
Ввод с помощью scanf() и fgets; вывод с помощью printf() и puts() scanf() вводит слово, ине вводит пробел, перевод строки т. п. — они остаются в буфере ввода;
→ надо явно писать scanf("%19s\n", s) для буфера из 20 байтов
fgets() вводит одну строку, включая перевод строки, для буфера из 20 байтов надо писать fgets(s, 20, stdin)
Курьёз: был ещё gets, но нет)
Написать программу которая вводит строку из 12 символов, переставляет в обратном порядке прямо внутри строки, и выводит её. На вход подавать строго больше, чем 12 символов
- Обратить внимание на то, как используются числа 11, 12 и 13
Строковые функции
Были на лекциях типы size_t и ssize_t? Если нет: size_t используется для размеров (например, длина буфера). Обычно это unsigned long int
ssize_t (aka «signed size_t») используется для отчёта о количестве введённых байтов, может быть нулевым и отрицательным
Функция (s) ищет 0 в массиве s; индекс этого нуля — это «длина строки»
В предыдущем задании считать, что размер строки не превосходит 100; вводить можно любое количество символов
Во всех строковых функциях Си нужно всегда следить:
- Чтобы в конце строки был нулевой байт
- Чтобы строка при копировании помещалась в отведённый ей массив
strlcpy(приёмник, источник, размер) / strlcat(приёмник, источник, размер)
не использовать: strcpy, strcat, strncpy, strncat (две последние не ставят '\0' в конец строки, если она не влезла!) (string_copying);
Ввести n и строку, после чего сформировать новую строку из n копий введённой строки, вывести эту новую строку Варианты на выбор: strlcpy() + strlcat(); или проинициализировать dst пустой строкой + strlcat()
Ввести две строки, сравнить их с помощью strcmp(строка, строка) (есть ещё strncmp)
Ввести две строки, проверить, входит ли одна в другую (strstr(строка, подстрока))
TODO Вот здесь мы остановились
Выделение памяти на куче
Повторение:
Бывает по-разному, но обычно у запущенной программы в ОС:
- ↓ стек
- недоступная память
- ↑ куча
- статическая память
Почему так? Потому что!!! (+потому что виртуальная память, а так удобнее)
Тип void * и двойные ссылки; malloc() и calloc()
Был ли void * на лекциях? Для чего нужен?
Тип int ** и ему подобные — для чего нужны?
Подсказка: все параметры передаются в функцию по значению
Модифицировать пример с умножением строки на n: перенести логику в функциюi в функцию передавать char **приёмник и там вызывать malloc())
Попробовать добавить наш любимый -fsanitize=address
А вот! free
Кто маллочит — тот и фрит!
Ввод строки произвольного размера
Работа getline
один из вариантов — ввод строки произвольного размера (требуется free()):
char *s; size_t bufsize; ssize_t length; length = getline(&s, &bufsize, stidn); … free(s);
Массив строк
Инициализированный массив строк
Ввести n, затем создать массив на n строк и ввести их; вывести только строки, в которых содержится первый символ последней строки (strchr) Не забыть free() для них для всех!
Д/З
В заданиях разрешается (и рекомендуется!) пользоваться стандартными функциями и l-функциями для строк
- Ввести строку размера не больше 1000, подсчитать в ней количество: цифр, строчных букв латиницы, прописных букв латиницы. Вывести результаты подсчета через пробел.
Подсказка: ASCII-коды можно сравнивать, а коды соответствующих символов идут в таблице подряд
Did you know that for the price of a 280-Z you can buy two Z-80's?
→5 40 3
- Ввести строку размера не больше 1000, состоящую из слов, разделённых одним или несколькими пробелами. Вывести через пробел слова, которые начинаются и оканчиваются одним и тем же символом (если в слове один символ, оно на него и начинается и заканчивается). Массив для хранения строки объявить глобально.
did you know that
→did that
Ввести построчно несколько строк, вывести длину их общего префикса (попарного сравнения строк-соседей достаточно). Признак конца ввода: EOF.
Feral dog Ferrum dwa o tri Ferrari turbo 128
→3
- Квадратор
- ввести положительные w и h — ширина и высота «экрана»
- в цикле вводить 0 или более 4-элементных последовательностей вида (c,X,Y,s), где X и Y — координаты левого верхнего угла квадрата, s — длина его стороны (не меньше 1), а c — символ которым он заполняется на экране. Признак конца ввода: EOF. Для ввода символа-заполнителя используйте в scanf спецификатор "%c".
вывести прямоугольник из h×w точек, на котором соответствующими символами «нарисованы» квадраты соответствующих размеров в соответствующих местах. Координаты левого верхнего угла поля — 0,0; координаты растут вправо вниз. Проверять, что квадраты не выходят за границы поля, не надо. Более поздние по порядку ввода квадраты рисуются поверх более ранних. Не занятые квадратами позиции содержат точки "."
20 23 @ 1 1 5 ! 2 3 1 # 4 5 11 / 8 11 9
→
.................... .@@@@@.............. .@@@@@.............. .@!@@@.............. .@@@@@.............. .@@@###########..... ....###########..... ....###########..... ....###########..... ....###########..... ....###########..... ....####/////////... ....####/////////... ....####/////////... ....####/////////... ....####/////////... ......../////////... ......../////////... ......../////////... ......../////////... .................... .................... ....................
Эту задачу можно решать вообще без использования строковых функций, но для удобства вывода можно завести двумерный массив screen[h][w+1] и заполнить точками все его элементы, а screen[i][w] — нулями. Тогда это будут строки!
