Параметры со значениями по умолчанию

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

int f(int a, int b = 0);void f1(int, int = 100, char* = 0); void err(int errValue = errno); // errno - глобальная переменная f(100); f(a, 1); // варианты вызова функции f// варианты вызова функции f1f1(a); f1(a, 10); f1(a, 10, "Vasia"); f1(a,,"Vasia") // неверно!

Функции стандартной библиотеки

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

Чтобы использовать их в программе, требуется с помощью директивы #include включить в исходный текст программы заголовочные файлы, в которых находятся соответствующие объявления.

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

Ниже приведен краткий обзор основных функций.

Функции ввода/вывода

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

Для использования функций ввода/вывода в стиле С необходимо подключить к программе заголовочный файл <stdio.h> или <cstdio>. При вводе/выводе данные рассматриваются как поток байтов. Физически поток представляет собой файл или устройство, например, клавиатуру или дисплей, рассматривающиеся как частный случай файла.

Открытие потока

Работа с потоком начинается с его открытия. Поток можно открыть для чтения и/или записи в двоичном или текстовом режиме. Функция открытия потока имеет формат:

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

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

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

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

"a+" - файл открывается для добавления информации в его конец;

"r+" - файл открывается для чтения и записи (файл должен существовать);

"w+" - открывается пустой файл для чтения и записи (если файл существует, он стирается);

"a" - файл открывается для чтения и добавления информации в его конец.

Режим открытия может также содержать символы t (текстовый режим) или b (двоичный режим), отличающиеся обработкой символов перехода на новую строку. По умолчанию файл открывается в текстовом режиме, при котором комбинация символов "возврат каретки" и "перевод строки" (0x13 0x10) при вводе преобразуются в одиночный символ перевода строки (при выводе выполняется обратное преобразование). В двоичном режиме преобразования не выполняются.

Пример:

FILE *f = fopen("d:\\cpp\\data.txt", "rb+");

Указатель f используется в дальнейших операциях с потоком. Его передают функциям ввода/вывода в качестве параметра.

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

Существует пять предопределенных потоков, которые открываются в начале работы программы: стандартный ввод stdin, стандартный вывод stdout, стандартный вывод сообщений об ошибках stderr, стандартный дополнительный поток stdaux и стандартная печать stdprn.

Ввод/вывод в поток

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

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

Ниже перечислены основные функции ввода/вывода потока.

· Чтение и запись потока байтов выполняют функции fread и fwrite.

· Чтение символа из потока - getc, fgetc, из стандартного потока stdin - getchar.

· Запись символа в поток - putc, fputc, в стандартный поток stdout - putchar.

· Чтение строки из потока - fgets, из стандартного потока stdin - gets.

· Запись строки в поток - fputs, в стандартный поток stdout - puts.

· Форматированный ввод из потока - fscanf, из стандартного потока stdin - scanf, из строки - sscanf.

· Форматированный вывод в поток - fprintf, в стандартный поток stdout - printf, в строку - sprintf.

Закрытие потока

Поток закрывается либо при завершении программы, либо явным образом с помощью функции fclose:

int fclose(FILE*);

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

Пример работы с потоками

Приведенная ниже программа построчно считывает данные из текстового файла в буферную переменную s, формирует из них структуру mon и записывает ее в двоичном режиме в выходной файл. Далее иллюстрируется считывание из этого файла произвольной записи.

#include <cstdio>

#include <cstdlib>

#include <cconio>

#include <iostream>

using namespace std;

int main()

{

FILE *fi, *fo;

if((fi = fopen("d:\\c\\binfile.txt", "r"))==0)

{

cout << "Ошибка открытия входного файла";

return 1;

};

if((fo = fopen("d:\\c\\binfile.out", "w+b"))==0)

{

cout << "Ошибка открытия выходного файла";

return 1;

};

const int dl = 80;

char s[dl];

struct

{

char type[20];

int opt, rozn;

char comm[40];

}mon;

while (fgets(s, dl, fi))

{

// Преобразование строки в структуру:

strncpy(mon.type, s, 19); //Описание strncpy см. в след. разделе

mon.opt = atoi(&s[20]); //Описание atoi см. в след. разделе

mon.rozn = atoi(&s[25]);

strncpy(mon.comm, &s[30], 40);

fwrite(&mon, sizeof mon, 1, fo);

}

fclose(fi);

int i; cin >> i; // Номер записи

// Установка указателя текущей позиции файла на запись i

fseek(fo, (sizeof mon)*i, SEEK_SET);

fread(&mon, sizeof mon, 1, fo);

cout << "mon.type "

<< mon.type << " opt "

<< mon.opt << " rozn "

<< mon.rozn << endl;

fclose(fo);

}

Допустим, что в файле хранятся сведения о мониторах. В каждой строке указан тип, оптовая и розничная цены и примечание. Для простоты данные в каждой строке записаны единообразно: первые 20 символов занимает тип монитора, далее по 5 символов оптовая и розничная цена, затем примечание длиной не более 40 символов.

Функции работы со строками и символами

Строка представляет собой массив символов, заканчивающийся нуль-символом. В С++ есть две возможности работы со строками: функции, унаследованные из библиотеки С (заголовочный файл <string.h> или <cstring>), и библиотечный класс С++ string, предоставляющий более широкие возможности представления, обработки и контроля строк.

Библиотека С содержит функции копирования строк ( strcpy, strncpy ), сравнения ( strcmp, strncmp ), объединения строк ( strcat, strncat ), поиска подстроки ( strstr ), поиска вхождения символа ( strchr, strrchr, strpbrk ), определения длины строки ( strlen ) и др.

В заголовочных файлах <stdlib.h> и <cstdlib> содержатся полезные функции преобразования строк в числа:

double atof(const char* p); //преобразует переданную строку в double

int atoi(const char* p); //преобразует переданную строку в int

long atol(const char* p); //преобразует переданную строку в long

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

Для работы с символами в стандартной библиотеке (заголовочные файлы <ctype.h> и <cctype>) есть следующие функции:

Таблица 4.1.
Имя Проверка на принадлежность символа множеству
isalnum букв и цифр (A-Z, a-z, 0-9)
isalfa букв (A-Z, a-z)
iscntrl управляющих символов (с кодами 0..31 и 127)
isdigit цифр (0-9)
isgraph Печатаемых символов, кроме пробела ( isalfa | isdigit | ispunct )
islower букв нижнего регистра (a-z)
isprint Печатаемых символов
ispunct знаков пунктуации
isspace символов-разделителей
isupper букв верхнего регистра (A-Z)
isxdigit шестнадцатеричных цифр (A-F, a-f, 0-9)

Математические функции

С++ унаследовал из С стандартные математические функции, описание которых находится в заголовочных файлах <stdlib.h>, <math.h> и <cmath>. Они позволяют получить абсолютное значение ( abs, fabs ), округленное число ( ceil, floor ), квадратный корень ( sqrt ), степень ( pow ), значения тригонометрических функций ( sin, cos, tan, sinh, и т. п.), экспоненту ( exp ), логарифм ( log, log10 ), дробную и целую часть числа ( modf ), остаток от деления ( fmod ) и некоторые другие.

Модульное программирование

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

Получившиеся в результате компиляции объектные модули объединяются в исполняемую программу с помощью компоновщика. Разбиение на модули уменьшает время перекомпиляции и облегчает процесс отладки. Чем более независимы модули, тем легче отлаживать программу.

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

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

Директивы препроцессора

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

Директива #include

Директива #include <имя_файла> вставляет содержимое указанного файла в ту точку исходного файла, где она записана. Включаемый файл также может содержать директивы #include.

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

Директива #include является простейшим средством обеспечения согласованности объявлений в различных файлах, включая в них информацию об интерфейсе из заголовочных файлов. Заголовочные файлы обычно имеют расширение .h и могут содержать:

· определения типов, констант, встроенных функций, шаблонов, перечислений;

· объявления функций, данных, имен, шаблонов;

· пространства имен;

· директивы препроцессора;

· комментарии.

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

Директива #define

Директива#define определяет подстановку в тексте программы. Она используется для определения:

· символических констант. Формат определения символической константы:

· /* Все вхождения имени заменяются на текст подстановки */#define имя текст_подстановки

· макросов, которые выглядят как функции, но реализуются подстановкой их текста в текст программы. Формат определения макроса:

#define имя( параметры ) текст_подстановки

· символов, управляющих условной компиляцией. Они используются вместе с директивами #ifdef и #ifndef. Формат:

#define имя

Примеры:

#define M 1000#define Vasia "Василий Иванович"#define MAX(a,b) ((x)>(y)?(x):(y))#define __cplusplus

Параметры используются при макроподстановке, например, если в тексте программы используется вызов макроса y = MAX(sum1, sum2);, он будет заменен на

y=((sum1)>(sum2)?(sum1):(sum2));

Использования макросов и символических констант в программах следует избегать.

Наши рекомендации