Функции и файлы


Работа с файлами

Для удобства обращения информация в запоминающих устройствах хранится в виде файлов.

Файл – именованная область внешней памяти, выделенная для хранения массива данных. Данные, содержащиеся в файлах, имеют самый разнообразный характер: программы на алгоритмическом или машинном языке; исходные данные для работы программ или результаты выполнения программ; произвольные тексты; графические изображения и т. п.

Каталог ( папка , директория ) – именованная совокупность байтов на носителе информации, содержащая название подкаталогов и файлов, используется в файловой системе для упрощения организации файлов.

Файловой системой называется функциональная часть операционной системы, обеспечивающая выполнение операций над файлами. Примерами файловых систем являются FAT (FAT – File Allocation Table, таблица размещения файлов), NTFS, UDF (используется на компакт-дисках).

Существуют три основные версии FAT: FAT12, FAT16 и FAT32. Они отличаются разрядностью записей в дисковой структуре, т.е. количеством бит, отведённых для хранения номера кластера. FAT12 применяется в основном для дискет (до 4 кбайт), FAT16 – для дисков малого объёма, FAT32 – для FLASH-накопителей большой емкости (до 32 Гбайт).

Рассмотрим структуру файловой системы на примере FAT32.

Файловая структура FAT32

Устройства внешней памяти в системе FAT32 имеют не байтовую, а блочную адресацию. Запись информации в устройство внешней памяти осуществляется блоками или секторами.

Сектор – минимальная адресуемая единица хранения информации на внешних запоминающих устройствах. Как правило, размер сектора фиксирован и составляет 512 байт. Для увеличения адресного пространства устройств внешней памяти сектора объединяют в группы, называемые кластерами.

Кластер – объединение нескольких секторов, которое может рассматриваться как самостоятельная единица, обладающая определёнными свойствами. Основным свойством кластера является его размер, измеряемый в количестве секторов или количестве байт.

Файловая система FAT32 имеет следующую структуру.

Нумерация кластеров, используемых для записи файлов, ведется с 2. Как правило, кластер №2 используется корневым каталогом, а начиная с кластера №3 хранится массив данных. Сектора, используемые для хранения информации, представленной выше корневого каталога, в кластеры не объединяются.
Минимальный размер файла, занимаемый на диске, соответствует 1 кластеру.

Загрузочный сектор начинается следующей информацией:

  • EB 58 90 – безусловный переход и сигнатура;
  • 4D 53 44 4F 53 35 2E 30 MSDOS5.0;
  • 00 02 – количество байт в секторе (обычно 512);
  • 1 байт – количество секторов в кластере;
  • 2 байта – количество резервных секторов.

Кроме того, загрузочный сектор содержит следующую важную информацию:

  • 0x10 (1 байт) – количество таблиц FAT (обычно 2);
  • 0x20 (4 байта) – количество секторов на диске;
  • 0x2С (4 байта) – номер кластера корневого каталога;
  • 0x47 (11 байт) – метка тома;
  • 0x1FE (2 байта) – сигнатура загрузочного сектора ( 55 AA ).

Сектор информации файловой системы содержит:

  • 0x00 (4 байта) – сигнатура ( 52 52 61 41 );
  • 0x1E4 (4 байта) – сигнатура ( 72 72 41 61 );
  • 0x1E8 (4 байта) – количество свободных кластеров, -1 если не известно;
  • 0x1EС (4 байта) – номер последнего записанного кластера;
  • 0x1FE (2 байта) – сигнатура ( 55 AA ).

Таблица FAT содержит информацию о состоянии каждого кластера на диске. Младшие 2 байт таблицы FAT хранят F8 FF FF 0F FF FF FF FF (что соответствует состоянию кластеров 0 и 1, физически отсутствующих). Далее состояние каждого кластера содержит номер кластера, в котором продолжается текущий файл или следующую информацию:

  • 00 00 00 00 – кластер свободен;
  • FF FF FF 0F – конец текущего файла.

Корневой каталог содержит набор 32-битных записей информации о каждом файле, содержащих следующую информацию:

  • 8 байт – имя файла;
  • 3 байта – расширение файла;

Корневой каталог содержит набор 32-битных записей информации о каждом файле, содержащих следующую информацию:

  • 8 байт – имя файла;
  • 3 байта – расширение файла;
  • 1 байт – атрибут файла:
  • 1 байт – зарезервирован;
  • 1 байт – время создания (миллисекунды) (число от 0 до 199);
  • 2 байта – время создания (с точностью до 2с):
  • 2 байта – дата создания:
  • 2 байта – дата последнего доступа;
  • 2 байта – старшие 2 байта начального кластера;
  • 2 байта – время последней модификации;
  • 2 байта – дата последней модификации;
  • 2 байта – младшие 2 байта начального кластера;
  • 4 байта – размер файла (в байтах).

В случае работы с длинными именами файлов (включая русские имена) кодировка имени файла производится в системе кодировки UTF-16. При этого для кодирования каждого символа отводится 2 байта. При этом имя файла записывается в виде следующей структуры:

  • 1 байт последовательности;
  • 10 байт содержат младшие 5 символов имени файла;
  • 1 байт атрибут;
  • 1 байт резервный;
  • 1 байт – контрольная сумма имени DOS;
  • 12 байт содержат младшие 3 символа имени файла;
  • 2 байта – номер первого кластера;
  • остальные символы длинного имени.

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

Работа с файлами в языке Си


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

Когда поток открывается для ввода-вывода, он связывается со стандартной структурой типа FILE , которая определена в stdio.h . Структура FILE содержит необходимую информацию о файле.

Открытие файла осуществляется с помощью функции fopen() , которая возвращает указатель на структуру типа FILE , который можно использовать для последующих операций с файлом.

  • «r» — открыть файл для чтения (файл должен существовать);
  • «w» — открыть пустой файл для записи; если файл существует, то его содержимое теряется;
  • «a» — открыть файл для записи в конец (для добавления); файл создается, если он не существует;
  • «r+» — открыть файл для чтения и записи (файл должен существовать);
  • «w+» — открыть пустой файл для чтения и записи; если файл существует, то его содержимое теряется;
  • «a+» — открыть файл для чтения и дополнения, если файл не существует, то он создаётся.

Возвращаемое значение — указатель на открытый поток. Если обнаружена ошибка, то возвращается значение NULL .

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

Возвращаемое значение: значение 0, если поток успешно закрыт; константа EOF , если произошла ошибка.

Чтение символа из файла:


Аргументом функции является указатель на поток типа FILE . Функция возвращает код считанного символа. Если достигнут конец файла или возникла ошибка, возвращается константа EOF .

Запись символа в файл:

Аргументами функции являются символ и указатель на поток типа FILE . Функция возвращает код считанного символа.

Функции fscanf() и fprintf() аналогичны функциям scanf() и printf() , но работают с файлами данных, и имеют первый аргумент — указатель на файл.

Функции fgets() и fputs() предназначены для ввода-вывода строк, они являются аналогами функций gets() и puts() для работы с файлами.


Символы читаются из потока до тех пор, пока не будет прочитан символ новой строки ‘\n’ , который включается в строку, или пока не наступит конец потока EOF или не будет прочитано максимальное символов. Результат помещается в указатель на строку и заканчивается нуль- символом ‘\0’ . Функция возвращает адрес строки.

Процедуры и функции для работы с файлами

Ниже описываются процедуры и функции, которые можно исполь­зовать с файлами любого вида. Специфика работы с типизированными, текстовыми и нетипизированными файлами рассматривается в следую­щих разделах.

Процедура CLOSE. Закрывает файл, однако связь файловой пере­менной с именем файла, установленная ранее процедурой ASSIGN, со­храняется. Формат обращения:

При создании нового или расширении старого файла процедура обеспечивает сохранение в файле всех новых записей и регистрацию файла в каталоге. Функции процедуры CLOSE выполняются автомати­чески по отношению ко всем открытым файлам при нормальном заверше­нии программы. Поскольку связь файла с файловой переменной сохра­няется, файл можно повторно открыть без дополнительного использова­ния процедуры ASSIGN.

Процедура RENAME. Переименовывает файл. Формат обращения:

Здесь строковое выражение, содержащее новое ими файла. Перед выполнением процедуры необходимо закрыть файл, если он ранее был открыт процедурами RESET, REWRITE или APPEND.

Процедура ERASE. Уничтожает файл. Формат обращения:

Перед выполнением процедуры необходимо закрыть файл, если он ранее был открыт процедурами RESET, REWRITE или APPEND.

Следующий фрагмент программы показывает, как можно использо­вать процедуры RENAME и CLOSE при работе с файлами. Предполо­жим, что требуется отредактировать файл, имя которого содержит пере­менная NAME. Перед редактированием необходимо убедиться, что нуж­ный файл имеется на диске, и переименовать его — заменить расширение этого файла на .ВАК (страховочная копия). Если файл с таким расшире­нием уже существует, его надо стереть.

If k=0 then k := length(name) + 1;

name_bak := copy(name,1,k-1) + bak;

If IOResult о 0 then halt;

<$I+>If IOResult = 0 then

Обратите внимание: проверка на существование BAK-файла в дан­ном примере необходима, так как обращение

вызовет ошибку в случае, если такой файл существует.

Процедура FLUSH. Очищает внутренний буфер файла и, таким образом, гарантирует сохранность всех последних изменений файла на диске. Формат обращения:

Любое обращение к файлу в Турбо Паскале осуществляется через некоторый буфер, что необходимо для согласования внутреннего пред­ставления файлового компонента (записи) с принятым в ДОС форматом хранения данных на диске. В ходе выполнения процедуры FLUSH все новые записи будут действительно записаны на диск. Процедура игнори­руется, если файл был инициирован для чтения процедурой RESET.

Функция EOF( ): BOOLEAN. Логическая функция, тести­рующая конец файла. Возвращает TRUE, если файловый указатель стоит в конце файла. При записи это означает, что очередной компонент будет добавлен в конец файла, при чтении — что файл исчерпан.

Процедура CHDIR. Изменение текущего каталога. Формат обраще­ния:

Здесь — строковое выражение, содержащее путь к устанав­ливаемому по умолчанию каталогу.


Процедура GETDIR. Позволяет определить имя текущего каталога (каталога по умолчанию). Формат обращения:

Здесь — выражение типа WORD , содержащее номер устройства: 0 — устройство по умолчанию, 1 — диск А, 2 — диск В и т.д.;

— переменная типа STRING, в которой возвращается путь к текущему каталогу на указанном диске.

Процедура MKDIR. Создает новый каталог на указанном диске. Формат обращения:

Здесь — выражение типа STRING, задающее путь к ката­логу. Последним именем в пути, т.е. именем вновь создаваемого каталога не может быть имя уже существующего каталога.

Процедура RMDIR. Удаляет каталог. Формат обращения:

Удаляемый каталог должен быть пустым, т.е. не содержать файлов или имен каталогов нижнего уровня.

Функция IORESULT : WORD. Возвращает условный признак по­следней операции ввода-вывода.

Если операция завершилась успешно, функция возвращает ноль. Коды ошибочных операций ввода-вывода представлены в прил.З. Следует помнить, что IORESULT становится доступной только при отключенном автоконтроле ошибок ввода-вывода. Директива компилятора <$I->отклю­чает, а директива <$I+>включает автоконтроль. Если автоконтроль от­ключен, а операция ввода-вывода привела к возникновению ошибки, устанавливается флаг ошибки и все последующие обращения к вводу-вы­воду блокируются, пока не будет вызвана функция IORESULT.

Ряд полезных файловых процедур и функций становится доступным при использовании библиотечного модуля DOS.TPU, входящего в стан­дартную библиотеку TURBO.TPL . Эти процедуры и функции указаны ниже. Доступ к ним возможен только после объявления USES DOS в начале программы (подробнее о работе с модулями см. гл.9).

Текстовые файлы

Текстовые файлы связываются с файловыми переменными, принад­лежащими стандартному типу TEXT. Текстовые файлы предназначены для хранения текстовой информации. Именно в такого типа файлах хра­нятся, например, исходные тексты программ. Компоненты (записи) тек­стового файла могут иметь переменную длину, что существенно влияет на характер работы с ними.

Текстовый файл трактуется в Турбо Паскале как совокупность строк переменной длины. Доступ к каждой строке возможен лишь последова­тельно, начиная с первой. При создании текстового файла в конце каждой записи (строки) ставится специальный признак EOLN (End Of LiNe -конец строки). а в конце всего файла — признак EOF (End Of File — конец файла). Эти признаки можно протестировать одноименными логически­ми функциями (см. ниже). При формировании текстовых файлов исполь­зуются следующие системные соглашения:

EOLN — последовательность кодов ASCII 13 (CR) и 10 (LF);

EOF — код 26 стандарта ASCII.

Для доступа к записям применяются процедуры READ, READLN, WRITE, WRITELN. Они отличаются возможностью обращения к ним с переменным числом фактических параметров, в качестве которых могут использоваться символы, строки и числа. Первым параметром в любой из перечисленных процедур может стоять файловая переменная. В этом случае осуществляется обращение к дисковому файлу или логическому устройству, связанному с переменной процедурой ASSIGN. Если файло­вая переменная не указана, происходит обращение к стандартным файлам Input и Output.

Процедура READ. Обеспечивает ввод символов, строки чисел. Фор­мат обращения:

Здесь — список ввода: последовательность из одной или более переменных типа CHAR, STRING, а также любого целого или вещественного типа.

При вводе переменных типа CHAR выполняется чтение одного сим­вола из файла и присваивание считанного значения переменной. Если перед выполнением чтения указатель файла достиг конца очередной стро­ки. то результатом чтения будет символ CR (ASCII код 13), а если достиг­нут конец файла, то — символ EOF (код 26). При вводе с клавиатуры символ CR вводится при нажатии на клавишу «Ввод», а символ EOF — при одновременном нажатии клавиш CTRL и Z .

При вводе переменных типа STRING количество считанных процедурой и помещенных в строку символов равно максимальной длине стро­ки, если только раньше не встретились символы CR или EOF. В этом случае сами символы CR и EOF в строку не помещаются. Если количество символов во входном потоке данных больше максимальной длины строки, «лишние» символы до конца строки отбрасываются, а новое обращение к READ возвращает пустую строку. Таким образом, процедура READ не в состоянии прочесть последовательность строк: первая строка будет прочи­тана нормально, а все последующие окажутся пустыми. Для ввода после­довательности строк нужно использовать процедуру READLN (см. ниже).

При вводе числовых переменных процедура READ вначале выделя­ет подстроку во входном потоке по следующему правилу: все ведущие пробелы, символы табуляции и маркеры конца строк EOLN пропускают­ся; после выделения первого значащего символа, наоборот, любой из пе­речисленных символов или символ EOF служат признаком конца под­строки. Выделенная таким образом подстрока затем рассматривается как символьное представление числовой константы соответствующего типа и преобразуется во внутреннее представление, а полученное значение присваивается переменной. Если в подстроке был нарушен требуемый формат представления численной константы, возникает ошибка ввода-вывода. Если при пропуске ведущих пробелов встретился символ EOF, перемен­ная получает значение 0. Отметим, что в Турбо Паскале не предусмотрен ввод шестнадцатиричных констант.

Процедура READ прекрасно приспособлена к вводу чисел. При об­ращении к ней за вводом очередного целого или вещественного числа процедура «перескакивает» маркеры конца строк, т.е. фактически весь файл рассматривается ею как одна длинная строка, содержащая текстовое представление чисел. В сочетании с проверкой конца файла функцией EOF процедура READ позволяет организовать простой ввод массивов данных, например, так:

m : array [1..N] of real;

while not EOF(f) and (I (см. процедуру READ), что приведет к пропуску всех символов текущей строки вплоть до EOLN.

Процедура WRITE. Обеспечивает вывод информации в текстовый файл или передачу ее на логическое устройство. Формат обращения:

WRITE( , ) или WRITE( );

Здесь — список вывода: последовательность из одного или более выражений типа CHAR, STRING, BOOLEAN, а также любого целого или вещественного типа.

Файловая переменная , если она указана, должна быть пред­варительно описана как переменная типа TEXT и связана с именем файла или логическим устройством процедурой ASSIGN. Если файловая пере­менная отсутствует, подразумевается вывод в стандартный файл OUTPUT, который обычно связан с экраном ПК.

Любой элемент списка вывода может иметь форму

OutExpr [ : MInWidth [ : DecPlaces ] ]

Здесь OUTEXPR — выводимое выражение;

MINWIDTH, DECPLACES — выражения типа WORD (квадратные скобки означают возможность отсутствия заключенных в них парамет­ров).

Подпараметр MINWIDTH , если он присутствует, указывает мини­мальную ширину поля, в которое будет записываться символьное пред­ставление значения OUTEXPR. Если символьное представление имеет меньшую длину, чем MINWIDTH, оно будет дополнено слева пробелами, если — большую длину, то подпараметр MINWIDTH итерируется и вы­водится необходимое число символов.

Подпараметр DECPLACES задает количество десятичных знаков в дробной части вещественного числа. Он может использоваться только совместно с MINWIDTH и только по отношению к выводимому выраже­нию одного из вещественных типов.

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

Символы и строки передаются выводному файлу без изменений, но снабжаются ведущими пробелами, если задана ширина поля вывода и эта ширина больше требуемой для вывода.


При выводе логических выражений в зависимости от их значения выводятся строки TRUE или FALSE. (Ввод логических констант проце­дурами READ или READLN не предусмотрен).

При выводе на экран в случае, когда длина выводимой последова­тельности символов превышает ширину экрана или созданного на нем окна, «лишние» символы переносятся на следующую экранную строку. При заполнении экрана или окна его содержимое сдвигается вверх на одну строку.

Процедура WRITELN. Эта процедура полностью идентична проце­дуре WRITE за исключением того, что выводимая строка символов завер­шается кодами CR и LF. При вызове WRITELN можно опускать параметр : в этом случае в файл передается маркер EOLN, что при выводе на экран приведет к переводу курсора в начало следующей строки.

Логическая функция EOLN. Возвращает TRUE, если во входном текстовом файле достигнут маркер конца строки. Формат обращения:

Если параметр опущен, функция проверяет стандартный файл INPUT.

Существует некоторое отличие в работе функций EOLN и EOF с дисковыми файлами и логическими устройствами. Дело в том, что для логического устройства невозможно предвидеть, каким будет результат чтения очередного символа. Поэтому при работе с логическим устройст­вом функция EOLN возвращает TRUE, если последним считанным с устройства символом был EOLN или EOF, в то время как при чтении с диска TRUE возвращается в случае, если следующим считываемым сим­волом будет EOLN или EOF. Аналогичное различие наблюдается и в функции EOF: для логического устройства TRUE возвращается в случае, если последним символом был EOF, а при чтении с диска — если следую­щим считываемым символом будет EOF. Иными словами, функции тес­тируют соответствующие признаки для логического устройства после оче­редного чтения, а для файла — перед чтением.

Логическая функция SEEKEOLN. Пропускает все пробелы и знаки табуляции до маркера конца строки EOLN или до первого значащего символа и возвращает TRUE, если маркер обнаружен. Формат обраще­ния;

Илон Маск рекомендует:  Что такое код movetext

Если параметр опущен, функция проверяет стандартный файл INPUT,

Логическая функция SEEKEOF. Пропускает все пробелы, знаки табуляции и маркеры конца строки EOLN до маркера конца файла или до первого значащего символа и возвращает TRUE, если маркер обнару­жен. Формат обращения:

Если параметр опущен, функция проверяет стандартный файл INPUT.

В следующем примере, иллюстрирующем работу с текстовым фай­лом, подсчитывается общее количество символов в файле и результат делится на 40000 — таким способом можно оценить объем рукописи в так называемых учетно-издательских листах:

Файл-функции

Читайте также:

  1. I Листинг 3.3. Файл-функция, работающая с массивом значений
  2. Листинг 3.5. Функция перевода секунд в часы, минуты и секунды
  3. Типы М-файлов

Рассмотренные выше файл-программы являются последовательностью команд MatLab, они не имеют входных и выходных аргументов. Для использования численных методов и при программировании собственных приложений в MatLab необходимо уметь составлять файл-функции, которые производят необходимые действия с входными аргументами и возвращают результат в выходных аргументах. Разберем несколько простых примеров, позволяющих понять работу с файл-функциями. Файл-функция, так же как и файл-процедуры, создаются в редакторе М-файлов.

Файл-функции с одним входным аргументом

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

Имеет смысл один раз написать файл-функцию, а потом вызывать его всюду, где необходимо вычисление этой функции. Откройте в редакторе М-файлов новый файл и наберите текст листинга 3.2.

Листинг 3.2. Файл-функция с одним аргументом

function f=myfun (x)

Слово function в первой строке определяет, что данный файл содержит функцию. Первая строка является заголовком функции, в которой размещается имя функции и списки входных и выходных аргументов. В примере приведенном в листинге 3.2, имя функции myfun, один входной аргумент х и один выходной — f. После заголовка следует тело функции (оно в данном примере состоит из одной строки), где и вычисляется ее значение. Важно, что вычисленное значение записывается в f. Не забудьте поставить точку с запятой для предотвращения вывода лишней информации на экран. Теперь сохраните файл в рабочем каталоге. Обратите внимание, что выбор пункта Save или Save as меню File приводит к появлению диалогового окна сохранения файла, в поле File name которого уже содержится название myfun. He изменяйте его, сохраните файл-функцию в файле с предложенным именем!

Теперь созданную функцию можно использовать так же, как и встроенные sin, cos и другие, например из командной строки:

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

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

Matrix must be square.

Error in ==> C:\MATLABRll\work\myfun.m

On line 2 ==>f=exp(-x)*sqrt((х^2+1)/(x^4+0.1));

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

Измените тело функции, как указано в листинге 3.3 (не забудьте сохранить изменения в файле myfun.m).

| следующая лекция ==>
Типы М-файлов | I Листинг 3.3. Файл-функция, работающая с массивом значений

Дата добавления: 2014-01-03 ; Просмотров: 413 ; Нарушение авторских прав? ;

Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет

Файл-функции

Дата добавления: 2015-06-12 ; просмотров: 516 ; Нарушение авторских прав

Подобно файл-сценарию, файл-функция представляет собой файл с простым текстом, который может находится в вашем текущем либо в любом другом каталоге. Файл-функции отличаются от сценариев тем, что позволяют задавать входные параметры, когда вы их запускаете из командной строки MATLAB или из другого M-файла.


Ниже представлен M-файл-функция с именем rad.m, созданный для нахождения длины d = радиус — вектора точки (x;y;z) трехмерного пространства:

%Вычисление длины d=sqrt(x^2+y^2+z^2) радиус-вектора точки (x;y;z)

Структура M-файлов-функций следующая.

Первая строка в M-файле-функции называется строкой определения функции и начинается со слова function. В окне редактора M-файлов это зарезервированное слово выделяется синим цветом. Первая строка M-файла задает имя функции, а также количество аргументов (или параметров) ввода и вывода. В этом примере функция называется rad. Имя файла (за исключением расширения .m) и имя функции должны совпадать. Когда вы создаете этот новый M-файл-функцию в безымянном окне редактора и выбираете команду Save (Сохранить), модуль Editor (Редактор) сам присваивает файлу имя rad.m. Функция в нашем примере имеет для ввода три элемента, которые внутри M-файла обозначены как x, y, z. В качестве результата возращаетсяодин элемент – значение d, появляющееся в конце выполнения функции.

За строкой определения функции может следовать несколько строк — комментариев, начинающихся со знака процента %. Эти строки называются текстом справки об используемой функции и отображаются при вводе команды help. В M-файле rad.m присутствует только одна строка текста справки; она отображается при введении команды help rad.

Остальные строки содержат выражения системы MATLAB, которые производят вычисление значений функции. Строки комментариев (строки, начинающиеся со знака процента %) могут быть в любой области M-файла. Они не являются исполняемыми инструкциями. Цель их размещения в тексте программы – пояснить смысл той или иной части программного кода. Все выражения в M-файле-функции, которые обычно производят вывод результатов, должны оканчиваться точкой с запятой с целью пресечения вывода результатов промежуточных вычислений.

Покажем, как используется файл-функция rad.m для вычисления длины радиус — вектора точки (2;3;4):

Ответ 5,3852 будет возвращен и сохранен под именем ans независимо от того, заданы или нет x, y, z и d в вашей рабочей области. Переменные, которые используются в файл-функции, такие как x, y, z и d в файле rad.m, являются локальными переменными. Запуск M-файла-функции не задает эти переменные в рабочей области и не изменяет их параметры, если переменные с такими же именами в рабочей области были заданы ранее. Система MATLAB не запоминает значения этих переменных после того, как M-файл-функция будет выполнен, а область оперативной памяти, в которой они хранились, освобождается. Убедимся в этом, выполнив команду who:

Your variables are:

M-файлы-функции могут иметь множество аргументов ввода и вывода. Ниже представлен пример файла с именем rad2.m с тремя входными и двумя выходными параметрами, вычисляющего длину d и квадрат длины d2 радиус — вектора точки трехмерного пространства (x; y; z):

Если вы введете rad2(2,3,4), то только первый аргумент вывода будет возвращен и сохранен под именем ans:

Чтобы увидеть оба результата вывода, надо присвоить эти результаты переменным, заключенным квадратные скобки:

Введя d=rad2(2,3,4), вы можете присвоить первый аргумент вывода переменной d:

При вводе d2=rad2(2,3,4) нельзя получить второй аргумент вывода, т. к. переменной d2 будет также присвоен первый результат:

Передача информации из командного окна MATLAB в файл-функцию осуществляется с помощью параметров функции. Другой механизм передачи информации – глобальные переменные. Файл-функция может и не иметь входных или выходных параметров, заголовки таких файл-функций приведены ниже:

function noout(a,b), function [v,u]=noin, function noarg().

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

Приведем пример файл-функции rad3 без входных параметров:

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

Параметрами файл-функций могут быть не только числа или скалярные переменные, но и массивы требуемых размеров. Поэтому желательно создавать векторизованные версии М-файлов вместо операторов , , следует применять операторы , , . Векторизация осуществляется командой vectorize (см. разд. 1.7).

Созданный M-файл можно сохранить не только в текущем, но и в любом другом каталоге. В этом случае перед запуском M-файла на выполнение нужно установить пути поиска, ведущие к нему. По умолчанию текущим является подкаталог work основного каталога MATLAB. Для того, чтобы увидеть его содержимое, в главном меню MATLAB выберите команду View => Current Directory (Вид=>Текущий каталог). В результате раскроется окно, в котором отобразится список файлов и вложенных папок активного в данный момент каталога.

Чтобы изменить текущий каталог, введите путь к новому каталогу в поле Current Directory либо выберите его в раскрывающемся списке этого поля. Или же щелкните на кнопке справа от от поля Current Directory, и отыщите нужную папку в раскрывшемся диалоговом окне Обзор папок.

Справочную информация по M-функциям можно получить, введя команду doc function.

Вопросы для самопроверки

1. Как вызвать редактор M-файлов?

2. Что такое сценарий?

3. Что такое файл-функция?

4. Какова структура M-файла, содержащего файл-функцию?

5. Какую роль играют строки комментариев, располагаемые сразу за заголовком файл-функции?

6. Как осуществляется передача информации из командного окна MATLAB в файл-функцию?

7. Что такое локальные, глобальные переменные?

Функции и Файлы

Итерация свойственна человеку, рекурсия божественна. — Л. Питер Дойч

Все нетривиальные программы собираются из нескольких раздельно компилируемых единиц (их принято называть просто файлами). В этой главе описано, как раздельно откомпилированные функции могут обращаться друг к другу, как такие функции могут совместно пользоваться данными (разделять данные), и как можно обеспечить согласованность типов, которые используются в разных файлах программы. Функции обсуждаются довольно подробно. Сюда входят передача параметров, параметры по умолчанию, перегрузка имен функций, и, конечно же, описание и определение функций. В конце описываются макросы.

4.1 Введение


Иметь всю программу в одном файле обычно невозможно, поскольку коды стандартных библиотек и операционной системы находятся где-то в другом месте. Кроме того, хранить весь текст пользовательской программы в одном файле как правило непрактично и неудобно. Способ организации программы в файлы может помочь читающему охватить всю структуру программы, а также может дать возможность компилятору реализовать эту структуру. Поскольку единицей компиляции является файл, то во всех случаях, когда в файл вносится изменение (сколь бы мало оно ни было), весь файл нужно компилировать заново. Даже для программы умеренных размеров время, затрачиваемое на перекомпиляцию, можно значительно снизить с помощью разбиения программы на файлы подходящих размеров.
Рассмотрим пример с калькулятором. Он был представлен в виде одного исходного файла. Если вы его набили, то у вас наверняка были небольшие трудности с расположением описаний в правильном порядке, и пришлось использовать по меньшей мере одно «фальшивое» описание, чтобы компилятор смог обработать взаимно рекурсивные функции expr(), term() и prim(). В тексте уже отмечалось, что программа состоит из четырех частей (лексического анализатора, программы синтаксического разбора, таблицы имен и драйвера), но это никак не было отражено в тексте самой программы. По сути дела, калькулятор был написан по-другому. Так это не делается; даже если в этой программе «на выброс» пренебречь всеми соображениями методологии программирования, эксплуатации и эффективности компиляции, автор все равно разобьет эту программу в 200 строк на несколько файлов, чтобы программировать было приятнее.
Программа, состоящая из нескольких раздельно компилируемых файлов, должна быть согласованной в смысле использования имен и типов, точно так же, как и программа, состоящая из одного исходного файла. В принципе, это может обеспечить и компоновщик* 1 .

Программист может скомпенсировать недостаток поддержки со стороны компоновщика, предоставив дополнительную информацию о типах (описания). После этого согласованность программы обеспечивается проверкой согласованности описаний, которые находятся в отдельно компилируемых частях. Средства, которые это обеспечивают, в вашей системе будут. C++ разработан так, чтобы способствовать такой явной компоновке* 2 .

4.2 Компоновка (линковка)

Если не указано иное, то имя, не являющееся локальным для функции или класса, в каждой части программы, компилируемой отдельно, должно относиться к одному и тому же типу, значению, функции или объекту. То есть, в программе может быть только один нелокальный тип, значение, функция или объект с этим именем. Рассмотрим, например, два файла:
a и f(), используемые g() в файле file2.c,- те же, что определены в файле file1.c. Ключевое слово extern (внешнее) указывает, что описание a в file2.c является (только) описанием, а не определением. Если бы a инициализировалось, extern было бы просто проигнорировано, поскольку описание с инициализацией всегда является определением. Объект в программе должен определяться только один раз. Описываться он может много раз, но типы должны точно согласовываться. Например:
Здесь три ошибки: a определено дважды (int a; является определением, которое означает int a=0;), b описано дважды с разными типами, а c описано дважды, но не определено. Эти виды ошибок (ошибки компоновки) не могут быть обнаружены компилятором, который за один раз видит только один файл. Компоновщик, однако, их обнаруживает.
Следующая программа не является C++ программой (хотя C программой является):
Во-первых, file2.c не C++, потому что f() не была описана, и поэтому компилятор будет недоволен. Во-вторых, (когда file2.c фиксирован) программа не будет скомпонована, поскольку a определено дважды.
Имя можно сделать локальным в файле, описав его static. Например:
Поскольку каждое a и f описано как static, получающаяся в результате программа является правильной. В каждом файле своя a и своя f().
Когда переменные и функции явно описаны как static, часть программы легче понять (вам не надо никуда больше заглядывать). Использование static для функций может, помимо этого, выгодно влиять на расходы по вызову функции, поскольку дает оптимизирующему компилятору более простую работу.
Рассмотрим два файла:
Раз правило «ровно одно определение» применяется к константам, inline-функциям и определениям функций так же, как оно применяется к функциям и переменным, то file1.c и file2.c не могут быть частями одной C++ программы. Но если это так, то как же два файла могут использовать одни и те же типы и константы? Коротко, ответ таков: типы, константы и т.п. могут определяться столько раз, сколько нужно, при условии, что они определяются одинаково. Полный ответ несколько более сложен (это объясняется в следующем разделе).

4.3 Заголовочные Файлы

Типы во всех описаниях одного и того же объекта должны быть согласованными. Один из способов это достичь мог бы состоять в обеспечении средств проверки типов в компоновщике, но большинство компоновщиков — образца 1950-х, и их нельзя изменить по практическим соображениям * 3 . Другой подход состоит в обеспечении того, что исходный текст, как он передается на рассмотрение компилятору, или согласован, или содержит информацию, которая позволяет компилятору обнаружить несогласованности. Один несовершенный, но простой способ достичь согласованности состоит во включении заголовочных файлов, содержащих интерфейсную информацию, в исходные файлы, в которых содержится исполняемый код и/или определения данных.
Механизм включения с помощью #include — это чрезвычайно простое средство обработки текста для сборки кусков исходной программы в одну единицу (файл) для ее компиляции. Директива
замещает строку, в которой встретилось #include, содержимым файла «to_be_included». Его содержимым должен быть исходный текст на C++, поскольку дальше его будет читать компилятор. Часто включение обрабатывается отдельной программой, называемой C препроцессором, которую CC вызывает для преобразования исходного файла, который дал программист, в файл без директив включения перед тем, как начать собственно компиляцию. В другом варианте эти директивы обрабатывает интерфейсная система компилятора по мере того, как они встречаются в исходном тексте. Если программист хочет посмотреть на результат директив включения, можно воспользоваться командой
для препроцессирования файла file.c точно также, как это сделала бы CC перед запуском собственно компилятора. Для включения файлов из стандартной директории включения вместо кавычек используются угловые скобки . Например:
Использование <> имеет то преимущество, что в программу фактическое имя директории включения не встраивается (как правило, сначала просматривается /usr/include/CC, а потом usr/include). К сожалению, пробелы в директиве include существенны:
Может показаться, что перекомпилировать файл заново каждый раз, когда он куда-либо включается, расточительно, но время компиляции такого файла обычно слабо отличается от времени, которое необходимо для чтения его некоторой заранее откомпилированной формы. Причина в том, что текст программы является довольно компактным представлением программы, и в том, что включаемые файлы обычно содержат только описания и не содержат программ, требующих от компилятора значительного анализа.
Следующее эмпирическое правило относительно того, что следует, а что не следует помещать в заголовочные файлы, является не требованием языка, а просто предложением по разумному использованию аппарата #include.
В заголовочном файле могут содержаться:

Определения типов struct point
Описания функций extern int strlen(const char*);
Определения inline-функций inline char get()
Описания данных extern int a;
Определения констант const float pi = 3.141593
Перечисления enum bool < false, true >;
Директивы include #include
Определения макросов #define Case break;case
Комментарии /* проверка на конец файла */

но никогда

Определения обычных функций char get()
Определения данных int a;
Определения сложных константных объектов const tbl[] = < /* . */ >

В системе UNIX принято, что заголовочные файлы имеют суффикс (расширение) .h. Файлы, содержащие определение данных или функций, должны иметь суффикс .c. Такие файлы часто называют, соответственно, «.h файлы» и «.c файлы». В #4.7 описываются макросы. Следует заметить, что в C++ макросы гораздо менее полезны, чем в C, поскольку C++ имеет такие языковые конструкции, как const для определения констант и inline для исключения расходов на вызов функции.
Причина того, почему в заголовочных файлах допускается определение простых констант, но не допускается определение сложных константных объектов, прагматическая. В принципе, сложность тут только в том, чтобы сделать допустимым дублирование определений переменных (даже определения функций можно было бы дублировать). Однако для компоновщиков старого образца слишком трудно проверять тождественность нетривиальных констант и убирать ненужные повторы. Кроме того, простые случаи гораздо более обиходны и потому более важны для генерации хорошего кода.

4.3.1 Один Заголовочный Файл

Проще всего решить проблему разбиения программы на несколько файлов поместив функции и определения данных в подходящее число исходных файлов и описав типы, необходимые для их взаимодействия, в одном заголовочном файле, который включается во все остальные файлы. Для программы калькулятора можно использовать четыре .c файла: lex.c, syn.c, table.c и main.c, и заголовочный файл dc.h, содержащий описания всех имен, которые используются более чем в одном .c файле:
Если опустить фактический код, то lex.c будет выглядеть примерно так:
Заметьте, что такое использование заголовочных файлов гарантирует, что каждое описание в заголовочном файле объекта, определенного пользователем, будет в какой-то момент включено в файл, где он определяется. Например, при компиляции lex.c компилятору будет передано:
Это обеспечивает то, что компилятор обнаружит любую несогласованность в типах, указанных для имени. Например, если бы get_token() была описана как возвращающая token_value, но при этом определена как возвращающая int, компиляция lex.c не прошла бы из- за ошибки несоответствия типов.
Файл syn.c будет выглядеть примерно так:
Файл table.c будет выглядеть примерно так:
Заметьте, что table.c сам описывает стандартные функции для работы со строками, поэтому никакой проверки согласованности этих описаний нет. Почти всегда лучше включать заголовочный файл, чем описывать имя в .c файле как extern. При этом может включаться «слишком много», но это обычно не оказывает серьезного влияния на время, необходимое для компиляции, и как правило экономит время программиста. В качестве примера этого, обратите внимание на то, как strlen() заново описывается в main() (ниже). Это лишние нажатия клавиш и возможный источник неприятностей, поскольку компилятор не может проверить согласованность этих двух определений. На самом деле, этой сложности можно было бы избежать, будь все описания extern помещены в dc.h, как и предлагалось сделать. Эта «небрежность» сохранена в программе, поскольку это очень типично для C программ, очень соблазнительно для программиста, и чаще приводит, чем не приводит, к ошибкам, которые трудно обнаружить, и к программам, с которыми тяжело работать. Вас предупредили!
И main.c, наконец, выглядит так:
Важный случай, когда размер заголовочных файлов становится серьезной помехой. Набор заголовочных файлов и библиотеку можно использовать для расширения языка множеством обще- и специально- прикладных типов (см. Главы 5-8). В таких случаях не принято осуществлять чтение тысяч строк заголовочных файлов в начале каждой компиляции. Содержание этих файлов обычно «заморожено» и изменяется очень нечасто. Наиболее полезным может оказаться метод затравки компилятора содержанием этих заголовочных фалов. По сути, создается язык специального назначения со своим собственным компилятором. Никакого стандартного метода создания такого компилятора с затравкой не принято.

4.3.2 Множественные Заголовочные Файлы

Стиль разбиения программы с одним заголовочным файлом наиболее пригоден в тех случаях, когда программа невелика и ее части не предполагается использовать отдельно. Поэтому то, что невозможно установить, какие описания зачем помещены в заголовочный файл, несущественно. Помочь могут комментарии. Другой способ — сделать так, чтобы каждая часть программы имела свой заголовочный файл, в котором определяются предоставляемые этой частью средства. Тогда каждый .c файл имеет соответствующий .h файл, и каждый .c файл включает свой собственный (специфицирующий то, что в нем задается) .h файл и, возможно, некоторые другие .h файлы (специфицирующие то, что ему нужно).
Рассматривая организацию калькулятора, мы замечаем, что error() используется почти каждой функцией программы, а сама использует только . Это обычная для функции ошибок ситуация, поэтому error() следует отделить от main():
При таком стиле использования заголовочных файлов .h файл и связанный с ним .c файл можно рассматривать как модуль, в котором .h файл задает интерфейс, а .c файл задает реализацию.
Таблица символов не зависит от остальной части калькулятора за исключением использования функции ошибок. Это можно сделать явным:
Заметьте, что описания функций работы со строками теперь включаются из . Это исключает еще один возможный источник ошибок.
Этот интерфейс лексического анализатора достаточно беспорядочен. Недостаток в надлежащем типе лексемы обнаруживает себя в необходимости давать пользователю get_token() фактические лексические буферы number_value и name_string.
Интерфейс синтаксического анализатора совершенно прозрачен:
Главная программа, как всегда, тривиальна:
Сколько заголовочных файлов использовать в программе, зависит от многих факторов. Многие из этих факторов сильнее связаны с тем, как ваша система работает с заголовочными файлами, нежели с C++. Например, если в вашем редакторе нет средств, позволяющих одновременно видеть несколько файлов, использование большого числа файлов становится менее привлекательным. Аналогично, если открывание и чтение 10 файлов по 50 строк в каждом требует заметно больше времени, чем чтение одного файла в 500 строк, вы можете дважды подумать, прежде чем использовать в небольшом проекте стиль множественных заголовочных файлов. Слово предостережения: набор из десяти заголовочных файлов плюс стандартные заголовочные файлы обычно легче поддаются управлению. С другой стороны, если вы разбили описания в большой программе на логически минимальные по размеру заголовочные файлы (помещая каждое описание структуры в свой отдельный файл и т.д.), у вас легко может получиться неразбериха из сотен файлов.

4.3.3 Скрытие Данных

Используя заголовочные файлы пользователь может определять явный интерфейс, чтобы обеспечить согласованное использование типов в программе. С другой стороны, пользователь может обойти интерфейс, задаваемый заголовочным файлом, вводя в .c файлы описания extern.
Заметьте, что такой стиль компоновки не рекомендуется:
Поскольку описания extern в file2.c не включаются вместе с определениями в файле file1.c, компилятор не может проверить согласованность этой программы. Следовательно, если только загрузчик не окажется гораздо сообразительнее среднего, две ошибки в этой программе останутся, и их придется искать программисту.
Пользователь может защитить файл от такой недисциплинированной компоновки, описав имена, которые не предназначены для общего пользования, как static, чтобы их областью видимости был файл, и они были скрыты от остальных частей программы. Например:
Это гарантирует, что любой доступ к table действительно будет осуществляться именно через look(). «Прятать» константу TBLSZ не обязательно.

4.4 Файлы как Модули

В предыдущем разделе .c и .h файлы вместе определяли часть программы. Файл .h является интерфейсом, который используют другие части программы; .c файл задает реализацию. Такой объект часто называют модулем. Доступными делаются только те имена, которые необходимо знать пользователю, остальные скрыты. Это качество часто называют скрытием данных, хотя данные — лишь часть того, что может быть скрыто. Модули такого вида обеспечивают большую гибкость. Например, реализация может состоять из одного или более .c файлов, и в виде .h файлов может быть предоставлено несколько интерфейсов. Информация, которую пользователю знать не обязательно, искусно скрыта в .c файлах. Если важно, что пользователь не должен точно знать, что содержится в .c файлах, не надо делать их доступными в исходом виде. Достаточно эквивалентных им выходных файлов компилятора (.o файлов).
Иногда возникает сложность, состоящая в том, что подобная гибкость достигается без формальной структуры. Сам язык не распознает такой модуль как объект, и у компилятора нет возможности отличить .h файлы, определяющие имена, которые должны использовать другие модули (экспортируемые), от .h файлов, которые описывают имена из других модулей (импортируемые).
В других случаях может возникнуть та проблема, что модуль определяет множество объектов, а не новый тип. Например, модуль table определяет одну таблицу, и если вам нужно две таблицы, то нет простого способа задать вторую таблицу с помощью понятия модуля. Решение этой проблемы приводится в Главе 5.
Каждый статически размещенный объект по умолчанию инициализируется нулем, программист может задать другие (константные) значения. Это только самый примитивный вид инициализации. К счастью, с помощью классов можно задать код, который выполняется для инициализации перед тем, как модуль каким- либо образом используется, и/или код, который запускается для очистки после последнего использования модуля; см. #5.5.2.

4.5 Как Создать Библиотеку

Фразы типа «помещен в библиотеку» и «ищется в какой-то библиотеке» используются часто (и в этой книге, и в других), но что это означает для C++ программы? К сожалению, ответ зависит от того, какая операционная система используется; в этом разделе объясняется, как создать библиотеку в 8-ой версии системы UNIX. Другие системы предоставляют аналогичные возможности.
Библиотека в своей основе является множеством .o файлов, полученных в результате компиляции соответствующего множества .c файлов. Обычно имеется один или более .h файлов, в которых содержатся описания для использования этих .o файлов. В качестве примера рассмотрим случай, когда нам надо задать (обычным способом) набор математических функций для некоторого неопределенного множества пользователей. Заголовочный файл мог бы выглядеть примерно так:
а определения этих функций хранились бы, соответственно, в файлах sqrt.c, sin.c, cos.c, exp.c и log.c.
Библиотеку с именем math.h можно создать, например, так:
Вначале исходные файлы компилируются в эквивалентные им объектные файлы. Затем используется команда ar, чтобы создать архив с именем math.a. И, наконец, этот архив индексируется для ускорения доступа. Если в вашей системе нет команды runlib, значит она вам, вероятно, не понадобится. Подробности посмотрите, пожалуйста, в вашем руководстве в разделе под заголовком ar. Использовать библиотеку можно, например, так:
Теперь разберемся, в чем же преимущества использования math.a перед просто непосредственным использованием .o файлов? Например:
Для большинства программ определить правильный набор .o файлов, несомненно, непросто. В приведенном выше примере они включались все, но если функции в myprog.c вызывают только функции sqrt() и cos(), то кажется, что будет достаточно
Но это не так, поскольку cos.c использует sin.c.
Компоновщик, вызываемый командой CC для обработки .a файла (в данном случае, файла math.a) знает, как из того множества, которое использовалось для создания .a файла, извлечь только необходимые .o файлы.
Другими словами, используя библиотеку можно включать много определений с помощью одного имени (включения определений функций и переменных, используемых внутренними функциями, никогда не видны пользователю), и, кроме того, обеспечить, что в результате в программу будет включено минимальное количество определений.

4.6 Функции

Обычный способ сделать что-либо в C++ программе — это вызвать функцию, которая это делает. Определение функции является способом задать то, как должно делаться некоторое действие. Функция не может быть вызвана, пока она не описана.

4.6.1 Описания Функций

Описание функции задает имя функции, тип возвращаемого функцией значения (если таковое есть) и число и типы параметров, которые должны быть в вызове функции. Например:
Семантика передачи параметров идентична семантике инициализации. Проверяются типы параметров, и когда нужно производится неявное преобразование типа. Например, если были заданы предыдущие определения, то
будет правильно обращаться к функции sqrt() со значением с плавающей точкой 2.0. Значение такой проверки типа и преобразования типа огромно.
Описание функции может содержать имена параметров. Это может помочь читателю, но компилятор эти имена просто игнорирует.

4.6.2 Определения Функций

Каждая функция, вызываемая в программе, должна быть где-то определена (только один раз). Определение функции — это описание функции, в котором приводится тело функции. Например:
Чтобы избежать расходов на вызов функции, функцию можно описать как inline (#1.12), а чтобы обеспечить более быстрый доступ к параметрам, их можно описать как register (#2.3.11). Оба средства могут использоваться неправильно, и их следует избегать везде где есть какие-либо сомнения в их полезности.

4.6.3 Передача Параметров

Когда вызывается функция, дополнительно выделяется память под ее формальные параметры, и каждый формальный параметр инициализируется соответствующим ему фактическим параметром. Семантика передачи параметров идентична семантике инициализации. В частности, тип фактического параметра сопоставляется с типом формального параметра, и выполняются все стандартные и определенные пользователем преобразования типов. Есть особые правила для передачи векторов (#4.6.5), средство передавать параметр без проверки (#4.6.8) и средство для задания параметров по умолчанию (#4.6.6). Рассмотрим
Когда вызывается f(), val++ увеличивает локальную копию первого фактического параметра, тогда как ref++ увеличивает второй фактический параметр. Например:
увеличивает j, но не i. Первый параметр, i, передается по значению, второй параметр, j, передается по ссылке. Как уже отмечалось в #2.3.10, использование функций, которые изменяют переданные по ссылке параметры, могут сделать программу трудно читаемой, и их следует избегать (но см. #6.5 и #8.4). Однако передача большого объекта по ссылке может быть гораздо эффективнее, чем передача его по значению. В этом случае параметр можно описать как const, чтобы указать, что ссылка применяется по соображениям эффективности, а также чтобы не позволить вызываемой функции изменять значение объекта:
Аналогично, описание параметра указателя как const сообщает читателю, что значение объекта, указываемого указателем, функцией не изменяется. Например:
Важность такой практики растет с размером программы.
Заметьте, что семантика передачи параметров отлична от семантики присваивания. Это важно для const параметров, ссылочных параметров и параметров некоторых типов, определяемых пользователем (#6.6).

4.6.4 Возврат Значения

Из функции, которая не описана как void, можно (и должно) возвращать значение. Возвращаемое значение задается оператором return. Например:
В функции может быть больше одного оператора return:
Как и семантика передачи параметров, семантика возврата функцией значения идентична семантике инициализации. Возвращаемое значение рассматривается как инициализатор переменной возвращаемого типа. Тип возвращаемого выражения проверяется на согласованность с возвращаемым типом и выполняются все стандартные и определенные пользователем преобразования типов. Например:
Каждый раз, когда вызывается функция, создается новая копия ее параметров и автоматических переменных. После возврата из функции память используется заново, поэтому возвращать указатель на локальную переменную неразумно. Содержание указываемого места изменится непредсказуемо:
Эта ошибка менее обычна, чем эквивалентная ошибка при использовании ссылок:
К счастью, о таких возвращаемых значениях предупреждает компилятор. Вот другой пример:

4.6.5 Векторные Параметры

Если в качестве параметра функции используется вектор, то передается указатель на его первый элемент. Например:
Иначе говоря, при передаче как параметр типа T[] преобразуется к T*. Следовательно, присваивание элементу векторного параметра изменяет значение элемента вектора, который является параметром. Другими словами, вектор отличается от всех остальных типов тем, что вектор не передается (и не может передаваться) по значению.
Размер вектора недоступен вызываемой функции. Это может быть неудобно, но эту сложность можно обойти несколькими способами. Строки оканчиваются нулем, поэтому их размер можно легко вычислить. Для других векторов можно передавать второй параметр, который задает размер, или определить тип, содержащий указатель и индикатор длины, и передавать его вместо просто вектора (см. также #1.11). Например:
С многомерными массивами все хитрее, но часто можно вместо них использовать векторы указателей, которые не требуют специального рассмотрения. Например:
С другой стороны, рассмотрим определение функции, которая работает с двумерными матрицами. Если размерность известна на стадии компиляции, то никаких проблем нет:
Матрица, конечно, все равно передается как указатель, а размерности используются просто для удобства записи.
Первая размерность массива не имеет отношения к задаче отыскания положения элемента (#2.3.6). Поэтому ее можно передавать как параметр:

4.6.6 Параметры по Умолчанию

Часто в самом общем случае функции требуется больше параметров, чем в самом простом и более употребительном случае. Например, в библиотеке потоков есть функция hex(), порождающая строку с шестнадцатиричным представлением целого. Второй параметр используется для задания числа символов для представления первого параметра. Если число символов слишком мало для представления целого, происходит усечение, если оно слишком велико, то строка дополняется пробелами. Часто программист не заботится о числе символов, необходимых для представления целого, поскольку символов достаточно. Поэтому для нуля в качестве второго параметра определено значение «использовать столько символов, сколько нужно». Чтобы избежать засорения программы вызовами вроде hex(i,0), функция описывается так:
Инициализатор второго параметра является параметром по умолчанию. То есть, если в вызове дан только один параметр, в качестве второго используется параметр по умолчанию. Например:
интерпретируется как
и напечатает:
Параметр по умолчанию проходит проверку типа во время описания функции и вычисляется во время ее вызова. Задавать параметр по умолчанию возможно только для последних параметров, поэтому
Заметьте, что в этом контексте пробел между * и = является существенным (*= является операцией присваивания):

4.6.7 Перегрузка Имен Функций

Как правило, давать разным функциям разные имена — мысль хорошая, но когда некоторые функции выполняют одинаковую работу над объектами разных типов, может быть более удобно дать им одно и то же имя. Использование одного имени для различных действий над различными типами называется перегрузкой (overloading). Метод уже используется для основных операций C++: у сложения существует только одно имя, +, но его можно применять для сложения значений целых, плавающих и указательных типов. Эта идея легко расширяется на обработку операций, определенных пользователем, то есть, функций. Чтобы уберечь программиста от случайного повторного использования имени, имя может использоваться более чем для одной функции только если оно сперва описано как перегруженное. Например:
Что касается компилятора, единственное общее, что имеют функции с одинаковым именем, это имя. Предположительно, они в каком-то смысле похожи, но в этом язык ни стесняет программиста, ни помогает ему. Таким образом, перегруженные имена функций — это главным образом удобство записи. Это удобство значительно в случае функций с общепринятыми именами вроде sqrt, print и open. Когда имя семантически значимо, как это имеет место для операций вроде +, * и 4 реализована с помощью векторов указателей на функции для представления действий. Подробно эту систему здесь описать не получится, но вот общая идея:
Затем определяем и инициализируем указатели, определяющие действия, выбранные в меню, которое связано с кнопками (button) мыши:
В полной реализации для определения каждого пункта меню требуется больше информации. Например, где-то должна храниться строка, задающая текст, который высвечивается. При использовании системы значение кнопок мыши часто меняется в зависимости от ситуации. Эти изменения осуществляются (частично) посредством смены значений указателей кнопок. Когда пользователь выбирает пункт меню, например пункт 3 для кнопки 2, выполняется связанное с ним действие:
Один из способов оценить огромную мощь указателей на функции — это попробовать написать такую систему не используя их. Меню можно менять в ходе использования программы, внося новые функции в таблицу действий. Во время выполнения можно также легко сконструировать новое меню.
Указатели на функции можно использовать для задания полиморфных подпрограмм, то есть подпрограмм, которые могут применяться к объектам многих различных типов:
Эта программа сортирует и печатает:
Можно взять адрес inline-функции, как, впрочем, и адрес перегруженной функции(#с.8.9).

4.7 Макросы

Макросы * 5 определяются в #с.11. В C они очень важны, но в C++ применяются гораздо меньше. Первое правило относительно них такое: не используйте их, если вы не обязаны это делать. Как было замечено, почти каждый макрос проявляет свой изъян или в языке, или в программе. Если вы хотите использовать макросы, прочитайте, пожалуйста, вначале очень внимательно руководство по вашей реализации C препроцессора.
Простой макрос определяется так:
Когда name встречается как лексема, оно заменяется на rest of line. Например:
после расширения даст:
Можно также определить макрос с параметрами. Например:
При использовании mac должно даваться две строки параметра. После расширения mac() они заменяют a и b. Например:
после расширения даст
Макросы обрабатывают строки и о синтаксисе C++ знают очень мало, а о типах C++ или областях видимости — ничего. Компилятор видит только расширенную форму макроса, поэтому ошибка в макросе диагностируется когда макрос расширен, а не когда он определен. В результате этого возникают непонятные сообщения об ошибках.
Вот такими макросы могут быть вполне:
Вот совершенно ненужные макросы:
А вот примеры опасных макросов:
Чтобы увидеть, чем они опасны, попробуйте провести расширения в следующем примере:
Если вы вынуждены использовать макрос, при ссылке на глобальные имена используйте операцию разрешения области видимости :: (#2.1.1) и заключайте вхождения имени параметра макроса в скобки везде, где это возможно (см. MIN выше).
Обратите внимание на различие результатов расширения этих двух макросов:
например,
расширяется в
С помощью макросов вы можете разработать свой собственный язык. Скорее всего, для всех остальных он будет непостижим. Кроме того, C препроцессор — очень простой макропроцессор. Когда вы попытаетесь сделать что-либо нетривиальное, вы, вероятно, обнаружите, что сделать это либо невозможно, либо чрезвычайно трудно (но см. #7.3.5).

4.8 Упражнения



  1. (*1) Напишите следующие описания: функция, получающая параметр типа указатель на символ и ссылку на целое и не возвращающая значения; указатель на такую функцию; функция, получающая такой указатель в качестве параметра; и функция, возвращающая такой указатель. Напишите определение функции, которая получает такой указатель как параметр и возвращает свой параметр как возвращаемое значение. Подсказка: используйте typedef.
  2. (*1) Что это значит? Для чего это может использоваться?
  3. (*1.5) Напишите программу вроде «Hello, world», которая получает имя как параметр командной строки и печатает «Hello, имя». Модифицируйте эту программу так, чтобы она получала получала любое количество имен и говорила hello каждому из них.
  4. (*1.5) Напишите программу, которая читает произвольное число файлов, имена которых задаются как аргументы командной стоки, и пишет их один за другим в cout. Поскольку эта программа при выдаче конкатенирует свои параметры, вы можете назвать ее cat (кошка).
  5. (*2) Преобразуйте небольшую C программу в C++. Измените заголовочные файлы так, чтобы описывать все вызываемые функции и описывать тип каждого параметра. Замените, где возможно, директивы #define на enum и const или inline. Уберите из .c файлов описания extern и преобразуйте определения функций к синтаксису C++. Замените вызовы malloc() и free() на new и delete. Уберите необязательные приведения типа.
  6. (*2) Реализуйте sort() (#4.6.7) используя эффективный алгоритм сортировки.
  7. (*2) Посмотрите на определение struct tnode в с.#8.5. Напишите функцию для введения новых слов в дерево узлов tnode. Напишите функцию для вывода дерева узлов tnode. Напишите функцию для вывода дерева узлов tnode со словами в алфавитном порядке. Модифицируйте tnode так, чтобы в нем хранился (только) указатель на слово произвольной длины, помещенное с помощью new в свободную память. Модифицируйте функции для использования нового определения tnode.
  8. (*2) Напишите «модуль», реализующий стек. Файл .h должен описывать функции push(), pop() и любые другие удобные функции (только). Файл .c определяет функции и данные, необходимые для хранения стека.
  9. (*2) Узнайте, какие у вас есть стандартные заголовочные файлы. Составьте список файлов, находящихся в /usr/include и /usr/include/CC (или там, где хранятся стандартные заголовочные файлы в вашей системе). Прочитайте все, что покажется интересным.
  10. (*2) Напишите функцию для обращения двумерного массива.
  11. (*2) Напишите шифрующую программу, которая читает из cin и пишет в cout закодированные символы. Вы можете воспользоваться следующей простой схемой шифровки: Зашифрованная форма символа c — это c^key[i], где key (ключ) — строка, которая передается как параметр командной строки. Программа использует символы из key циклически, пока не будет считан весь ввод. Перекодирование зашифрованного текста с той же строкой key дает исходный текст. Если не передается никакого ключа (или передается пустая строка), то никакого кодирования не делается.
  12. (*3) Напишите программу, которая поможет расшифровывать тексты, зашифрованные описанным выше способом, не зная ключа. Подсказка: David Kahn: The Code-Breakers, Macmillan, 1967, New York, pp 207-213.
  13. (*3) Напишите функцию error, которая получает форматную строку в стиле printf, которая содержит директивы %s, %c и %d, и произвольное количество параметров. Не используйте printf(). Если вы не знаете значения %s и т.д., посмотрите #8.2.4. Используйте .
  14. (*1) Как вы будете выбирать имя для указателя на тип функции, определенный с помощью typedef?
  15. (*2) Посмотрите какие-нибудь программы, чтобы создать представление о разнообразии стилей и имен, использующихся на практике. Как используются буквы в верхнем регистре? Как используется подчерк? Где используются короткие имена вроде x и y?
  16. (*1) Что неправильно в следующих макроопределениях?
  17. (*3) Напишите макропроцессор, который определяет и расширяет простые макросы (как C препроцессор). Читайте из cin и пишите в cout. Сначала не пытайтесь обрабатывать макросы с параметрами. Подсказка: В настольном калькуляторе (#3.1) есть таблица имен и лексический анализатор, которые вы можете модифицировать.

* 1 или линкер. (прим. перев.)
* 2 C разработан так, чтобы в большинстве случаев позволять осуществлять неявную компоновку. Применение C, однако, возросло неимоверно, поэтому случаи, когда можно использовать неявную линковку, сейчас составляют незначительное меньшинство. (прим. автора)
* 3 Легко изменить один компоновщик, но сделав это и написав программу, которая зависит от усовершенствований, как вы будете переносить эту программу в другое место? (прим. автора)
* 4 Мышь — это указывающее устройство по крайней мере с одной кнопкой. Моя мышь красная, круглая и с тремя кнопками. (прим. автора)
* 5 часто называемые также макроопределениями. (прим. перев.)

Про функции и файлы

—— Построение начато: проект: 1, Конфигурация: Debug Win32 ——
Компиляция.
main.cpp
c:\program files\microsoft visual studio 9.0\vc\include\fstream(803) : error C2248: std::basic_ios ::basic_ios: невозможно обратиться к private член, объявленному в классе «std::basic_ios »
with
[
_Elem=char,
_Traits=std::char_traits
]
c:\program files\microsoft visual studio 9.0\vc\include\ios(151): см. объявление ‘std::basic_ios ::basic_ios’
with
[
_Elem=char,
_Traits=std::char_traits
]
Сообщение диагностики возникло в созданной компилятором функции «std::basic_ofstream ::basic_ofstream(const std::basic_ofstream &)»
with
[
_Elem=char,
_Traits=std::char_traits
]
Журнал построения был сохранен в «file://c:\Documents and Settings\Admin\Мои документы\Visual Studio 2008\Projects\Cons\1\1\Debug\BuildLog.htm»
1 — ошибок 1, предупреждений 0
========== Построение: успешно: 0, с ошибками: 1, без изменений: 0, пропущено: 0 ==========

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

Заранее спасибо за помощь.

23.08.2009, 16:34

Вопрос про файлы
где распологать текстовый файл, чтобы программа видела его сразу без прописания директории? пишу в.

Про файлы .dll
Здравствуйте, я заинтересовался фалами .dll. Я заметил, что в некоторых приложениях скачивают эти.

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

не могли бы вы проверить задачу про двоичные файлы?
Всем здравствуйте. наверно немного странная просьба: проверьте на правильность задачку «вывод числа.

Задача про ГАИ и файлы (где накосячил в коде?)
Добрый день! Задача звучит так: Вдоль шоссе в точках X1,X2. XN расположены посты ГАИ. В точке.

Функции и файлы

помогите :) Я учусь из pythonhardway Упражнение 20: Функции и файлы

если текущая строка = 2, она печатает вторую строку, как. .

& **rewind(current_file)** почему мы помещаем (f) почему not input_file?!


Я попытался объяснить, что я думаю, что он делает.

Извините, если я задаю глупые вопросы :(

Здесь есть два вопроса.

1 — разница между именем файла и файлом, на котором вы можете работать

2 — разница между именами параметров в функциях и значениями, используемыми для вызова этих функций

Когда у вас есть файл с именем (например) data.csv , вы можете ссылаться на него с помощью строки:

. но это всего лишь строка символов. Чтобы работать с файлом с таким именем, выполните следующие действия:

Теперь у вас есть дескриптор файла, который можно использовать с функциями чтения, записи, удаления, поиска и т.д. Итак, первая часть вашего ответа: имена файлов не совпадают с файловыми объектами; поэтому вы вызываете функцию перемотки с помощью current_file (дескриптор файла) not input_file (имя файла).

Другая проблема, возможно, очевидна — параметр placeholder, который вы используете для определения функции (например, f в вашем примере), является просто заполнителем — когда вы вызываете эту функцию позже, используется значение, которое вы вызываете с ним.

Таким образом, хотя функция определяется как rewind(f) , когда вы вызываете ее позже как rewind(current_file) вы фактически выполняете поиск по current_file — не f , это просто местозаполнитель.

Короче говоря, вы вызываете seek (внутри определения функции), используя f потому что имя заполнителя/символа, которое вы выбрали для использования для вашей многоразовой функции (и это имя может быть изменено практически на все, что вы хотите, в определении функции и функции тело), не затрагивая ничего. И причина, по которой вы вызываете rewind с помощью current_file — это тот объект, который вы открыли для работы.

Файл-функции и файл-программы

Встроенный язык программирования MatLab достаточно прост, он содержит необходимый минимум конструкций, которые описаны в следующем параграфе. Прежде чем программировать в MatLab, необходимо понять, что все программы могут быть либо файл-функциями, либо файл-программами. Файл-программа является текстовым файлом с расширением m (M-файлом), в котором записаны команды и операторы MatLab. Разберем, как создать простую файл-программу.

В MatLab имеется редактор M-файлов, для запуска которого следует нажать кнопку New M-file на панели инструментов рабочей среды, либо выбрать в меню File в пункте New подпункт M-file. На экране появляется окно редактора. Наберите в нем какие-либо команды, например для построения графика (см. листинг 5.1):

Листинг 5.1. Простейшая файл-программа

Для запуска программы или ее части есть несколько способов. Первый, самый простой — выделить операторы при помощи мыши, удерживая левую кнопку, или при помощи клавишы[1] со стрелками,

и выбрать в меню View пункт Evaluate Selection (или нажать ). Выделенные операторы выполняются последовательно, точно так же, как если бы они были набраны в командной строке. Очевидно, что работать в M-файле удобнее, чем из командной строки, поскольку можно сохранить программу, добавить операторы, выполнять отдельные команды не пробегаясь по истории команд, как в случае командной строки.

После того, как программа сохранена в M-файле, к примеру в myprog.m, для ее запуска можно использовать пункт Tools меню Run, либо просто набрать в командной строке имя M-файла (без расширения) и нажать , то есть выполнить, как обычную команду MatLab. При таких способах запуска программы следует учесть важное обстоятельство — путь к каталогу с M-файлом должен быть известен MatLab. Сделайте каталог с файлом myprog текущим.

§ В MatLab 5.3 в меню File рабочей среды перейдите к пункту Set Path… Появляется диалоговое окно Path Browser (навигатор путей). В строке ввода Current Directory установите требуемый каталог. Воспользуйтесь кнопкой, расположенной справа от строки ввода, для выбора каталога.

§ В MatLab 6.x установка текущего каталога производится из окна Current Directory рабочей среды. Если это окно отсутствует, то следует выбрать пункт Current Directory меню View рабочей среды. Для выбора желаемого каталога на диске нажмите кнопку, расположенную справа от раскрывающегося списка.

Когда текущий каталог установлен, то все M-файлы, находящиеся в нем, могут быть запущены из командной строки, либо из редактора M-файлов. Все переменные файл-программы после ее запуска доступны в рабочей среде, т. е. являются глобальными. Убедитесь в этом, выполнив команду whos. Более того, файл-программа может использовать переменные рабочей среды. Например, если была введена команда:

» a=[0.1 0.4 0.3 1.9 3.3];

то файл-программа, содержащая строку bar(а), построит столбцевую диаграмму вектора a (разумеется, если он не был переопределен в самой файл-программе).

Файл-функции отличаются от файл-программ тем, что они могут иметь входные и выходные аргументы, а все переменные, определенные внутри файл-функции, являются локальными и не видны в рабочей среде. M-файл, содержащий файл-функцию, должен начинаться с заголовка, после него записываются операторы MatLab. Заголовок состоит из слова function, списка выходных аргументов, имени файл-функции и списка входных аргументов. Аргументы в списках разделяются запятой. Листинг 5.2 содержит пример простейшей файл-функции с двумя входными и одним выходным аргументами.

Листинг 5.2. Файл-функция mysum

Наберите этот пример в новом файле в редакторе и сохраните его. Обратите внимание, что MatLab предлагает в качестве имени M-файла название файл-функции, т.е. mysum.m. Всегда сохраняйте файл-функцию в M-файле, имя которого совпадает с именем файл-функции! Убедитесь, что каталог с файлом mysum.m является текущим и вызовите файл-функцию mysum из командной строки:

При вызове файл-функции mysum произошли следующие события:

§ входной аргумент a получил значение 2;

§ входной аргумент b стал равен 3;

§ сумма a и b записалась в выходной аргумент c;

§ значение выходного аргумента c получила переменная s рабочей среды и результат вывелся в командное окно.

Заметьте, что оператор c=a+b в файл-функции mysum завершен точкой с запятой для подавления вывода локальной переменной c в командное окно. Для просмотра значений локальных переменных при отладке файл-функций, очевидно, не следует подавлять вывод на экран значений требуемых переменных.

Практически все функции MatLab являются файл-функциями и хранятся в одноименных M-файлах. Функция sin допускает два варианта вызова: sin(x) и y=sin(x), в первом случае результат записывается в ans, а во втором — в переменную y. Наша функция mysum ведет себя точно так же. Более того, входными аргументами mysum могут быть массивы одинаковых размеров или массив и число.

Разберем теперь, как создать файл-функцию с несколькими выходными аргументами. Список выходных аргументов в заголовке файл-функции заключается в квадратные скобки, сами аргументы отделяются запятой. В качестве примера на листинге 5.3 приведена файл-функция quadec, которая по заданным коэффициентам квадратного уравнения находит его корни.

Листинг 5.3. Файл-функция для решения квадратного уравнения


При вызове quadeq из командной строки используйте квадратные скобки для указания переменных, в которые будут занесены значения корней:

Заметьте, что файл-функцию quadec можно вызвать без выходных аргументов, или только с одним выходным аргументом. В этом случае вернется только первый корень.

Файл-функция может и не иметь входных или выходных аргументов, заголовки таких файл-функций приведены ниже:

function noout(a,b), function [v,u]=noin, function noarg()

Умение писать собственные файл-функции и файл-программы необходимо как при программировании в MatLab, так и при решении различных задач средствами MatLab (в частности, поиска корней уравнений, интегрирования, оптимизации[2]). Разберем только один пример, связанный с построением графика функции на отрезке . Запрограммируйте файл-функцию myfun для вычисления . Используйте поэлементные операции (см. листинг 5.4) для того, чтобы myfun можно было вызывать от вектора значений аргумента и получать вектор соответствующих значений функции.

Листинг 5.4. Файл-функция myfun

График можно получить двумя способами. Первый очевидный — надо создать вектор значений аргумента, скажем с шагом 0.01, заполнить вектор значений функции и вызвать plot:

В результате получается график, приведенный на рис. 5.1, а, который, очевидно, неверен. Действительно, при вычислении значений функции на отрезке с шагом 0.01 слагаемое все время обращалось в ноль и plot построила график не , а другой функции. Непродуманный выбор шага часто приводит к потере существенной информации о поведении функции. В MatLab имеется встроенная функция fplot — некоторый аналог plot, но с автоматическим подбором шага при построении графика. Первым входным аргументом fplot является имя файл-функции, а вторым — вектор, элементы которого есть границы отрезков: fplot(‘имя файл-функции’, [a,b]). Постройте теперь в новом окне график при помощи fplot:

Получился график, точно отражающий поведение функции (рис. 5.1, б).

Задания для самостоятельной работы

Написать файл-функции и построить графики на заданном отрезке при помощи plot (с шагом 0.05) и fplot для следующих функций:

Задания для самостоятельной работы

Написать файл-функцию для решения поставленной задачи.

1. Написать файл-функцию, которая по заданному вектору определяет номер его элемента с наибольшим отклонением от среднего арифметического всех элементов вектора.

2. Написать файл-функцию, возвращающую сумму всех элементов вектора с нечетными индексами.

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

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

5. Написать файл-функцию, которая суммирует все внедиагональные элементы заданной матрицы.

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

7. Написать файл-функцию, заменяющую элемент матрицы с индексами 1,1 произведением всех элементов матрицы.

8. Написать файл-функцию, которая строит многоугольник (замкнутый) по заданным векторам x и y с координатами вершин.

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

10. Написать файл-функцию, переводящую время в секундах в часы, минуты и секунды.

[1] Так, как выделяется блок текста в текстовом редакторе.

[2] Использование численных методов MatLab выходит за рамки этого пособия.

| следующая лекция ==>
Управление культуры Администрации г.о.Новокуйбышевск | МОСКОВСКАЯ МЕДИЦИНСКАЯ АКАДЕМИЯ им. И. М. СЕЧЕНОВА

Дата добавления: 2020-09-06 ; просмотров: 391 | Нарушение авторских прав

Функции и файлы

В се нетривиальные программы собираются из нескольких раздельно компилируемых единиц (их принято называть просто файлами). В этой главе описано, как раздельно откомпилированные функции могут обращаться друг к другу, как такие функции могут совместно пользоваться данными (разделять данные), и как можно обеспечить согласованность типов, которые используются в разных файлах программы. Функции обсуждаются довольно подробно. Сюда входят передача параметров, параметры по умолчанию, перегрузка имен функций, и, конечно же, описание и определение функций. В конце описываются макросы.

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

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

8 Заголовочные Файлы
Один несовершенный, но простой способ достичь согласованности состоит во включении заголовочных файлов, содержащих интерфейсную информацию, в исходные файлы, в которых содержится исполняемый код и/или определения данных.

8 Файлы как Модули
В предыдущем разделе .c и .h файлы вместе определяли часть программы. Файл .h является интерфейсом, который используют другие части программы; .c файл задает реализацию. Такой объект часто называют модулем.

8 Как Создать Библиотеку
Фразы типа «помещен в библиотеку» и «ищется в какой-то библиотеке» используются часто (и в этой книге, и в других), но что это означает для C++ программы?

8 Функции
Обычный способ сделать что-либо в C++ программе — это вызвать функцию, которая это делает. Определение функции является способом задать то, как должно делаться некоторое действие. Функция не может быть вызвана, пока она не описана.

8 Макросы
Макросы в C они очень важны, но в C++ применяются гораздо меньше.

Описание функций языка Си

All | _ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

fopen – открытие потока данных.

#include
FILE *fopen (const char *filename, const char *mode);

filename – указатель на строку содержащую имя (включая путь) открываемого файла.
mode – указатель на строку содержащую режим доступа к открытому файлу.

Указатель на управляющую таблицу открытого потока данных, если открытие файла произошло успешно.

NULL – если при открытии файла произошла ошибка. В переменную errno будет записан код ошибки.

Функция fopen открывает файл, указанный аргументом filename с режимом доступа, указанным в аргументе mode и связывает с открытым файлом поток данных.

Предусмотрены следующие режимы доступа к открытому файлу:

r или rb – открытие файла для чтения. Если файла не существует, работа программы завершиться с ошибкой.

w или wb – создать файл для записи, если файла уже существует, он будет открыт, он все имеющиеся в файле данные будут уничтожены.

a или ab – открыть файл для записи в конец файла, если файла не существует, он будет создан.

r+ или rb+ или r+b – открыть файл для чтения и записи. Если файла не существует, работа программы завершиться с ошибкой.

w+ или wb+ или w+b – создать файл для чтения и записи, если файл уже существует, он будет открыт, но все имеющиеся в файле данные будут уничтожены.

a+ или ab+ или a+b — открыть файл для записи в конец файла, если файла не существует, он будет создан.

В примере создается файл для записи с именем test.txt, располагающейся в папке myfile (папка создана до запуска программы и располагается в директории, из которой запускается программа) и в файл записывается строка «Тест записи в файл». Затем файл закрывается. Отчет о работе выводится на консоль.

Вывод на консоль:

Открытие файла: выполнено
Запись в файл выполнена
Файл закрыт

Илон Маск рекомендует:  Scanf форматный ввод
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL