Директивы условий компиляции#if, #else, #elif и #endif
⇐ ПредыдущаяСтр 3 из 3 Возможно, самыми распространенными директивами условной компиляции являются #if, #else, #elif и #endif. Они дают возможность в зависимости от значения константного выражения включать или исключать те или иные части кода. Стандартные заранее определенные макросы Стандартные заранее определенные макросы могут применяться вне зависимости от используемой платформы или операционной системы на которой функционирует. Их имена начинаются и заканчиваются двойным символом подчеркивания '__FILE__' '__LINE__' '__DATE__' '__TIME__'
Компилятор распознает предопределенных макросов ANSI c и C++ реализация Майкрософт предоставляет несколько более. Эти макросы не принимает аргументы и не могут быть переопределены 34)Тэги Используется для объявления перечислений, структур и объединений. Тег не является самостоятельным именем типа (в С++ может быть) Тег структуры определяется следующим образом: struct тег { список описаний; }; где тег является идентификатором. В приведенном ниже примере идентификатор student описывается как тег структуры: struct student { char name[25]; int id, age; char prp; }; Тег структуры используется для последующего объявления структур данного вида в форме: struct тег список-идентификаторов; Пример: struct studeut st1,st2; Использование тегов структуры необходимо для описания рекурсивных структур. Перечислимые типы Переменная, которая может принимать значение из некоторого списка значений, называется переменной перечислимого типа или перечислением. Объявление перечисления начинается с ключевого слова enum и имеет два формата представления. Формат 1. enum [имя-тега-перечисления] {список-перечисления} описатель[,описатель...]; Формат 2. enum имя-тега-перечисления описатель [,описатель..];
Объявление перечисления задает тип переменной перечисления и определяет список именованных констант, называемый списком-перечисления. Значением каждого имени списка является некоторое целое число. Переменная типа перечисления может принимать значения одной из именованных констант списка. Именованные константы списка имеют тип int. Таким образом, память соответствующая переменной перечисления, это память необходимая для размещения значения типа int. Структура - это множество, состоящее из одного или более объектов, возможно имеющих различные типы, объединенных под одним именем. Тип данных struct - один из основных строительных блоков данных в языке. Он предоставляет удобный способ объединения различных элементов, связанных между собой. Описание структуры начинается со служебного слова struct, за которым может следовать необязательное имя, называемое именем типа структуры (здесь это date), которое еще называется именем шаблона. Такое имя типа структуры может использоваться в дальнейшем как сокращенная запись подробного описания однотипных структур. За именем типа структуры идет заключенный в фигурные скобки список элементов структуры, с описанием типа каждого элемента (элементом структуры может быть переменная, массив, структура или объединение). Элементы структуры отделяются друг от друга точкой с запятой. Например:
Динамические структуры данных, основанные на структурах-двунаправленные списки Представление списков в программе Основные операции над двунаправленными списками. а этот вопрос лучше перечислить по пунктам: 1. присваивание полю структуры значение того же типа 2. можно получить адрес структуры. Не забываем операцию взятия адреса (&) 3. можно обращаться к любому полю структуры 4. для того, что бы определить размер структуры можно использовать
Основные операции над двунаправленными списками Ну, перед тем, как проводить какие-то операции с компонентами, их необходимо добавить в список, чем мы сейчас и займемся. Прежде всего, нам необходимо создать новый компонент и заполнить его информационную часть. Так как мы будем помещать его в конец списка, то ссылочная часть узла будет иметь значение NULL. Теперь давайте поймем, что должно происходить со ссылками head и tail при этой операции. Здесь рассматриваются 2 случая - наш список пуст или в нем есть хотя бы один компонент. Если пуст, то и head и tail будут указывать на только что созданный компонент. Если же узлы в списке присутствуют, очевидно, что сначала нужно последний узел связать с добавляемым (для этого ссылочной части компонента, на который указывает tail, присвоить адрес того, который хотим добавить), а затем "передвинуть" tail. Вот как просто все это выглядит на С++: // Включение в список нового компонента void comp_in(dyn_list &l, char* n, char* v) { comp* c = new comp(); strcpy_s(c->name, 20, n); strcpy_s(c->value, 10, v); c->next = NULL; if (chk_empty(l)) l.head = c; else l.tail->next = c; l.tail = c; } Теперь займемся поиском компонента. Искать будет по имени переменной, по желанию вы можете искать и по значению. В качестве аргументов, функции поиска передаем сам список и искомый текст. Возвращать наша функция будет адрес найденного узла или NULL, если ничего не найдено. Искать начнем с компонента, на который указывает head и, двигаясь вперед, сравнивать имя текущей переменной с искомым. В функции поиска мы можем не боясь, передвигать ссылку head, так как передаем ее не по ссылке. // Поиск компонента в списке по имени comp* search(dyn_list l, char *n) { while (l.head!= NULL) { if (!strcmp(l.head->name,n)) return l.head; l.head = l.head->next; } return l.head; } А сейчас удалим компонент. В качестве аргумента, передаем по ссылке список, а также ссылку на компонент, который собираемся удалить. В самой же функции рассматриваем 2 случая. Первый случай простой: если компонент является первым (то есть на него указывает head), то достаточно лишь переместить ссылку на первый элемент вперед. В противном случае, нам понадобится рабочая переменная-узел, которую мы будем использовать для движения по списку. Двигаться будем до тех пор, пока следующий за текущим узел не будет
тем, который мы собираемся удалить. Ну а после этого, "перепрыгиваем" удаляемый компонент, присваивая ссылочной части предшествующего удаляемому компоненту адрес следующего за удаляемым. Все эти слова умещаются буквально в несколько строк исходного кода: // Удаление компонента из списка void comp_del(dyn_list &l, comp* c) { if (c == l.head) { l.head = c->next; return; } comp* r = new comp(); r = l.head; while (r->next!= c) r = r->next; r->next = c->next; delete c; } Последняя и самая простая операция - это изменение значения информационной части узла. Менять будем поле value. В качестве параметров, по ссылке передадим адрес компонента, а также новое значение изменяемого поля. Ну и в одну строчку все изменим. Вот как просто это выглядит: // Изменение значения компонента void comp_edit(comp &c, char* v) { strcpy_s(c.value, 10, v); } Инициализация структур Полями структур могут быть, в частности, поля битов. Хотя правила языка не имеют ограничений на характер этих полей, кроме требования, чтобы они помещались в объеме машинного слова, в типичных применениях поля битов служат для хранения целых данных (чаще типа unsigned). Описание поля битов состоит из описания типа поля, его имени и указанного после двоеточия размера поля в битах, например: unsigned status: 6;. Если имя поля опущено, то создается скрытое поле. Если размер поля битов представлен числом 0, то следующее поле битов начнется с границы машинного слова. Структура данных объединение подобна структуре, однако в каждый момент времени может использоваться (является активным) только один из его компонентов. Шаблон объединения может задаваться записью вида: Объединения минимизации используемого объема памяти, если в каждый момент времени только один объект из многих является активным; интерпретации основного представления объекта одного типа, как если бы этому объекту был присвоен другой тип. Таким образом, после задания рассмотренной структуры данных в программе будет находиться переменная, которая на законных основаниях может хранить "в себе" значения нескольких типов.
Инициализация . Объединение - это еще один структурированный тип данных. Объединение похоже на структуру и в своем описании отличается от структуры тем, что вместо ключевого слова struct используется слово union. union имя_типа {определения_элементов}; Объединение отличается от структуры способом организации во внутренней памяти. Все элементы объединения в памяти начинаются с одного байта. Пусть в программе описана структура: struct S { int i; char ch; long int L; }; Расположение ее элементов в памяти будет следующим: байт байт | байт | байт байт байт байт i | ch | L
Элементы структуры занимают последовательные ячейки памяти с размером, соответствующим типу. Общий размер структуры равен сумме длин полей. А теперь рассмотрим объединение со следующим описанием: union S { int i; char ch; long int L; }; Величина с таким типом в памяти будет расположена следующим образом: байт | байт | байт | байт | ch | i | L |
Поля объединения накладываются друг на друга. Общий объем занимаемой памяти равен размеру самого большого поля. Изменение значения любого поля объединения меняет значения других полей. 38) Для осуществления операций с файлами предусмотрено три класса: ifstream, ofstream и fstream. Эти классы являются производными, соответственно, от классов istream, ostream и iostream. Поскольку эти последние классы, в свою очередь, являются производными от класса ios, классы файловых потоков наследуют все функциональные возможности своих родителей (перегруженные операции << и >> для встроенных типов, функции и флаги форматирования, манипуляторы и пр.). Для реализации файлового ввода-вывода нужно включить в программу заголовочный файл fstream.h. Существует небольшое отличие между использованием предопределенных и файловых потоков. Файловый поток должен быть связан с файлом прежде, чем его можно будет использовать. С другой стороны, предопределенные потоки могут использоваться сразу после запуска программы, даже в конструкторах статических классов, которые выполняются даже раньше вызова функции main(). Можно позиционировать файловый поток в произвольную позицию в файле, в то время как для предопределенных потоков это обычно не имеет смысла. Для создания файлового потока эти классы предусматривают следующие формы конструктора: создать поток, не связывая его с файлом: ifstream(); создать поток, открыть файл и связать поток с файлом: ifstream(const char *name, ios::openmode mode = ios::in); Чтобы открыть файл для ввода или вывода, можно использовать вторую форму нужного конструктора
fstream fs("FileName.dat"); или вначале создать поток с помощью первой формы конструктора, а затем открыть файл и связать поток с открытым файлом, вызвав функцию-член open(). Эта функция определена в каждом из классов потокового ввода-вывода и имеет следующие прототипы: void ifstream::open(const char *name, ios::openmode mode = ios::in); Здесь name - имя файла, mode - режим открытия файла. Параметр mode является перечислением и может принимать значения, указанные в табл. 8. Таблица 8 Режимы открытия и их назначение
Режимы открытия файла представляют собой битовые маски, поэтому можно задавать два или более режима, объединяя их побитовой операцией ИЛИ. В следующем фрагменте кода файл открывается для вывода с помощью функции open(): ofstream ofs; Обратим внимание, что по умолчанию режим открытия файла соответствует типу файлового потока. У потока ввода или вывода флаг режима всегда установлен неявно. Например, для потока вывода в режиме добавления файла можно вместо оператора ofstream ofs("FName.txt", ios::out | ios::app); Между режимами открытия файла ios::ate и ios::app имеется небольшая разница. Если файл открывается в режиме добавления, весь вывод в файл будет осуществляться в позицию, начинающуюся с текущего конца файла, безотносительно к операциям позиционирования в файле. В режиме открытия ios::ate (от английского "at end") можно изменить позицию вывода в файл и осуществлять запись, начиная с нее. Для потоков вывода режим открытия эквивалентен ios::out | ios::trunc, то есть можно опустить режим усечения файла. Однако для потоков ввода-вывода его нужно указывать явно. Файлы, которые открываются для вывода, создаются, если они еще не существуют. Если открытие файла завершилось неудачей, объект, соответствующий потоку, будет возвращать 0: if (!ofs){ cout << "Файл не открыт\n";} Проверить успешность открытия файла можно также с помощью функции-члена is_open(), имеющей следующий прототип: int is_open() const; Функция возвращает 1, если поток удалось связать с открытым файлом. Например, if (!ofs.is_open()){ cout << "Файл не открыт\n"; return; } Если при открытии файла не указан режим ios::binary, файл открывается в текстовом режиме и после того, как файл успешно открыт, для выполнения операций ввода-вывода можно использовать операторы извлечения и вставки в поток. Для проверки, достигнут ли конец файла, можно использовать функцию ios::eof(), имеющую прототип int eof(); Завершив операции ввода-вывода, необходимо закрыть файл, вызвав функцию-член close() с прототипом void close(): ofs.close(); Закрытие файла происходит автоматически при выходе потокового объекта из области существования, когда вызывается деструктор потока. 39) 40) long ftell (FILE *f); ftell – возвращает текущее значение указателя позиции в файл, отсчитанное в байтах от его начала. int fseek – возвращает 0, если удалось переместить указатель и не0, если ошибка. int fseek (FILE *f, long offset int origin); offset – смещение в байтах int origin – с какой позиции задавать смещение Константы: SEEK_SET с начала SEEK_CUR текущее положение SEEK_END с конца fseek (f, i * size of (struct Record), SEEK_SET);
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|