Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Размещение структурных переменных в памятиСодержание книги
Похожие статьи вашей тематики
Поиск на нашем сайте
При анализе размеров структурных переменных иногда число байт, выделенных компилятором под структурную переменную, оказывается больше, чем сумма байт ее полей. Это связано с тем, что компилятор выделяет участок ОП для структурных переменных с учетом выравнивания границ, добавляя между полями пустые байты по следующим правилам: – структурные переменные, являющиеся элементами массива, начинаются на границе слова, т.е. с четного адреса; – любое поле структурной переменной начинается на границе слова, т.е. с четного адреса и имеет четное смещение по отношению к началу переменной; – при необходимости в конец переменной добавляется пустой байт, чтобы общее число байт было четное.
Объединения Объединение – поименованная совокупность данных разных типов, размещаемых с учетом выравнивания в одной и той же области памяти, размер которой достаточен для хранения наибольшего элемента. Объединенный тип данных декларируется подобно структурному типу: union ID_объединения { описание полей }; Пример описания объединенного типа: union word { int nom; char str[20]; }; Пример объявления объектов объединенного типа: union word *p_w, mas_w[100]; Объединения применяют для экономии памяти в случае, когда объединяемые элементы логически существуют в разные моменты времени либо требуется разнотипная интерпретация поля данных. Практически все вышесказанное для структур имеет место и для объединений. Декларация данных типа union, создание переменных этого типа и обращение к полям объединений производится аналогично структурам. Пример использования переменных типа union: ... typedef union q { int a; double b; char s[5]; } W; void main(void) { W s, *p = &s; s.a = 4; printf(“\n Integer a = %d, Sizeof(s.a) = %d”, s.a, sizeof(s.a)); p –> b = 1.5; printf(“\n Double b = %lf, Sizeof(s.b) = %d”, s.b, sizeof(s.b)); strcpy(p–>s, “Minsk”); printf(“\n String a = %s, Sizeof(s.s) = %d”, s.s, sizeof(s.s)); printf(“\n Sizeof(s) = %d”, sizeof(s)); } Результат работы программы: Integer a = 4, Sizeof(s.a) = 2 Double b = 1.500000, Sizeof(s.b) = 4 String a = Minsk, Sizeof(s.s) = 5 Sizeof(s) = 5
Перечисления Перечисления – средство создания типа данных посредством задания ограниченного множества значений. Определение перечисляемого типа данных имеет вид enum ID_перечисляемого_типа { список_значений }; Значения данных перечисляемого типа указываются идентификаторами, например: enum marks { zero, one, two, three, four, five }; Компилятор последовательно присваивает идентификаторам списка значений целочисленные величины 0, 1, 2,.... При необходимости можно явно задать значение идентификатора, тогда очередные элементы списка будут получать последующие возрастающие значения. Например: enum level { low=100, medium=500, high=1000, limit }; Константа limit по умолчанию получит значение, равное 1001. Примеры объявления переменных перечисляемого типа: enum marks Est; enum level state; Переменная типа marks может принимать только значения из множества {zero, one, two, three, four, five}. Основные операции с данными перечисляемого типа: – присваивание переменных и констант одного типа; – сравнение для выявления равенства либо неравенства. Практическое назначение перечисления – определение множества различающихся символических констант целого типа. Пример использования переменных перечисляемого типа: ... typedef enum { mo=1, tu, we, th, fr, sa, su } days; void main(void) { days w_day; // Переменная перечисляемого типа int t_day, end, start; // Текущий день недели, начало и конец недели соответственно puts(“ Введите день недели (от 1 до 7): ”); scanf(“%d”, &t_day); w_day = su; start = mo; end = w_day – t_day; printf(“\n Понедельник – %d день недели, \ сейчас %d – й день и \n\ до конца недели %d дн. ”, start, t_day, end); } Результат работы программы: Введите день недели (от 1 до 7): 5 Понедельник – 1 день недели, сейчас 5-й день и до конца недели 2 дн.
Битовые поля Битовые поля – это особый вид полей структуры. Они используются для плотной упаковки данных, например, флажков типа «да / нет». Минимальная адресуемая ячейка памяти – 1 байт, а для хранения флажка достаточно одного бита. При описании битового поля после имени через двоеточие указывается длина поля в битах (целая положительная константа), не превышающая разрядности поля типа int: struct fields { unsigned int flag: 1; unsigned int mask: 10; unsigned int code: 5; }; Битовые поля могут быть любого целого типа. Имя поля может отсутствовать, такие поля служат для выравнивания на аппаратную границу. Доступ к полю осуществляется обычным способом – по имени. Адрес поля получить нельзя, однако в остальном битовые поля можно использовать точно так же, как обычные поля структуры. Следует учитывать, что операции с отдельными битами реализуются гораздо менее эффективно, чем с байтами и словами, так как компилятор должен генерировать специальные коды и экономия памяти под переменные оборачивается увеличением объема кода программы. Размещение битовых полей в памяти зависит от компилятора и аппаратуры. В основном битовые поля размещаются последовательно в поле типа int, а при нехватке места для очередного битового поля происходит переход на следующее поле типа int. Возможно объявление безымянных битовых полей, а длина поля 0 означает необходимость перехода на очередное поле int: struct areas { unsigned f1: 1; : 2; – безымянное поле длиной 2 бита; unsigned f2: 5; : 0 – признак перехода на следующее поле int; unsigned f3:5; double data; char buffs[100]; – структура может содержать элементы любых типов данных; }; Битовые поля могут использоваться в выражениях как целые числа соответствующей длины поля разрядности в двоичной системе исчисления. Единственное отличие этих полей от обычных объектов – запрет операции определения адреса (&). Следует учитывать, что использование битовых полей снижает быстродействие программы по сравнению с представлением данных в полных полях из-за необходимости выделения битового поля.
ГЛАВА 14. Файлы в языке Си
Файл – это набор данных, размещенный на внешнем носителе и рассматриваемый в процессе обработки как единое целое. В файлах размещаются данные, предназначенные для длительного хранения. Различают два вида файлов: текстовые и бинарные. Текстовые файлы представляют собой последовательность ASCII символов и могут быть просмотрены и отредактированы с помощью любого текстового редактора. Эта последовательность символов разбивается на строки символов, при этом каждая строка заканчивается двумя кодами «перевод строки», «возврат каретки»: 13 и 10 (0xD и 0xA). Бинарные (двоичные) файлы представляют собой последовательность данных, структура которых определяется программно. В языке Си не предусмотрены никакие заранее определенные структуры файлов. Все файлы рассматриваются компилятором как последовательность (поток байт) информации. Для файлов определен маркер или указатель чтения-записи данных, который определяет текущую позицию доступа к файлу. Напомним, что с началом работы любой программы автоматически открываются стандартные потоки stdin и stdout. В языке Си имеется большой набор функций для работы с файлами, большинство которых находятся в библиотеках stdio.h и io.h. При этом потоки данных, с которыми работают функции ввода-вывода данных по умолчанию, буферизированы. Это означает, что при открытии потока с ним автоматически связывается определенный участок ОП, который и называется буфером. Все операции чтения-записи ведутся через этот буфер. Его размер фиксирован специальной константой BUFSIZ, которая определена в файле stdio.h как 512 (хотя программно ее можно изменять).
Открытие файла Каждому файлу в программе присваивается внутреннее логическое имя, используемое в дальнейшем при обращении к нему. Логическое имя (идентификатор файла) – это указатель на файл, т.е. на область памяти, где содержится вся необходимая информация о файле. Формат объявления указателя на файл следующий: FILE * ID_указателя_на_файл; FILE – идентификатор структурного типа, описанный в стандартной библиотеке stdio.h и содержащий следующую информацию: struct FILE {
};
Прежде чем начать работать с файлом, т.е. получить возможность чтения или записи информации в файл, его нужно открыть для доступа. Для этого обычно используется функция FILE* fopen (char * ID_файла, char *режим); Данная функция берет внешнее представление – физическое имя файла на носителе (дискета, винчестер) и ставит ему в соответствие логическое имя (программное имя – указатель файла). Физическое имя, т.е. ID файла и путь к нему задается первым параметром – строкой, например, “ a:Mas_dat.dat ” – файл с именем Mas_dat и расширением dat, находящийся на дискете, “ d:\\work\\Sved.txt ” – файл с именем Sved и расширением txt, находящийся на винчестере в каталоге work. Внимание. Обратный слеш «\», как специальный символ в строке записывается дважды. При успешном открытии функция fopen возвращает указатель на файл (в дальнейшем – указатель файла). При ошибке возвращается NULL. Данная ситуация обычно возникает, когда неверно указывается путь к открываемому файлу, например, если указать путь, запрещенный для записи. Второй параметр – строка, в которой задается режим доступа к файлу. Возможные значения данного параметра следующие: w – файл открывается для записи (write); если файла с заданным именем нет, то он будет создан; если же такой файл уже существует, то перед открытием прежняя информация уничтожается; r – файл открывается для чтения (read); если такого файла нет, то возникает ошибка; a – файл открывается для добавления (append) новой информации в конец; r + (w +) – файл открывается для редактирования данных, т.е. возможны и запись, и чтение информации; a + – то же, что и для a, только запись можно выполнять в любое место файла (доступно и чтение файла); t – файл открывается в текстовом режиме; b – файл открывается в двоичном режиме; Последние два режима используются совместно с рассмотренными выше. Возможны следующие комбинации режимов доступа: “ w + b ”, “ wb +”, “ rw +”, “ w + t ”, “ rt +”, а также некоторые другие комбинации. По умолчанию файл открывается в текстовом режиме. Текстовый режим отличается от двоичного тем, что при открытии файла как текстового пара символов «перевод строки» и «возврат каретки» заменяется на один символ «перевод строки» для всех функций записи данных в файл, а для всех функций вывода – наоборот – символ «перевод строки» заменяется на два символа – «перевод строки» и «возврат каретки». Пример открытия файла: FILE *f; – объявляется указатель на файл f; f = fopen (" d:\\work\\Dat_sp.dat ", "w"); – открывается для записи файл с логическим именем f, имеющий физическое имя Dat_sp.dat и находящийся на диске d в каталоге work, или более кратко: FILE *f = fopen ("d:\\work\\Dat_sp.dat", "w");
Закрытие файла После работы с файлом доступ к нему необходимо закрыть с помощью функции int fclose (указатель файла); Например, для предыдущего примера файл закрывается так: fclose (f); Для закрытия нескольких файлов введена функция: void fcloseall (void); Если требуется изменить режим доступа к открытому в настоящий момент файлу, то его необходимо сначала закрыть, а затем вновь открыть с другими правами доступа. Для этого используется функция FILE* freopen (char *ID_файла, char *режим, FILE *указатель_файла); которая сначала закрывает файл, заданный в третьем параметре (указатель файла), как это выполняет функция fclose, а затем выполняет действия, аналогичные функции fopen, используя указанные первый и второй параметры (открывает файл с ID_файла и правами доступа режим). В языке Си имеется возможность работы с временными файлами, которые нужны только в процессе работы программы и должны быть удалены после выполнения некоторых вычислений. В этом случае используется функция FILE* tmpfile (void); которая создает на диске временный файл с правами доступа w + b. После завершения работы программы или закрытия этого (временного) файла он автоматически удаляется.
Запись-чтение информации Все действия по чтению-записи данных в файл можно разделить на три группы: – операции посимвольного ввода-вывода; – операции построчного ввода-вывода; – операции ввода-вывода по блокам. Рассмотрим основные функции для записи-чтения данных из файлов. Для работы с текстовыми файлами в библиотеке языка Си содержится достаточно много функций, самыми распространенными из которых являются функции fprintf, fscanf, fgets, fputs. Формат параметров этих функций практически такой же, как и формат рассмотренных ранее (см. разд. 5.3, 5.4) функций printf, scanf, gets и puts. Так же практически совпадают и действия этих функций. Отличие состоит в том, что printf и другие функции работают по умолчанию с экраном монитора и клавиатурой, а функции fprintf и другие – с файлом, указатель которого является одним из параметров этих функций. Рассмотрим общий пример создания текстового файла: #include<stdio.h> void main(void) { FILE *f1; int a=2, b=3; if(! (f1 = fopen(“d:\\work\\f_rez.txt”,”w+t”))) { // f 1 = NULL puts(“Open File Error!”); return; // exit (1); } fprintf(f1,”\t Файл результатов \n”); fprintf(f1,” %d плюс %d = %d\n”, a, b, a+b); fclose(f1); } Просмотрев содержимое файла любым текстовым редактором, можно убедиться, что данные в нем располагаются точно так, как на экране, если воспользоваться функцией printf с такими же списками параметров. Создание текстовых результирующих файлов обычно необходимо для оформления отчетов, различных документов, а также других текстовых материалов. Бинарные (двоичные) файлы обычно используются для организации баз данных, состоящих, как правило, из объектов структурного типа. При чтении-записи бинарных файлов удобнее всего пользоваться функциями fread и fwrite, которые выполняют ввод-вывод данных блоками. Такой способ обмена данными требует меньше времени. Функция unsigned fread (void * p, unsigned size, unsigned n, FILE * f); выполняет считывание из файла f n блоков размером size байт каждый в область памяти, адрес которой p. В случае успеха функция возвращает количество считанных блоков. При возникновении ошибки или по достижении признака окончания файла – значение EOF (End Of File – признак окончания файла). Обратное действие выполняет функция: unsigned fwrite (void * p, unsigned size, unsigned n, FILE * f); при вызове которой в файл f будет записано n блоков размером size байт каждый из области памяти, начиная с адреса p.
Позиционирование в файле Каждый открытый файл, как уже отмечалось, имеет скрытый указатель на текущую позицию в нем. При открытии файла этот указатель устанавливается на начало данных, и все операции в файле будут производиться с данными, начинающимися в этой позиции. При каждом выполнении функции чтения или записи указатель смещается на количество прочитанных или записанных байт, т.е. устанавливается после прочитанного или записанного блока данных в файле – это последовательный доступ к данным. В языке Си/С++ можно установить указатель на некоторую заданную позицию в файле. Для этого используют стандартную функцию fseek, которая позволяет выполнить чтение или запись данных в произвольном порядке. Декларация функции позиционирования следующая: int fseek (FILE * f, long size, int code); Значение параметра size задает количество байт, на которое необходимо сместить указатель в файле f, в направлении параметра code, который может принимать следующие значения:
Таким образом, смещение может быть как положительным, так и отрицательным, но нельзя выходить за пределы файла. В случае успеха функция возвращает нулевое значение, а в случае ошибки (например, попытка выхода за пределы файла) – единицу. Доступ к файлу с использованием функции позиционирования (fseek) называют произвольным доступом. Иногда нужно определить текущее положение в файле. Для этого используют функцию со следующей декларацией: long ftell (FILE * f); которая возвращает значение указателя на текущую позицию в файле или –1 в случае ошибки.
|
|||||||||||||||||||||||||||||||
Последнее изменение этой страницы: 2016-04-19; просмотров: 756; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.119.28.173 (0.011 с.) |