Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
шпора основы.docx
Скачиваний:
9
Добавлен:
09.02.2015
Размер:
49.22 Кб
Скачать

Int main()

{

struct emp prgmr, raise(struct emp, double);

...

printf("Old salary: %.2f\n", prgmr.salary);

prgmr = raise(prgmr, .12);

printf("New salary: %.2f\n", prgmr.salary);

}

struct emp raise(struct emp person, double increase)

{

person.salary *= (1+ increase);

return person;

}

Данная программа выполнялась бы более эффективно, если в функцию raise() передавался указатель на структуру. В этом случае при передаче управления в функцию передается лишь значение указателя, что делает доступными в функции элементы структуры. Этот вариант программы показан в прим. 2.

Пример 2

#include <stdio.h>

#include "emp.h" /* содержит шаблон структуры emp */

int main()

{

struct emp prgmr;

void raise(struct emp *, double);

...

printf("Old salary: %.2f\n", prgmr.salary);

raise(&prgmr, .12);

printf("New salary: %.2f\n", prgmr.salary);

}

void raise(struct emp *person, double increase)

{

person->salary *= (1+ increase);

}

  • Объединения. Сравнение объединения и структуры.

Объединение — объект, который в каждый момент времени содержит один из нескольких элементов различных типов.

Все компоненты объявления структур, такие как шаблоны, имена типа, имена элементов и т.д. применимы и при объявлении объединений. Единственное отличие состоит в том, что при объявлении объединения вместо ключевого слова struct используется union.

Примечание 1

Объединение не может иметь битовые поля.

Операции доступа к элементу структуры (операция . и операция ->) могут применяться и к объединениям. Допустимы массивы объединений и указатели на объединения. Объединения могут передаваться функции как параметры и возвращаться функцией.

В отличие от структуры, объединение может в любой момент времени содержать только один из своих элементов. Объединение позволяет использовать одну область памяти для хранения различных видов данных в разные моменты времени. Фактически, объединение — это структура, в которой все поля начинаются со смещением 0, таким образом, поля накладываются друг на друга.

  • Шаги компиляции Си.

На первом шаге программа "препроцессируется". Специальные директивы обрабатываются препроцессором. Результат этой обработки - расширенный исходный текст программы на языке Си.

На следующем шаге программа действительно компилируется и переводится на низкоуровневый язык ассемблера.

Затем ассемблер транслирует ассемблерную программу в объектный код. Хотя объектный код - это машинный код, он еще невыполним.

Исполняемый код строит программа - компоновщик, называемая в ОС UNIX редактором связей. Одна из задач редактора связей состоит в согласовании неразрешенных ссылок.

Неразрешенная ссылка - ссылка на объект, который в данной части программы неопределен. Редактор связей связывает объявления внешних переменных с соответствующими внешними определениями. Другим типом неразрешенной ссылки является вызов функции, не определенной в программе, например, вызов функции printf(). Редактор связей ищет объектный код функции в одной или более библиотеках и включает этот код в исполнимый модуль. Результатом работы редактора связей при отсутствии ошибок является исполнимая программа.

В системе ОС UNIX процесс компиляции может быть остановлен после любого шага путем использования соответствующего флага команды cc, который определяет режим работы команды. Создается файл с тем же именем, что и исходный файл, и окончанием .i, .s или .o, указывающем на тип файла. По умолчанию имя исполнимой программы - a.out.

  • Препроцессор Си. Поименованные константы. Макросы.

Препроцессор языка Си – это составная часть компилятора, реализующая первую стадию компиляции.

Препроцессор - это мощный инструмент, часто используемый для повышения удобочитаемости, надежности и переносимости программ.

Обработка препроцессором выполняется на первом этапе компиляции исходного текста программы.

Препроцессор читает исходный текст, отыскивая и обрабатывая директивы препроцессора, которые представляют собой строки текста, начинающиеся с символа #.

Пример 1

#include <stdio.h>

#define SIXE 100

Для переносимости программы следует указывать символ # в позиции 1, а непосредственно после него – управляющее слово (include, define , и т.п.), поскольку некоторые препроцессоры языка K&R Си не допускают, чтобы символы промежутков предшествовали символу # или следовали непосредственно после него.

Препроцессор позволяет определять константы и макросы, включать файлы, предоставляет возможности условной компиляции.

Поименованные константы определяются с помощью директивы препроцессора define:

#define идентификатор строка-шаблон

Поименованные константы используются для того, чтобы облегчить чтение и изменение программ.

До и после идентификатора в директиве define должен быть один или более пробелов. Строка-шаблон начинается с первого отличного от пробела символа и заканчивается символом перевода строки. Строку-шаблон можно продолжить более чем на одну строку, начиная новые строки символом \.

После определения поименованной константы препроцессор заменяет в исходном тексте программы идентификатор значением строки-шаблона. Внутри комментариев и строковых констант такая замена не производится.

Макрос — это короткая процедура, у которой могут быть аргументы.

Макрос определяется с помощью директивы препроцессора #define.

Определение макроса похоже на определение поименованной константы.

#define идентификатор(аргумент[,аргумент]...) строка-шаблон

В скобках непосредственно после идентификатора могут быть указаны имена аргументов. Между идентификатором и символом ( не должно быть символов промежутка. При расширении макроса препроцессор осуществляет вставку строк.

  • Файлы заголовков. Организация сложных программ.

Директива препроцессора include влечет вставку в текущую позицию текста программы на языке Си копии указанного файла.

#include <file.h>

#include "file.h"

Подобные файлы, называемые файлами заголовков или файлами вставок, обычно содержат директивы define для поименованных констант и макросов, объявления функций, внешних переменных и т.п., необходимые для нескольких исходных файлов. Преимущество подобного выделения в отдельный файл в том, что такие определения локализуются в общем месте. Несколько программ могут включать этот файл и быть уверенными в использовании одинаковой информации. Если необходимо изменение, его можно сделать в одном месте.

По соглашению, имена файлов-вставок имеют расширение .h , что означает файл заголовков (header), названных так потому, что директивы include обычно указываются в начале исходных файлов языка Си. Если имя файла заключено в угловые скобки < и >, препроцессор ищет файл в "стандартном месте". В операционных системах UNIX таким стандартным местом является каталог /usr/include. Если имя файла заключено в двойные кавычки ", используется стандартное соглашение операционной системы для доступа к файлу. В операционных системах UNIX может использоваться полное или относительное путевое имя.

Пример 1

#include "proj.h"

#include "/local/include/x33.h"

#include "../include/defs.h"

Файлы вставки могут быть вложены; файл заголовков может содержать директивы include.

В файле заголовков не должно быть ни определений функций (программ этих функций), ни определений внешних переменных, по которым выделяется память (например, int x). Иначе, если в нескольких файлах используется один и тот же файл заголовков, возникнут неприятности. При связывании этих файлов редактор связей может сообщить о "многократном определении идентификаторов".

В файле заголовков могут содержаться и другие директивы препроцессора и языка Си, например, операторы typedef, шаблоны структур и объединений (struct, union) и операторы enum.

  • Условная компиляция.

Условная компиляция — это средство препроцессора, которое в зависимости от условия включает в программу операторы языка Си или препроцессора.

Условная компиляция позволяет строить гибкие программы на языке Си. Это средство особенно часто используется при разработке программ, которые должны переноситься на различные процессоры, в различные операционные системы и в прочие операционные среды.

Условная компиляция реализуется с помощью следующих директив препроцессора:

#if

#else

#elif (аналогично else if)

#endif

#ifdef

#ifndef

В основном, условная компиляция выполняется следующим образом:

если это-и-это истинно

вставить указанные здесь операторы в исполнимую программу

Можно задать и ветвь иначе.

Директивы #if используются для вставки строк в файл, в случае, если истинно некоторое константное выражение.

Директивы #ifdef используются для вставки строк, если определена указанная поименованная константа.

Для вставки строк при условии, что константа не имеет определения, вместо директивы #ifdef можно использовать директиву #ifndef.

  • Буферизованный ввод-вывод.

Буферизация - способ организации ввода-вывода в программе, позволяющий минимизировать число обращений к устройству.

При чтении из дискового файла, блок данных копируется с диска в пользовательский буфер. Многими операционными системами используется также промежуточный "системный буфер". Этот блок данных, называемый также физическим блоком или блоком ввода-вывода, имеет объем, заданный поименованной константой BUFSIZ, определенной в файле заголовков stdio.h. Операции чтения из файла фактически читают данные из этого буфера. При исчерпании буфера вновь выполняется чтение с диска, и буфер пополняется. Обращение к диску лишь при необходимости обеспечивает существенную экономию времени. Программисты могут читать из файла множеством способов (посимвольно, построчно и т.д.) и не задумываться о минимизации количества обращений к диску. Стандартный пакет ввода-вывода гарантирует решение этой проблемы.

  • Файл. Открытие и закрытие файла.

Структура FILE — это структура, в которой хранится информация о том, как открыт файл (например, для чтения), и где позиция следующего чтения или записи. Структура FILE инициализируется вызовом функции fopen(). Она используется операционной системой и доступна различным функциям для чтения-записи. Программисту не нужно обращаться прямо к полям этой структуры и даже знать, что это за поля. Программист должен лишь объявить указатель на FILE перед открытием файла. Этот указатель получает значение во время открытия файла вызовом функции fopen() и должен впоследствии передаваться как параметр другим функциям, работающим с данным файлом. Программисту никогда нельзя изменять значение этого указателя. После закрытия файла соответствующая ему переменная файлового указателя на FILE может использоваться повторно.

Функция fopen() — функция открытия файла.

FILE *fopen(const char *имя_файла, const char *тип)

Первым аргументом функции fopen() является адрес строки, содержащей путевое имя файла. Второй аргумент—это адрес строки, определяющей тип работы с открываемым файлом.

Заданный именем файл открывается в соответствии с указанным типом. Тип может принимать следующие значения:

"r" — текстовый файл открывается для чтения (read);

"w"- текстовый файл создается для записи; старое содержимое, если оно было, выбрасывается (write);

"a" — текстовый файл открывается или создается для записи в конец файла (add);

"r+" — текстовый файл открывается для исправления, т.е. для чтения и записи;

"w+"- текстовый файл создается для исправления, старое содержимое, если оно было, выбрасывается;

"a+" — текстовый файл открывается или создается для исправления уже существующей информации и добавления новой в конец файла.

Функция fopen() возвращает указатель на структуру FILE, который затем присваивается переменной. Этот указатель называют внутренним. После открытия файла к нему обращаются с использованием указателя на этот файл, имя файла больше не потребуется..

Функция fclose() - стандартная функция ввода-вывода языка Си, с помощью которой осуществляется закрытие файла.