From cdda268119457626ea768ba23bf60a35067933d8 Mon Sep 17 00:00:00 2001 From: PvlukhinaYA Date: Wed, 25 Dec 2024 23:03:47 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D1=80=D0=B8=D0=BC=D0=B5=D1=80=20=D1=82?= =?UTF-8?q?=D0=B5=D0=BA=D1=81=D1=82=D0=B0=20=D0=B4=D0=BB=D1=8F=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D1=8F=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- text on task 3.txt | 111 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 text on task 3.txt diff --git a/text on task 3.txt b/text on task 3.txt new file mode 100644 index 0000000..1e16fb6 --- /dev/null +++ b/text on task 3.txt @@ -0,0 +1,111 @@ +4. Работа со строками C +Данная часть лабораторной работы выполняется отдельно от предыдущей части, в новом проекте. +Вместо пошагового выполнения ЛР рассмотрим решение двух типовых задач: ввода и обработки строки C функциями стандартной библиотеки и загрузки текста из файла в строку C. Задание на ЛР представляет собой их комбинацию. + +4.1. Ввод строки C и её обработка функциями стандартной библиотеки +Решим задачу: считать строку C и напечатать по отдельности слов в ней (слова разделены пробелами и знаками препинания). + +Ввод строки C +Для определенности предположим, что длина строки не превышает некоторой заранее заданной, например, 255 символов. С учетом завершающего '\0' под строку нужно 256 символов: + +const size_t MAX_SIZE = 256; +char text[MAX_SIZE]; +Ввести с строку C можно функцией fgets(). Ознакомимся с документацией по ссылке. В документации обычно есть и примеры использования описываемых функций. + +Прототип функции: + +char* fgets(char* str, int count, std::FILE* stream); +Над прототипом написано: Defined in header — это значит, что для использования функции нужно включить заголовочный файл . + +Под прототипом написано, что делает данная функция: считывает не более count - 1 символов и записывает их в массив, на который указывает str; чтение ведется из файлового потока stream. + +Нам необходимо считывать строку со стандартного ввода, где взять файловый поток для него? В справочнике std::FILE является ссылкой на статью «C-style file input/output» («Файловый ввод-вывод средствами C»). В конце её в разделе Macros можно найти запись: + +stdin expression of type FILE* associated with the input stream +То есть глобальная переменная stdin из и есть нужный поток. + +Итак, вызов для чтения строки: + +fgets(text, MAX_SIZE, stdin); +Заметим, что на практике, а не в учебных целях, удобнее считывать строки C++: + +string text; +getline(cin, text); +Если затем нужен указатель на массив считанных символов, его можно получить как text.c_str() (менять символы с этом массиве нельзя; при необходимости есть метод text.data()). + +Разбиение строки на слова +Чтобы напечатать слова строки по отдельности, нужно искать границы слов и печатать часть строки от начала до конца слова. Чтобы найти конец слова, нужно найти первый (от любой позиции внутри слова, в том числе от его начала) символ-разделитель. Разделители могут идти подряд. Вот пример текста: + +News,from beyond the Narrow Sea. Haven't you heard?! + ↑ ↑↑ +нет пробела два пробела +Кроме знаков препинания, разделители включают также пробел и символы перевода строк: + +const char* separators = " \r\n,.!?:;()-"; +Функции стандартной библиотеки для работы со строками C — в заголовочном файле . Из обширного списка наиболее подходящими для задачи выглядят описания: + +strspn() — определяет, сколько первых символов строки подряд относятся к множеству, заданному другой строкой; + +strсspn() — определяет, сколько первых символов строки подряд не относятся к множеству, заданному другой строкой (например, сколько символов с начала строки — не разделители слов); + +Алгоритм решения: + +Определить, сколько разделителей находятся в начале строки — strspn(). + +Пропустить их (сместить указатель на начало строки). + +Если достигнут конец строки (начальный символ — '\0'), закончить работу. + +Найти первый разделитель от нового начала строки (или слова), то есть длину слова — strcspn(). + +Напечатать часть строки от начала слова до разделителя (это можно сделать методом cout.write() или функцией fwrite()). Также напечатать символ перевода строки. + +Сдвинуть начало строки вперед на длину слова. + +Перейти к пункту 1. + +Почти каждый шаг алгоритма — всего одна строка или конструкция. Начало строки (то есть еще не разобранной части) будем хранить в переменной: + +const char* start = text; +Алгоритм представляет собой цикл: + +while (true) { +Определить, сколько разделителей находятся в начале строки: + +const size_t separator_count = strspn(start, separators); +Пропустить их: + +start += separator_count; +Если достигнут конец строки, закончить работу. + +if (start[0] == '\0') { + break; +} +Найти первый разделитель от нового начала строки: + +const size_t word_length = strcspn(start, separators); +Напечатать часть строки от начала слова до разделителя: + +cout.write(start, word_length); +Также напечатать символ перевода строки: + + cout << '\n'; +Сдвинуть начало строки вперед на длину слова: + +start += word_length; +} + +Соединив участки кода в полноценную программу, можно убедиться, что она работает правильно: + +echo "News,from beyond the Narrow Sea. Haven't you heard?" | lab04.exe +Вывод: + +News +from +beyond +the +Narrow +Sea +Haven't +you +heard \ No newline at end of file