Вспомогательные типы и функции задачника для языка C++ до версии 4.23
Описанные на данной странице типы и функции использовались в задачнике для языка C++
до версии 4.22 включительно. В версии 4.23 набор функций был переработан и дополнен,
чтобы обеспечить согласование с набором функций для языка C.
Инициализация заданий, ввод-вывод данных
void Task(const char* name);
Функция инициализирует задание с именем name. Она должна вызываться в
начале программы, выполняющей это задание (до вызова функций ввода-вывода
GetPut). Если в программе, выполняющей задание, не указана функция Task,
то при запуске программы будет выведено окно с сообщением «Не вызвана
процедура Task с именем задания».
Имя задания name должно включать имя группы заданий и порядковый номер в
пределах группы (например, "Begin3" ). Регистр букв в имени группы может быть
произвольным. Если указана неверная группа, то программа выведет сообщение об
ошибке «Указана неверная тема задания»
(список всех доступных групп можно получить с помощью программных модулей PT4Demo и PT4Load). Если указан
недопустимый номер задания, то программа выведет сообщение, в котором будет
указан диапазон допустимых номеров для данной группы. Если после имени задания
в параметре name указан суффикс «?» (например, "Begin3?" ), то
программа будет работать в демонстрационном режиме.
Начиная с версии 4.8, функция Task может также использоваться для
генерации и вывода на экран html-страницы с текстом задания или группы заданий.
Для этого необходимо указать в качестве параметра name имя конкретного задания или группы
заданий и суффикс «#», например, "Begin3#" или
"Begin#" . Дополнительные сведения о генерации html-страниц с описаниями заданий приводятся
в разделе, посвященном демонстрационному режиму задачника.
Начиная с версии 4.13, задачник обеспечивает автоматическое тестирование программы на нескольких
наборах исходных данных при ее однократном запуске. Для отключения этой возможности достаточно
указать в параметре Name после имени задания суффикс «!» (например, "Begin3!" );
в этом случае при запуске программы она будет протестирована на единственном наборе исходных данных,
и для проверки правильности решения программу потребуется запустить несколько раз (как в предыдущих версиях
задачника).
Если функция Task вызывается в программе несколько раз, то все
последующие ее вызовы игнорируются. Исключением является ситуация, когда
функция используется для генерации html-страницы с описанием нескольких заданий или групп
заданий; в этом случае учитываются все вызовы данной функции.
Начиная с версии 4.12, параметр name может содержать суффикс «_ru»
или «_en», позволяющий явным образом задать язык интерфейса
(русский или английский соответственно) для окна задачника и выполняемого задания.
В версиях 4.124.14 специальные суффиксы «?», «#» и «!» должны указываться перед данным суффиксом,
например, "Begin3#_en" ; начиная с версии 4.15, суффиксы могут указываться в любом порядке.
В случае нескольких вызовов функции Task (для генерации
html-страницы) учитывается только суффикс, указанный при первом вызове функции.
При отсутствии суффикса используется язык интерфейса, определенный в качестве основного для данного рабочего каталога
(в универсальном варианте задачника основной язык интерфейса можно настроить с помощью программного модуля PT4Load,
используя его контекстное меню).
void GetB(bool& a);
void GetN(int& a);
void GetD(double& a);
void GetC(char& a);
void GetS(char* a);
void GetS(string& a);
void GetP(TNode*& a);
Функции обеспечивают ввод исходных данных в программу, выполняющую
учебное задание. Они должны вызываться после вызова функции Task; в случае их
вызова до вызова функции Task при запуске программы будет выведено сообщение
об ошибке «В начале программы не вызвана процедура Task с именем
задания».
Используемая функция ввода должна соответствовать типу очередного элемента
исходных данных; в противном случае выводится сообщение об ошибке
«Неверно указан тип при вводе исходных данных» (такое сообщение
будет выведено, например, если очередной элемент данных является символом, а для
его ввода используется функция GetN).
При попытке ввести больше исходных данных, чем это предусмотрено в
задании, выводится сообщение об ошибке «Попытка ввести лишние исходные
данные». Если исходные данные, необходимые для решения задания, введены
не полностью, то выводится сообщение «Введены не все требуемые исходные
данные».
Следует обратить внимание на то, что строковые данные могут считываться
либо в переменную типа char*, либо в объект string.
bool GetBool();
int GetInt();
double GetDouble();
char GetChar();
string GetString();
TNode* GetNode();
Эти варианты функций ввода добавлены в версии задачника 4.22.
Их удобно использовать в ситуации, когда значение элемента исходных данных
достаточно передать в конструктор какого-либо объекта или в какую-либо функцию. Кроме того,
они позволяют совместить описание и инициализацию переменных, связанных с
исходными данными.
void PutB(bool a);
void PutN(int a);
void PutD(double a);
void PutC(char a);
void PutS(const char* a);
void PutS(string a);
void PutP(TNode* a);
Функции обеспечивают вывод на экран результирующих данных, найденных
программой, и их сравнение с контрольными данными (т. е. с правильным
решением). Как и функции группы Get, эти функции должны вызываться после
вызова функции Task; в противном случае при запуске программы будет выведено
сообщение об ошибке «В начале программы не вызвана процедура Task с
именем задания».
В отличие от функций группы Get, в качестве параметра функций группы Put
можно указывать не только переменные, но и выражения (в частности, константы
соответствующего типа). Используемая функция должна соответствовать типу
очередного элемента результирующих данных, в противном случае выводится
сообщение об ошибке «Неверно указан тип при выводе результатов».
Как и в случае функций группы Get, при вызовах функций группы Put
программа осуществляет контроль за соответствием количества требуемых и
выведенных результирующих данных. Если программа выведет недостаточное или
избыточное количество результирующих данных, то после проверки этих данных
появится сообщение «Выведены не все результирующие данные» или,
соответственно, «Попытка вывести лишние результирующие данные».
Следует обратить внимание на то, что в функции PutS можно указывать
параметры двух типов: const char* и string.
Поток ввода-вывода pt
Поток ввода-вывода pt может использоваться вместо функций групп
GetPut.
С его использованием операторы ввода-вывода могут быть оформлены более
компактно. Например, вместо последовательности вызовов функций GetN(a);
GetD(b); GetS(s); достаточно указать один оператор чтения из потока:
pt >> a >> b >> s; .
В версии задачника 4.22 возможности потока вывода pt существенно расширены.
Теперь в качестве выводимых данных для потока pt можно указывать переменные типа pair
и любого контейнерного типа, причем элементами контейнера могут быть данные
скалярных типов, типа pair и контейнерного типа. Компоненты типа pair
также могут иметь любой скалярный тип, тип pair и контейнерный тип.
Итератор чтения ptin_iterator<T>
Итератор записи ptout_iterator<T>
Начиная с версии 4.15, для ввода и вывода элементов последовательностей типа T
можно использовать специализированные итераторы ptin_iterator<T> и ptout_iterator<T>
соответственно. Эти итераторы обладают теми же свойствами, что и
стандартные потоковые итераторы istream_iterator<T> и ostream_iterator<T> .
Перечислим свойства итератора чтения, совпадающие с аналогичными свойствами потоковых итераторов:
- тип T определяет тип элементов последовательности;
- чтение элемента последовательности из потока pt выполняется в начальный момент работы с итератором,
а затем при каждой операции инкремента ++;
- имеются два варианта операции ++: префиксный инкремент (++i) и постфиксный инкремент (i++);
- операция * возвращает последнее прочитанное значение, причем эту операцию можно использовать неоднократно
для получения того же самого значения;
- итератор конца последовательности создается с помощью конструктора без параметров;
- при достижении конца последовательности итератор становится равным итератору конца последовательности,
последующие вызовы операции инкремента игнорируются, а в результате вызова операции * всегда возвращается
значение последнего прочитанного элемента последовательности.
Свойства итератора записи, совпадающие с аналогичными свойствами потоковых итераторов:
- специальный конструктор для создания итератора конца последовательности не предусмотрен;
- операции * и ++ не выполняют никаких действий и просто возвращают сам итератор;
- операция присваивания вида o = выражение (где o - имя итератора записи) записывает значение
выражения в поток pt.
В отличие от стандартного потокового итератора istream_iterator, конструктор для итератора ptin_iterator
(за исключением конструктора итератора конца последовательности) имеет один параметр типа unsigned int,
определяющий размер считываемой последовательности (в элементах). В случае особого значения параметра,
равного 0, размер последовательности считывается из самого потока pt непосредственно перед считыванием
первого элемента последовательности. Если при считывании размера оказывается, что прочитанный элемент
данных не является целым числом или это число не является положительным, то итератор сразу переходит
в состояние конца последовательности (т. е. становится равным итератору ptin_iterator<T>() ).
Подобная организация итераторов чтения ptin_iterator<T> позволяет легко реализовывать
с их помощью считывание из потока ввода pt нескольких последовательностей, если заранее известен
их размер или если размер указывается непосредственно перед началом последовательности.
В качестве примера использования итераторов потока pt для ввода и вывода данных приведем
решение задачи Array7, в которой требуется ввести массив вещественных чисел указанного размера,
а затем вывести его элементы в обратном порядке (обратите внимание на подключение стандартных заголовочных файлов
<vector> и <algorithm>; для хранения массива используется контейнер vector):
#include "pt4.h"
#include <vector>
#include <algorithm>
using namespace std;
void Solve()
{
Task("Array7");
vector<double> a(ptin_iterator<double>(0), ptin_iterator<double>());
copy(a.rbegin(), a.rend(), ptout_iterator<double>());
}
Работа с динамическими структурами
struct TNode
{
int Data;
TNode* Next;
TNode* Prev;
TNode* Left;
TNode* Right;
TNode* Parent;
};
typedef TNode* PNode;
Типы PNode и TNode используются в заданиях групп Dynamic
и Tree. В заданиях на
стеки и очереди (Dynamic1Dynamic28) при работе со структурами типа TNode
используются только поля Data и Next; в заданиях на двусвязные списки
(Dynamic29Dynamic80) используются поля Data, Next и Prev. В большинстве заданий на
бинарные деревья (группа Tree) используются поля Data, Left и Right;
в заданиях на обработку бинарных деревьев с обратной связью
(Tree48Tree56 и Tree70Tree71) дополнительно используется поле Parent.
Все исходные и результирующие данные-указатели в заданиях имеют тип
PNode; их ввод и вывод должен осуществляться с помощью функций GetP и PutP
или потока ввода-вывода pt.
void DeleteNode(TNode* p);
Данная функция обеспечивает освобождение памяти, выделенной под структуру
типа TNode (см. ее описание, приведенное выше). Функция DeleteNode используется только при
выполнении заданий групп Dynamic и Tree.
Начиная с версии задачника 4.11, вместо данной функции можно использовать стандартный оператор
освобождения памяти delete.
Вывод отладочной информации
Описываемые далее отладочные средства появились в версии 4.9 задачника Programming Taskbook.
С их помощью можно выводить отладочную информацию
непосредственно в окно задачника (в специальный раздел отладки).
void Show(string s);
void Show(wstring s);
Отображает текстовую строку s в разделе отладки окна задачника.
Вариант с параметром типа wstring добавлен в версии 4.22 для возможности
вывода в раздел отладки текстов, содержащих произвольные символы Юникода.
Если текущая экранная строка в разделе отладки уже содержит некоторый текст, то
строка s снабжается начальным пробелом и приписывается к этому тексту,
за исключением случая, когда при таком приписывании размер
полученного текста превысит ширину области данных (равную 80 символам).
В последнем случае вывод строки s осуществляется с начала
следующей экранной строки; если же и в этой ситуации строка s превысит
ширину области данных, то строка s будет выведена на нескольких
экранных строках, причем разрывы текста будут выполняться по
пробельным символам строки s, а при отсутствии пробелов при
достижении очередного фрагмента строки длины, равной 80.
Строка s может содержать явные команды перехода на новую
экранную строку. В качестве таких команд можно использовать или
символ с кодом 13 («возврат каретки» символ '\r' ),
или символ с кодом 10 («переход на новую
строку» символ '\n' ), или их комбинацию в
указанном порядке: "\r\n" .
void Show([string s,] int a[, int w]);
void Show([string s,] double a[, int w]);
void Show(wstring s, int a[, int w]);
void Show(wstring s, double a[, int w]);
Перегруженные варианты функции Show, предназначенные для вывода числовых отладочных данных.
Использование этих вариантов позволяет максимально упростить действия
учащегося, связанные с выводом числовых данных, поскольку избавляет
его от необходимости применять стандартные средства языка C++,
предназначенные для преобразования чисел в их строковые
представления.
При вызове приведенных вариантов можно не указывать один или оба параметра,
заключенные в квадратные скобки.
Строковый параметр s определяет необязательный комментарий,
который указывается перед выводимым числом; если параметр s
отсутствует, то комментарий полагается равным пустой строке.
Варианты со строковым параметром s типа wstring добавлены в версии задачника 4.22.
Числовой параметр a определяет выводимое число.
Необязательный целочисленный параметр w определяет
ширину поля вывода (т. е. количество экранных
позиций, отводимое для вывода числа). Если указанной ширины w поля вывода недостаточно, то
значение параметра w игнорируется; в этом случае (а также в случае, если параметр w отсутствует)
используется ширина поля вывода, минимально необходимая для
отображения данного числа. Если число не занимает всего поля вывода, то
оно дополняется слева пробелами (т. е. выравнивается по
правой границе поля вывода). В качестве десятичного разделителя
для чисел с дробной частью используется точка.
Вещественные числа по умолчанию выводятся в формате с
фиксированной точкой и двумя дробными знаками. Изменить формат
вывода вещественных чисел можно с помощью вспомогательной
функции SetPrecision, описываемой далее.
void ShowLine([string s]);
void ShowLine([string s,] int a[, int w]);
void ShowLine([string s,] double a[, int w]);
void ShowLine(wstring s);
void ShowLine(wstring s, int a[, int w]);
void ShowLine(wstring s, double a[, int w]);
Модификации ранее описанных функций Show; после вывода указанных данных в раздел отладки
дополнительно осуществляют автоматический переход на следующую экранную строку.
Смысл параметров тот же, что и для соответствующих вариантов функции Show.
Варианты со строковым параметром s типа wstring добавлены в версии задачника 4.22.
Параметры, указанные в квадратных скобках, могут отсутствовать.
Если функция ShowLine вызывается без параметров, то она
просто обеспечивает переход на новую экранную строку в разделе отладки.
void HideTask();
Вызов данной функции обеспечивает автоматическое скрытие всех разделов окна
задачника, кроме раздела отладки. Если раздел отладки в окне задачника
не отображается (в частности, если программа запущена в
демонстрационном режиме), то вызов функции HideTask игнорируется.
Игнорируются также все повторные вызовы данной функции.
Скрыть/восстановить основные разделы окна
задачника после его отображения на экране можно также с помощью клавиши
пробела или соответствующей команды контекстного меню раздела
отладки.
void SetPrecision(int n);
Функция предназначена для настройки формата вывода
вещественных отладочных данных. Если параметр n положителен, то он
определяет количество выводимых дробных разрядов; при этом число
выводится в формате с фиксированной точкой.
Если параметр n равен
нулю или является отрицательным, то число выводится в формате с
плавающей точкой (экспоненциальном формате); при этом
число дробных знаков полагается равным модулю параметра n; если
же параметр n равен нулю, то по умолчанию устанавливается количество
дробных знаков, равное 6.
Действие текущей настройки числового формата, определенной
функцией SetPrecision, продолжается до очередного вызова этой
функции. До первого вызова функции SetPrecision вещественные
числа выводятся в формате с фиксированной точкой и двумя дробными
знаками.
Отладочные средства, добавленные в версии 4.16
Описываемые в данном пункте отладочные средства предназначены,
прежде всего, для использования при выполнении заданий из электронного задачника Programming Taskbook for STL.
Вместе с тем, они могут применяться при выполнении любых заданий, поскольку
реализованы в версии 4.16 базового варианта задачника Programming Taskbook.
template<typename T1, typename T2>
void Show([string s,] pair<T1, T2> a)
template<typename T1, typename T2>
void Show(wstring s, pair<T1, T2> a)
template<typename T1, typename T2>
void ShowLine([string s,] pair<T1, T2> a)
template<typename T1, typename T2>
void ShowLine(wstring s, pair<T1, T2> a)
Варианты функций Show и ShowLine, позволяющие выводить в раздел отладки данные типа pair<T1, T2>;
при этом в качестве типов T1 и T2 могут использоваться типы int, double, char, const char* и string,
а также типы pair (глубина вложения типов pair может быть произвольной) и контейнеры vector, deque, list, set, multiset,
map, multimap с данными указанных типов.
Перед выводом первого элемента пары выводится необязательный строковый комментарий s
и открывающая круглая скобка, между элементами пары выводится запятая,
после вывода второго элемента выводится закрывающая круглая скобка. Например, элемент данных типа
pair<int, pair<int, int>> со значениями 5, 2 и 9 и комментарием «p=»
будет выведен следующим образом:
p=( 5 , ( 2 , 9 ) )
Варианты со строковым параметром s типа wstring добавлены в версии задачника 4.22.
void Show(string s, string a)
void Show(string s, char a)
void ShowLine(string s, string a)
void ShowLine(string s, char a)
void Show(wstring s, string a)
void Show(wstring s, char a)
void ShowLine(wstring s, string a)
void ShowLine(wstring s, char a)
Варианты функций Show и ShowLine, позволяющие выводить в раздел отладки данные типа char и string
вместе с предваряющими их строковыми комментариями s.
Варианты со строковым параметром s типа wstring добавлены в версии задачника 4.22.
template<typename InIter>
void Show(InIter first, InIter last[, string s])
template<typename InIter>
void ShowLine(InIter first, InIter last[, string s])
template<typename InIter>
void Show(InIter first, InIter last, wstring s)
template<typename InIter>
void ShowLine(InIter first, InIter last, wstring s)
Варианты функций Show и ShowLine, позволяющие выводить в раздел отладки элементы последовательности,
используя связанные с ней итераторы ввода first и last. Элементы последовательности могут иметь тип
int, double, char, const char* и string, а также pair<T1, T2>
(глубина вложения типов pair может быть произвольной); кроме того, сами элементы (или компоненты пары pair)
могут быть контейнерами vector, deque, list, set, multiset, map, multimap.
Необязательный последний параметр s позволяет задать строковый комментарий,
который указывается перед выводимой последовательностью.
Варианты со строковым параметром s типа wstring добавлены в версии задачника 4.22.
В частности, данные варианты можно использовать для вывода элементов массива a размера n:
Show(a, a + n);
Вариант Show выводит элементы последовательности на одной строке, разделяя их пробелами;
после завершения вывода автоматически
выполняется переход на новую строку. Вариант ShowLine выводит каждый элемент последовательности на новой строке; строковый
комментарий выводится в той же строке, что и первый элемент.
string s("Пример");
ShowLine("s1=", s);
Show(s.begin(), s.end(), "s2=");
ShowLine(s.begin(), s.end(), "s3=");
В результате выполнения этих операторов в разделе отладки будет выведен следующий текст:
1> s1=Пример
2> s2=П р и м е р
3> s3=П
4> р
5> и
6> м
7> е
8> р
Show("s=", "Пример"); // Приведет к неверной работе программы!
При подобном вызове в разделе отладки выводятся посторонние данные, а программа обычно завершается ошибкой
Access Violation. Для правильного вывода данных следует либо объединить эти параметры в одну литеральную строку,
либо преобразовать хотя бы один из них к типу string:
Show("s=Пример");
Show("s=", string("Пример"));
Преобразование кодировок (версия задачника 4.22)
string RuAnsi(wstring s);
Данная функция появились в версии 4.22.
Она позволяет решить проблему, связанную с несоответствием кодировок символьных
данных. Эта проблема возникает при использовании редактора кода, поддерживающего кодировку UTF-8
(в частности, редактора VS Code). Любые строковые константы, содержащие символы, отличные от символов ASCII,
должны оформляться в этом редакторе как «длинные строки» (типа wstring, например, L"Строка типа wstring").
Это не препятствует их выводу в разделе отладки (поскольку в версии 4.22 появились варианты
функций Show и ShowLine с параметрами-комментариями типа wstring), однако не позволяет их использовать
при формировании выходных текстовых данных, содержащих русские буквы (так как
функции вывода, как и функции ввода, работают с однобайтными строками типа string).
Поэтому, если требуется использовать при преобразовании или выводе данных строковые константы,
определенные в программе и содержащие русские буквы, необходимо предварительно
преобразовать эти константы (типа wstring) в однобайтную ANSI-кодировку 1251 с помощью функции RuAnsi.
Если преобразуемые константы содержат символы Юникода, отличные от русских букв и символов,
входящих в набор ASCII, то эти символы заменяются на знаки вопроса «?».
Таким образом, необходимость в использовании функции RuAnsi возникает
только при решении задач, требующих обработки символьных данных на русском языке и только в редакторах кода,
поддерживающих кодировку UTF-8.
Заметим, что «обратная» проблема, связанная с корректным выводом в разделе отладки
однобайтных строк (полученных, например, при считывании или преобразовании исходных строковых данных),
не возникает, поскольку функции Show и ShowLine автоматически преобразуют все строковые параметры
типа string в кодировку UTF-8 при выводе в раздел отладки (при этом предполагается, что
однобайтные строки содержат только символы ASCII и, возможно, русские буквы в ANSI-кодировке 1251).
|