Text
                    Введение 19
1 Типы данных, переменные и константы 21
2 Функции, области видимости, пространства
имен и заголовки 43
3 Операторы 63
4 Препроцессор и комментарии , 79
5 Ключевые слова 91
6 Стандартные функции ввода-вывода языка С.... 131
7 Строковые и символьные функции 167
8 Математические функции языка С 183
9 Математические функции языка C++ 209
10 Функции времени, даты
и геополитической среды 217
11 Функции динамического выделения памяти 231
12 Функции смешанного типа 235
13 Функции обработки двубайтовых символов 259
14 Система ввода-вывода
старого стиля в языке C++ 271
15 Классы ввода-вывода библиотеки стандарта
ANSI/ISO для языка C++...; л............ 297
16 Стандартная библиотека шаблонов C++ 329
17 Строки, исключения и классы арифметики
комплексных чисел в языке C++ 393
18 Библиотечные средства, добавленные
в версии С99 417
Предметный указатель 430


Введение 19 1 Типы данных, переменные и константы 21 Основные типы 21 Объявление переменных 24 Инициализация переменных 24 Идентификаторы ; 24 Классы 25 Наследование 28 Структуры 29 Объединения 30 Перечисления 32 Теги языка С 33 Спецификаторы классов памяти 33 extern 33 auto 34 register .., .'¦ 34 static 35 mutable .-«... ,........35 Квалификаторы типов 35 const 35 volatile ;.. < 36 restrict .,., 37 Массивы ....':... 37 Определение имен типов с помощью typedef 38 Константы 38 Шеетнадцатеричные и восьмеричные константы »...» 39 Строковые константы 40 Логические (булевы) константы.. 40 Комплексные константы 41 Специальные (управляющие) символьные константы....... 41 2 Функций, области видимости, пространства имен и заголовки ........43 Функции 43 . Рекурсия 44 Перегрузка функций....... ; ......:. 46 Передача аргументов функции по умолчанию 47 Прототипы функций , 48 Области видимости и время жизни переменных 49 Пространства имен ; .1.: 50 Функция main О .51 Аргументы функции ....52 Передача указателей 54
Параметры-ссылки 55 Конструкторы и деструкторы 56 Спецификаторы функций 56 Спецификация компоновки 57 Стандартные библиотеки С и C++ 58 3 Операторы 63 Арифметические операторы 63 Операторы отношений и логические операторы 64 Поразрядные операторы 65 Операторы &, i ил 65 Оператор дополнения до единицы 66 Операторы сдвига 66 Адресные операторы 68 Оператор взятия адреса & 68 Оператор разыменования адреса * 68 Операторы присваивания 69 Оператор ? 70 Операторы доступа к членам объектов 70 Оператор последовательного вычисления 71 Оператор sizeof ; 72 Оператор приведения типа 72 Операторы приведения типа в языке C++ 72 Операторы ввода-вывода 73 Операторы указания на члены . * и->* 74 Оператор разрешения области видимости :: 76 Операторы new И delete 76 Оператор typeid..... 76 Перегрузка операторов 77 Сводная таблица приоритетов операторов 77 4 Препроцессор и комментарии 79 ttdefine ¦..„ 79 terror 81 #if, #ifdef, #ifndef, #else,#elifИtendif 81 «include 83 #line 84 tpragma 85 Оператор _Pragma в версии С99 85 Встроенные прагмы версии С99 85 #undef 86 Операторы препроцессора # и ## 86 Зарезервированные имена макросов 88 Дополнительные встроенные макросы, определенные в версии С99 88 Комментарии 89 Списки с переменным количеством аргументов 89
5 Ключевые слова 91 asm 92 auto 92 bool 92 _Bool 93 break 93 case 94 catch 94 char 94 class 94 _Complex , 95 const 95 const_cast : 96 continue 96 default 96 delete 97 do 97 double 97 dynamic_cast 98 else 98 enum 98 explicit 99 export , 99 extern 99 false 100 float 100 for 100 friend 101 goto 101 if 103 „Imaginary 104 inline 104 int 105 long 105 mutable 105 namespace 105 new 107 operator 108 private 109 protected 110 public. 111 register 112 reinterpret_cast 112 restrict .....,..,. 113 return 114 short 114 signed 115 sizeof 115 static 115
static_cast 116 struct 116 switch 117 template 118 this .., 123 throw ';'.\ 123 true *4 126 try , 3. 126 typedef -.i 126 typeid.... .'. л 126 typename 127 union r 127 unsigned 128 using 128 virtual , 128 void 129 volatile 129 wchar_t 130 while : 130 6 Стандартные функции ввода-вывода языка С.... 131 clearerr 132 f close ....133 feof ...133 f err or , 134 f flush 134 fgetc 135 fgetpos 135 fgets 136 fopen 136 fprintf 139 fputc 139 fputs 140 fread 141 f reopen 141 fscanf 142 fseek 142 fsetpos 143 ftell 144 f write 144 getc 145 get char 145 gets 146 perror 146 printf 148 Модификаторы формата, добавленные к функции printf О стандартом С99 152 putc 152 put char 153 puts 153
remove 154 rename 154 rewind 154 scanf „ 154 Модификаторы формата, добавленные к функции scanf () стандартом С99 159 setbuf , 160 setvbuf 160 snprintf я. 161 sprint f 161 sscanf 162 tmpf ile ,. 163 tmpnam... 163 ungetc 164 vprintf, vfprintf, vsprintf и vsnprintf 164 vscanf. vfscanf и vsscanf 165 7 Строковые и символьные функции 167 isalnum 168 isalpha 168 isblank 168 iscntrl 169 isdigit 169 isgraph 169 is lower 170 isprint 170 ispunct 170 isspace 170 isupper 171 isxdigit 171 memchr 171 memcmp 172 memcpy , 172 memmove 173 memset 173 strcat 173 strchr 174 strcmp.. 174 strcoll 174 strcpy 175 strcspn 175 strerror 176 strlen 176 strncat 176 strncmp 177 strncpy 177 strpbrk 178 strrchr 178 strspn 179 strstr 179
strtok 179 strxfrm 180 tolower 182 toupper ; 182 8 Математические функции языка С 183 acos 186 acosh 187 asin -:. 187 'asinh 187 atari 188 atanh 188 atan2 189 cbrt 189 ceil 189 copy sign 190 cos 190 cosh 190 erf ¦. 191 erf с 191 exp 191 exp2 192 expml ; 192 fabs 193 fdim 193 floor 193 fma 194 fmax 194 fmin 194 fmod 195 frexp : 195 hypot 195 ilogb 196 ldexp 196 lgamma 197 llrint 197 llround 197 log 198 loglp ; : 198 loglO , 198 Iog2 199 logb 199 lrint 200 lround 200 modf 200 nan 201 nearby int 201 nextafter 202 next toward 202 pow 203
remainder 203 remquo 203 rint 204 round... 204 scalbn > 205 scalbln 205 sin 206 sinh 206 sqrt 206 tan 207 tanh 207 tgairana 207 trunc 208 9 Математические функции языка C++ 209 acos 210 asin 210 atan '. 210 atan2 211 ceil 211 cos 211 cosh .- 212 exp 212 fabs 212 floor 212 fmod 213 frexp 213 ldexp 213 log 214 loglO 214 modf 214 pow 215 sin 215 sinh 215 sqrt 216 tan 216 tanh 216 10 Функции времени, даты и геополитической среды 217 asctime 218 clock... 218 ctime 219 difftime 219 gmtime 220 localeconv 220 localtime 223 mktime 223 set locale 225 strf time 226 time 229
11 Функции динамического выделения памяти 231 calloc 232 free 232 malloc 233 realloc ; 233 12 Функции смешанного типа 235 abort 236 abs 236 assert 236 atexit 237 atof 237 atoi 238 atol , 238 atoll 239 bsearch 239 div 240 exit.... 240 _Exit 240 getenv 241 labs 241 ldiv 242 llabs 242 lldiv 242 longjmp 243 mblen 244 mbstowcs 244 mbtowc 245 qsort 245 raise 246 rand.... 247 setjmp 247 signal 248 srand 249 strtod 249 strtof 250 strtol 250 strtold 251 strtoll 252 strtoul 252 strtoull 253 system 254 va_arg, va_start, va_end И va_copy 254 wcstombs 256 wctomb 257 13 Функции обработки двубайтовых символов 259 Функции классификации двубайтовых символов 260 Функции ввода-вывода двубайтовых символов 261 Строковые функции двубайтовых символов 264
Преобразование строк двубайтовых символов 266 Работа с массивами двубайтовых символов 267 Преобразование объектов в двубайтовые символы 268 14 Система ввода-вывода старого стиля в языке C++ 271 Базовые классы потоков ввода-вывода 272 Встроенные потоки C++ 273 Флаги форматирования 274 Манипуляторы ввода-вывода 275 Функции iostream старого стиля 277 bad 277 clear 277 eatwhite 277 eof 278 fail 278 fill 278 flags 279 flush 279 f stream, ifstreamnofstream 279 gcount 281 get 281 get line 282 good 283 ignore 283 open 284 peek 287 precision 287 put 288 putback 288 rdstate 288 read 289 seekgnseekp 289 setf 291 setmode 292 str 292 strstream, istrstream И ostrstream 293 sync_with_stdio 294 tellgntellp.. 294 unset f. 295 width 295 write 296 15 Классы ввода-вывода библиотеки стандарта ANSI/ISO для языка C++ 297 Библиотека iostream стандарта C++ 297 Классы ввода-вывода библиотеки стандарта C++ 298 Встроенные потоки C++ 301 Заголовки ввода-вывода 302 Флаги форматирования 302
Манипуляторы ввода-вывода 304 О некоторых типах данных 307 Типы streamsize И streamof f 307 Типы streampos Hwstreampos 308 Tnnblpos_typeHoff_type 308 Тип open_mode 308 Тип iostate 308 Тип seekdir 309 Класс failure 309 Перегруженные операторы « и » 309 Функции ввода-вывода стандарта C++ 309 bad 310 clear 310 eof 310 exceptions 311 fail 311 fill 311 flags 312 flush 312 f stream, if stream И of stream 313 gcount 314 get ! 314 get line 315 good 316 ignore 316 open 317 peek 318 precision 318 put 320 putback 321 rdstate 321 read 322 readsome 322 seekgM seekp 322 setf 324 setstate 325 str 325 stringstream, istringstreamn ostringstream 325 sync_with_stdio „. 326 tellgntellp 327 unset f 327 width 328 write 328 16 Стандартная библиотека шаблонов C++ 329 Обзор STL 329 Контейнеры 329 Алгоритмы 330 Итераторы 330
Другие элементы библиотеки STL 331 Контейнерные классы 335 bitset 336 deque 339 list 342 map 346 multimap 350 multiset 353 queue 355 prior ity_queue 356 set 357 stack 360 vector 361 Алгоритмы библиотеки STL 365 " adjacent_f ind ,....366 binary _search 366 copy 367 copy_backward 367 count 367 count_if 367 equal ..368 equal_range 368 fill И fill_n 369 find 369 find_end 369 find_first_of.. 370 find_if 370 for_each 371 generate И generate_n 371 includes 371 inplace_merge .....372 iter_swap 372 lexicographical_compare 373 lower_bound 373 make_heap 374 max 374 max_element 374 merge 375 min 375 min_element 375 mismatch 376 next_permutation '. 376 nth_element 377 partial_sort 377 * partial_sort_copy 378 partition 378 pop_heap 379 prev_permutation 379 push_heap 380 random_shuf f le 380
remove, remove_if, remove_copy И remove_copy_i f 380 replace, replace_copy, replace_if И replace_copy_if 381 reverse И reverse_copy 382 rotate И rotate_copy 383 search 383 search_n 384 set^difference 384 set_intersect ion 385 set_syiranetric_dif ference 385 set_union 386 sort 387 sort_heap 387 stable_partition 387 stable_sort 388 swap 388 swap_ranges 388 transform 388 unique Hunique_copy 391 upper_bound..... .- 391 17 Строки, исключения и классы арифметики комплексных чисел в языке C++ 393 Строки 393 Исключения 410 <exception> 410 <stdexcept> 412 Классы арифметики комплексных чисел 413 18 Библиотечные средства, добавленные в версии С99 417 Библиотека комплексных чисел 417 Библиотека вычислений с плавающей точкой 421 Заголовок <stdint.h> 424 Функции преобразования целого формата 426 Математические макросы обобщенного типа 427 Заголовок <stdbool.h> 429 Предметный указатель 430
Введение С и C++ — самые значительные языки программирования в мире. И в самом деле, быть сегодня профессиональным программистом означает знать эти два языка на высоком уровне, поскольку они представляют собой фундамент, на котором строится современное программирование. Язык С изобрел Дэнис Ритчи (Dennis Ritchie) в начале 70-х годов. С относится к языкам среднего уровня, поскольку в нем управляющие структуры языков высокого уровня сочетаются со способностью манипулировать битами, байтами и указателями (адресами). Таким образом, С предоставляет программисту возможность практически полностью управлять компьютером. В 1989 году Американским национальным институтом стандартов (American National Standards Institute — ANSI) был принят стандарт для языка С. Эту версию языка С обычно называют С89. Кроме того, этот же стандарт был принят и Международной организацией стандартов (International Standards Organization — ISO). В 1995 году стандарт С89 был немного улучшен. Язык C++ создан Бьярни Страуструпом (Bjarne Stroustrup), и годом создания считается 1979-й. Разработка и усовершенствование языка C++ потребовали от создателя больших усилий на протяжении 80-х и большей части 90-х годов. Наконец, в 1998 году был принят ANSI/ISO-стандарт для языка C++. Говоря в самых общих словах, язык C++ является объектно-ориентированной версией языка С. C++ построен на основе версии С89, включающей все усовершенствования 1995 года, и теперь эту версию С89 называют С-подмножеством языка C++. Несмотря на то что язык C++ был задуман как набор объектно-ориентированных расширений для языка С, вскоре он развился в самостоятельный язык программирования. В настоящее время его новые средства почти удвоили объем исходного языка. Вряд ли стоит доказывать, что C++ — один из самых мощных компьютерных языков, разработанных до сих пор. В 1999 году был принят новый ANSI/ISO-стандарт для языка С. Эта версия называется С99. Она включает ряд усовершенствований и несколько новых средств. Одни из этих "новых" средств заимствованы из языка C++, а другие предо-
20 Введение ставляют совершенно новые возможности. Следовательно, отдельные элементы, добавленные в версии С99, несовместимы с языком C++. Это означает, что с появлением версии С99 стандарт языка С больше не является чистым подмножеством языка C++. К счастью, многие "несовместимости" связаны со средствами специального назначения, которые можно легко обойти. Таким образом, и новый вариант языка С позволяет создавать программы, совместимые с языком C++. На момент написания этой книги большинство компиляторов не принимали все новшества версии С99, но, безусловно, ситуация вскоре изменится. В следующей таблице демонстрируются отношения между версиями С89, С99 и языком C++. С89 Оригинальный стандарт ANSI/ISO языка С, который большинство программистов считают "настоящим" языком С C++ Объектно-ориентированная версия языка С. Действующий в данный момент стандарт ANSI/ISO для языка C++ построен на основе версии С89. Следовательно, С89 является подмножеством языка C++ С99 Последний стандарт языка С. Включает в полном ' объеме вариант С89, но с несколькими новыми средствами. Причем некоторые из них не поддерживаются текущим стандартом языка C++ В этой книге описаны версии С89, С99 и действующий стандарт языка C++. Если какое-нибудь средство является уникальным для одного из вариантов языков, этот факт обязательно отмечается в настоящем справочнике. При отсутствии специальной отметки можно предполагать, что описываемое средство работает во всех трех версиях. Безусловно, в справочнике невозможно раскрыть все многогранные аспекты языков С и C++. Назначение справочника —дать краткое описание самых важных средств этих языков в удобной и понятной для использования форме.
Глава 1 Типы данных, переменные и константы Языки С и C++ предлагают программисту богатый ассортимент встроенных типов данных. При этом для удовлетворения практически любых нужд могут быть созданы типы данных, определяемые самим программистом. Для каждого действительного типа данных можно создавать переменные. Кроме того, можно определять константы встроенных типов данных. В этой главе рассматриваются различные языковые средства, связанные с типами данных, переменными и константами. | Основные типы В версии С89 определены следующие основные типы данных. Тип Ключевое слово Символьный char Целочисленный int С плавающей запятой float С плавающей запятой двойной точности double Пустой ' void К перечисленным выше типам в версии С99 добавлены следующие. Тип Ключевое слово Логический, или булев (истина/ложь) _Воо1 Комплексный „Complex Мнимый „.Imaginary В языке C++ определены следующие основные типы.
22 Основные типы Тип Ключевое слово Логический, или булев (true/false) bool Символьный char Целочисленный int С плавающей запятой float С плавающей запятой двойной точности double Пустой void Символьный двубайтовый wchar_t Как видите, все версии языков С и C++ предоставляют возможность работать со следующими пятью основными типами: char, int, float, double и void. Заметьте также, что ключевые слова, используемые для обозначения логического типа данных в версии С99 и языке C++, отличаются одно от другого: _Bool (C99) и bool (C++). В версии С89 логический тип данных вообще отсутствует. Некоторые основные типы могут быть модифицированы с помощью одного или нескольких модификаторов типов. • signed • unsigned • short • long Модификаторы указываются перед наименованием типа, который они модифицируют. В следующей таблице приведены все разрешенные в языках С и C++ встроенные типы данных, включая модификаторы, а также их гарантированные минимальные диапазоны. Большинство компиляторов расширяют указанные минимумы для одного или нескольких типов. Кроме того, если в вашем компьютере используется двоичная арифметика (что имеет место в большинстве случаев), самое маленькое отрицательное значение, которое можно хранить с помощью целочисленного типа данных со знаком, будет на единицу больше указанных минимумов. Например, диапазон типа int для большинства компьютеров составляет -32 768-32 767. От конкретной реализации компилятора также зависит, каким является тип char: знаковым или беззнаковым.
Основные типы 23 Тип Минимальный диапазон char unsigned char signed char int unsigned int signed int short int unsigned short int signed short int long int signed long int unsigned long int long long int signed long long int -127-127 или 0-255 0-255 -127-127 -32 767-32 767 0-65 535 Аналогичен типу int Аналогичен типу int 0-65 535 Аналогичен типу short int -2 147 483 647-2 147 483 647 Аналогичен типу long int 0-4 294 967 295 -Bвз-1)-263-1 (только в С99) Аналогичен типу long long int (только в С99) unsigned long long int 0-2M-l (только в С99) float 6 значащих цифр double 10 значащих цифр long double 10 значащих цифр wchar_t Аналогичен типу uns i gned int Если при объявлении переменных используется один модификатор (без наименования типа), то предполагается использование типа int. Например, целочисленную переменную без знака можно объявить, используя лишь ключевое слово unsigned. Таким образом, следующие объявления эквивалентны. unsigned int i; // тип int указан явно unsigned i; // здесь тип int подразумевается
24 Объявление переменных [ Объявление переменных || Все переменные должны быть объявлены до их использования. Общая форма объявления имеет следующий вид. type имя_л временной; Например, чтобы объявить х переменной типа float, у — целочисленной переменной и ch — символьной, необходимо записать следующее. float x; int у; * char ch; Используя форму списка, можно в одной записи объявить сразу несколько переменных, разделив их запятыми. Например, следующий оператор объявляет три целые переменные. int a, b, с; Инициализация переменных Переменную можно инициализировать, записав после ее имени знак равенства и начальное значение. Например, следующее объявление позволяет присвоить переменной count начальное значение 100. int count = 100; Инициализатором может быть любое выражение, которое действительно при объявлении переменной. Оно может включать другие переменные и вызовы функций. Однако в языке С глобальные переменные и статические (static) локальные переменные должны быть инициализированы только с использованием константных выражений. | Идентификаторы Д Имена переменных, функций и типов, определенных пользователем, — это примеры идентификаторов. В языках С и C++ идентификаторы представляют собой последовательности, состоящие из одной или нескольких букв, цифр и символов подчеркивания. (Однако идентификатор не может начинаться с цифры.)
Классы 25 Идентификаторы могут иметь любую длину, но не все символы являются значащими. Различают два типа идентификаторов: внешние и внутренние. Внешние идентификаторы участвуют во внешнем процессе компоновки. Они называются внешними именами и включают имена функций и глобальных переменных, которые используются в различных файлах. Если идентификатор не участвует во внешнем процессе компоновки, он является внутренним. Идентификаторы, относящиеся к этому типу, называются внутренними именами и включают, например, имена локальных переменных. В версии С89 значащими являются по крайней мере первые 6 символов внешнего и по крайней мере первый 31 символ внутреннего идентификатора. В версии С99 эти "пределы значимости" расширены: внешний идентификатор имеет по крайней мере 31 значащий символ, а внутренний — по крайней мере 63 значащих символа. В языке C++ по крайней мере 1 024 символа любого идентификатора являются значащими. Символ подчеркивания часто используется для удобочитаемости (например, f irst_time) или в качестве первого символа идентификатора (например, _count). Идентификаторы, записанные прописными и строчными буквами, распознаются как разные. Например, test a TEST — это две различные переменные. В языках С и C++ резервируются все идентификаторы, начинающиеся с двух символов подчеркивания или одного символа подчеркивания, за которым следует прописная буква. Классы 1 Класс — это основной элемент инкапсуляции в языке C++. Класс определяется с помощью ключевого слова class. В языке С понятие класса отсутствует. По сути, класс представляет собой коллекцию переменных и функций, которые манипулируют этими переменными. Переменные и функции, образующие класс, называются членами. Ниже показана общая форма записи класса. class имя_класса : список_наследования { II Закрытые члены, установленные по умолчанию. protected: // Закрытые члены, которые могут быть унаследованы. public:
26 Классы II Открытые члены. } список_объектов; Здесь имя_класса — это имя типа класса. После компиляции объявления класса имя_класса становится именем нового типа данных, который можно использовать для объявления объектов класса. Список_объектов — это список объектов типа имя^класса, разделенных запятыми. Такой список необязателен. Объекты класса могут быть объявлены позже в программе путем простого использования имени класса. Спи- сок_наследования также необязателен. С его помощью указывается базовый класс или классы, наследуемые новым классом. (См. раздел "Наследование", приведенный ниже в этой главе.) Класс может включать функцию конструктора и функцию деструктора. (Обе функции необязательны.) Конструктор вызывается при первоначальном создании объекта класса, а деструктор — при разрушении этого объекта. Имя конструктора совпадает с именем класса. Функция деструктора имеет имя, совпадающее с именем класса, но ему предшествует символ "тильда" (~). Ни конструкторы, ни деструкторы не имеют типов возврата. В иерархии классов конструкторы выполняются в порядке их "классового происхождения", а деструкторы — в обратном порядке. По умолчанию все элементы класса закрыты, и к ним могут получить доступ только другие члены этого класса. Чтобы разрешить доступ к некоторому элементу класса со стороны функций, не являющихся членами данного класса, необходимо объявить этот элемент в качестве открытого члена после ключевого слова public, как в приведенном ниже примере. class myclass { int a, b; // закрытые члены класса myclass public: // Члены класса, доступные для не членов класса. void setab(int i, int j) {a=i;b=j; } void showab() { cout « a « ' ' << b « endl; } myclass obi, ob2; Это объявление создает тип класса с именем myclass, который содержит две закрытые переменные: а и Ь. Он также содержит две открытые функции setab () и showab ().
Классы 27 В приведенном выше фрагменте программы также объявляются два объекта типа ту с lass с именами оЫ и оЬ2. Чтобы сделать некоторый член клаеса наследуемым, но недоступным (закрытым) для внешних операторов, объявите его защищенным, т.е. используйте в объявлении спецификатор доступа protected. Защищенный член доступен для производных классов, но закрыт в пределах иерархии классов. При выполнении операций над объектом класса для ссылки на отдельные его члены используйте оператор "точка" (.). Оператор "стрелка" (->) используется для доступа к объекту с помощью указателя. Например, в следующем фрагменте программы доступ к функции put info () объекта ob реализуется с использованием оператора "точка", а к функции show () — с помощью оператора "стрелка" . struct cl_type { int x; float f; public: void putinfo(int a, float t) { x = a; f = t; } void show() { cout << a « ' ' « f « endl; } cl_type ob, *p; // ... ob.putinfoA0, 0.23); p' = &ob; // помещаем адрес объекта ob в переменную p->show(); // отображаем данные объекта ob С помощью ключевого слова template можно создавать обобщенные, или шаблонные, классы. (См. раздел "template", приведенный в главе 5.)
28 Наследование [Наследование В языке C++ один класс может наследовать свойства другого. Унаследованный класс обычно называется базовым классом, а класс-наследник—'производным классом. Когда один класс наследует другой, формируется иерархия классов. Общая форма наследования классов имеет следующий вид. class имя_класса : спецификатор_доступа имя_базового_класса { Здесь спвцификатор_доступа определяет способ наследования базового класса и указывается с помощью одного из трех ключевых слов: private, public или protected. Его можно опустить, и в этом случае предполагается использование спецификатора public, если базовый класс является структурой (struct), или private, если базовый класс является классом (class). При наследовании нескольких классов используется список имен классов, разделенных запятыми. Если в качестве элемента спецификатор_доступа используется вариант pub I i с, все pubIi с - и рго t eс t e d-члены базового класса остаются publ ic- и protected-членами производного класса соответственно. Если в качестве элемента специфика- тор_доступа используется вариант private, все public- и protected-члены базового класса становятся private-членами производного класса. В случае защищенного доступа (protected) все public- и protected-члены базового класса становятся protected-членами производного класса. В приведенной ниже иерархии классов класс derived наследует класс base закрытым способом, т.е. с использованием спецификатора private. Это означает, что переменная i становится закрытым членом класса derived. class base { public: int i ; class derived : private base { int j;
Структуры 29 public: derived(int a) {j=i=a; } ' int getjt) { return j¦; } v int geti() { return i; } // OK, derived имеет доступ к переменной i derived ob(9); // создаем объект класса derived cout « ob.geti() << " " << ob.getjO; //OK // ob.i = 10; // ОШИБКА: переменная i закрыта, //для объекта класса derived! Структуры J Структура создается с помощью ключевого слова struct. В языке C++ структура также определяет класс. Единственное различие между class- и struct-объектами состоит в том, что по умолчанию все члены структуры являются открытыми. Чтобы сделать член закрытым, необходимо использовать ключевое слово private. Общая форма объявления структуры имеет следующий вид. struct имя_структуры: список_наследования { // Открытые члены по умолчанию, protected: // Закрытые члены, которые могут быть унаследованы. у private: // Закрытые члены. } список_объектов; В языке С к структурам применяются некоторые ограничения. Они могут содержать только данные-члены; функции-члены здесь не разрешены. С-структуры не поддерживают наследования. Кроме того, все члены являются открытыми, а ключевые слова public, protected и private использовать нельзя.
30 Объединения I Объединения Объединение.— это тип класса, в котором все данные- члены разделяют одну и ту же область памяти. В языке C++ объединение может включать как функции-, так и данные- члены. Все члены объединения открыты по умолчанию. Для создания закрытых элементов необходимо использовать ключевое слово private. Общая форма объявления объединения выглядит следующим образом. union имя_класса { // Открытые члены по умолчанию, private: // Закрытые члены. } список_объектов; В языке С объединения могут содержать только данные- члены и ключевое слово private не поддерживается. Элементы объединения перекрывают друг друга. Например, в записи union torn { char ch; int x; } t; объявляется объединение torn, которое предполагает следующее распределение памяти (при использовании двубайтовых целых). Байт! | Байт2 I Как и в классе, на отдельные переменные, составляющие объединение, можно ссылаться с помощью оператора "точка". Оператор "стрелка" используется для доступа к объединению с помощью указателя. Применительно к объединениям существует несколько ограничений. Объединение не может наследовать любые другие классы любого типа. Объединение не может быть базовым классом. Объединение не может иметь виртуальные функ-
Объединения 31 ции-члены. Никакие члены не могут быть объявлены как статические. Объединение не может иметь в качестве члена объект, перегружающий оператор "равно" (=). Наконец, ни один объект не может быть членом объединения, если класс этого объекта явно определяет функцию конструктора или деструктора. (Иначе говоря, приемлемы объекты, которые имеют только стандартные конструкторы и деструкторы.) В языке C++ существует специальный тип объединения, называемый анонимным объединением. В объявлении анонимного объединения не содержится имени класса и не объявляются никакие объекты. Анонимное объединение просто уведомляет компилятор о том, что его переменные-члены должны разделять одну и ту же область памяти. Однако к самим переменным можно обращаться напрямую, не прибегая к обычному синтаксису операторов "точка" и "стрелка". Переменные, составляющие анонимное объединение, находятся на том же уровне области видимости, что и другие переменные, объявленные внутри того же блока. Это означает, что имена переменных объединения не должны конфликтовать с именами других переменных, которые действительны в пределах своей области видимости. Приведем пример анонимного объединения. union { // анонимное объединение int a; // переменные а и f разделяют float f; // одну и ту же область памяти а = 10; II получаем доступ к переменной а cout « f; // доступ к переменной f Здесь обе переменные, а и f, разделяют одну и ту же область памяти. Как видите, на имена переменных объединения можно ссылаться напрямую, без оператора "точка" или "стрелка". Все ограничения, которые вообще применяются к объединениям, применимы и к анонимным объединениям. Кроме того, анонимные объединения должны содержать только данные — никакие функции-члены не разрешены. Анонимные объединения не могут содержать ключевые слова private и protected. Наконец, анонимное объединение, действующее в области видимости, определенной с заданием пространства имен (namespace), должно быть объявлено с использованием модификатора типа данных static.
32 Перечисления Совет программисту В языке C++ при создании структур в стиле языка С (С- стиле), которые включают только данные-члены, обычной практикой считается использование типа struct. Тип class, как правило, резервируется для создания классов, содержащих функции-члены. Иногда для описания структуры, создаваемой в С-стиле, используется аббревиатура POD (Plain Old Data — простые старые данные). I Перечисления | Перечисление представляет собой тип переменной, создаваемый программистом. Перечисление— это список именованных целочисленных констант. Таким образом, тип перечисления — это просто спецификация списка имен, принадлежащих конкретному перечислению. Для создания перечисления используется ключевое слово enum. Общая форма типа перечисления имеет следующий вид. enum имя_пере числения {список_имен} спи- сок_переменных; Здесь имя_перечисления — имя типа данного перечисления. В списке имен, как и в списке переменных, элементы списка отделяются один от другого запятыми. Например, в следующем фрагменте программы сначала определяется перечисление городов, именуемое cities, и переменная с типа cities, а затем переменной с присваивается значение Houston. enum cities {Houston, Austin, Amarillo} c; с = Houston; В любом перечислении значение первого (крайнего слева) имени по умолчанию равно 0, значение второго имени равно 1, третье имеет значение 2 и т.д. Вообще, каждому имени присваивается значение, на единицу большее значения предыдущего имени. Добавив инициализатор, можно придать имени некоторое конкретное значение. Например, в следующем перечислении имя Aust in будет иметь значение 10.
Теги языка С 33 enum cities {Houston, Austin=10, Amarillo }; В этом примере имя Amarillo будет иметь значение 11, поскольку каждое имя должно иметь значение, на единицу большее значения предыдущего имени. II Теги языка С "" I В языке С, в отличие от C++, имя структуры, объединения или перечисления не определяет в полной мере имя типа. Например, следующий фрагмент программы правомерен для языка C++, но не для С. struct s_type { int i; i double d; s_type x; //OK для C++, но не для С В языке C++ идентификатор s_type определяет полное имя типа и его можно самостоятельно использовать для объявления объектов. В языке С s_type определяет лишь некоторый тег (признак). Поэтому в С при объявлении объектов имя тега необходимо предварять соответствующим ключевым словом (struct, union или enum), как в приведенном ниже примере. struct s_type x; // теперь приемлемо для язйка С • Этот синтаксис разрешен и в языке C++, но используется довольно редко. | Спецификаторы классов памяти ^ Спецификаторы классов памяти extern, auto, register, s tat iс и mut able используются для изменения способа создания памяти для переменных в языках С и C++. Эти спецификаторы ставятся перед типом, который они модифицируют. extern Если спецификатор extern размещается перед именем переменной, компилятор будет "знать", что переменная имеет внеш-
34 Спецификаторы классов памяти нюю "привязку", т.е. что память для этой переменной выделена где-то в другом месте программы. Внешняя "привязка" означает, что данный объект виден вне его собственного файла. По сути, спецификатор extern сообщает компилятору лишь тип переменной, не выделяя для нее области памяти. Чаще всего спецификатор extern используется в тех случаях, когда одни и те же глобальные переменные используются в двух или более файлах. auto Спецификатор auto уведомляет компилятор о том, что локальная переменная, перед именем которой он стоит, создается при входе в блок и разрушается при выходе из блока. Все переменные, определенные внутри функции, являются автоматическими по умолчанию, и потому ключевое слово auto используется довольно редко. register Когда язык С был только-только изобретен, спецификатор register можно было использовать лишь для локальных целых или символьных переменных, поскольку он заставлял компилятор пытаться сохранить эту переменную в регистре центрального процессора вместо того, чтобы разместить ее в памяти. В таком случае все ссылки на эту переменную работали исключительно быстро. С тех пор определение спецификатора register расширилось. Теперь любую переменную можно определить как register и тем самым возложить заботу об оптимизации доступа к ней на компилятор. Для символов и целых это по-прежнему означает их хранение в регистре процессора, но для других типов данных это может означать, например, использование кэш-памяти. Следует иметь в виду, что использование спецификатора register — всего лишь "заявка", которая может быть и не удовлетворена. Компилятор волен ее проигнорировать. Причина такого "неуважения" состоит в том, что только ограниченное число переменных можно оптимизировать ради ускорения обработки данных. При превышении этого предела компилятор будет просто игнорировать дальнейшие register-aaBKH".
Квалификаторы типов 35 static Спецификатор static указывает компилятору на хранение локальной переменной во время всего жизненного цикла программы вместо ее создания и разрушения при каждом входе в область^ действия и выходе из нее. Следовательно, возведение локальных переменных в ранг статических позволяет поддерживать их значения между вызовами функций. Модификатор static можно также применить к глобальным переменным. В этом случае область'видимости такой переменной ограничивается файлом, в котором она объявлена. Это означает, что переменная будет иметь внутреннюю "привязку". Внутренняя "привязка" говорит о том, что иденг тификатор известен только внутри своего файла. В языке C++ использование спецификатора static для данных-членов класса приводит к созданию только одной копии этих членов, совместно используемой всеми объектами класса. mutable Спецификатор mutable применим только в языке C++. Он позволяет члену любого объекта переопределить "тавро постоянства", т.е. любой член, определенный как mutable и принадлежащий объекту, который определен с Помощью квалификатора типа const, не несет на себе "печати" const и может быть модифицирован. • ¦--'< Квалификаторы типов Квалификаторы типов const и volatile предоставляют дополнительную информацию о переменных,, перед именами которых они стоят. const Объекты типа const не могут быть изменены программой в процессе ее: выполнения. Кроме того, объект, адресуемый с помощью указателя, который определен как const, также не может быть модифицирован. Компилятор волен поместить переменные этого типа в память, предназначенную только для чтения (read-only memory — ROM). Переменная, определенная как const, получит свое значение либо из явной инициализации,
36 Квалификаторы типов либо посредством выполнения аппаратно-зависимых методов. Например, в результате выполнения строки const int a =10; будет создана целая переменная с именем а и со значением 10, которое не может быть модифицировано программой. Тем не менее эту переменную вполне можно использовать в выражениях других типов. ; Совет программисту Если функция-член класса модифицирована квалифи- катором типа const, то она не может изменить объект, вызвавший эту функцию. Чтобы объявить функцию-член постоянной, укажите ключевое слово const после списка ее параметров, как, например, показано ниже. class MyClass { int i ; public: // const-функция. void fl(int a) const { i = a; // ОШИБКА! Нельзя модифицировать объект, вызывающий функцию. } . void f2(int a) { i = a; // OK, не const-функция Ь^ ¦" *"'¦""'¦ * '-. ¦ Как видно из комментариев, функция f 1 () определена с использованием квалификатора const и не может модифицировать объект, который ее вызывает. volatile Модификатор volatile сообщает компилятору, что значение переменной может быть изменено средствами, заданными в программе неявным образом. Например, адрес глобальной переменной можно передавать системной процедуре отсчета времени и обновлять после каждого тиканья системных часов. В этом случае содержимое переменной изменяется без выполнения каких-либо явных операторов присваивания
Массивы 37 в программе. Это очень важный момент, поскольку компиляторы иногда автоматически оптимизируют определенные выражения, исходя из предположения, что содержимое переменной не изменяется внутри этого выражения. Оптимизация выполняется для достижения более высокой производительности. Однако модификатор volatile не допускает выполнения операций по оптимизации программного кода в тех редких ситуациях, когда это предположение не оправдано. restrict В версию С99 добавлен новый квалификатор типа, именуемый restrict. Он применяется только к указателям. Указатель, квалифицированный с помощью ключевого слова restrict, изначально является единственным средством доступа к объекту, на который он указывает. Доступ к объекту с помощью другого указателя возможен только в том случае, если второй указатель основан на первом. Таким образом, доступ к объекту ограничивается выражениями, основанными на restrict-квалифицированном указателе. Указатели, определенные с помощью квалификатора restrict, используются, главным образом, как параметры функций или для указания на память, выделенную с помощью функции malloc (). Квалификатор restrict не изменяет семантику программы. В языке C++ квалификатор restrict не поддерживается. | Массивы | Массивы могут быть объявлены с использованием любого типа данных. Общая форма объявления одномерного массива имеет следующий вид. тип Имя_массива[размер]; Здесь тип определяет тип данных для каждого элемента в массиве, а размер указывает количество элементов в массиве. Например, чтобы объявить целочисленный массив х из 100 элементов, запишите следующее. int х[100]; ' . : Эта запись создает массив, содержащий 100 элементов, причем номер первого элемента — 0, а последнего — 99. На- ¦
38 Определение имен типов с помощью typedef пример, при выполнении следующего цикла в массив х загрузятся числа от 0 до 99. for(t=0; t<100; t++) x[t] = t; Массивы можно объявлять, используя любой допустимый тип данных, в том числе созданные вами классы. Многомерные массивы объявляются посредством размещения дополнительных измерений внутри дополнительных квадратных скобок. Например, чтобы объявить массив целых размерностью 10 х 20, необходимо записать следующее^ int x[10][20] ; Массивы можно инициализировать с помощью списка инициализаторов, заключенного в фигурные скобки, как, например, показано ниже. int count[5] = { 1, 2, 3, 4, 5 }; Определение имен типов С ПОМОЩЬЮ typedef С помощью ключевого слова typedef можно создать новое имя для уже существующего типа. Фбщая форма записи такова. typedef тип новое_имя_типа; Например, следующий фрагмент программы сообщает компилятору, что feet -^ это еще одно имя для типа int. typedef int feet; После этого следующее объявление совершенно законно и создает целую переменную с именем distance. feet distance; Константы "~ Константы, называемые также литералами, относятся к фиксированным значениям, которые не могут быть изменены программой. Константы могут иметь любой базовый тип данных. Способ представления каждой константы зависит от ее типа. Символьные крнстанть,! заключаются, в одинарной? кавьгаки. Напри-
Константы 39 мер, ' a' и ' + ' являются символьными константами. Целочисленные константы задаются как числа без дробной части. Например, 10 и-100 — целочисленные константы. Вещественные константы содержат десятичную точку, за которой следует дробная часть числа, например 11.123. Для вещественных констант можно также использовать экспоненциальное представление чисел. Существует два вещественных типа: float и double. Кроме того, существует несколько базовых типов, которые образуются с помощью модификаторов типов. По умолчанию компилятор присваивает числовой константе совместимый и одновременно наименьший по занимаемой памяти тип данных. Единственным исключением из правила "наименьшего типа" являются вещественные (с плавающей точкой) константы, которым по умолчанию присваивается тип double. Во многих случаях такие стандарты работы компилятора вполне приемлемы. Однако у программиста есть возможность точно определить нужный тип. Чтобы задать точный тип числовой константы, используйте соответствующий суффикс. Для вещественных типов действуют следующие суффиксы: если вещественное число завершить буквой F, оно будет обрабатываться с использованием типа float, а если буквой L, подразумевается тип long double. Для Целых типов суффикс U означает использование типа uns igned, а суффикс L — тип long. Ниже приведены некоторые примеры. Тип данных Примеры констант int 1, 123, 21000, -234 , long int 35000L, -34L unsigned int 10000U, 987U float 123.23F, 4.34e-3F double 123.23, 12312333, -0.9876324 long double 1001.2L Шестнадцатеричные и восьмеричные константы Иногда удобно вместо десятичной системы счисления использовать восьмеричную или шестнадцатеричную. В восьмеричной системе основанием служит число 8, а для выражения всех чисел используются цифры от 0 до 7. В восьмеричной системе число 10 имеет то же значение, что число 8 в десятичной. Щ
40 Константы Система счисления по основанию 16 называется шестнадцате- ричной и использует цифры от 0 до 9 плюс буквы от А до F, означающие шестнадцатеричные "цифры" 10, 11, 12, 13,14 и 15. Например, шестнадцатеричное число 10 равно числу 16 в десятичной системе. Поскольку эти две системы счисления (шестнадцатеричная и восьмеричная) используются в программах довольно часто, в языках С и C++ разрешено при желании задавать целые константы не в десятичной, а в шестнад- цатеричной или восьмеричной системе. Шестнадцатеричная константа должна начинаться с префикса Ох (нуль и буква х) или Ох, а восьмеричная — с нуля. Приведем два примера. int hex = 0x80; // 128 в десятичной системе int oct = 012; // 10 в десятичной системе Строковые константы Языки С и C++ поддерживают еще один встроенный тип данных, именуемый строковым. Строка — это набор символов, заключенных в двойные кавычки, например " это тест". Не следует путать строки с символами. Символьная константа заключается в одинарные кавычки, например ' а'. Однако "а" — это уже строка, содержащая только одну букву. Строковые константы автоматически завершаются нулевым символом при компиляции. Кроме того, в языке C++ поддерживается класс string, который описан ниже в этой книге. Логические (булевы) константы В языке C++ определены две булевы константы: true и false. В версии С99, которая обогатила язык С типом _Воо1, тем не менее, не определена ни одна встроенная логическая константа. Однако, если в программу включить заголовок <stdbool .h>, будут определены макросы true и false. Кроме того, после включения в программу заголовка <stdbool. h> ' определяется макрос bool как еще одно имя для типа _Воо1. Это позволяет создать программу, которая будет совместимой как с версией С99, так и с языком C++. Однако не забывайте, что в версии С89 логический тип не определен вообще.
Константы 41 Комплексные константы Во время работы в версии С99, если в программу включить заголовок <complex.h>, будут определены следующие константы, позволяющие работать с комплексными числами. _Complex_I (const float _Complex)i _Imaginary_I (const float _Imaginary)i I lmaginary_l (или _Complex_l, если мнимые типы не поддерживаются) Здесь элемент i представляет мнимое значение, которое равно квадратному корню из-1. Специальные (управляющие) символьные константы С выводом большинства печатаемых символов прекрасно справляются символьные константы, заключенные'в одинарные кавычки, но есть такие "экземпляры" (например, символ возврата каретки), которые невозможно ввести в исходный текст программы с клавиатуры. Поэтому в языках С и C++ разрешено использовать ряд специальных символьных констант (включающих символ "обратная, черта"), которые так* же называются управляющими последовательностями. Приведем список этих констант. Код Значение \Ъ Возврат на одну позицию \f Подача бланка \п Новая строка \г Возврат каретки \ t Горизонтальная табуляция \" Двойная кавычка \ ' Одинарная кавычка (апостроф) \ \ Обратная косая черта \v Вертикальная табуляция Щ
42 Константы Код . Значение \N Восьмеричная константа (где N — это сама восьмеричная константа) \xN Шестнадцатеричная константа (где N — это сама шестнадцатеричная константа) \ ? Вопросительный знак Специальные константы можно использовать везде, где уместно использование символов. Например, следующий оператор выполняет переход на новую строку, выводит символ табуляции, а затем строку " Это тест". cout « "\n\t3TO тест";
Глава 2 Функции, области видимости, пространства имен и заголовки Функции — это строительные блоки любой С/С++- программы. Элементы программы, включая функции, существуют в одной или нескольких областях действия (областях видимости). В языке C++ существует специальная область действия, называемая пространством имен. Прототипы для всех стандартных функций объявляются внутри различных заголовков. Эти темы и рассматриваются в данной главе. 1 Функции I LsBBSsassii^BSSBSsiiSBSssBssi^Bss^sssssssad В основе С/С++-программы лежит функция. Именно в функции сосредоточена вся деятельность любой программы. Основная форма записи функции имеет следующий вид. тип_возврата имя_функции(список_параметров) { тело_функции } Тип данных, возвращаемый функцией, задается с помощью элемента тип_возврата. Под элементом список__параметров подразумевается список разделенных запятыми переменных, которые могут принимать любые аргументы, передаваемые функции. Например, следующая функция имеет два целых параметра, именуемых i и j, а также параметр типа doubl e с именем count. void f(int i, int j , double count) { ¦ ¦ ¦ Обратите внимание на необходимость объявления каждого параметра в отдельности.
44 Рекурсия В версии С89, если тип данных, возвращаемый функцией, явно не задан, подразумевается тип int. В языке C++ и версии С99 "тип int по умолчанию" не поддерживается, хотя в большинстве компиляторов C++ такое положение по-прежнему остается в силе. При обнаружении последней фигурной скобки работа функции завершается и управление автоматически передается вызывающей процедуре. Однако с помощью оператора return можно выполнить принудительный (преждевременный) возврат в вызывающую процедуру. Все функции, за исключением тех, которые объявлены с помощью слова void, возвращают какое-либо значение. Тип возвращаемого значения должен совпадать с объявлением типа функции. Если оператор return является частью не Void-функции, то возвращаемым значением функции является значение, указанное в операторе return. В языке C++ можно создавать обобщенные функции, используя ключевое слово template. (См. раздел "template", приведенный в главе 5.) |Рекурсия В языках С и C++ функции могут вызывать сами себя. Этот процесс называют рекурсией, а функцию, которая сама себя вызывает, — рекурсивной. В качестве простого примера приведем функцию f actr (), вычисляющую факториал целого числа. Факториал числа N — это произведение всех целых чисел от 1 до N. Например, факториал числа 3 равен 1x2x3, т.е. 6. // Вычисляем факториал числа, используя рекурсию. int factr(int n) { int answer; if(n==l) return 1; answer = factr(n-1)*n; return answer; } Если функция factr () вызывается с аргументом, равным 1, значение возврата функции равно числу 1; в противном случае она возвращает произведение factr (п - 1) * п. Чтобы вычислить
Рекурсия 45 это выражение, функция factrO вызывается с аргументом п - 1. Процесс вызовов продолжается до тех пор, пока аргумент не станет равным единице (п = 1), после чего начнется процесс вычисления, возвращаемых значений. Когда наконец функция factrO вернется к инициатору исходного вызова, последнее значение возврата даст факториал исходного аргумента. ¦ Совет программисту Несмотря на всю свою мощь рекурсивные функции следует использовать с осторожностью. Рекурсивные варианты многих процедур выполняются гораздо медленнее, чем их итеративные эквиваленты, из-за "накладных расходов", связанных с повторяющимися вызовами функции. Кроме того, большое количество рекурсивных обращений к функции может вызвать переполнение стека. Поскольку параметры функции и локальные переменные хранятся в стеке и при каждом новом вызове создается новая копия этих переменных, стековое пространство может быстро исчерпаться. В таком случае и происходит переполнение стека. Если это замечено при отладке рекурсивной функции, попробуйте увеличить память стека, выделяемую вашей программе. В разрабатываемую рекурсивную функцию необходимо включить условный оператор, который непременно приведет к возврату из функции без выполнения рекурсивного вызова. Если этого не сделать, то одно-единственное обращение к данной функции приведет к тому, что она будет вызывать себя до тех пор, пока не исчерпается ее стек. Это весьма распространенная ошибка программистов, которые впервые берутся за разработку рекурсивных функций. Не скупитесь на операторы вывода во время разработки, чтобы вы могли наблюдать за происходящим в программе и прекратить ее выполнение, если увидите, что была допущена ошибка. Когда функция обращается к самой себе, в стеке выделяется память для новых локальных переменных и параметров и код функции с самого начала выполняется с этими новыми переменными. Рекурсивный вызов не создает новой копии функции. Новыми являются только аргументы. При возврате из каждого рекурсивного вызова из стека удаляются старые локальные переменные и параметры и выполнение возобновляется с места рекурсивного вызова внутри функций. О рекурсивных функциях говорят, что они "разворачиваются" и "сворачиваются"'. ¦,.•:.¦
46 Перегрузка функций Г Перегрузка функций | В языке C++ функции могут перегружаться. Когда говорят, что функция перегружена, это означает, что две или больше функций имеют одинаковые имена. Однако все версии перегруженной функции должны иметь различное количество или тип параметров. (Типы значений, возвращаемых перегруженными функциями, также могут отличаться один от другого, но это не является обязательным условием.) При вызове перегруженной функции компилятор точно определяет, какую версию функции нужно использовать. Решение компилятора основано на результатах анализа количества и типа аргументов, и вызова "удостаивается" та функция, которая точнее всего соответствует заданной "модели" вызова. Рассмотрим, например, следующие три перегруженные функции. void myfunc(int a) { cout « "а равно " << а << endl; // Перегружаем функцию myfunc. void myfunc(int a, int b) { cout « "а равно " « a « endl; cout « "b равно " << b « endl; // Ещё больше перегружаем'функцию myfunc". void myfunc(int a, double b) { cout <<. "а равно " << a << endl; cout <<" "b равно " << b « endl; } Теперь можно выполнять следующие обращения к функциям. myfuncA0); // вызов функции myfunc(int) myfuncA2,.24); // вызов функции myfunc(int, int) myfunc(99, 123 .33.) ;;// вызов функции myfunc(int,. double) В каждом случае для определения того, какая версия функции myfunc () будет в действительности выполнена, анализируются тип и количество аргументов. Перегрузка функций языком С не поддерживается.
Передача аргументов функции по умолчанию 47 Передача аргументов функции по умолчанию В языке C++ параметру функции можно присвоить значение по умолчанию, которое автоматически будет использовано в том случае, если при вызове функции соответствующий аргумент не будет задан. Задание значения, действующего по умолчанию, синтаксически аналогично инициализации переменной. Например, следующая функция по умолчанию присваивает своим двум параметрам заранее определенные (стандартные) значения. void myfunc(int a = 0, int b = 10) В результате такой "предусмотрительности" по части определения аргументов функцию myfunc () можно вполне законно вызывать следующими тремя способами. myfunc(); // а по умолчанию равно 0; Ь по умолчанию равно 10 ¦ , myfunc(-1); // для а передано значение -1; b по умолчанию равно 10 myfunc(-1, 99); // для а передано значение -1, для b —значение 99 При создании функции со стандартными значениями аргументов эти значения необходимо задать только однажды: либо в прототипе функции, либо в ее определении. (Значения, действующие по умолчанию, нельзя задавать дважды, даже если это будут те же самые значения.) Как правило, стандартные значения указываются в прототипе функции. Наделяя функцию стандартными значениями аргументов, помните, что сначала нужно задавать все нестандартные аргументы. Значения по умолчанию должны указываться последними в списке параметров функции, т.е. если уж вы начали задавать стандартные аргументы, то проследите, чтобы после этого в списке не было нестандартных. Передача аргументов по умолчанию в языке С не поддерживается.
48 Прототипы функций [Прототипы функций ¦ В языке C++ все функции должны иметь прототипы, а в языке С прототипы формально необязательны, но весьма желательны. Общая форма прототипа имеет следующий вид. тип_возврата имя_функции(список_параметров) ,• По сути, прототип — это просто объявление типа возвращаемого значения, имени и списка параметров функции, завершающееся точкой с запятой. Приведем пример прототипа функции f n (). float fn(float x); // прототип // Определение функции, float fn(float x) Чтобы задать прототип функции, которая принимает переменное количество аргументов, поставьте три точки в том месте, с которого начинается список, состоящий из переменного числа параметров. Например, прототип функции print f () может быть объявлен следующим образом. int printf(const char *format, ...); При задании прототипа для перегруженной функции каждая версия этой функций должна иметь собственный прототип. При объявлении функции-члена внутри своего класса используется прототип этой функции. В языке С для задания прототипа функции, не имеющей параметров, вместо списка параметров используется ключевое слово void, как, например, показано ниже. int f(void); В языке C++ пустой список параметров в прототипе функции означает, что функция не имеет параметров. Слово void
Области видимости и время жизни переменных 49 в этом случае необязательно. Следовательно, приведенный выше оператор можно переписать в таком виде. int f (); Использование в этом контексте слова void в языке C++ разрешено, но несет в себе избыточность. Совет программисту В программировании на языках С и C++ обычно путают два термина: объявление и определение. В объявлении указываются имя и тип объекта. Определение предназначено для выделения памяти для этого объекта. То же самое относится и к функциям. В объявлении функции (прототипе) указываются тип возвращаемого значения, имя и параметры функции. Сама же функция (т.е. функция с телом) является определением. Во многих случаях объявление также является определением. Например, объявление не extern-переменной является одновременно ее определением. Или, когда функция определяется до первого использования, ее определение также служит в качестве ее объявления. Области видимости и время жизни переменных В языках С и C++ определены правила видимости, которые устанавливают такие понятия, как видимость и время жизни объектов. Хотя существует несколько тонкостей, в самом общем смысле достаточно различать две области видимости: глобальную и локальную. Глобальная область видимости существует вне всех других областей. Имя, объявленное в глобальной области, известно всей программе. Например, глобальная переменная доступна для использования всеми функциями в программе. Глобальные переменные существуют на протяжении полного жизненного цикла программы. Локальная область видимости определяется границами блока, т.е. локальная область начинается с открывающей фигурной скобки и оканчивается закрывающей фигурной скобкой. Имя, объявленное внутри локальной области, известно только внутри
50 Пространства имен этой области. Поскольку блоки могут быть вложенными, локальные области также могут быть вложенными. Самой распространенной локальной областью является область, определенная функцией. Локальные переменные создаются при входе в их блок, а разрушаются при выходе из блока. Это означает, что локальные переменные не хранят своих значений между вызовами функций. А чтобы сохранить значения переменных между вызовами, можно использовать модификатор static. В языке C++ и версии С99 локальные переменные можно объявлять практически в любом месте блока, а в версии С89 они должны быть объявлены в начале блока, до выполнения каких-либо операторов "действия". Например, следующий код годится для языка C++ и версии С99, но никак не для С89. void f(int a) { int a; - а = 10; int b; // OK для C++ и версии С99, но не для С89 Глобальная переменная должна быть объявлена вне всех функций, включая функцию main (). Глобальные переменные, как правило, размещаются в начале файла, перед функцией main (), поскольку любая переменная должна быть объявлена до ее использования; кроме того, разместив глобальные переменные в определенном месте, можно облегчить чтение программы. Формальные параметры функции также являются локальными переменными, и их можно использовать не только как средство для получения значений аргументов при вызове функции, но и как любые другие локальные переменные. Пространства имен В языке C++ можно создать локальную область видимости, используя ключевое слово namespace. Пространство имен определяет некоторую декларативную область. Ее назначение — ограничить действие имен. Общая форма задания пространства имен имеет следующий вид.
Функция mainO 51 namespace имя { II . . . } Здесь имя означает имя пространства имен. Приведем пример. namespace. MyNameSpace { int count; } Этим объявлением создается пространство имен MyNameSpace, а внутри него объявляется переменная count. На имена, объявленные внутри некоторого пространства имен, могут напрямую ссылаться другие операторы внутри того же пространства имен. Вне своего пространства имен к именам можно получить доступ двумя путями. Во-первых, можно использовать оператор разрешения области видимости. Например, с учетом приведенного выше объявления MyNameSpace следующий оператор вполне правомочен. MyNameSpace::count =10; Во-вторых, можно использовать оператор using, который привносит заданное имя или пространство имен в текущую область видимости, как в примере, приведенном ниже. using namespace MyNameSpace; count = 100; В данном случае к переменной count можно обращаться напрямую, поскольку она теперь относится к текущей области видимости. Сразу после "рождения" языка C++ элементы, объявленные в библиотеке C++, относились к глобальному (т.е. безымянному) пространству имен. Однако действующий стандарт языка C++ все эти элементы относит к пространству имен std. Я Функция main () || Выполнение С/С++-программы начинается с выполнения функции main (). (Windows-программы вызывают функцию WinMain (), но это особый случай.) Программа не должна иметь более одной функции main (). По окончании работы
52 Аргументы функции функции main () выполнение программы завершается и управление возвращается операционной системе. Функция main ()' не имеет прототипа. Следовательно, можно использовать различные формы функции main (). Как для языка С, так и для языка C++ допустимы следующие варианты функции main (). (Разрешены и другие формы.) int main() int main(int argc, char *argv[]) Как видно из второй формы записи, функция main () поддерживает по крайней мере два параметра. Они называются argc и argv. (Некоторые компиляторы допускают использование дополнительных параметров.) Эти две переменные будут хранить количество аргументов командной строки и указатель на них соответственно. Параметр argc имеет целый тип, и его значение всегда будет не меньше числа 1, поскольку, как предуемотрено в языках С и C++, первым аргументом всегда является имя программы. Параметр argv должен быть объявлен как массив символьных указателей, в котором каждый элемент указывает на аргумент командной строки. Ниже приведена короткая программа, в которой демонстрируется использование этих аргументов. Итак, выполнив эту программу, вы увидите на экране дисплея свое имя. iinclude <iostream> using namespace std; int main(int argc, char *argv[]) { if(argc<2) cout << "Введите свое имя.Хп"; else cout << "Привет " << argv[l]; return 0; Аргументы функции Если в функции используются аргументы, она должна объявить переменные, которые принимают значения аргументов. Эти переменные называются формальными параметрами
Аргументы функции 53 функции. Они ведут себя подобно любым другим локальным переменным внутри функции, создаются при входе в функцию и разрушаются при выходе из нее. Как и в случае с локальными переменными, формальным параметрам функции можно присваивать значения или использовать их в любом выражении, разрешенном в языках С и C++. Несмотря на то что эти переменные выполняют специальную задачу получения значений аргументов, переданных функции, их можно использовать подобно любым другим локальным переменным. Вообще говоря, аргументы могут передаваться функциям двумя способами. Первый называется передачей по' значению. В этом случае значение аргумента копируется в формальный параметр функции. Изменения, вносимые в параметры функции, не оказывают никакого влияния на переменные, используемые при ее вызове. Второй способ, при котором функция может получить переданные ей аргументы, называется передачей по ссылке. В этом случае в параметр копируется адрес аргумента. Внутри функции адрес используется для получения доступа к реальному аргументу, используемому при вызове. Это значит, что изменения, внесенные в параметр, влияют на саму переменную, используемую для вызова функции. По умолчанию в языках С и C++ для передачи аргументов используется метод передачи по значению. Это значит, что внутри функции вообще нельзя изменить переменные, используемые при вызове функции. Рассмотрим следующую функцию. int sqr(int x) { х = х*х; return x; } В этом примере при выполнении присваивания х = х * х модифицируется только локальная переменная х. Аргумент, используемый для вызова функции sqr (), имеет свое первоначальное значение. Помните, что функции передается только копия значения аргумента. То, что происходит внутри функции, не оказывает никакого влияния на переменную, используемую при ее вызове.
54 Аргументы функции Передача указателей Несмотря на то что в языках С и C++ по умолчанию используется передача параметров по значению, можно вручную построить вызов функции с передачей параметров по ссылке. Для этого нужно аргументу передать указатель. Поскольку в таком случае функции передается адрес аргумента, оказывается возможным изменить значение аргумента вне функции. Указатели передаются функциям подобно любым другим значениям. Конечно же, необходимо объявить параметры как указатели. Например, рассмотрим функцию swap (), которая меняет местами значения двух своих целых аргументов. // Используем параметры-указатели. void swap{int *x, int *y) { int temp; temp = *x; // сохраняем значение, расположенное по адресу х *х = *у; // помещаем у-значение по адресу х *у = temp; // помещаем х-значение по адресу у } Важно помнить, что функцию swap () (или любую другую функцию, использующую параметры-указатели) нужно вызывать с адресами аргументов. В следующем фрагменте демонстрируется корректный способ вызова функции swap (). int a, b; а = 10; Ь = 20; swap(&a, &b); В этом примере функция swap () вызывается с адресами переменных а и Ь. Для получения адресов этих переменных используется унарный оператор &. Следовательно, функции swap () передаются адреса переменных а и Ь, а не их значения. После вызова этой функции переменная а примет значение 2 0, а переменная b — значение 10.
Аргументы функции 55 Параметры-ссылки В языке C++ адрес переменной можно передать функции автоматически. Это реализуется с помощью параметра- ссылки. При использовании параметра-ссылки функции передается адрес аргумента, и функция работает с аргументом, а не с копией. Чтобы создать параметр-ссылку, предварите его имя символом "амперсанд" (&). Внутри функции этот параметр можно использовать обычным способом, не прибегая к оператору "звездочка" (*). Компилятор будет автоматически разыменовывать адрес вместо вас. Например, в следующем фрагменте программы создается версия функции swap (), которая для обмена значениями двух своих аргументов использует два параметра-ссылки. // Используем параметры-ссылки, void swap(int &x, int &y) ,{ int temp; temp = x; // сохраняем значение, расположенное по адресу х х = у; // помещаем у в х у = temp; // помещаем х в у } При вызове функции swap () используйте обычный синтаксис вызова функции, как показано ниже. int a, b; а = 10; Ь = 20; swap(а, b); Поскольку х и у являются теперь параметрами-ссылками, адреса переменных а и Ь генерируются автоматически и передаются функции при ее вызове. Внутри функции имена параметров используются без оператора "звездочка" (*), поскольку компилятор автоматически обращается к аргументам вызова при каждом использовании параметров х и у. Параметры-ссылки применяются только в языке C++. щ
56 Конструкторы и деструкторы Конструкторы и деструкторы В языке C++ класс может содержать функцию конструктора, функцию деструктора или сразу обе. Конструктор вызывается при первоначальном создании объекта класса, а деструктор — при его разрушении. Имя конструктора совпадает с именем класса, членом которого он является. Имя деструктора также совпадает с именем класса, но ему предшествует символ "тильда" (--)• Ни конструкторы, ни деструкторы не имеют значений возврата. Функции конструкторов могут иметь параметры. Эти параметры можно использовать для передачи значений функции конструктора, чтобы инициализировать объект. Аргументы, передаваемые параметрам, задаются при каждом создании объекта. Например, в следующем фрагменте программы иллюстрируется передача аргумента конструктору. class myclass { int a ; public: myclass(int i) { a = i; } // конструктор -myclass() { cout << "Разрушение..."; } myclass obC); // передаем параметру i значение З При объявлении объекта ob значение 3 передается параметру конструктора i, которое затем присваивается члену а. Спецификаторы функций || В языке C++ определены три спецификатора функций: inline,-virtual и explicit. Спецификатор inline представляет собой обращенное к компилятору требование: вместо создания вызова функций раскрыть ее код прямо в строке. Если компилятор не может встроить функцию в строку, он имеет право проигнорировать это требование. Спецификатором inline могут определяться как функции-члены, так и не функции-члены.
Спецификация компоновки 57 В качестве виртуальной (с помощью спецификатора virtual) функция определяется в базовом классе и переопределяется производным классом. На примере виртуальных функций можно понять, как язык C++ поддерживает полиморфизм. Спецификатор explicit применяется только к конструкторам. Конструктор, определенный как explicit, будет задействован только в том случае, когда инициализация в точности соответствует тому, что задано конструктором. Никаких преобразований выполняться не будет (т.е. спецификатор explicit создает "неконвертирующий конструктор"). | Спецификация компоновки || Поскольку иногда некоторые С++-функции приходится компоновать с функциями, сгенерированными в других языковых средах (например, в среде языка С), C++ позволяет указывать спецификацию компоновки, которая сообщает компилятору, как компоновать данную функцию. Общая форма записи этой спецификации имеет следующий вид. extern "язык" прототил_функции Как видите, спецификация компоновки включает ключевое слово extern. Элемент язык означает среду создания функции, которую вы собираетесь компоновать. Компоновка языков С и C++ гарантированно поддерживается. Ваш компилятор может поддерживать также компоновку функций, созданных в других языках. Чтобы объявить несколько функций, используя одну и ту же спецификацию компоновки, можно использовать следующую общую форму. extern "язык" { прототипы_функций } Спецификация компоновки применяется в языке C++ и не поддерживается языком С.
58 Стандартные библиотеки С и C++ Стандартные библиотеки С и C++ || Ни в С, ни в C++ нет ключевых слов, обеспечивающих ввод- вывод, обрабатывающих строки, выполняющих различные математические вычисления или какие-нибудь другие полезные процедуры. Все эти операции выполняются за счет использования набора библиотечных функций, поддерживаемых компилятором. Существует два основных вида библиотек: библиотека С-функций, которая поддерживается всеми компиляторами С и C++, и библиотека классов C++, которая, разумеется, годится только для языка C++. Подробнее об этих библиотеках речь пойдет ниже в настоящем справочнике. Прежде чем ваша программа сможет использовать какую-нибудь библиотеку функций, она должна включить соответствующий заголовок. Вообще-то, под заголовками понимают заголовочные файлы, но на самом деле это необязательно должны быть именно файлы. Компилятор может внутренне предопределять содержимое заголовка. Однако для всех практических нужд стандартные С-заголовки содержатся в файлах, которые соответствуют их именам. Ниже перечислены стандартные заголовки, определенные стандартом С89 и поправкой 1995 года (Amendment 1). Заголовок Что поддерживает <assert.h> Макрос assert() <ctype. h> Обработка символов <errno.h> Сообщения об ошибках <f loat .h> Значения с плавающей точкой, зависящие от конкретной реализации компилятора <iso646 .h> Макросы, соответствующие различным операторам, например && и л. Добавлено в 1995 году (Поправка 1) <limits.h> Различные ограничения, зависящие от конкретной реализации компилятора <locale.h> Функция setlocale() <math. h> Различные определения, используемые библиотекой math
Стандартные библиотеки С и C++ 59 Заголовок Что поддерживает <setjmp.h> Нелокальные переходы <signal.h> Значения сигналов < s t darg. h> Списки аргументов переменной длины <stddef . h> Распространенные константы <stdio.h> Ввод-вывод файлов <stdlib.h> Смешанные объявления < s t r ing. h> Функции обработки строк < t ime. h> Функции системного времени и даты <wctype. h> Функции обработки многобайтовых слов и двубайтовых символов. Добавлено в 1995 году (Поправка 1) <wchar. h> Функции классификации многобайтовых слов и двубайтовых символов. Добавлено в 1995 году (Поправка 1) В следующей таблице перечислены заголовки, добавленные стандартом С99. щ Заголовок Что поддерживает <complex. h> Арифметика комплексных.чисел < f env. h> Флажки (признаки) состояния и другие аспекты среды обработки чисел с плавающей точкой <int types . h> Стандартный переносимый набор имен целочисленных типов; также функции, обрабатывающие целые числа самого широкого формата <stdbool. h> Логические типы данных; также определяет макрос bool, способствующий достижению совместимости с языком C++ <stdint. h> Стандартный переносимый набор имен целочисленных типов. Этот файл включен в заголовок <int types .h> <tgmath. h> Макросы, позволяющие работать с вещественными типами
60 Стандартные библиотеки С и C++ В современной спецификации для языка C++ заголовки указываются с использованием стандартных имен заголовков, которые не имеют расширения . h (т.е. заголовки C++ не означают имена файлов). Это просто стандартные идентификаторы, которые компилятор может обрабатывать так, как считает нужным (т.е. заголовок может быть преобразован в имя файла, но это вовсе необязательно). С++-заголовки приведены ниже. Указанная в скобках аббревиатура STL означает прямую или косвенную связь данного заголовка со стандартной библиотекой шаблонов (Standard Template Library). Заголовок C++ Что поддерживает Различные операции на контейнерах (STL) Битовые множества (STL) Комплексные числа Двухсторонние очереди (STL) Обработка исключительных ситуаций Работа с файловыми потоками для чтения и записи в один и тот же файл Различные объекты-функции (STL) Манипуляторы ввода-вывода Классы ввода-вывода нижнего уровня Упреждающие объявления для систем ввода-вывода Стандартные классы ввода-вывода Обработка входных потоков Доступ к содержимому контейнеров (STL) Различные ограничения реализации Линейные списки (STL) Информация, связанная с традициями конкретных стран или географических регионов Отображения (ключи и значения) (STL) Распределение памяти с помощью распределителей памяти (STL) <algorithm> <bitset> <complex> <deque> <exception> <fstream> <functional> <iomanip> <ios> <iosfwd> <iostream> <istream> <iterator> <limits> <locale> <map> <memory>
Стандартные библиотеки С и C++ 61 Заголовок C++ Что поддерживает <new> Выделение памяти с помощью оператора new <numeric> Универсальные операции над числами <ostream> Обработка выходных потоков <queue> Очереди (STL) <set> Множества (STL) <sstream> Обработка строковых потоков <stack> Стеки(SLT) <stdexcept> Стандартные исключительные ситуации <streambuf > Буферизированная обработка потоков <string> Стандартный класс string (STL) <typeinf o> Динамическая информация о типе <utility> Шаблоны общего назначения (STL) <valarray> Операции над массивами, содержащими значения <vector> Векторы (динамические массивы) (STL) В языке C++ также определены следующие заголовки, которые соответствуют С-заголовкам. <cassert> <cfloat> <clocale> <csignal> <cstdio> <ctime> <cctype> <ciso646> <cmath> <cstdarg> <cstdlib> <cwchar> <cerrno> <climits> <csetjmp> <cstddef> <cstring> <cwctype> В стандартном языке C++ вся информация, связанная со стандартной библиотекой, определена в пространстве имен std. Следовательно, для получения прямого доступа к этим элементам после включения нужного заголовка вам придется использовать следующий оператор using. using namespace std;
62 Стандартные библиотеки С и C++ В качестве альтернативного варианта, чтобы не вносить целую библиотеку в глобальное пространство имен, каждый библиотечный идентификатор можно квалифицировать с помощью обозначения std: :, например std: :cout. Однако в этом случае квалификация каждого имени будет выглядеть весьма громоздко. Совет программисту Если вы используете более старый компилятор C++, то может оказаться, что он не поддерживает С++-заголовки нового стиля или команду namespace. В этом случае вам придется использовать заголовки более старого традиционного стиля. Это значит, что к тем же самым именам заголовков нужно добавить расширение .h, после чего они будут напоминать С-заголовки. Например, так выглядит включение заголовка <iostream> при использовании традиционного подхода. #include <iostream.h> При использовании заголовка в традиционном стиле все имена, определенные этим заголовком, размещаются в глобальном пространстве имен, а не в пространстве имен std. Следовательно, в этом случае оператор us ing не требуется.
Глава 3 Операторы Языки С и C++ обладают богатым набором операторов, которые можно разделить на следующие категории: арифметические, операторы отношений и логические, поразрядные, адресные, операторы присваивания, ввода-вывода и смешанные. | Арифметические операторы Языки С и C++ позволяют использовать следующие семь арифметических операторов. Оператор Действие Вычитание, унарный минус + Сложение * Умножение / Деление % Деление по модулю Декремент ++ Инкремент ~~ В работе операторов +, -, * и / нет ничего неожиданного. Оператор % возвращает остаток от деления нацело (целочисленного деления). Операторы инкремента и декремента увеличивают или уменьшают значение операнда на единицу. Эти операторы подчиняются следующему порядку действий. Приоритет Операторы Наивысший ++ -- - (унарный минус) * / % Низший + - Операторы одного уровня старшинства вычисляются слева направо. щ
64 Операторы отношений и логические операторы Операторы отношений и логические операторы Операторы отношений и логические операторы, которые часто идут "рука об руку", используются для получения результатов в виде значений true/false ("истина"/"ложь"). В языках С и C++ любое ненулевое число оценивается как true. Нуль эквивалентен значению false. В языке C++ результат выполнения операторов отношений или логических операторов имеет тип bool, а в языке С — тип int (нуль или ненулевое целое). Ниже перечислены операторы отношений. Оператор Значение > Больше >=¦ Больше или равно < Меньше <= Меньше или равно == Равно ! = Не равно Список логических операторов вдвое короче. Оператор Значение && И I I ИЛИ ! НЕ Операторы отношений используются для сравнения, а логические операторы — для объединения двух значений или (в случае оператора !) для реверсирования значения. Приоритет этих операторов показан в следующей таблице. Приоритет Операторы Наивысший ! > >= < <= Низший I I
Поразрядные операторы 65 В качестве примера следующий оператор if оценивает выражение в скобках как равное значению true и выводит строкух меньше 10. х .= 9; if(x < 10) cout « "x меньше 10"; Однако в приведенном ниже примере сообщение выведено не будет, поскольку для того, чтобы результат был равен значению true, оба операнда, связанные оператором &&, должны быть истинными (равными значению true). х = 9; ' У = 9; if(х < 10 && у > 10) cout << "Эта строка выведена не будет."; | Поразрядные операторы ~J| В языках С и C++ реализованы операторы, которые выполняют действия над битами (двоичными разрядами), содержащими значения. Поразрядные операторы (они перечислены в следующей таблице) можно использовать только с целыми типами. ОператорЗначение & 1 » « Операторы &, И ИЛИ Исключающее ИЛИ Дополнение до 1 Сдвиг вправо Сдвиг влево I И А Таблица истинности для операторов &, 1 и Л ющий вид. р q 0 0 0 1 1 1 1 0 р & q Р 1 q 0 0 0 1 1 1 0 1 имеет следу- Р А q 0 1 0 1
66 Поразрядные операторы При выполнении поразрядных операций И, ИЛИ и исключающего ИЛИ эти правила применяются к каждому биту каждого операнда. :; ,.,, Приведем пример выполнения каждой из этих поразрядных операций. Итак, операция И. 01001101 & 0 0 11 10 11 0 0 0 0 10 0 1 Операция ИЛИ. ' 01001101 | 0011 1011 01111111 Операция исключающего ИЛИ. 01001101 0011 1011 0 1 1Д 0 110 Оператор дополнения до единицы Оператор дополнения до единицы, ~, будет инвертировать все биты операнда* Например, если символьная переменная ch имеет двоичный код 00111001, то после выполнения оператора ch = -ch,; двоичный код переменной ch будет иметь вид 11000110. Операторы сдвига Операторы сдвига вправо (») и влево («) сдвигают все биты целого значения на заданное число разрядов. При выполнении сдвига "выдвинутые" с одного конца операнда биты "теряются", а на другом конце освободившиеся позиции заполняются нулями. (Если же сдвигаемое вправо значение от-
Поразрядные операторы 67 рицательно, то для сохранения знака вдвигаются не нули, а единицы.) Число, стоящее справа от оператора сдвига, указывает количество сдвигаемых позиций. Общая форма записи операторов сдвига .имеет следующий вид. значение » количество значение « количество Здесь количество означает количество позиций, на которое будет сдвинуто значение. Если двоичный код значения (в предположении, что оно не имеет знака) равен , 00111101, то после сдвига вправо получим 0 0 0 11110, а после сдвига влево результатом будет 01111010. Совет программисту Сдвиг вправо эквивалентен делению на 2, а сдвиг влево— умножению на 2. Для большинства компьютеров операция сдвига выполняется намного быстрее., чем, ум» ножение или деление. Поэтому, если вам нужен быстрый способ умножения или деления на 2, воспользуйтесь операторами сдвигов. Например, в следующем .фрагменте программы значение переменной х сначала умножается, а затем делится на 2. int х; . , . :...-. . х '= 10; ¦•.•.*--¦ • • х = х « 1; ' •«•-''¦ • •¦'..'-.¦ х = х » 1; Конечно, при использовании операторов сдвига для выполнения умножения необходима проявить-бдительность, чтобы не "выдвинуть" навсегда все значащие биты. Ниже показан приоритет поразрядных операторов.
68 Адресные операторы Приоритет Операторы , Наивысший Низший Адресные операторы Адресными называются операторы * и &. Указатель — это переменная, содержащая адрес другого объекта. Или же о переменной, которая содержит адрес другого объекта, говорят, что она "указывает" на другой объект. Оператор взятия адреса & Оператор & возвращает адрес объекта, перед которым он стоит. Например, если целая переменная х расположена в памяти по адресу 1000, то после выполнения оператора Р = &х; ' , ' в переменную р будет помещено значение 1000. Поэтому оператор & можно называть оператором взятия адреса. Например, приведенную выше программную инструкцию можно прочитать как "поместить адрес переменной х в переменную р". Оператор разыменования адреса * Оператор * называют также оператором косвенности. Он использует текущее значение стоящей после него переменной в качестве адреса, по которому будут сохранены или получены некоторые данные. Например, после выполнения фрагмента программы р = &х; /* помещаем адрес переменной х в переменную р */ *р = 100; /* используем адрес, содержащийся в переменной р */ значение 100 будет помещено в переменную х. Оператор * можно "озвучивать" как фразу "по адресу". В данном примере вторую строку можно прочитать следующим образом:
Операторы присваивания 69 "размещаем значение 100 по адресу р". Поскольку переменная р содержит адрес переменной х, значение 100 фактически сохраняется в переменной х. О переменной р говорят, что она "указывает" на переменную х. Оператор * можно также использовать справа от оператора присваивания. Например, после выполнения фрагмента р = &х ; *р = 100; z = *р/10; значение 10 будет помещено в переменную z. | Операторы присваивания | В языках С и C++ оператором присваивания служит одиночный знак равенства (=). Присваивая "общее" значение сразу нескольким переменным, можно "связать воедино" несколько присваиваний. Например, программная строка а = Ь = с = 10'; присваивает значение 10 переменным а, Ь и с. Языки С и C++ поддерживают "сокращенный" вариант некоторых операторов присваивания. Если "полная" версия оператора присваивания выражается в общей форме записи переменная = переменная оператор выражение;, то запись такого типа можно "сократить" до следующего "укороченного" варианта: переменная оператор = выражение;. Например, операторы присваивания ' <: X = х+10; У = y/z; можно переписать в таком виде: х += 10; У /= Z;
70 Оператор? I Оператор ? Оператор ? называется тернарным оператором (поскольку он имеет дело с тремя операндами). Общая форма его записи такова. выражение! ? выражение2 : выражениеЗ; Если выражение1 истинно, то результатом этой операции будет значение операнда выражение2; в противном случае — значение операнда выражениеЗ. Совет программисту Оператор ? часто используется вместо операторов if- else следующего общего типа. .:-..,,,-, if (выражений!-/"переменная = выражеше2; else переменная = выражениеЗ; Например, программные строки if(У < 10) X = 20; else' х = 40; .' ' . . . можно переписать в более лаконичном виде: '., х =,Ду<10У?' 20'': '40;. " •'; В данном примере переменной х присваивается значение 20, если у меньше 10, и значение 40 в противном случае. Преимущество использования оператора ? состоит не только в экономии вашего времени при вводе текста программы, но и в том, что для этого оператора компилятор генерирует весьма быстродействующий к'од, который работает гораздо быстрее, чем код эквивалентного ему оператора i f - е 1 s e. Операторы доступа к членам объектов Оператор . (точка) и оператор -> (стрелка) используются для доступа к отдельным членам классов, структур и объединений. Оператор "точка" применяется к реальному объекту, а
Оператор последовательного вычисления 71 оператор "стрелка" используется с указателем на объект. Например, объявим следующую структуру. struct date_time**-f char date[16]; ' . int time; } tm; Затем, чтобы присвоить значение /12/99" члену date объекта tm, запишем следующее. strcpyUm.date, lL/12/99") ; Однако если переменную p_tm объявить указателем на объект типа dat e_t ime, то нужно использовать следующий оператор. strcpy(p_tm->date, /12/99"); щ Оператор последовательного вычисления Оператор последовательного вычисления (оператор "запятая") указывает на необходимость выполнения некоторой последовательности операций. Значение всего выражения, состоящего из списка выражений,' разделенных запятыми, равно значению последнего выражения в этом списке. Например, после выполнения фрагмента программы У = 15; , ' х = (у=у-5, 50/у); переменная х примет значение 5, поскольку исходное значение переменной у, равное числу 15, уменьшено на 5, а затем число 50 разделено на полученную разность A0). В результате имеем число 5, которое и присваивается переменной х. Оператор "запятая" можно представить себе как инструкцию "сделать это, затем то и т.д.". Оператор "запятая" чаще всего используется в операторе for, как, например, показано ниже. for(z=10, b=20; z<b; z++, b—) {//... Здесь переменные z и b инициализируются и модифицируются с использованием списка выражений, разделенных запятыми.
72 Оператор sizeof Оператор sizeof Ключевое слово sizeof может послужить в качестве оператора времени компиляции, используемого для определения размера (в байтах) переменной или типа данных, включая классы, структуры и объединения. При использовании вместе с типом имя типа должно быть заключено в круглые скобки. Для большинства 32-разрядных компиляторов при выполнении следующего примера будет выведено число 4. int x; cout << sizeof x; [ Оператор приведения типа Д Оператор приведения типа заставляет компилятор преобразовать один тип данных в другой. Как язык С, так и язык C++ поддерживают следующую форму записи операции приведения типа. [тип) выражение Здесь элемент тиггозначает желаемый тип данных. Например, после выполнения следующей операции приведения типа результат деления заданных целых чисел будет иметь тип double. . double d; d = (double) 10/3; Операторы приведения типа в языке C++ Язык C++ поддерживает дополнительные операторы приведения типа: const_cast, dynamic_cast, reinterpret_cast и static_cast. Их общие формы записи выглядят следующим образом. const_cast<Tnn> (объект) dynamic_cast<Tnn> (объект) reinterpret_cast<Tjm> (объект) static_cast<T*m> (объект) Здесь элемент тип задает новый тип, а элемент объект — объект, который должен приобрести новый тип.
Операторы ввода-вывода 73 Оператор const_cast используется для явного переопределения модификаторов const и/или volatile. Новый тип должен совпадать с исходным типом, за исключением изменения его атрибутов const или volatile. Чаще всего оператор const_cast используется для удаления атрибута const. Оператор dynamic_cast проверяет законность выполнения заданной операции приведения типа. Если такую операцию выполнить нельзя, то выражение устанавливается равным нулю. Этот оператор в основном используется для полиморфных типов. Например, если даны два полиморфных класса, В и D, причем класс D выведен из класса В, то оператор dynamic_cast всегда может преобразовать указатель D* в указатель В*. Оператор dynamic_cast может преобразовать указатель В* в указатель D* только в том случае, если адресуемым объектом является объект D. И вообще, оператор dynamic_cast будет успешно выполнен только при условии, что разрешено полиморфное приведение типов (т.е. если новый тип можно законно применять к типу объекта, который подвергается этой операции). Если операцию приведения типа выполнить нельзя, результат действия оператора dynamic_cast оценивается как нулевой. Оператор static_cast выполняет неполиморфное приведение типов. Например, его можно использовать для приведения указателя на базовый класс к типу указателя на производный класс. Его можно также использовать Для любого стандартного преобразования. При этом никакие проверки во время работы программы не выполняются. Оператор reinterpret_cast переводит один тип в совершенно другой. Например, его можно использовать для перевода указателя в целый тип, Оператор :reinterpret_cast следует использовать для перевода типой* указателей, которые несовместимы по своей природе. Однако следует помнить, что только оператор const_cast может освободить от "обета постоянства", т.е. ни один из остальных операторов этой группы (dynamic_cast, static_cast, reinterpret_cast) не может "снять" с объекта атрибут const. | Операторы ввода-вывода || В языке C++ операторы « и » перегружены для выполнения операций ввода-вывода. Если в выражении левым операн- т
74 Операторы указания на члены.* и ->* дом является поток, то символы » служат для обозначения оператора ввода, а символы « — оператора вывода. В языке C++ оператор » называется экстрактором (extractor), поскольку он выделяет данные из входного потока. Оператор « можно назвать реализатором вставки (inserter), поскольку он вставляет данные в выходной поток. Общие формы записи этих операторов имеют следующий вид. входной_поток >> переменная выходной_поток.« выражение ... Например, приведенный ниже фрагмент программы обеспечивает ввод значений двух целых переменных. int i, j; cin » i » j; ' После выполнения следующего оператора на экране появится надпись Это тест 10 20. cout « "Это тест " « 10 « ' ' « 4*5; Рассмотренные операторы ввода-вывода не поддерживаются языком С. | Операторы указания на члены . * и -| Язык C++ позволяет генерировать специальный тип указателя, который отсылает не к конкретному экземпляру этого члена в объекте, а к члену класса вообще. Данный вид указателя называется указателем на член. Указатель на член — это совсем не то же самое, что обычный указатель, поддерживаемый в языке C++. Указатель на член предоставляет лишь смещение в объекте класса, которому этот член может принадлежать. Поскольку указатели на члены не являются настоящими указателями, к ним нельзя применять операторы . и ->. Для получения доступа к члену класса, заданного указателем, необходимо использовать специальные операторы указания на члены . * и ->*. При доступе к члену объекта, заданного самим объектом или ссылкой на него, используйте оператор . *. При доступе к члену, заданному указателем на объект, используйте оператор - > *. Указатель на член объявляется с помощью следующей общей формы записи.
Операторы указания на члены .* и ->* 75 тип имя_класса::*ptr; Здесь тип представляет собой базовый тип члена, имя_класса задает имя класса, ар?г — это имя создаваемой переменной указателя на член. После создания элемент ptr может отсылать к любому члену своего класса, который имеет тип, заданный элементом тип. Ниже приведен короткий пример, демонстрирующий использование оператора . *. Обратите особое внимание на способ объявления указателей на члены. ¦ include <iostreain> '¦''¦' ¦ using namespace sfcd; class cl { public: cl(int i) { val=i; } int val; int double_val() { return val+val; } int main() int сГ: :*dataV '7,А'-у1сЬзатёль й // с именем data типа int » int (cl: :*func)-() ; // указатель на член с именем ¦ // func cl obl(l), ob2 B'j'¦;¦'// создаем объекты data = &cl::val; // получаем смещение func = &cl::double_Val; // получаем смещение "Вот исходные значения: "; cout « obl.*data « " " « ob2.*data « "\n"; cout << "А теперь они удвоены: "; cout « (obl.*func)() « " cout «: (ob2. *func) () « "\n"; , . : • ' return 0; } Операторы указания на члены в языке С не поддерживаются.
76 Оператор разрешения области видимости:: Оператор разрешения области ВИДИМОСТИ : : Оператор разрешения области видимости -. : задает область видимости, которой принадлежит некоторый член. Этот оператор имеет следующую общую форму записи. имя::имя_члена Здесь элемент имя задает имя класса или пространства имен, в котором содержится член, заданный элементом имя_члена. Другими словами, имя определяет область видимости, внутри которой может находиться идентификатор, заданный элементом имя_члена. При ссылке на глобальную область видимости элемент имя задавать не нужно. Например, чтобы обратиться к глобальной переменной с именем count, которая "скрыта" за локальной переменной с таким же именем count, используйте оператор : : следующим образом. ::count Оператор разрешения области видимости в языке С не поддерживается. [ Операторы new И delete _) Операторы new и delete — это С++-операторы динамического выделения памяти. Одновременно они являются ключевыми словами. (Подробнее об этом речь пойдет в главе 5.) В языке С операторы new и delete не поддерживаючрся. | Оператор typeid В языке C++ оператор typeid возвращает ссылку на объект type_inf о, описывающий тип объекта, к которому применяется оператор typeid. Общая форма записи оператора typeid такова. typeid(объект)
Перегрузка операторов 77 Оператор typeid поддерживает в языке C++ возможность идентификации динамической информации о типе (RTTI). Класс type_inf о определяет следующие открытые члены. bool operator==(const type_info &оЬ) const; bool operator!=(const type_info &ob) const; bool before(const type_infо bob) const; const char *name() const; Перегруженные операторы == и ! = служат для сравнения типов. Функция before () возвращает значение true, если вызывающий объект в порядке сопоставления стоит перед объектом, используемым в качестве параметра. (Эта функция предназначена в основном для внутреннего использования. Ее значение возврата не имеет ничего общего с наследованием или иерархией классов.) Функция name () возвращает указатель на имя типа. Если оператор typeid применяется к указателю полиморфного класса, он автоматически возвращает тип объекта, на который он указывает. (Полиморфный класс — это класс, который содержит хотя бы одну виртуальную функцию.) Следовательно, оператор typeid можно использовать для определения типа объекта, адресуемого указателем на базовый класс. В языке С оператор typeid не поддерживается. [ Перегрузка операторов "| В языке C++ операторы могут перегружаться С помощью ключевого слова operator (см. гл. 5). В языке С перегрузка операторов не поддерживается. щ Сводная таблица приоритетов операторов В следующей таблице показан приоритет выполнения всех операторов С и C++. Обратите внимание на то, что все операторы, за исключением унарных, операторов присваивания и оператора ?, выполняются слева направо.
78 Сводная таблица приоритетов операторов Приоритет Операторы Наивысший ( ¦) []->::. ! _++___* & s-izeof new delete typeid Операторы приведеюот типа .* ->* * / % + . - ... ,... I I a += -= *= /= %= »= «= Sc= л= | = Низший , ^
Глава 4 Препроцессор и комментарии Щ Языки С и C++ включают ряд директив препроцессора, которые используются для выдачи инструкций компилятору. #define terror ¦include ielif #if #line #else #ifdef ipragma #endif iifndef #undef Все директивы препроцессора кратко рассматриваются в следующих разделах. #define Директива #define используется для выполнения макроподстановок одного текстового фрагмента другим по всему файлу, в который включена эта директива. Общая форма записи директивы idef ine имеет следующий вид. #define имя_макроса последователъность_символов После включения этой директивы каждое вхождение текстового фрагмента, определенное как имя_макроса, заменяется заданным элементом последовательность_символов. Обратите внимание на то, что в этом операторе нет точки с запятой. Кроме того, заданная последовательность_символов завершается только символом конца строки. Например, если вы хотите использовать значение 1 для слова TRUE и значение 0 для слова FALSE, объявите эти два макроса с помощью отдельных директив #def ine. ttdefine TRUE 1 ttdefine FALSE 0
80 #define Данные операторы вынудят компилятор подставлять 1 или 0 каждый раз, когда встретится слово TRUE или FALSE соответственно. Совет программисту , При создании макросов, внешне напоминающих функции, нужно позаботиться о наличии скобок. Если этого не сделать, в некоторых ситуациях такие макросы могут попросту не сработать. Например, круглые скобки, в которые заключен аргумент а в предыдущем примере, необходимы для гарантии корректной замены абсолютно во всех случаях. Если бы круглых скобок вокруг аргумента а не было, то выражение ABSCL0-20) было бы преобразовано в выражение 10-20<0 ? -10-20 : 10-20. Такая подстановка, конечно же, приводит к неверному результату. Если у вас есть макрос, который "плохо себя ведет", то, в первую очередь, проверьте наличие круглых скобок вокруг его аргумента. Директива idefine имеет еще один {более сложный) вариант применения: макрос может иметь аргументы. Макрос, который принимает аргументы, действует во многом подобно функции. Он и выглядит как функция, оставаясь при этом макросом, или макроопределением. Каждый раз, когда компилятор обнаруживает такой макрос, его аргументы заменяются реальными аргументами, заданными в программе, как, например, показано ниже. iinclude <iostream> using namespace std; #define ABS(a) <(a)<0 г -(a) : (a) ) int main() { cout « "abs of -1 and 1: " « ABS(-l) « ' ' « ABSA); return 0;
#error 81 При компиляции этой программы переменная а в макроопределении будет заменена значениями -1 и 1. 1#error Директива #error дает указание компилятору остановить компиляцию. Она используется в основном для отладки. Общая форма ее записи такова. terror сообщение При встрече с директивой #error отображается заданное сообщение и номер строки. #if, #ifdef, #ifndef, #else, #elif И ttendif Директивы #if, #ifdef, #ifndef, #else, #elif и ttendif используются для избирательной компиляции различных фрагментов программы. Главная идея состоит в том, что если выражение, стоящее после директив #if, #ifdef и ttifndef, оказывается истинным, то будет скомпилирован код, расположенный между одной из этих трех директив и директивой ttendif; в противном случае данный код будет опущен. Директива ttendif используется для обозначения конца блока #if. Директиву ttelse можно использовать с любой из перечисленных выше директив для предоставления альтернативного варианта компиляции. Общая форма записи директивы #if выглядит так. #if константное_выражение Если константное выражение является истинным, будет скомпилирован код, расположенный непосредственно за этой директивой. Общая форма записи директивы # i f def такова. ttifdef имя_макроса Если имя_макроса определено в операторе ttdefine, то будет скомпилирован блок кода, следующий за оператором #ifdef.
82 #if, #ifdef, #ifndef, #else, #elif и #endif Общая форма записи директивы #ifndef такова. #ifndef имя_макроса Если имя__макроса не определено в операторе #def ine, то будет скомпилирован блок кода, следующий за оператором #ifndef. Вот пример совместной работы некоторых директив препроцессора. #define ted 10 II... #ifdef ted cout « "Привет, Тэд\п"; < #endif cout « "Привет, Джон\п" ,- #if 10<9 cout << "Привет, Жорж\п"; #endif В результате выполнения этого фрагмента программы на экран будут выведены фразы Привет, Тэд и Привет, Джон, а фраза Привет, Жорж — нет. Директива #eli? используется для создания оператора if -else-if. Его общая форма имеет такой вид. #elif выражение_константа Для обработки сразу нескольких альтернатив можно использовать ряд директив # е 1 i f. С помощью директив #if и ielif и оператора предпроцес- сорной обработки defined можно также выяснить, определено ли имя конкретного макроса директивой препроцессора define. Для этого используется следующая общая форма записи. #if defined имя_макроса последовательность_операторов #endif Если имя_макроса определено, последователь- ность_операторов будет скомпилирована. В противном случае она будет опущена. Например, в следующем фрагменте условный оператор компилируется, поскольку имя макроса DEBUG определено в программе.
#include 83 Idefine DEBUG // ... int i=100; // ... #if defined DEBUG cout << "Значение переменной i равно: " << i « endl ; #endif Можно также оператор defined предварить оператором отрицания (!), и тогда условная компиляция будет выполнена в случае, если заданное имя макроса не определено. | #include ' Директива #include заставляет компилятор прочитать и скомпилировать указанный исходный файл. Для записи этой директивы используются следующие общие формы. #include "имя_файла" ¦include <имя_файла> Имя исходного файла, подлежащего прочтению, должно быть заключено в двойные кавычки или угловые скобки. Например, оператор # incIude <MyFunc s.h> заставит компилятор прочитать и скомпилировать файл MyFuncs.h. Если имя файла заключено в угловые скобки, то поиск файла будет осуществляться способом, определенным создателем компилятора. Часто это означает, что поиск выполняется в некотором специальном каталоге, выделенном для заголовочных файлов. Если же имя файла заключено в кавычки, поиск файла выполняется другим способом, зависящим от конкретной реализации. Во многих случаях это. означает поиск текущего рабочего каталога. Если заданный файл не найден, поиск повторяется с использованием первого способа (как если бы имя файла было заключено в угловые скобки). Чтобы ознакомиться с подробностями, связанными с различной обработкой директивы #include в случае использования угловых скобок и двойных кавычек, обратитесь к руководст-
84 #line ву пользователя, прилагаемому к вашему компилятору. Операторы #include могут быть вложенными внутри других включаемых файлов. Помимо включения файлов, С/С++-программы используют директиву #include для включения заголовков. В языках С и C++ определен набор стандартных заголовков, которые предоставляют информацию, необходимую для различных библиотек (т.е. под заголовком может подразумеваться файл, но это совсем необязательно). Таким образом, заголовок— это просто абстракция, которая гарантирует включение соответствующей информации. Однако на практике С-заголовки почти всегда являются файлами, а имена заголовков — действительными именами файлов. Но для языка C++ ситуация совсем иная. Все имена С++-заголовков представляют собой стандартные идентификаторы, которые компилятор может преобразовать в имена файлов или обработать каким-либо другим способом. А поскольку С++- заголовки не являются именами файлов, они не имеют расширения . п. Например, чтобы включить заголовочную информацию для системы ввода-вывода, используйте следующий оператор. #include <iostream> Здесь <iostream>— стандартный заголовок для классов ввода-вывода. #line Директива #line используется для изменения содержимого псевдопеременных LINE и FILE .которые являются зарезервированными идентификаторами. Базовая форма записи этой команды имеет следующий вид. #line номер "имя_файла" Здесь номер — это любое положительное число, а имя_файла — любой допустимый идентификатор файла. Значение элемента номер становится номером текущей исходной строки, а значение элемента имя_файла — именем исходного файла. Имя файла — элемент необязательный. Директива iline используется, главным образом, в целях отладки и в специальных приложениях. Идентификатор LINE_ _ имеет целый тип, а псевдопеременная _ _FILE_ _ определена как строка с завершающим нулевым символом.
#pragma 85 Например, следующий фрагмент программы устанавливает текущий счетчик строк равным 10, а имя файла — строке "test". #line 10 "test" I#pragma Работа директивы ipragma зависит от конкретной реализации компилятора. Она позволяет выдавать компилятору различные инструкции. Например, компилятор способен поддерживать трассировку выполнения программы. Заставить компилятор работать в режиме трассировки можно именно с помощью оператора #pragma. Для получения подробной информации о возможных вариантах использования директивы #pragma обратитесь к системной документации по используемому вами компилятору. Оператор „Pragma В версии С99 Версия С99 включает еще один способ выдачи указаний компилятору с помощью оператора _Pragma. Общая форма записи такова. _Pragma ("директива") Здесь элемент директива, означает задаваемую инструкцию (прагму). Оператор _Pragma был добавлен, чтобы дать возможность компиляторным инструкциям участвовать в макрозаменах. Встроенные прагмы версии С99 В версии С99 определены следующие встроенные прагмы. Прагма Значение STDC FP_CONTRACT Во включенном состоянии (ON) с выра- ON/OFF/DEFAULT жениями с плавающей точкой компилятор обращается, как с неделящими- ся нацело элементами, которые обрабатываются аппаратными методами. Стандартное состояние определяется конкретной реализацией
86 #undef Прагма Значение STDC FENV_ACCESS Сообщает компилятору о возможнос- ON / OFF / DEFAULT ти доступа к среде вычислений с плавающей точкой. Стандартное состояние определяется конкретной реализацией STDC Во включенном состоянии (ON) сооб- CX_LIMITED_RANGE щает компилятору, что определенные ON/ OFF /DEFAULT формулы, содержащие комплексные значения, безопасны для использования. Стандартное состояние — от- . ключенное (OFF) #unde? J Директива #undef удаляет определенное ранее имя макроса. Общая форма записи такова. #undef имя_макроса Например, в фрагменте программы #define LEN 100 #define WIDTH 100 char array[LEN][WIDTH]; #undef LEN iundef WIDTH /* С этого момента идентификаторы LEN и WIDTH не определены. */ идентификаторы LEN и WIDTH определены до тех пор, пока не встретятся соответствующие операторы #undef. [ Операторы препроцессора # и ## Д В языках С и C++ предоставляется возможность работы с двумя операторами препроцессора: # и ##. Эти операторы используются в директиве определения макроса #def ine.
Операторы препроцессора # и ## 87 Оператор # превращает аргумент, которому он предшествует, в строку, заключенную в кавычки. Рассмотрим, например, следующую программу. ttinclude <iostream> using namespace std; #define mkstr(s) # s int main(> { - cout << mkstr(H люблю C++); return 0; } Препроцессор превратит строку cout << mkstr(H люблю C++); в строку cout « "Я люблю C++";. Оператор ## используется для конкатенации двух лексем. Например, в программе iinclude <iostream>. using namespace std; #define concat(a, b) a ## b int main{) { int xy = 10; cout « concat(x, y); R^^^^^H] return 0; • | ' i препроцессор превратит строку cout << concat(x,у); в строку cout « xy;.
88 Зарезервированные имена макросов Если эти операторы кажутся вам странными, имейте в виду, что большинство программ обходится без них. Они существуют, главным образом, для того, чтобы сделать возможной обработку препроцессором некоторых специальных случаев. Зарезервированные имена макросов В языках С и C++ определены пять встроенных имен макросов. LINE FILE DATE TIME cplusplus Макросы _ _LINE_ _ и _ _FILE_ _ описаны при рассмотрении директивы #line выше в этой главе. Остальные приводятся ниже. Макрос _ _DATE_ _ представляет собой строку в формате месяцIденьIгод, которая означает дату трансляции исходного файла в объектный код. Время трансляции исходного файла в объектный код содержится в виде строки в макросе TIME . Формат строки следующий: часы:минуты:секунды. Макрос _ _cplusplus определяется при компиляции С++-программы. Этот макрос не определяется компилятором языка С. Макрос STDC определяется при компиляции С-программы и может быть определен компилятором языка C++. В обоих случаях за деталями лучше обратиться к системной документации по используемому вами компилятору. Большинство компиляторов C/C++ определяют несколько других встроенных макросов, которые связаны с конкретной средой и реализацией. Дополнительные встроенные макросы, определенные в версии С99 В версии С99 к опиеанным выше макросам добавлены следующие макросы. Они не поддерживаются в языке C++.
Комментарии 89 STDCJHOSTED 1, если операционная система присутствует STDC_VERSION 199901L или больше: представляет версию языка С _ _STDC_IEC_559_ _ 1, если поддерживается арифметика с плавающей запятой IEC 60559 _ _STDC_IEC_559_COMPLEX 1, если поддерживается арифметика комплексных чисел IEC 60559 _ _STDC_ISO_10646_ _ Значение в формате yyyymmL, сообщающее год и месяц поддерживаемой компилятором спецификации ISO/IEC 10646 щ ) Комментарии В языке C++ и версии С99 определены два стиля комментариев. Первый — многострочный. Он начинается с символов /* и завершается символами */. Все, что находится между символами комментария, компилятор игнорирует. Многострочный комментарий может занимать несколько строк. Второй тип комментария — однострочный. Он начинается с символов / / и завершается в конце той же строки. В версии С89 поддерживается только один тип комментария — многострочный. Однако большинство компиляторов С89 допускают и однострочные комментарии, несмотря на их? нестандартность. Списки с переменным количеством аргументов В версии С99 добавлена возможность создания макросов, которые принимают переменное количество аргументов. В определении макроса этот момент обозначается многоточием (...). Встроенный идентификатор предпроцессорной обработки
90 Списки с переменным количеством аргументов _ _VA_ARGS_ „определяет, куда будут подставляться аргументы. Например, после включения в программу определения #define MyMax(...) max( VA_ARGS ) оператор . МуМах(а, b); преобразуется в оператор max(а, Ь);. До обозначения переменного количества аргументов (...) макрос может иметь другие аргументы. Например, после определения #define compare(compfunc, ...) compfunc(_ _VA_ARGS ) оператор compare(s trcmp, "one", "two"); преобразуется в оператор strcmp("one", "two");. Как видно из примера, встроенный идентификатор _ _VA_ARGS заменяется всеми остальными аргументами.
Глава 5 Ключевые слова В версии С89 определено 32 ключевых слова. auto break case char const continue default do double else - enum extern float s for goto if mt long register return short signed sizeof static struct switch typedef union unsigned void volatile while В языке C++ содержатся все ключевые слова, определенные в версии С89, а также следующие. asm export bool catch class const_cast delete dynamic_cast explicit false friend inline reinterpret_cast mutable namespace new operator private protected public static_cast template this throw true try typeid typename using virtual wchar_t В более старых версиях языка C++ было также определено ключевое слово overload, но сейчас оно не используется. Все ключевые слова состоят только из строчных букв.
92 asm В версии С99 содержатся все ключевые слова, определенные в версии С89, а также следующие. _Bool „Complex „Imaginary inline restrict Ниже приводится краткое описание этих ключевых слов. (asm II Ключевое слово asm используется для вставки в С++- программу одной или нескольких инструкций ассемблерного кода. Общая форма записи оператора asm имеет следующий вид. asm ("инструкция"); Здесь элемент инструкция означает оператор языка Assembler, который передается непосредственно компилятору для сборки в вашей программе. Многие компиляторы языка C++ позволяют использовать дополнительные формы оператора asm. Например, Borland C++ допускает применение следующих операторов asm. asm инструкция; asm { послвдовательность_инструкций > Здесь последовательность_инструкций означает список инструкций ассемблерного кода. lauto I Ключевое слово auto объявляет локальные переменные. Оно совершенно необязательно и используется крайне редко. |bool Д Спецификатор типа bool используется для объявления в языке C++ логических значений (т.е. истина/ложь).
Bool 93 1-B°O1 I Версия С99 включает тип данных _Воо1, который позволяет хранить значения 1 и 0 (т.е. истина/ложь). _Воо1 означает целый тип, который отличается от ключевого слова bool, определенного в языке C++. Таким образом, языки С99 и C++ несовместимы по этому типу. Кроме того, в языке C++ определены логические константы true и false, а в версии С99 — нет. Но вместе с тем в версию С99 добавлен заголовок <stdbool. h>, который определяет макросы bool, true и false. Поэтому С/С++- совместимый код можно создать без особых проблем. Причина того, что в качестве ключевого для версии С99 было определено слово _Воо1, а не bool, состоит в том, что во многих существующих программах уже были определены собственные пользовательские версии слова bool. Поэтому определение логического типа _Воо1 позволило избежать приведения уже существующего кода в нерабочее состояние. Однако для новых С-программ лучше включать заголовок <stdbool. h>, а затем использовать макрос bool. Ключевое слово break используется для выхода из циклов do, f or и whi I e в обход обычного условия выхода из цикла. Оно также используется для выхода из блока оператора s wi t ch. Ниже показан пример оператора break в цикле. do { х = getx () ,- if(x < 0) break; // выход из цикла, если значение х отрицательно process(x); } while(!done); На этом работа цикла завершается, если значение переменной х оказалось отрицательным. В операторе switch оператор break не позволяет программе выполнять набор операторов, относящихся к следующему оператору case. (За подробностями обращайтесь к разделу "switch", приведенному ниже в этой главе.)
94 case Оператор break прекращает работу только тех циклов for, do, while и оператора switch, которые его содержат. Он не прервет работу ни одного из вложенных циклов или операторов swi t ch. case Оператор case используется вместе с оператором switch. (См. раздел "switch", приведенный ниже в этой главе.) |catch | Оператор catch обрабатывает исключение, сгенерированное оператором throw. (См. раздел "throw", приведенный ниже в этой главе.) I char. ¦, .. - ,. .¦ _ . ¦ .. ¦ '¦..¦'¦¦ Тип данных char используется для объявления символьных переменных. I class . "-'¦' : ¦¦'•¦'" ¦;•'" '" ' • ¦ I Ключевое слово class используется для объявления класса — основного элемента инкапсуляции в языке C++. Ниже показана общая форма записи класса. class имя_класса :- список_наследования { // Закрытые члены по умолчанию, protected: // Закрытые члены, которые могут быть // унаследованы, public: // Открытые члены. } список_объектов; Здесь имя_класса — это имя нового типа данных, генерируемого объявлением class. Список_наследования, который необязателен, задает базовые классы, наследуемые новым классом. По умолчанию члены класса являются закрытыми.
.Complex 95 Их можно объявить защищенными или открытыми с помощью ключевых слов protected или public соответственно. Элемент список_объектов также необязателен. Если он отсутствует, то объявление класса просто задает форму класса, но не создает ни одного объекта класса. (За дополнительной информацией о классах обращайтесь к главе 1.) _Complex Версия С99 содержит ключевое слово „Complex, которое поддерживает арифметику комплексных чисел. В новом стандарте языка С определены следующие типы „Complex. float „Complex double „Complex long double „Complex Причина того, что в качестве ключевого для версии С99 было определено слово „Complex, а не complex, состоит в том, что во многих существующих программах для работы с комплексными числами уже были определены собственные пользовательские типы данных, использующие слово complex. Поэтому использование ключевого слова „Complex позволило избежать приведения уже существующего кода в нерабочее состояние. Заголовок <complex.h> определяет (кроме всего прочего) макрос complex, которому соответствует значение „Complex. Поэтому для новых С-программ лучше включать заголовок <complex. h>, а затем использовать макрос complex. COnat Модификатор const уведомляет компилятор о том, что данная переменная не может быть изменена программой. Однако const-переменной при ее объявлении можно присвоить любое начальное значение.
96 const_cast c6n6t cast Оператор const_cast используется для явного переопределения модификаторов const и/или volatile. Общая форма его записи такова. const_cast<Tjm> (объект) Новый тип должен совпадать с исходным типом, за исключением изменения его атрибутов const и volatile. Чаще всего оператор const_cast используется для удаления признака постоянства (атрибута const). I continue ^^ J Оператор continue используется для пропуска оставшихся операторов в теле цикла и передает управление на следующую итерацию, которая начинается с вычисления условного выражения. Например, следующий цикл while будет просто читать символы с клавиатуры до тех пор, пока не будет введена буква s. while(ch = getchar(J) ¦{ if(ch != 's') continue; // читаем следующий / / символ. process(ch); } . . Обращение к функции process () не произойдет до тех пор, пока переменная ch не будет содержать символ s. default Ключевое слово default используется в операторе switch, чтобы сигнализировать о том, что, если в операторе switch не обнаружится ни одного совпадения, будет выполнен блок кода, помеченный ключевым словом default. (См. раздел "switch", приведенный ниже в этой главе.)
delete 97 delete Оператор delete освобождает память, на которую указывает аргумент. Эта память предварительно должна быть выделена с помощью оператора new. Общая форма оператора del et e такова. delete p_var; Здесь p_var — это указатель на ранее выделенную память. Чтобы освободить массив, который был выделен с помощью оператора new, используйте следующую общую форму записи оператора delete. delete ['] p_var; Щ do J Цикл do — это одна из трех циклических конструкций, доступных в языке C++. Общая форма записи цикла do имеет такой вид. do { '¦'¦'¦. блок_опвраторов } while{условие); Если при выполнении цикла повторяется только один оператор, то фигурные скобки можно опустить, хотя они вносят в этот оператор определенную ясность. Цикл do — это единственный цикл в языке C++, который будет всегда иметь по крайней мере одну итерацию, поскольку условие проверяется после выполнения тела цикла. double J Ключевое слово double — это спецификатор типа данных, используемый для объявления вещественных переменных с двойной точностью.
98 dynamic_cast Idynamic_cast • Оператор dynamic_cast динамически проверяет законность выполнения заданной операции приведения типа. Он имеет следующую общую форму записи. dynamic_cast<TKn> (объект) Этот оператор в основном используется для выполнения операций приведения типа среди полиморфных типов. Например, если даны полиморфные классы В и D, причем класс D выведен из класса В, то оператор dynamic_cast всегда может преобразовать указатель D* в указатель В*. Оператор dynamic_cast может преобразовать указатель В* в указатель D* только в том случае, если адресуемым объектом является объект D. И вообще, оператор dynamic_cast будет успешно выполнен только при условии, если разрешено полиморфное приведение типов (т.е. если новый тип можно законно применять к типу объекта, который подвергается этой операции). Если операцию приведения типа выполнить нельзя, результат действия оператора dynamic_cast оценивается как нулевой. (В этом случае возникает исключение bad_cast.) else См. раздел "i f", приведенный ниже в этой главе. ешш Спецификатор типа епшп используется для создания перечислимых типов. Перечисление представляет собой список именованных целочисленных констант. Вот как выглядит общая форма перечисления. епшп имя {список_имен) список_переменных; Здесь имя — это имя типа перечисления. Элемент спи- сок_переменных не обязателен, и переменные перечисления можно объявлять отдельно от объявления типа, как показано в следующем примере. В данном фрагменте программы объявляются перечисление с именем color и переменная этого типа с именем с, а затем выполняются присваивание и проверка условия. епшп color {red, green, yellow} с;
explicit 99 с = red; if(c==red) cout << "красный\п"; За дополнительной информацией о перечислениях обращайтесь к главе 1. | explicit Спецификатор explicit применяется только к конструкторам. Конструктор, определенный с помощью спецификатора explicit, будет использоваться только в том случае, когда инициализация в точности совпадет с тем, что задано конструктором. Никаких автоматических преобразований выполнено не будет (т.е. спецификатор explicit создает "неконвертирующий конструктор"). (export .... | Ключевое слово export может предварять объявление template. Оно позволяет другим файлам использовать шаблон, объявленный в другом файле путем задания лишь его объявления (вместо дублирования его полного определения). extern Ключевое слово extern — это модификатор типа данных, который сообщает компилятору о том, что переменная определяется где-то в другом месте программы. Этот модификатор часто используется в случае, когда файлы, компилируемые отдельно, используют одни и те же глобальные данные, а затем компонуются в одно приложение. По сути, этот модификатор уведомляет компилятор о типе переменной, не переопределяя ее. Например, если переменная first была определена в другом файле как целая, то в последующих файлах нужно использовать следующее объявление. extern int first; Это объявление лишь задает тип переменной first; область хранения для нее не создается. щ
100 false В языке C++ модификатор extern также используется для создания спецификации компоновки. Общая форма записи этой спецификации имеет следующий вид. extern "язык" прототип__функции Здесь элемент язык означает среду создания функции, которую вы собираетесь скомпоновать. Компоновка языков С и C++ гарантированно поддерживается. Ваш компилятор может поддерживать также компоновку функций, созданных в других языках. Чтобы объявить несколько функций, используя одну и ту же спецификацию компоновки, можно использовать следующую общую форму. extern "язык" { прототипы_функций Ключевое слово false в языке C++ представляет собой логическую константу, имеющую значение "ложь". float | Ключевое слово float — это спецификатор типа данных, используемый для объявления переменных с плавающей точкой. •for" '• ';'-,;' '• - ¦' 5: Д Цикл for позволяет выполнить автоматическую инициализацию и инкрементирование переменной счетчика. Общая форма записи такова. for{инициализация; условие; инкремент) { блок_операторов У ¦-.¦¦¦' ¦ Если блок операторов состоит только из одного оператора, в фигурных скобках необходимость отпадает. Несмотря на то что цикл for допускает ряд отклонений, как правило, инициализация устанавливает переменную управления циклом равной ее начальному значению. Элемент условие Ьбыч-
friend 101 но представляет собой оператор отношения, сравнивающий значение переменной цикла с ее конечным значением, а элемент инкремент инкрементирует (или декрементирует) значение переменной цикла. Если условие дает ложное значение сразу после инициализации, тело цикла for ни разу не будет выполнено. При выполнении следующего оператора сообщение "Привет" будет выведено десять раз. for(t=0; t<10; t++) cout « "Привет\п"; I friend Ключевое слово friend предоставляет функции, не являющейся членом класса, доступ к закрытым членам этого класса. Для задания дружественной функции включите ее прототип в открытый раздел объявления класса й предварите прототип ключевым словом friend. Например, в следующем классе функция myfunc (), которая не входит в состав класса myc lass, является дружественной по отношению к этому классу. class myclass { publrc: '•' ¦• ¦ ¦¦ • friend void myfunc(int a, float b); Следует иметь в виду, что дружественная функция не имеет указателя this, поскольку она не является членом этого класса. J Ключевое слово goto передает управление программой оператору, помеченному меткой, которая задана в операторе goto. Общая форма записи оператора goto имеет следующий вид. goto метка; метка:
102 goto Совет программисту Хотя оператор goto как метод управления программой давно "впал в немилость", он порой оправдывает свое существование. Одним из таких особых случаев является выход из глубоко вложенной процедуры. Рассмотрим, например, следующий фрагмент программы. int i, j, k; int stop = 0; - - for(i=0; i<100- && istop; for(j=0; j<10 && istop; for(k=0; k<20; k++) { // ... if(something()) {¦ .stop = 1; break; } ¦ ' Переменная stop используется для отмены двух внешних циклов при условии возникновения некоторого программного события. Однако все же лучше достичь того же эффекта с помощью оператора goto. k ; int i, for(i-0; ; ...for{j=0;. ii; j for(k=0; k<20; // ... " if{something()) { goto done; done: // ...
if 103 Как видите, используя"оператор goto, можно обойтись без дополнительных затрат ресурсов, которые связаны с повторением проверки значения переменной stop в предыдущем варианте. Несмотря на то что следует избегать использования оператора goto в качестве универсальной формы управления циклами, в особых случаях его все-таки можно применять с большим успехом. Все метки должны оканчиваться двоеточием и не должны вступать в конфликт ни с какими ключевыми словами или именами функций. Кроме того, оператор goto может передавать управление только внутри текущей функции (не от одной функции к другой). щ if Ключевое слово if позволяет менять направление выполняемых программой действий в зависимости от результата проверки условия. Общая форма записи оператора i ? имеет следующий вид. if (условие) { блок_операторов_1 > else { 6лок_операторов_2 ) Если блок_операторов состоит только из одного оператора, в фигурных скобках необходимость отпадает. Оператор else необязателен. В качестве элемента условие можно использовать любое выражение. Если это выражение имеет значение, оцениваемое как истинное (любое значение, отличное от нуля), будет выполнен блок_операторов_1; в противном случае будет выполнен 6лок_операторов_2, если таковой существует. В следующем фрагменте программы проверяется, больше ли значение переменной х числа 10.
104 „Imaginary if(x > 10) cout « "x больше 10."; else cout << "x меньше или равен 10. „Imaginary I ввввашшвававваввавввавД В версии С99 содержится ключевое слово „Imaginary, которое поддерживает арифметику комплексных чисел. Однако для работы с мнимыми типами никакой специальной реализации не требуется и никакие независимые реализации (работающие без операционных систем) не обязаны поддерживать комплексные типы. В версии С99 определены следующие типы „Imaginary. • float „Imaginary • double „Imaginary • long double '^.Imaginary Причина того, что в качестве ключевого для версии С99 было определено слово „Imaginary, а не imaginary, состоит в том, что во многих существующих программах для работы с комплексными числами (и, а частности, с их мнимыми составляющими) уже были определены собственные пользовательские типы данных, применяющие слово imaginary. Поэтому ключевое слово „Imaginary позволило избежать приведения уже существующего кода в нерабочее состояние. Заголовок <complex.h> определяет (кроме всего прочего) макрос , imaginary, которому соответствует значение „Imaginary. Поэтому в новые С-программы лучше включать заголовок <complex.h>, а затем использовать макрос imaginary. inline Спецификатор inline сообщает компилятору о намерении программиста поместить тело функции непосредственно в текст программы (вместо организации обычного вызова функции). Спецификатор inline является "заявкой", а не командой, поскольку существуют определенные факторы, способные поме- I
int 105 шать встраиванию кода функции в текст программы. Такие ограничения касаются рекурсивных функций, функций, содержащих циклы или операторы switch, а также функций, содержащих статические данные. Спецификатор inline должен стоять перед остальной частью объявления функции. В следующем фрагменте программы компилятору предлагается сгенерировать встраиваемый код для функции my f unc (). inline void myfunc(int i) Когда определение функции включается в объявление класса, код этой функции автоматически встраивается в текст программы, если это возможно. int L Ключевое слово int означает спецификатор типа, используемый для объявления целочисленных переменных. Ключевое слово long означает спецификатор типа, используемый для объявления длинных целочисленных переменных. | mutable Д Спецификатор mutable позволяет члену некоторого объекта переопределить свойство постоянства, т.е. атрибут const. Иначе говоря, mutable-член const-объекта не является константным и может быть модифицирован. И namespace Д Ключевое слово namespace позволяет разделить глобальное пространство имен путем создания некоторой декларативной области. По сути, пространство имен определяет об-
106 namespace ласть видимости. Общая форма задания пространства имен имеет следующий вид. namespace имя { II Объявления. } Помимо именованных, можно иметь и безымянные пространства имен. namespace { // Объявления. } Безымянные пространства имен позволяют установить уникальные идентификаторы, которые известны только внутри области видимости одного файла. Приведем пример использования ключевого слова namespace. namespace MyNameSpace { int i, k; void myfunc(int j) { cout « j; } } Здесь переменные i, k и функция myf unc () являются частью области видимости, определенной пространством имен MyNameSpace. Поскольку пространство имен определяет область видимости, для доступа к определенным внутри нее объектам необходимо использовать оператор разрешения видимости. Например, чтобы присвоить значение 10 переменной i, необхо- ¦ димо использовать следующий оператор. MyNameSpace::i =10; Если члены пространства имен будут использоваться часто, то для упрощения доступа к ним можно применить директиву using. Оператор using имеет две общие формы записи. using namespace имя; using имя::член; В первой форме элемент имя задает имя пространства имен, к которому вы хотите получить доступ. Все члены, определенные внутри заданного пространства имен, можно затем использовать без квалификации. Во второй форме дела-
new 107 ется видимым только указанный член пространства имен. Например, предполагая, что пространство имен MyNameSpace определено (как показано выше), следующие операторы using и присваивания будут вполне законными. using MyNameSpace::k; // только переменная к // сделана видимой к = 10; // ОК, поскольку переменная к видима using namespace MyNameSpace; // все члены // MyNameSpace видимы i = 10; //OK, поскольку все члены MyNameSpace II сейчас видимы Оператор new выделяет динамическую память и возвращает указатель соответствующего типа на эту область памяти. Общая форма записи данного оператора такова. p_var = new тип; Здесь p_var — это переменная указателя, которая будет принимать адрес выделенной памяти, а элемент тип представляет собой тип данных, которые будут храниться в этой памяти. Оператор new автоматически выделяет достаточный объем памяти, чтобы поместить один элемент данных заданного типа. Например, в следующем фрагменте программы выделяется область памяти, достаточная для хранения значения типа double. double *p; р = new double; Если запрос на выделение памяти не удовлетворяется, возбуждается исключение bad_alloc. ПРИМЕЧАНИЕ. Более старые Компиляторы при отклонении запроса на выделение памяти могут демонстрировать поведение, отличное от описанного выше. Например, вполне возможно, что никакой исключительной ситуации возбуждено не будет и все закончится лишь возвратом нулевого указателя. Чтобы уточнить эти моменты, нужно изучить системную документацию к компилятору и узнать особенности работы в вашей среде.
108 operator Инициализировать выделенную память можно, задав инициализатор и использовав при этом следующую общую форму записи. p_var - new тип {инициализатор) ; Здесь инициализатор — это значение, которое будет присвоено выделенной памяти. Чтобы выделить память для одномерного массива, используйте следующую общую форму. p_var = new тип[размер]; Здесь элемент размер указывает длину массива. Оператор new автоматически выделит объем памяти, достаточный для хранения массива заданного типа и заданного размера. При выделении памяти для массивов инициализация не проводится. Если ваш компилятор C++ работает в полном соответствии со стандартом ANSI/ISO, он должен поддерживать "не возбуждающую исключение" форму оператора new, которая имеет следующий вид. p_var = new(nothrow) тип; Эта nothrow-форма оператора new при неудачной попытке выделить память не возбуждает ^исключительную ситуацию, а возвращает нулевой указатель. Чтобы использовать эту форму, в программу нужно включить заголовок <new>. [operator Ключевое слово operator используется для создания перегруженных функций-операторов. Функции-операторы существуют в двух ипостасях: члена и не члена. Общая форма записи функции-оператора как члена имеет следующий вид. тип_возврата имя__класса: : operator# (список_параметров) { Здесь тип_возврата означает тип значения, возвращаемого функцией, имя_класса — имя класса, для которого перегружается этот оператор, а элемент # — сам перегружаемый one-
private 109 ратор. При перегрузке унарного оператора список_пара- метров пуст. (Операнд передается неявным образом в указателе this.) При перегрузке бинарного оператора список_пара- метров задает операнд справа от оператора. (Операнд слева передается неявным образом в указателе this.) Что касается функций-не членов, функция-оператор имеет следующую общую форму. тип_возврата operator*(список_параметров) { Здесь список_параметров содержит один параметр при перегрузке унарного оператора и два параметра при перегрузке бинарного оператора. При перегрузке бинарного оператора операнд слева передается в первом параметре, а операнд справа — во втором параметре. Применительно к перегрузке операторов действует несколько ограничений. Нельзя изменять приоритет оператора. Нельзя также изменять количество операндов, требуемых оператором. Нельзя изменять значение оператора, связанного со встроенными типами данных языка C++. Нельзя создавать новый оператор. Операторы препроцессора # и ## не могут быть перегруженными. Нельзя перегружать следующие операторы. щ |private Спецификатор доступа private объявляет закрытые члены класса. Он также используется для наследования базового класса закрытым способом. При объявлении закрытых членов спецификатор private имеет следующую общую форму. class имя_класса { II... private: // Закрытые члены. }; Поскольку члены класса закрыты по умолчанию, спецификатор доступа private будет использоваться в объявлении class
110 protected только для того, чтобы начать еще один блок закрытых объявлений. Например, следующее объявление класса вполне законно. class myclass { int a, b; // закрыты по умолчанию public: // начало открытых объявлений int х, у; II эти данные-члены открыты private: // снова закрытые объявления int с, d; // эти данные-члены закрыты }; При использовании ключевого слова private в качестве спецификатора наследования используется следующая общая форма записи. class имя_класса : private имя_базового__класса { 1,1 ... После задания базового класса с атрибутом private все открытые (public) и защищенные (protected) члены базового класса становятся закрытыми членами производного класса. Все private-члены базового класса остаются закрытыми внутри этого (базового) класса. I' ц protected . , 1 Спецификатор доступа protected объявляет члены в классе, которые являются закрытыми для этого класса^ но могут быть унаследованы любым производным классом. Он имеет следующую общую форму. ©lass- имя±_кпасса.{. :-.--¦ ¦¦¦¦¦-..¦¦¦ .¦¦-:?¦:-..с ;-.. ¦„-.-... ¦,. , // . . . protected: // следующие члены делаем защищенными // Защищенные члены. }; Рассмотрим следующий пример. class base { / / . . . protected: int a ;
public 111 // Теперь передаем класс base в наследство классу // derived. class derived : public base { public: // Класс derived имеет доступ к члену а. voidf() { cout «a; } В этом фрагменте программы переменная а является "частной собственностью" класса base И к ней не может получить доступ ни одна функция, не являющаяся членом класса. Однако класс derived (благодаря спецификатору protected в классе base) наследует доступ к члену а. Если бы переменная а была просто определена с атрибутом private, класс derived не имел бы к ней доступа. В качестве спецификатора наследования ключевое слово protected используется в следующей общей форме. class имя__класса : protected имя_базового_класса { После задания базового класса с атрибутом protected все открытые и защищенные члены базового класса становятся защищенными членами производного класса. Во всех случаях private-члены базового класса остаются закрытыми членами внутри своего (базового) класса. | public ¦ ....-,- .- .,-¦• , •".'•'";'•'¦•:'"у-• I Спецификатор доступа public объявляет открытые (общедоступные) члены класса. Он также используется для открытого наследования базового класса. При использовании для объявления открытых членов его общая форма записи имеет следующий вид. class имя_класса { II Закрытые члены класса по умолчанию, public: //Следующие члены делаем открытыми. // Открытые члены.
112 register Члены класса закрыты по умолчанию. Для объявления открытых членов класса необходимо использовать атрибут publ ic. При использовании ключевого слова public в качестве спецификатора наследования применяется следующая общая форма записи. class имя__класса : public имя_6азового_класса { II При задании базового класса с атрибутом public^ все открытые члены базового класса становятся открытыми членами производного класса, а все защищенные члены базового класса— защищенными членами производного класса. Во всех случаях private-члены базового класса остаются закрытыми членами внутри своего (базового) класса. (register ¦ 1 Спецификатор класса памяти register заявляет о том, что желательно оптимизировать скорость доступа к данной переменной. Традиционно спецификатор register применяли только к целым или символьным переменным либо к указателям, что означало их хранение (по возможности) не в памяти, а в регистре центрального процессора (CPU). Однако с тех пор назначение спецификатора register было расширено до включения всех типов данных. Но данные, отличные от целых, символов или указателей, обычно не могут храниться; в регистре CPU. Поэтому для других типов данных либо» используется кэш-память (или некоторый другой способ оптимизации), либо register-заявка попросту игнорируется. Спецификатор register можно использовать только для локальных переменных. В языке С нельзя получить адрес регистровой переменной. Однако в языке C++ это возможно (но тогда оптимизация переменной становится проблематичной). |reinterpret_cast BBSBSSBSaSSBEBBSSBSSSi Оператор reinterpret_cast преобразует один тип в совершенно другой. Например, его можно использовать для перевода указателя в целое значение. Он имеет следующую общую форму записи.
restrict 113 reinterpret_cast<T*OT> {объект) Оператор reinterpret_cast следует использовать для приведения типов указателей, которые несовместимы по своей природе. (restrict В версию С99 добавлен квалификатор типа restrict, который применяется только к указателям. Указатель с атрибутом restrict является изначально единственным средством, позволяющим получить доступ к объекту, на который он указывает. Доступ к этому объекту с помощью другого указателя возможен только в том случае, если второй указатель основан на первом. Таким образом, доступ к объекту ограничивается выражениями, основанными на restrict-квали- фицированном указателе. Указатели, определенные с помощью квалификатора restrict, используются, главным образом, как параметры функций или для указания на память, выделенную с помощью функции malloc (). Если указатель квалифицирован с помощью ключевого слова restrict, компилятор имеет шанс лучше оптимизировать определенные типы программы на том основании, что restrict-указатель является единственным средством доступа к объекту. Например, если функция задает два параметра- указателя, квалифицированных как restrict, компилятор может предположить, что эти указатели отсылают к различным объектам (которые не перекрываются). Рассмотрим следующий пример использования квалификатора restrict (который стал классическим), а именно — функцию memcpy (). В версии С89 и языке C++ ее прототип имеет следующий вид. void *memcpy(void *strl, const void *str2, size_t размер) ; В описании функции memcpy () отмечается, что если объекты, адресуемые параметрами strl и str2, перекрываются, то поведение этой функции не определено. Таким образом, функция memcpy () гарантированно работает только с неперекрывающимися объектами. В версии С99 квалификатор restrict можно использовать для явного заявления в прототипе функции memcpy () о том,
114 return что в версии С89 и языке C++ приходится разъяснять словами. Вот как выглядит прототип функции memcpy () в версии С99. Void *memcpy(void * restrict strl, const void * restrict str2, size_t размер); Квалифицируя параметры с помощью ключевого слова restrict, этот прототип явно утверждает, что они указывают на неперекрывающиеся объекты. return Оператор return обеспечивает возврат из функции и может быть использован для передачи некоторого значения в вызывающую процедуру. Он имеет следующие две формы записи. return; return значение; В версии С99 и языке C++ форма оператора return, которая не задает возвращаемого значения, должна использоваться только в void-функциях. Следующая функция возвращает произведение двух своих аргументов. int mul(int a, int b) { ..,; return a*b; } Следует иметь в виду, что как только компилятор обнаружит оператор return, сразу же будет выполнен возврат из функции и любой код, который может присутствовать в функции после оператора return, будет опущен. Кроме того, функция может содержать более одного оператора return. [short Ключевое слово short представляет собой модификатор типа данных, используемый для объявления коротких целочисленных значений.
signed 115 (signed BBBBBBB Модификатор типа signed используется, главным образом, для задания такого типа данных, как signed char. В других случаях использование этого модификатора для целочисленных типов излишне, поскольку они по умолчанию имеют знак. sizeof Оператор периода компиляции sizeof возвращает длину (в байтах) переменной или типа, перед которым он поставлен. Если он стоит перед типом, этот тип должен быть заключен в круглые скобки. Если он предшествует переменной, круглые скобки нео- •бязательны. Например, в результате выполнения операторов int i ; cout « sizeof(int); cout « sizeof i; ¦ > ¦¦ в обоих случаях будет выведено число 4 (при работе в большинстве 32-разрядных сред). |static Модификатор типа static обеспечивает постоянное хранение локальной переменной, перед именем которой он стоит. Это позволяет поддерживать значение указанной переменной между вызовами функции. Модификатор типа static также можно использовать для объявления глобальных переменных. В этом случае он ограничивает область видимости модифицируемой им переменной файлом, в котором она объявлена. В языке C++ при использовании модификатора типа static в объявлении данных-членов класса создается только одна копия этого члена, предназначенная для совместного использования всеми объектами класса. >
116 static cast Оператор static_cast выполняет неполиморфное приведение типа. Например, его можно использовать для приведения указателя на базовый класс к указателю на производный класс. Кроме того, его можно использовать для любого стандартного преобразования. При этом никаких проверок во время работы программы не выполняется. Он имеет следующую общую форму записи. static_cast<crarn> [объект) [struct I Ключевое слово struct используется для создания сборного типа данных, именуемого структурой. В языке C++ структура может содержать как функции-, так и данные- члены. При этом она обладает теми же возможностями, что и класс (class), но по умолчанию члены структуры открыты, а не закрыты, как в классе. Общая форма объявления структуры имеет следующий вид. struct имя_структуры: список_наследования { II Открытые члены по умолчанию, protected: // Закрытые члены, которые могут быть унаследованы, private: // Закрытые члены. } список_объектов; С помощью элемента имя_структуры указывается имя структуры, которая имеет тип класса. К отдельным членам структуры можно получить доступ с помощью оператора "точка" (.), если использовать при этом саму структуру, или с помощью оператора "стрелка" (->), если использовать указатель на структуру. Элементы список_объектов и спи- сок_наследования необязательны. В языке С структуры могут содержать только данные- члены, спецификаторы public, protected и private использовать нельзя и С-структуры не поддерживают наследования.
switch 117 В приведенной ниже С-структуре содержатся строка с именем name и две целые переменные с именами highrij low. В ней такжеобъявляется одна переменная с именем my^var. struct my_struct .{ char name[80]; int high; int lowr ' , } my_var; ПРИМЕЧАНИЕ. В главе 1 приводится более подробная информация о структурах. Д switch 1 Оператор switch — это С/С++-оператор многоканального ветвления. Он используется для организации работы программы по одному из нескольких направлений. Общая форма записи этого оператора имеет следующий вид. switch (выражение) { . case константа_1: последовательность_операторов_1; break; case константа_2: последовательность_операторов_2; break; case константа_Ы: последовательность_операторов_Ы; break; default: default-операторы; } Каждая последовательность операторов может состоять из одного или нескольких операторов. Раздел default необязателен. Как выражение, так и константы, расположенные после директив case,.должны иметь целочисленный тип. Работа оператора switch заключается в сравнении элемента выражение с константами. При обнаружении совпадения выполняется соответствующая последовательность операторов. Если в выполняемой последовательности операторов нет
118 template оператора break, программа перейдет к выполнению операторов, Относящихся к следующей директиве case. Другими словами, начиная с точки совпадения элемента выражение и константы, выполнение операторов будет продолжаться до тех пор, пока либо не обнаружится оператор break, либо не закончится оператор switch. Если не обнаружится никакое совпадение, то при наличии директивы default будет выполняться последовательность операторов, относящаяся к этой директиве. В противном случае (при отсутствии директивы default) никакие действия выполнены не будут. В следующем примере анализируется и выполняется команда меню. switch(ch) { case 'e': enter(); break; case '1' : list (); break; case 's': sort(); break; case 'q': exit@); - break; default: ; cout « "Неизвестная команда!\n"; ¦cout << "Попробуйте еще раз.\п"; / *' ~ Д template II Ключевое слово template используется для создания обобщенных функций и классов. Тип данных, обрабатываемых обобщенной функцией или классом, задается как параметр. Следовательно, одно определение функции или класса можно использовать с несколькими различными типами данных. Обобщенная функция определяет общий набор операций, которые могут применяться к различным типам данных. Тип данных, обрабатываемых обобщенной функцией, передается как параметр. Используя этот механизм, одну и ту же общую процедуру можно применить к широкому диапазону данных. Как известно, многие алгоритмы имеют одну и ту же логику и не зависят от типа обрабатываемых данных. Например, алгоритм быстрой сортировки (Quicksort) одинаково подходит и для массива
template 119 целых, и для массива вещественных чисел. Единственное отличие — тип сортируемых данных. Создавая обобщенную функцию, можно определить суть алгоритма независимо от типа данных. В этом случае компилятор автоматически сгенерирует корректный код для типа тех данных, которые в действительности будут использованы при выполнении функции. По сути, при создании обобщенной функции вы создаете функцию, которая автоматически перегружает саму себя. Общая форма определения шаблонной функции имеет следующий вид. template <class тип> тип_возврата имя_функции (список_параметров) { // Тело функции. } Здесь тип означает метку-заполнитель для типа данных, с которым эта функция фактически будет иметь дело. В операторе template можно определить несколько параметров- типов данных, используя форму списка элементов, разделенных запятыми. Рассмотрим пример. В следующей программе создается обобщенная функция, меняющая значения двух переменных, с которыми она вызывается. Поскольку общий процесс обмена двух значений не зависит от типа переменных, он может послужить прекрасным кандидатом для создания обобщенной функции. // Пример шаблонной функции, ttinclude <iostream> using namespace std; // Определение шаблонной функции. .-^- template <class X> void swapvals(X &a, X &b) { X temp; . • temp = a; a = b; b = temp; int main()
120 template { - ¦¦ ¦¦¦¦(¦: int i=10, j=20; ,; float x=10.1, y=23.3; cout « "Исходные значения i, j: " « i « ' ' « j << endl; cdut « "Исходные значения х, у: " « x « ' ' «у « endl; swapvals(i, j); // обмен целых чисел swapvals(x, у); // обмен вещественных чисел cout << "После обмена i, j: " << i << ' ' << j << endl; cout << "После обмена х, у: " << x << ' ' << у << endl; return 0; } В этой программе строка template <class X> void swapvals(X &a, X &b) сообщает компилятору, во-первых, о том, что создается шаблонная функция, и, во-вторых, что X — это обобщенный тип, который задается в виде метки-заполнителя. Тело функции swapvals () определяется с использованием X в качестве типа данных значений, которые будут меняться местами. В функции main () при вызове функции swapvals () используются два различных типа данных: целые и вещественные числа. Поскольку функция swapvals () является обобщенной, компилятор автоматически создает две версии функции swapvals () г первая будет менять местами целые значения, а вторая — значения с плавающей точкой. Обобщенные функции напоминают перегруженные функции с одним исключением: они более ограничены. При перегрузке функций внутри тела каждой функции можно организовать выполнение различных действий. Обобщенная же функция должна выполнять один и тот же набор действий во всех версиях. Помимо обобщенных функций, можно также определить обобщенный класс. В этом случае создается класс, который определяет все используемые в нем алгоритмы, но реальный
template 121 тип обрабатываемых данных будет задан как параметр при создании объектов этого класса. Обобщенные классы полезно использовать в тех случаях, когда класс содержит обобщенную логику. Например, один и тот же алгоритм, который управляет очередью целых, будет так же успешно работать и с очередью символов. Кроме того, один и тот же механизм, обрабатывающий связный список почтовых адресов, так же прекрасно справится со связным списком запчастей к автомобилям. Иными словами, используя обобщенный класс, можно создать класс, который будет управлять очередью, связным списком и т.д. для любого типа данных. Компилятор автоматически сгенерирует корректный код объекта на основе типа, задаваемого при создании этого объекта. Вот как выглядит общая форма объявления обобщенного класса. template <class тил_данных> class имя_класса { Здесь тип_данных является меткой-заполнителем для типа данных, с которыми этот класс будет работать. При объявлении объекта обобщенного класса тип данных нужно задать в угловых скобках, используя следующую общую форму. имя_класса<тип_данных> объект; Рассмотрим пример обобщенного класса. В следующей программе создается очень простой класс связного списка и демонстрируется работа этого класса путем создания связного списка, предназначенного для хранения символов. // Простой обобщенный класс связного списка. #include <iostream> using namespace std; template <class data_t> class list { data_t data; list *next; public: list(data_t d); void add(list *node) { node->next = this,- next =0; } list *getnext() { return next; } data_t getdataO { return data; } m
122 template template <class data_t> list<data_t>::list(data_t d) { data = d; next = 0; int main() { list<char> start('a'); list<char> *p, *last; int i; // Строим список, last = &start; for(i=0; i<26; i++) { p = new list<char> ('a' + i) p->add(last); last = p; // Отслеживаем список. p = &start; while(p) { cout « p->getdata() P = p->getnext(); return 0; } • . Как видите, объявление обобщенного класса напоминает объявление обобщенной функции. Реальный тип данных, сохраняемых списком, сделан в объявлении класса обобщенным. В функции main () создаются объекты и указатели, которые задают, что типом данных списка будет тип char. При этом может быть также создан список значений другого типа. Обратите особое внимание на следующее объявление. list<char> start('a');
this 123 Также обратите внимание на то, что желаемый тип данных передается внутри угловых скобок. [this| bi^SSBSBBSSSSSBSSSBSBSSSSSaS-BSBBBBSBS^SsJI Ключевое слово this используется для обозначения указателя на объект, который сгенерировал обращение к функции-члену. Всем функциям-членам указатель this передается автоматически. ¦ I throw Оператор throw является частью подсистемы обработки исключительных ситуаций {исключений) в среде C++. Обработка исключений строится на использовании трех ключевых слов: try, catch и throw. Сначала рассмотрим этот процесс в самых общих чертах. Операторы программы, предназначенные для управления исключениями, содержатся в блоке try. Если исключение (т.е. ошибка) возникает в блоке try, происходит его "выброс" (с помощью оператора throw). "Выброшенное" исключение подхватывается (вернее, перехватывается) с помощью оператора catch и затем обрабатывается. А теперь более детально. Как отмечено выше, любой оператор, который генерирует исключение, должен выполняться внутри блока try. (Функции, вызываемые из блока try, также могут генерировать исключения.) Любое исключение должно быть перехвачено оператором catch, который располагается сразу после оператора try, сгенерировавшего исключение. Общая форма записи блоков try и catch имеет следующий вид. try { • • // блок_Ьгу ' ' }-•¦¦¦¦ ¦ • ;-., catch (тип1 агд) { // 6hoK_catch_l } catch {тип2 агд) { II блок_саtch_2 } catch (типЗ агд) {
124 throw // 6noK_catch_3 catch (типы arg) { // блок_саtch_N } ' " Блок try должен содержать ту часть программы, которая предназначена для обработки ошибок. Она может быть совсем небольшой и состоять всего из нескольких операторов, принадлежащих одной функции, или настолько всеобъемлющей, что в блок try будет помещено тело функции main () (в этом случае будет эффективно обрабатываться вся программа). После генерации исключение перехватывается соответствующим оператором catch, который и обрабатывает это исключение. С блоком try может быть связан не один, а несколько операторов catch. Какой из них использовать, определяется типом исключения, т.е. если тип данных, заданный оператором catch, совпадает с типом исключения, именно этот оператор catch выполняется (а все другие опускаются). При перехвате исключения аргумент агд получает некоторое значение. В перехвате могут участвовать данные любого типа, в том числе классы, создаваемые программистом. Если не сгенерировано ни одно исключение (т.е. если внутри блока try не обнаружилось ни одной ошибки), то не выполнится ни один оператор catch. Вот как выглядит общая форма оператора throw, throw исключение; Оператор throw должен выполняться либо из самого блока try, либо из любой функции, вызываемой (прямо или косвенно) из блока try. Элемент исключение представляет собой "выбрасываемое" в этот критический момент значение. Если программа сгенерирует исключение, для которого не найдется соответствующего оператора catch, может произойти аварийное завершение программы. При генерации необработанных исключений будет вызвана функция terminate (). По умолчанию функция terminate () вызывает функцию abort (¦), предназначенную для останова программы. Однако, используя функцию set_terminate (), можно указать свои обработчики таких ситуаций. Ниже приведен простой пример, демонстрирующий процесс обработки исключений в среде C++.
throw 125 // Простой пример обработки исключений. #include <iostream> using namespace std; int main() { cout « "Начало\п"; . try { // начало блока try cout << "Внутри блока try\n"; throw 100; // генерируем ошибку cout << "Этот оператор выполнен не будет" } catch (int i) { //перехватываем ошибку cout « "Перехватываем исключение - "; cout « "значение равно: "; cout << i << "\n"; cout « "Конец"; return 0; , } При выполнении этой программы будут выведены следующие сообщения. Начало Внутри блока try Перехватываем исключение - значение равно: 100 Конец Как видите, в программе присутствует блок try, содержащий три оператора, и оператор catch (int i), который обрабатывает исключения целого типа. Внутри блока try будут выполнены только два из трех операторов: первый (из двух) оператор cout и оператор throw. Как только будет сгенерировано исключение, управление сразу перейдет к выражению catch и блок try прекратит свою работу, т.е. оператор catch не вызывается: просто ему передается управление программой. (Для реализации этой передачи стек программы автоматически устанавливается должным образом.) Значит, оператор cout, следующий за оператором throw, никогда не будет выполнен. щ .л
126 true I true Ключевое слово true в языке C++ представляет собой логическую константу, имеющую значение "истина". [try Ключевое слово try является частью механизма обработки исключительных ситуаций (исключений) в среде C++. (См. раздел "throw", приведенный выше в этой главе.) Д typedef || Ключевое слово typedef позволяет создать новое имя для уже существующего типа данных. Под существующими подразумеваются как встроенные типы данных, так и классы, структуры, объединения и перечисления. Общая форма записи оператора typedef имеет следующий вид. typedef спецификатор_типа новое_имя; 1 Например, чтобы использовать слово balance вместо спецификатора типа float запишите следующее. typedef float balance; Itypeid В языке C++ оператор typeid возвращает ссылку на объект type_inf о, описывающий тип объекта, к которому применяется оператор typeid. Общая форма записи оператора typeid выглядит так. typeid(объект) Оператор typeid поддерживает в среде C++ возможность идентификации динамической информации о типе (RTTI). ПРИМЕЧАНИЕ. См. раздел "typeid", приведенный в главе 3.
typename 127 I typename ,, || Язык C++ поддерживает ключевое слово typename, которое можно использовать вместо ключевого слова class в объявлении template или для обозначения неопределенного типа. union Ключевое слово union используется для обозначения специального типа класса, который назначает двум или более переменным одну и ту же область памяти. Форма определения и характер ссылки на члены объединения — с помощью Операторов "точка" (.) и "стрелка" (->) — те же, что и для объектов класса {class). По умолчанию все члены объединения открыты. Общая форма записи имеет следующий вид. union имя_класса { // Открытые члены, заданные по умолчанию, private: // Закрытые члены. } список_объектов; Элемент имя_класса представляет собой имя типа для конкретного объединения. ПРИМЕЧАНИЕ. В языке С объединения могут содержать только данные-члены и спецификатор private применять не разрешается. Например, в следующем фрагменте программы создаются объединение значения типа double и строки символов,' а также одна переменная с именем my_var. union ray_union { char time[3 0]; double offset; } my_var; Более подробно объединения описаны в главе 1.
128 unsigned [unsigned ,. у ¦..¦:'¦ -.,_-;•. Д Ключевое слово unsigned используется в качестве модификатора типа данных для объявления целых без знака, Беззнаковые целые могут хранить только положительные значения. [using | См. раздел "namespace", приведенный выше в этой главе. virtual Спецификатор функций virtual создает виртуальную функцию. Виртуальная функция — это член базового класса, который может быть переопределен производным классом. Если функция не переопределяется производным классом, используется определение базового класса. Чистая виртуальная функция представляет собой функцию-член, которая не имеет определения. Это значит, что чистая виртуальная функция должна быть переопределена в производном классе. Прототип чистой виртуальной функции записывается следующим образом. virtual тип_возврата имя_функции(список_параметров) = 0; Здесь тип_возврата — это тип значения, возвращаемого функцией, имя_функции — имя функции, а список^параметров означает возможность задания любых параметров. Обратите внимание на элемент = 0, который сообщает компилятору, что эта виртуальная функция не имеет определения, связанного с базовым классом. Динамический полиморфизм достигается в том случае, когда к виртуальным функциям можно получить доступ через указатель на базовый класс. При реализации такой возможности именно тип адресуемого объекта определяет, какая версия виртуальной функции будет вызвана.
void 129 В6Ш Спецификатор типа void используется, главным образом, для явного объявления функций, которые не возвращают никакого значения. Он также используется для создания void- указателей (указателей на тип void), которые являются обобщенными указателями, обладающими способностью указывать на объект любого типа. В языке С спецификатор void также используется для объявления пустого списка параметров в объявлении функции. Совет программисту . Класс, который содержит хотя бы одну чистую виртуальную функцию, называется абстрактным. Абстрактные классы нельзя использовать для создания экземпляров объектов. Их также нельзя использовать в качестве типов параметров функций или типа возвращаемых значений. Однако можно создать указатель на абстрактный класс- .-'¦¦¦ Класс, который наследует абстрактный класс и при этом не переопределяет все чистые виртуальные функции, сам является абстрактным классом. Производный класс должен переопределить все чистые виртуальные функции " всех своих базовых классов до конкретизации этого производного класса и, естественно, до того, когда можно будет создавать объекты этого класса. ¦¦'''""'- 'Т*&:- V^-'-v: *>?»»" '¦ volatile J Модификатор volatile уведомляет компилятор о том, что со- держимое переменной может быть изменено способами, неявно [определенными программой. Например, переменные, значения 'которых меняются в результате использования определенных ап- ? паратных средств (часов реального времени, прерываний или дру- ¦ гих входных воздействий), должны быть объявлены с модификатором volatile.
130 wchar t wchar t Ключевое слово wchar_t задает тип двубайтовых симво- ,лов. Для хранения символов широкого, или двойного, формата отводится 16 разрядов. I while Для цикла while используется следующая общая форма. while{условие} { блок_операторов } Если блок_операторов цикла while состоит только из одного оператора, фигурные скобки можно опустить. При выполнении цикла while сначала проверяется условие. Следовательно, если условие дает ложный результат при первой же проверке, тело цикла (блок_операторов) не выполняется ни разу. Элемент условие может быть любым выражением. Ниже приведен пример цикла while, который читает 100 символов и сохраняет их в массиве символов. char s[256]; t = 0; while(t<100) { s[t] = stream.get\);
Глава 6 Стандартные функции ввода-вывода языка С В этой главе описаны стандартный С-функции ввода- вывода, т.е. функции, определенные стандартом С89 и добавленные стандартом С99. Функции, определенные в версии С89, поддерживаются и компиляторами C++ для обеспечения совместимости с языком С, поэтому их можно уверенно использовать в С++-программе. В языке С с функциями ввода-вывода связан заголовок <stdio. h>, а в C++ аналогичный заголовок называется <stdio>. Для простоты в этой главе будет использовано имя С-заголовка, но ссылки на <stdio. h> применимы и к заголовку <stdio>. Заголовок <stdio.h> определяет несколько макросов и типов, требуемых файловой системой в среде С. Тип FILE — самый важный; он используется для объявления указателя на файл. Двумя другими часто используемыми типами являются size_t и fpos_t, которые представляют собой некоторую разновидность целых без знака. Тип size_t определяет объект, который предназначен для хранения размера самого большого файла, разрешенного операционной средой. Тип fpos_fe определяет объект, который может хранить всю информацию, необходимую для уникального определения каждой позиции внутри файла. Самым популярным макросом, определенным в этом заголовке, является макрос EOF, значение которого указывает на конец файла. Другие типы данных и макросы, определенные в заголовке <stdio.h>, описаны вместе с функциями, с которыми они связаны. Многие функции ввода-вывода при возникновении ошибки устанавливают встроенную глобальную переменную целого типа с именем errno. Ваша программа может проанализировать ее, чтобы получить более подробную информацию об ошибке. Значения, которые может иметь переменная errno, зависят от конкретной реализации компилятора.
432 clearerr В системе ввода-вывода, действующей в среде С, используется понятие потока. Поток — это логическое устройство, связываемое с реальным физическим устройством, которое называют файлом, в момент его открытия. В С-системе ввода- вывода все потоки имеют одни и те же свойства, но файлы могут отличаться один от другого своими качествами. Например, дисковый файл позволяет произвольный доступ, а модем — нет. Поэтому С-система ввода-вывода обеспечивает определенный уровень абстракции между программистом и физическим устройством. Абстракция — это поток, а устройство — это конкретный файл. В таком случае, несмотря на различия, присущие реальным физическим устройствам, можно поддерживать согласованный логический интерфейс. Поток связывается с файлом посредством обращения к функции f open (), и вся дальнейшая работа с потоком происходит благодаря использованию файлового указателя (который является указателем типа FILE *). В определенном смысле файловый указатель играет роль клея, который обеспечивает целостность всей системы. В начале работы программы автоматически открываются три заранее определенных потока: stdin, stdout и stderr. Их называют стандартными потоками ввода, вывода и ошибок соответственно. По умолчанию они связаны с консолью, но их можно перенаправить на устройство любого другого типа, В версии С99 введен квалификатор restrict, который применяется к некоторым параметрам нескольких функций, первоначально определенных в версии С89. При рассмотрении каждой такой функции будет приведен ее прототип, использу- емый в среде С89 (а также в среде C++), а параметры с атрибу- ; том restrict будут отмечены в.описании этой функции. Iclearerr | ¦include <stdio.h> void clearerr(FTLE * stream); Функция clearerr () сбрасывает (т.е. устанавливает равным нулю) флажок (признак) ошибки, связанный с потоком, на который указывает элемент stream. При этом также сбрасывается индикатор конца файла. . .
fclose 133 Признаки ошибок для всех потоков первоначально устанавливаются равными нулю при успешном обращении к функции f open (). Ошибки при работе с файлами могут возникать по различным причинам, многие из которых зависят от конкретной системы. Точную природу ошибки можно определить в результате вызова функции perror (), которая выводит сообщение, описывающее ошибку (см. раздел "perror", приведенный ниже в этой главе). См. также функции f eof (), f error () и perror (). fclose JE ¦include <stdio.h> int fclose(FILE *stream); Функция fclose (} закрывает файл, связанный с потоком stream, и освобождает его буфер. После обращения к функции fclose () элемент stream больше не связан с файлом, и любые автоматически выделяемые буфера освобождаются. При успешном выполнении функция f close () возвращает нуль; в противном случае возвращается значение EOF. Попытка закрыть уже закрытый файл расценивается как ошибка. При удалении носителя данных до закрытия файла будет сгенерирована ошибка, как и в случае недостатка свободного пространства на диске. См. также функции fopen(), f reopen Q и fflush(). I f eof ¦'"'"¦ "¦ ;f'!" ¦'" '4 '¦'"-'-'*' "* ' '-r-" "J 4/ ""*' Vl i;''"' -1 #include <stdio.h> int feof(FILE * stream); Функция f eof () проверяет индикатор позиции файла, чтобы выяснить, достигнут ли конец файла, связанного с элементом stream. Если индикатор позиции файла расположен в конце файла, возвращается ненулевое значение; в противном случае возвращается нуль. При достижении конца файла последующие операции чтения будут возвращать значение EOF до тех пор, пока не будет вызвана функция rewind () или пока индикатор пози-
134 terror ции файла не изменит своего местоположения с помощью функции fseek(). Функция f eof () особенно полезна при работе с двоичными файлами, поскольку маркер конца файла также является действительным двоичным целым. Например, для определения факта достижения конца двоичного файла вместо простой проверки значения, возвращаемого функцией getc (), следует явным образом обратиться к функции f eof (). См. также функции clearerr (), f error (), perror (), pUtc() и getc(). ?error #include <stdio.h> int ferror(FILE *stream); Функция f error () проверяет наличие файловой ошибки для данного потока, определенного элементом stream. Нулевое значение, возвращаемое этой функцией, означает, что не было обнаружено никакой ошибки, а ненулевое значение означает ее наличие. Чтобы определить точную природу ошибки, используйте функцию perror (). См. также функции clearerr (), f eof (¦), и perror (). #include <stdio.h> int fflush(FILE * stream); • Если поток stream связан с файлом, открытым для записи, то при обращении к функции f flush () содержимое выходного буфера будет физически записано в этот файл. Если элемент stream указывает на входной файл, содержимое входного буфера очищается. В любом случае файл остается открытым. Нулевое значение, возвращаемое функцией, свидетельствует о ее успешном выполнении, а значение EOF — о возникновении ошибки записи.
fgetc 135 Все буфера автоматически сбрасываются при нормальном завершении программы или при их заполнении. Кроме того, буфер сбрасывается при закрытии файла. См. также функции fclosef), fopen(), fread(), fwrite(),getc() и putc(). [I fgetc #include <stdio.h> int fgetc(FILE * stream); Функция fgetc () возвращает из входного потока stream следующий символ, соответствующий текущей позиции, и инкрементирует индикатор текущей позиции файла. Этот символ читается как значение типа unsigned char, которое преобразуется в целое. При достижении конца файла функция fgetc () возвращает значение EOF. Однако поскольку значение EOF является действительным целым значением, при работе с двоичными файлами Для обнаружения конца файла необходимо использовать функцию f eof (). Если функция fgetc () обнаруживает ошибку, возвращается значение EOF. Для выявления ошибок при работе с двоичными файлами необходимо использовать функцию ferror(). См. также функции f putc (), getc (), putc () и f open (). #include <stdio.h> int fgetpos(FILE *stream, fpos_t *position); Функция fgetpos () сохраняет текущее значение индикатора позиции файла в объекте, адресуемом элементом- указателем position. Объект, адресуемый элементом position, должен иметь тип fpos_t, определенный в заголовке <stdio.h>. Сохраняемое значение полезно только для последующего обращения к функции f setpos (). В версии С99 как параметр stream, так и параметр position определяются квалификатором restrict.
136 fgets При обнаружении ошибки функция f getpos () возвращает ненулевое значение; в противном случае возвращается нуль. См. также функции f setpos (), fseek() и f tell (). I fgets BBBBBB8B tinclude <stdip.h>. char *fgets(char *str, int пит, FILE * stream); Функция fgets {) читает из входного потока stream не более (пит - 1) символов и помещает их в массив символов, адресуемый указателем str. Символы читаются до тех пор, пока не будет прочитан символ новой строки или значение EOF либо пока не будет достигнут заданный предел. По завершении чтения символов сразу за последним прочитанным символом размещается нулевой символ. Символ новой строки сохраняется и остается частью строки, адресуемой элементом str. При успешном выполнении функция fgets () возвращает значение str, а при неудачном (в случае сбоя) — нулевой указатель. В случае ошибки содержимое массива, к которому отсылает указатель йсг, не определено. Поскольку функция fgets () возвращает нулевой указатель и при возникновении ошибки, и при достижении конца файла, то для выяснения, что же произошло на самом деле, необходимо использовать функцию f eof () или f error (). См. также функции fputs (), fgetcf), gets () и puts (). fopen #include <stdio.h> FILE *fopen(const char *fname, const char *mode); Функция fopen () открывает файл, имя которого задается параметром fname, и возвращает поток, связываемый с этим файлом. Типы операций, которые разрешено выполнять с файлом, определяются параметром mode. Возможные значения параметра mode показаны в приведенной ниже таблице. Элемент fname должен представлять строку символов, составляющих имя файла, которое разрешено определенными в данной операционной системе правилами. Эта строка может
fopen 137 включать спецификацию пути, если действующая среда поддерживает такую возможность. В версии С99 к параметрам fname и mode применен ква- лификатор restrict. mode Назначение " г" Открывает текстовый файл для чтения " w" Создает текстовый файл для записи " а" Открывает текстовый файл для записи в конец файла " rb" Открывает двоичный файл для чтения " wb" Создает двоичный файл для записи " ab" Открывает двоичный файл для записи в конец файла " г +" Открывает текстовый файл для чтения и записи " w+" Создает текстовый файл для чтения и записи " а+" Открывает текстовый файл для чтения и записи в конец файла " rb+" или Открывает двоичный файл для чтения "r+b" и записи "wb+" или Создает двоичный файл для чтения и записи /"w+b" "ab+" или Открывает двоичный файл для чтения "а+b" и записи в конец файла Если функция fopen () успешно открыла заданный файл, она возвращает указатель FILE. Если файл не удается открыть, возвращается нулевой указатель. , Как видно из таблицы, файл можно открывать либо в тексто- : вом, либо в двоичном режиме. При открытии в текстовом режиме выполняются преобразования некоторых последовательностей |.символов. Например, символы новой строки преобразуются в по- Гследовательности символов "возврат каретки"/"перевод строки". f В двоичном режиме подобные преобразования не выполняются. В следующем фрагменте программы иллюстрируется корректный способ открытия файла. т
138 fopen FILE *fp; if ((fp = fopen("test", "w"))==NULL) { printf("He удается открыть файл.\п"); exitA); } При таком методе выявляется любая ошибка, связанная с открытием файла (например, при использовании защищенного от записи или заполненного диска), и только после этого можно предпринимать попытку записи в заданный файл. Если вы используете функцию f open (), чтобы открыть файл исключительно для выполнения операций вывода (записи), любой уже существующий файл с заданным именем будет стерт и вместо него будет создан, новый. Если файл с таким именем не существует, он будет создан. Чтобы открыть файл для выполнения операций чтения, необходим этот файл. В противном случае функция возвратит значение ошибки. Если вам нужно добавлять данные в конец файла, используйте режим " а". Если окажется, что указанный файл не существует, он будет создан. Совет программисту Любой файл можно открыть либо в текстовом, либо в двоичном режиме. Что в действительности содержит файл, не имеет при этом никакого значения. Например, файл, содержащий текст ASCII, все равно можно открыть и обрабатывать, как двоичный. Различное поведение файловой системы ANSI С при обработке двоичных и текстовых файлов проявляется лишь в том, что при открытии файла в двоичном режиме никаких преобразований символов не происходит. При выполнении различных нетекстовых операций с файлом действительно стоит открывать текстовый файл, как двоичный. Например, файловые утилиты, которые выполняют функции сравнения, сжатия или сортировки, обычно открывают файлы в режиме двоичного доступа. Кроме того, программы шифрования файлов практически всегда работают в двоичном режиме. Главное различие между текстовым и двоичным файлом не в том, что файл содержит, а в том, каким способом он открыт.
fprintf 139 При доступе к файлу, открываемому для чтения и записи, нельзя сразу за операцией ввода выполнять операцию вывода, не прибегнув прежде к промежуточному вызову одной из следующих функций: fflush(), fseek(), fsetpos() или rewindO. Нельзя также сразу за операцией вывода выполнять операцию ввода, не прибегнув прежде к промежуточному вызову одной из перечисленных выше функций. Исключением является момент достижения конца файла во время операции ввода, т.е. в конце файла вывод может непосредственно следовать за вводом. В любой момент максимальное количество файлов, которые могут быть открыты, ограничивается значением FOPEN_MAX, определенным в заголовке <stdio. h>. См. также функции f close (), fread(), fwrite(), putc() ngetcf). fprintf I #include <stdio.h> int fprintf(FILE *stream, const char * format, Функция f print f () выводит в поток, адресуемый параметром stream, значения аргументов, составляющих список аргументов, в соответствии с заданной строкой format. Значение возврата равно количеству реально выведенных символов. При возникновении в процессе вывода ошибки возвращается отрицательное число. В версии С99 к параметрам stream и format применен квалификатор restrict. ; , : Операции преобразования, заданные в строке управления форматом, и команды вывода аналогичны операциям и командам, используемым в функции print ? (); полное описание приводится в разделе "print f". См. также функции printf () и f scanf (). fputc |L#include <stdio.h> ;"int fputc (int ch, FILE * stream)
140 fputs Функция fputc () записывает символ ch в заданный поток stream (в текущую позицию файла), а затем продвигает индикатор позиции файла. Несмотря на то что в силу исторических причин символ ch объявлен с помощью типа int, он преобразуется функцией fputc () в тип unsigned char. Поскольку символьный аргумент возводится в ранг целого в момент вызова, вы можете спокойно использовать в качестве аргументов символьные переменные. А если бы вы использовали целое значение, старший байт попросту был бы отброшен. Значением, возвращаемым функцией fputc (), является значение записанного символа. При возникновении ошибки возвращается значение EOF. Для файлов, открытых для выполнения двоичных операций, значение EOF может оказаться действительным символом, поэтому, чтобы определить реальный факт возникновения ошибки, придется использовать функцию f error (). См. также функции fgetc(), fopen(), fprintf(), fread() и fwriteO. fputs ¦include <stdio.h> int fputs(const char *str, FILE *stream); Функция fputs () записывает в заданный поток stream содержимое строки, адресуемой указателем str. При этом завершающий нулевой символ не записывается. В версии С99 к параметрам str и stream применен ква- При успешном выполнении функция fputs () возвращает неотрицательное значение, а при неудачном — значение EOF. Если поток открыт в текстовом режиме, могут произойти преобразования некоторых символов. Это значит, что однозначного отображения строки в файл может и не быть. Однако в случае, если поток открыт в двоичном режиме, никаких преобразований символов не будет и можног говорить о существовании взаимно однозначного соответствия между строкой и файлом. См. также функции f gets О, gets (), puts О, fprintff) и fscanf().
fread 141 fread #include <stdio.h> int fread(void *buf, size_t size, size_t count, FILE *stream); Функция fread () читает из потока, адресуемого указателем stream, count объектов длиной size байт и размещает их в массиве buf. Индикатор позиции файла перемещается затем на прочитанное количество символов. В версии С99 к параметрам buf и stream применен ква- лификатор restrict. Функция fread () возвращает число реально прочитанных элементов. Если оказалось, что прочитано меньше элементов, чем затребовано при вызове, значит, либо при выполнении операции произошла ошибка, либо был достигнут конец файла. Для выяснения действительных причин происшедшего нужно вызвать функцию f eof () или f error (). Если поток открывается для текстовых операций, мбгут выполняться преобразования некоторых последовательностей символов, например последовательности символов "возврат карет- ки"/"перевод строки" преобразуются в символы новой строки. См. также функции fwriteO, fopen(), fscanf(), fgetc{) и getc ().,-. , .• . #include <stdio.h> FILE *freopen(const char *fname, const'char *mode, FILE *stream); Функция f reopen () связывает существующий поток с другим файлом. Имя нового файла задается параметром fname, режим доступа — параметром mode, а на переназначаемый поток отсылает указатель stream. Возможные значения строки mode— те же, что и для функции fopeh() (полное их описание можно найти в разделе "f open"). В версии С99 к параметрам fname, mode и stream применен квалификатор restrict.
142 fscanf После вызова функция f reopen () сначала пытается закрыть файл, который в данный момент связан с потоком stream. Однако, если попытка закрыть этот файл оказывается неудачной, функция f reopen () все равно переходит к открытию другого файла. При успешном выполнении функция f reopen () возвращает указатель на поток и нулевой указатель — в противном случае. Чаще всего функция f reopen () используется для перенаправления таких определенных системой файлов, как stdin, stdout и stderr, на другой файл. См. также функции f open () и f close (). I f scanf |l ¦include <stdio.h> int fscanf(FILE *stream, const char * format, ...); Функция f scanf () работает подобно функции scanf (), но читает информацию из потока, заданного указателем stream, а не из стандартного потока ввода stdin. Подробности приводятся в разделе "scanf" ниже в этой главе. В версии С99 к параметрам stream и format применен квалификатор restrict. Функция fscanf () возвращает количество аргументов, которым действительно присвоены значения. Это число не включает опущенные поля. Значение возврата, равное EOF, означает, что до выполнения первого присваивания произошел сбой. См. также функции scanf () и f print f (). Ifseek #include <stdio.h> int fseek(FILE * stream, long offset, int origin); Функция fseek() устанавливает индикатор позиции файла, связанного с потоком stream, в соответствии со значениями смещения offset и исходного положения origin. Назначение этой функции — поддерживать операции ввода-вывода с произвольным доступом. Параметр offset представляет собой
fsetpos 143 количество байтов, на которые будет перемещен внутренний указатель файла (индикатор позиции файла) относительно точки отсчета, заданной параметром origin. В качестве значения для параметра origin должен быть взят один из следующих макросов (определенных в заголовке <stdio. h>). Имя Назначение SEEK_SET Поиск с начала файла SEEK_CUR Поиск с текущей позиции SEEK_END Поиск с конца файла Нулевое значение возврата свидетельствует об успешном выполнении функции f seek (), а ненулевое — о возникновении сбоя. Вообще говоря, функцию f seek () следует использовать только при работе с двоичными файлами. При использовании же с текстовым файлом параметр origin должен иметь значение SEEK_SET, а параметр offset — значение, полученное в результате вызова функции f tell О для того же файла, или нуль (чтобы установить индикатор позиции файла в начало). Функция fseek() очищает признак конца файла, связанный с заданным потоком. Более того, она обнуляет любой установленный ранее признак наличия для файла символа, возвращенного в тот же поток посредством вызова функции ungetc () (см.. раздел "ungetc" ). См. также функции ftell О, rewindO, fopen(), fgetpos () и fsetpos ('). |fsetpos #include <stdio.h> int fsetpos(FILE * stream, const fpos_t *position); Функция fsetpos () перемещает индикатор позиции файла в место, заданное объектом, к которому отсылает указатель position. Это значение должно быть предварительно получено путем обращения к функции f getpos (). После выполнения функции fsetpos () индикатор конца файла сбрасывается. Кроме того, обнуляется любой предыдущий результат обращения к функции ungetс ().
144 ftell При неудачном выполнении функции f setpos () возвращается ненулевое значение, а при успешном — нуль. См. также функции fgetpos (Ь fseek() Hftell(). ftelf #include <stdio.h> long ftell(FILE *sBream); Функция ftell () возвращает текущее значение индикатора позиции файла для заданного потока stream. В случае двоичных потоков это значение равно количеству байтов, которые отделяют индикатор от начала файла. Для текстовых потоков возвращаемое значение может быть не определено за исключением случая, когда оно служит в качестве аргумента функции fseek(). Все дело в возможных преобразованиях символов, когда, например, последовательности символов "возврат каретки'У'перевод строки" заменяются символами новой строки, что, бесспорно, влияет на размер файла. При возникновении ошибки функция f tell () возвращает значение-1. < См. также функции f seek () и fgetpos (). I fwrite ¦ •, ¦ ¦ *.».-¦;. с- ч>*. ¦ • -• #include <stdio.h> . int fwrite(const void *buf, size_t size, size_t count, FILE * stream); Функция fwrite () записывает в поток, адресуемый указателем stream, count объектов длиной size байт каждый из символьного массива, адресуемого указателем buf. Индикатор позиции файла перемещается затем не записанное количество символов. В версии С99 к параметрам buf и stream применен ква- лификатор restrict. Функция fwrite () возвращает число реально записанных элементов, которое будет равно числу затребованных элементов, если функция выполнилась успешно. Если же записано J
getc 145 меньше элементов, чем затребовано при вызове, значит, при выполнении операции произошла ошибка. См. также функции f read (), f scanf (), getc () и f getc (). tinclude <stdio.h> int getc(FILE * stream); Функция getc () возвращает из входного потока stream следующий символ, соответствующий текущему состоянию индикатора позиции файла, а затем инкрементирует этот индикатор. Символ читается с использованием типа unsigned char, после чего преобразуется в целый тип. При достижении конца файла функция getc () возвращает значение EOF. Но, поскольку значение EOF является действительным целым значением, для реального обнаружения символа конца файла при работе с двоичными файлами необходимо использовать функцию feof (). При обнаружении ошибки функция getc () также возвращает значение EOF. Поэтому для выявления ошибок при работе с двоичными файлами необходимо использовать функцию f error (). Функции getc () и f getc () идентичны, но в большинстве реализаций функция getc () определена как макрос. См. также функции fputc (), f getc (), putc () и f open (). |getchar "-У "¦ • ¦ •-.¦'"'•- • " •"'"'.' ':,,'- #include <stdio.h> int getchar(void); Функция getchar () возвращает следующий символ из стандартного потока stdin. Символ читается с использованием типа unsigned char, после чего преобразуется в целый тип. При достижении конца файла функция getchar () возвращает значение EOF. При обнаружении ошибки функция getchar () также возвращает значение EOF. Функция getchar () чаще всего реализована как макрос. См. также функции fputc (), f getc (), putc () и f open ().
146 gets |'geЬвЖ #include <stdio.h> char *gets(char *str); Функция gets () читает символы из стандартного потока stdin и помещает их в символьный массив, адресуемый указателем str. Символы читаются до тех пор, пока не встретится символ новой строки или значение EOF. Символ новой строки не является частью строки, поэтому он преобразуется в нулевой символ, завершающий строку. При успешном выполнении функция gets() возвращает указатель str; а при сбое возвращается нулевой указатель. Если произошла ошибка, содержимое массива, адресуемого параметром str, не определено. Поскольку функция gets () возвращает нулевой указатель и при возникновении ошибки, и при достижении конца файла, то для выяснения, что же произошло на самом деле, необходимо использовать функцию feof() или ferror(). Не существует способа ограничить число символов, которое прочитает функция gets (), а это значит, что массив, адресуемый указателем str, может переполниться. Следовательно, данная функция опасна по своей природе. Ее следует использовать только в пробных программах или утилитах "внутреннего" назначения, т.е. для себя. Ее не рекомендуется использовать в коммерческих программах. См. также функции fputs (), fgetc (), fgets () и puts (). I perror - I #include <stdio.h> void perror(const char *str); Функция perror () преобразует значение глобальной переменной errno в строку и записывает эту строку в поток ошибок stderr. Если значение параметра str не равно нулю, то сначала записывается сама строка, за ней — двоеточие, а затем следует сообщение об ошибке, определяемое конкретной реализацией.
perror 147 Совет программисту При использовании функции gets() возможно переполнение массива, предназначенного для размещения символов, вводимых пользователем, поскольку эта функция не предусматривает никакой проверки факта нарушения границ. Чтобы обойти эту проблему, можно использовать функцию fgets () и задать в качестве входного потока стандартный поток stdin. Поскольку функция fget () требует задания максимальной длины, можно предотвратить переполнение массива. Вам остается позаботиться лишь о том, чтобы вручную удалить символ новой строки, завершающий ввод, поскольку функция fgets () этого не делает (в отличие от функции gets()). Рассмотрим следующую программу. ¦include <stdio.h> ¦include' <string.h> int main(void) { . char str[10]; int i ,- printf("Введите строку: ") ; fgets(str, 10, stdin); /* Удаляем символ новой строки, если таковой существует. */ I = strlen(str)-1; if(str[i]=='\n' strti] = '\0'; printf("BoT ваша строка: %s", str); return 0; } Хотя использование функции fgets () требует приложения чуть больших усилий, ее преимущество перед функцией gets () состоит в том, что она позволяет защитить массив ввода от переполнения.
148 printf |printf ¦include <stdio.h> int printf(const char * format, ...); Функция printf () записывает в стандартный поток stdout значения аргументов из заданного списка аргументов в соответствии со строкой форматирования, адресуемой параметром format. Строка форматирования состоит из элементов двух типов. К элементам первого типа относятся символы, которые выводятся" на экран. Элементы второго типа содержат команды форматирования, которые определяют способ отображения аргументов. Команда форматирования начинается с символа процента, за которым следует код формата. Количество аргументов должно в точности совпадать с количеством команд форматирования, причем совпадение обязательно и в порядке их следования. Например, при вызове следующей функции printf () на экранебудет отображено "Hi с 10 there!". printf("Hi %c %d %s", 'с1, 10, "there!"); Бели заданных аргументов меньше, чем команд форматирования, результат будет не определен. Если аргументов больше, чем команд форматирования, оставшиеся "без пары" аргументы отбрасываются. Команды форматирования перечислены ниже. Код Формат %а Шестнадцатеричное целое в форме Oxh. hhhhp+d. (только С99) %А Шестнадцатеричное целое в форме OXh. hhhhP+d. (только С99) %с Символ %d Десятичное целое со знаком %i Десятичное целое со знаком %е Экспоненциальное представление {строчная буква е) %Е Экспоненциальное представление (прописная буква Е) %f Значение с плавающей точкой
printf 149 Код Формат %F Значение с плавающей точкой (только в С99; при бесконечном результате или когда значение не является числом, выводит INF, INFINITY или NAN; спецификатор % f генерирует строчные эквиваленты) %д Использует более короткий из двух форматов: %е или % f (если %е, использует строчную букву е) %G Использует более короткий из двух форматов: %Е или %F (если %Е, использует прописную букву Е) %о Восьмеричное целое без знака % s Строка символов %и Десятичное целое без знака %х Шестнадцатеричное целое без знака (строчные буквы) % X Шестнадцатеричное целое без знака (прописные буквы) %р Указатель %п Соответствующий аргумент должен быть указателем на целое. Данный спецификатор сохраняет в этом целом число символов, выведенных в выходной поток к текущему моменту (до обнаружения спецификатора %п) % % Печатает символ % Функция printf () возвращает число реально выведенных символов. Отрицательное значение возврата свидетельствует об ошибке. Команды формата могут иметь модификаторы, которые задают ширину поля, точность и признак выравнивания по левому краю. Целое значение, расположенное между знаком % и командой форматирования, выполняет роль спецификатора минимальной ширины поля. Наличие этого спецификатора приведет к тому, что результат будет заполнен пробелами или нулями, чтобы гарантированно обеспечить для выводимого значения заданную минимальную длину. Если выводимое значение (строка или число) больше этого минимума, оно будет выведено полностью, несмотря на превышение минимума. По умолчанию в качестве заполнителя используется пробел. Для заполнения нулями нужно поместить 0 перед спецификатором ширины поля. Например, строка формати-
150 printf рования %05d дополнит Выводимое число нулями (их будет меньше 5), чтобы общая длина была равной 5 символам. Точное значение модификатора точности зависит от кода формата, к которому он применяется. Чтобы добавить модификатор точности, поставьте за спецификатором ширины поля десятичную точку, а после нее — значение спецификации точности. Для форматов а, А, е, Е, f и F модификатор точности определяет число выводимых десятичных знаков. Например, строка форматирования %10.4f обеспечит вывод числа, ширина которого составит не меньше десяти символов, с четырьмя десятичными знаками. Если модификатор точности применяется к коду формата g или G, то он определяет максимальное число выводимых значащих цифр. Применительно к целым, модификатор точности задает минимальное количество выводимых цифр. При необходимости будут добавлены начальные нули. Если модификатор точности применяется к строкам, число, следующее за точкой, задает максимальную длину поля. Например, строка форматирования %5.7s отобразит строку длиной не менее пяти, но не более семи символов. Если выводимая строка окажется длиннее максимальной длины поля, конечные символы будут отсечены. По умолчанию все выводимые значения выравниваются по правому краю: если ширина поля больше выводимого значения, оно будет выровнено по правому краю поля. Чтобы установить выравнивание по левому краю, поставьте знак "минус" сразу после знака %. Например, строка форматирования %-10.2 f обеспечит выравнивание вещественного числа (с двумя десятичными знаками в 10-символьном поле) по левому краю. Существуют два модификатора команд форматирования, которые позволяют функции print f () отображать короткие и длинные целые. Эти модификаторы могут применяться к спецификаторам типа d, i, о, и, х и X. Модификатор 1 уведомляет о длинном формате значения. Например, строка %ld означает, что выводится длинное целое. Модификатор h сообщает о коротком формате. Следовательно, строчка %hu означает, что выводимое данное имеет тип short unsigned integer. Если вы используете современный компилятор, который поддерживает добавленные в 1995 году средства работы с символами широкого формата (двубайтовыми символами), то мо-
printf 151 жете задействовать модификатор 1 применительно к спецификатору с, чтобы уведомить об использовании двубайтовых символов. Модификатор 1 можно также использовать с командой формата s для вывода строки двубайтовых символов. Модификатор 1 можно также поставить перед командами форматирования вещественных чисел а, А, е, Е, f, F, g и G. В этом случае он уведомит о выводе значения типа long double. Команда п сохраняет в целой переменной, указатель на которую задан в списке аргументов, число символов, которые были записаны в выходной поток к моменту обнаружения спецификатора п. Например, следующий фрагмент программы выведет число 14 после строки "This is a test". int i ; printf("This is a test%n", &i); printf("%d", i); Чтобы обозначить, что соответствующий аргумент указывает на длинное целое, к спецификатору п можно применить модификатор 1. Для указания на короткое целое примените к спецификатору п модификатор п. Символ # имеет специальное значение при использовании с некоторыми кодами формата функции print f (). Символ #, поставленный перед кодами a, A, g, G, f, е и Е, гарантирует присутствие десятичной точки даже в случае, если десятичных цифр нет. Если поставить символ # перед кодами формата х и X, то шестнадцатеричное число будет выведено с префиксом Ох. Если поставить символ # перед кодами формата о и О, то восьмеричное число будет выведено с префиксом 0. Символ # нельзя применять ни к каким другим спецификаторам формата. * Спецификаторы минимальной ширины поля и точности могут задаваться не константами, а аргументами функции priritf (). Для этого в строке форматирования используется символ "звездочка" (*). При сканировании строки форматирования функции printf () каждый символ * будет сопоставляться с соответствующим аргументом в порядке их следования.
152 putc Модификаторы формата, добавленные к функции print f () стандартом С99 В версии С99 добавлено несколько модификаторов формата для использования в функции printf (¦): hh, 11, j, z и t. Модификатор hh можно применять к спецификаторам d, i, о, и, х, X и п. Он означает, что соответствующий аргумент является значением типа signed char или unsigned char, а в случае спецификатора п— указателем на переменную типа signed char. Модификатор 11 также можно применять к спецификаторам d, i, о, и, х, X и п. Он означает, что соответствующий аргумент является значением типа signed long long int или unsigned long long int, а в случае спецификатора n — указателем на переменную типа long long int. Модификатор формата j, который применяется к спецификаторам d, i, о, и, х, X и п, означает, что соответствующий аргумент имеет тип intmax_t или uintmax_t. Эти типы объявлены в заголовке <stdint .h> и служат для хранения целых самой большой длины. Модификатор формата z, который применяется к спецификаторам d, i, о, и, х, X и п, означает, что соответствующий аргумент имеет тип size_t. Этот тип объявлен в заголовке <stddef .h> и служит для хранения результата операции s i z eo f. Модификатор формата t, который применяется к спецификаторам d, i, о, и, х, X и п, означает, что соответствующий аргумент имеет тип ptrdif f_t. Этот тип объявлен в заголовке <stddef . h> и служит для хранения значения разности между двумя указателями. В версии С99 также разрешено применять модификатор 1 к спецификаторам вещественных типов а, А, е, Е, f, F, g и G, но он не работает. * См. также функции scanf () nfprintf(). [putC ,. , ;,/ I #include <stdio.h> int putc(int ch, FILE * stream); Функция putc () записывает символ, содержащийся в младшем байте параметра ch, в выходной поток, адресуемый
putchar 153 параметром stream. Поскольку символьные аргументы возводятся в ранг целого в момент вызова, их вполне можно использовать в качестве аргументов для функции put с (). Функция putc () часто реализуется как макрос. При успешном выполнении функция putc () возвращает записанный символ, а в случае ошибки — значение EOF. Если' выходной поток был открыт в двоичном режиме, EOF может быть вполне нормальным значением для параметра ch. Значит, для установления факта ошибки необходимо в этом случае использовать функцию f error (). См. также функции fgetc(), fputc {), getchar() и putchar(). putchar #include <stdio.h> int putchar(int ch) ; Функция putchar () записывает символ, содержащийся в младшем байте параметра ch, в стандартный выходной поток stdout. По выполняемому действию она эквивалентна функции putc(ch-, stdout). Поскольку символьные аргументы возводятся в ранг целого в момент вызова, их вполне можно использовать в качестве аргументов для функции putchar (). При успешном выполнении функция putchar () "возвращает записанный символ, а в случае ошибки — значение EOF. См. также функцию putc (). lputa I #include <stdio.h> int puts(char *str); Функция puts () записывает строку, адресуемую параметром str, в стандартное выходное устройство. Завершающий нуль преобразуется в символ новой строки. При успешном выполнении функция puts () возвращает неотрицательное значение, а в случае сбоя — значение EOF. См. также функции putc ()., gets () и print f().
154 remove remove #include <stdio.h> int remove(const char *fname); Функция remove () удаляет файл, заданный параметром fname. При успешном удалении файла функция возвращает нуль, а в случае ошибки — ненулевое значение. См. также функцию rename (). rename #include <stdio.h> int rename(const char *oldfname, const char * newfname); Функция rename () заменяет имя файла, заданное параметром old fname, именем newfname. Имя new fname не должно совпадать ни с одним из существующих имен файлов в каталоге. При успешном выполнении функция rename () возвращает нуль, а в случае ошибки — ненулевое значение. См. также функцию remove (). rewind iinclude <stdio.h> void rewind(FILE *stream); Функция rewind () перемещает индикатор позиции файла jj в начало заданного потока. Она также очищает признаки || конца файла и ошибки, связанные с потоком stream. См. также функцию f seek (). " l8canf I #include <stdib.h> int scanf(const char * format, ...);
scant 155 Функция scanf () представляет собой процедуру общего назначения, которая читает поток stdin и сохраняет информацию в переменных, заданных аргументами, перечисленными в списке аргументов. Она может читать все встроенные типы данных и автоматически преобразовывать их в соответствующий внутренний формат. В версии С99 к параметру format применен квалификатор restrict. Управляющая строка, задаваемая параметром format, состоит из символов трех категорий: • спецификаторов формата; • пробельных символов; • символов, отличных от пробельных. Спецификаторы формата — им предшествует знак процента (%) — сообщают, какого типа данное будет прочитано следующим. Например, спецификатор %s прочитает строку, а %d — целое значение. Строка форматирования читается слева направо, и спецификаторы формата по порядку сопоставляются с аргументами, перечисленными в списке аргументов. Эти коды приведены в следующей таблице. Код Назначение % а Читает значение с плавающей точкой (только С99) %А Аналогично коду %а (только С99) %с Читает один символ %d Читает десятичное целое %i Читает целое в любом формате (десятичное, восьмеричное, шестнадцатеричное) %е Читает вещественное число %Е Аналогично коду %е % f Читает вещественное число %F Аналогично коду % f (только С99) %д Читает вещественное число %G Аналогично коду %д %о Читает восьмеричное число
156 scant Код Назначение %s Читает строку ¦ %х Читает шестнадцатеричное число %Х Аналогично коду %х %р Читает указатель %п Принимает целое значение, равное количеству символов, прочитанных до сих пор %и Читает десятичное целое без знака % [ ] Просматривает набор символов %% Читает знак процента Чтобы прочитать длинное целое, поставьте перед спецификатором формата модификатор 1, а чтобы прочитать короткое целое— модификатор h. Эти модификаторы можно использовать с кодами формата d, i, о, и и х. , По умолчанию спецификаторы а, f, e и g заставляют функцию scanf () присваивать данные переменным типа float. Если поставить перед одним из этих спецификаторов формата модификатор 1, функция scanf () присвоит прочитанное данное переменной типа double. Использование же модификатора L означает, что переменная, принимающая значение, имеет тип long double. Если вы используете современный компилятор, который поддерживает добавленные в 1995 году средства работы с двубайтовыми символами, можете задействовать модификатор 1 применительно к спецификатору с, чтобы обозначить указатель на двубайтовый символ с типом данных whcar_t. Модификатор 1 можно также использовать с кодом формата s, чтобы обозначить указатель на строку двубайтовых символов. Кроме того, модификатор 1 можно использовать для модификации набора сканируемых двубайтовых символов. Пробельные символы в строке форматирования заставляют функцию scanf () пропустить один или несколько пробельных символов во входном потоке. Под пробельным сим- ¦ волом подразумевается пробел, символ табуляции или символ новой строки. По сути, один пробельный символ в управляющей строке заставит функцию scanf () читать, но не со-
scanf 157 хранить любое количество (пусть даже нулевое) пробельных символов до первого не пробельного. Не пробельный символ в строке форматирования заставляет функцию scanf () прочитать и отбросить соответствующий символ. Например, при использовании строки форматирования %d, %d функция scanf () сначала прочитает целое значение, затем прочитает и отбросит запятую и наконец прочитает еще одно целое. Если заданный символ не обнаружится, работа функции scanf (¦) будет завершена. Все переменные, используемые для приема значений с помощью функции scanf (), должны передаваться посредством их адресов. Это значит, что все аргументы должны быть указателями на переменные. Элементы входного потока должны быть разделены пробелами, символами табуляции илТГ новой строки. Такие символы, как запятая, точка с запятой и т.п., не распознаются в качестве разделителей. Это означает, что оператор scanf("%d%d", &r, &с) ; примет значения, введенные как 10 20, но наотрез откажется от "блюда", поданного в виде 10,2 0. Символ *, стоящий после знака % и перед кодом формата, прочитает данные заданного типа, но запретит их присваивание. Следовательно, оператор scanf("%d%*c%d", &х, &у); при вводе данных в виде 10/20 поместит значение 10 в переменную х, отбросит знак деления и присвоит значение 2 0 переменной у. Команды форматирования могут содержать модификатор максимальной длины поля. Он представляет собой целое число, располагаемое между знаком % и кодом формата, которое ограничивает количество символов, читаемых для любого поля. Например, если вы хотите прочитать в переменную address не более 20 символов, используйте следующий оператор. scanf("%20s", address); Если входной поток содержит более 20 символов, то при последующем обращении к операции ввода чтение начнется с того места, в котором "остановился" предыдущий вызов функции scanf (). При обнаружении пробельного символа
158 scanf ввод данных для поля может завершиться до достижения максимальной длины поля. В этом случае функция scanf () переходит к чтению следующего поля. Несмотря на то что пробелы, символы табуляции и новой строки используются в качестве разделителей полей, при чтении одиночного символа они читаются подобно любому другому символу. Например, если входной поток состоит из символов х у, то оператор scanf("%с%с%с", &а, &Ь, &с); поместит символ х в переменную а, пробел — в переменную Ь* и символ у — в переменную с. Помните, что любые другие символы управляющей строки, не являющиеся спецификаторами формата (включая пробелы, символы табуляции и новой строки), используются для установления соответствия и отбрасывания символов из входного потока. Например, если поток ввода выглядит, как 10t20,оператор scanf("%st%s", &х, &у); поместит 10 в переменную х и 20 — в переменную у. Символ t отбрасывается, так как он присутствует в управляющей строке. Еще один способ использования функции scanf() называется набором сканируемых символов (scanset). В этом случае определяется набор символов, которые могут быть прочитаны функцией scanf () и присвоены соответствующему массиву символов. Для определения такого набора необходимо заключить символы, подлежащие сканированию, в квадратные скобки. Открывающая квадратная скобка должна следовать сразу за знаком процента. Например, следующий набор сканируемых символов говорит о том, что необходимо прочитать только символы А, В и С. %[АВС] При использовании набора сканируемых символов функция scanf () продолжает читать символы и помещать их в соответствующий символьный массив до тех пор, пока не встретится символ, отсутствующий в заданном наборе. Соответствующая набору переменная должна быть указателем на массив символов. При возврате из функции scanf {) этот массив будет содержать строку с завершающим нулем, состоящую из прочитанных символов.
scanf 159 Если первый символ в наборе является знаком вставки (Л), то получаем обратный эффект: входное поле читается до первого символа из заданного набора символов, т.е. знак вставки заставляет функцию scanf () принимать любые символы, которые не определены в наборе. Многие компиляторы позволяют с помощью дефиса задать диапазон. Например, следующий оператор заставляет функцию scanf () принимать символы от А до Z. %[A-Z] Важно помнить, что набор сканируемых символов различает прописные и строчные буквы. Следовательно, если вы хотите сканировать как прописные, так и строчные буквы, задайте их отдельно. Функция scanf () возвращает число, равное количеству полей, для которых были успешно присвоены значения. К этим полям не относятся поля, которые были прочитаны, но присвоение не состоялось в связи с использованием модификатора * для подавления присваивания. При обнаружении ошибки до присвоения значения первого поля функция scanf () возвращает значение EOF. Модификаторы формата, добавленные к функции scanf () стандартом С99 В версии С99 добавлено несколько модификаторов формата для использования в функции scanf (): hh, 11, j, z и t. Модификатор hh можно применять к спецификаторам d, i, о, u, x и п. Он означает, что соответствующий аргумент является указателем на значение типа signed char или unsigned char. Модификатор 11 также можно применять к спецификаторам d, i, о, u, x и п. Он означает, что соответствующий аргумент является указателем на значение типа signed long long int или unsigned long long int. Модификатор формата j, который применяется к спецификаторам d, i, о, u, x и п, означает, что соответствующий аргумент является указателем на значение типа intmax_t или uintmax_t. Эти типы объявлены в заголовке <stdint .h> и служат для хранения целых максимально возможной длины.
160 setbuf Модификатор формата z, который применяется к спецификаторам d, i, о, u, х и п, означает, Что соответствующий аргумент является указателем на объект типа size_t. Этот тип объявлен в заголовке <stddef. h> и служит для хранения результата операции sizeof. Модификатор формата t, который применяется к спецификаторам d, i, о, и, х и п, означает, что соответствующий аргумент является указателем на объект типа ptrdiff_t. Этот тип объявлен в заголовке <stddef.h> и служит для хранения значения разности между двумя указателями. См. также функции print f () и f scanf (). setbu? #include <stdio.h> void setbuf(FILE * stream, char *buf); Функция setbuf () задает буфер, которым будет пользоваться поток stream, либо, если параметр buf установлен равным нулю, отключает буферизации^ Если необходимо задать буфер, определенный программистом, то его длину следует установить равной BUFSIZ символам. Идентификатор BUFSIZ определяется в заголовочном файле <stdio. h>. В версии С99 к параметрам stream и buf применен ква- лификатор restrict. См. также функции f open (-), f close () и setvbuf (). setvbuf J #include <stdio.h> int setvbuf(FILE *stream, char *buf, int mode, size_t size); Функция setvbuf () позволяет программисту задать буфер, его размер и режим работы с указанным потоком. Символьный массив, адресуемый параметром buf, используется в качестве буфера потока для операций ввода-вывода. Размер буфера устанавливается с помощью параметра size, а режим mode определяет, как будет выполняться буферизация. Если параметр buf нулевой, функция setvbuf () выделяет собственный буфер.
snprintf 161 В версии С99 к параметрам stream и buf применен ква- лификатор restrict. Возможными значениями параметра mode являются константы _IOFBF, _IONBF и _IOLBF, которые определены в заголовочном файле <stdio.h>. Когда параметр mode установлен равным значению _IOFBF, буферизация выполняется в расчете на полный объем буфера. Если mode равен значению _IOLBF, поток будет буферизирован построчно, т.е. буфер будет сбрасываться при каждой записи в выходной поток символа новой строки, а при чтении из входного потока появление символа новой строки приведет к прекращению подкачки в буфер. В любом случае буфер сбрасывается по окончании заполнения. Если установлен режим, определяемый значением _IONBF,' поток вообще не буферизируется. Функция setvbuf () возвращает нуль при успешном выполнении и ненулевое значение в противном случае. См. также функцию setbuf (). I snprintf , I #inclu&e;<stdio.h> int snprintf(char * restrict buf, size_t пит, const char * restrict format,...) ; Функция snprintf () добавлена в версии С99. Она идентична функции sprint f () за исключением того, что в массиве, адресуемом указателем buf, будет сохранено максимум лшп-1 символов. По окончании работы функции, этот массив имеет завершающий нуль-символ. Таким образом, функция snprint f () позволяет предотвратить переполнение буфера buf. См. также функции print f (), sprint f () и f sprint f (). Isprintf \ I #include <stdio.h> int sprintffchar *buf, const char * format,...); Функция sprintf () идентична функции printf () за исключением того, что выходной поток записывается в массив,
162 sscanf адресуемый указателем buf, а не в стандартный поток stdout. По окончании работы функции этот массив имеет завершающий нуль-символ. Подробности приводятся в разделе "print f". • В версии С99 к параметрам buf и format применен ква- лификатор restrict. Возвращаемое значение равно числу символов, действительно помещенных в массив. Важно понимать, что функция sprint f () не обеспечивает никакой проверки факта переполнения массива, адресуемого указателем buf. Это значит, что массив будет переполнен, если объем выводимых символов превысит длину массива. В качестве альтернативного решения рассмотрите применение функции snprintf () (см. раздел "snprintf", приведенный выше в этой главе). См. также функции print f () и f sprint f (). sscanf 'Ш~:ШУШ^ finclude.,<stdio.h> . . . . _ .. .... : ..-.—....¦. int sscanf(const char *buf, const char *format, ....);. ^ ...,...-. ^ .•.,.... Функция sscanf () идентична функции scanf (), но данные читаются из массива, адресуемого параметром buf, а не из стандартного потока ввода stdin. Подробности приводятся в разделе "scanf". , ¦¦> В версии С99 к параметрам buf и format применен ква- лификатор restrict. Значение, возвращаемое функцией, равно количеству переменных, которым реально были присвоены значения. К ним не относятся поля, опущенные благодаря использованию модификатора команды формата *. Нулевое значение свидетельствует о том, что ни одно поле не было присвоено, а значение EOF сигнализирует об ошибке, обнаруженной до первого присваивания. См. также функции scanf () и f scanf ().
tmpfile 163 I ff [ tinclude <stdio.h> FILE *tmpfile(void); Функция tmpfile {) открывает временный двоичный файл для операций чтения/записи и возвращает указатель на поток. Она автоматически использует уникальное имя файла, чтобы избежать конфликтов с существующими файлами. Функция tmpfile () при неудачном выполнении возвращает нулевой указатель, а при успешном — указатель на поток. Временный файл, созданный функцией tmpfile (), автоматически удаляется при закрытии файла или по завершении программы. Количество временных файлов, которь!е можно открыть, равно значению ТМР_МАХ (которое не превышает предел, определяемый значением FOPEN_MAX). См. также функцию tmpnam (). I tmpnam I ^include <stdio.h> , -¦, . char *tmpnam(char *name); Функция tmpnam () генерирует уникальное имя файла и сохраняет его в массиве с именем пате. Длина этого, массива должна составлять не меньше L^tmpnam символов. (Константа L_tmpnam определена в заголовочном файле <stdio.h>.) Основное назначение функции tmpnam () — сгенерировать имя временного файла, которое не совпадало бы ни с одним из имен файлов в текущем каталоге диска. Эту функцию можно вызвать не более ТМР_МАХ раз. Константа ТМР_МАХ определена^ заголовочном файле <stdio. h>, и ее значение равно не менее 25. При каждом вызове функция tmpnam () будет генерировать новое имя временного файла. При успешном выполнении функции возвращается указатель на массив пате, в противном случае — нулевой указатель. Если значение параметра name равно NULL, то имя вре-
164 ungetc менного файла содержится в статическом массиве, принадлежащем функции tmpnam (), которая в этом случае возвращает указатель на свой массив. Этот массив будет перезаписан при последующем вызове функции tmpnam (). См. также функцию tmpf ile (). uhgretcil ttinclude <stdio.h> int ungetc(int ch, FILE *stream); Функция ungetc () возвращает символ, заданный младшим байтом параметра ch, в поток ввода stream. Этот символ будет затем получен при последующей операции чтения потока stream. Обращение к таким функциям, как f flush (), f seek () и rewind (), аннулирует операцию ungetc () и сбрасывает этот символ. Возврат в поток одного символа гарантирован, однако некоторые реализации допускают возврат большего числа символов. Попытка вернуть в поток ввода значение EOF игнорируется. Обращение к функции ungetc () очищает признак конца файла, связанный с заданным потоком. Значение индикатора позиции файла для текстового потока не определено до тех пор, пока не будут прочитаны все возвращенные символы, и в этом случае оно остается таким же, каким было до первого вызова функции ungetc (). При работе с двоичными потоками каждый вызов функции ungetc () декрементирует индикатор позиции файла. Функция возвращает значение ch при успешном завершении и значение EOF в противном случае. См. также функцию getc (). vprintf, vfprintf, vsprintf И vsnprintf iinclude <stdarg.h> #include <stdio.h> int vprintf(char *format, va_list arg_ptr); L int vfprintf(FILE *stream, const char *format,
vscanf, vfscanf и vsscanf 165 va_list argr_ptr) ; int vsprintf(char *buf, char * format, va_list arg^ptr); . int vsnprintf(char * restrict buf, size^t-пшп, const char * restrict format, va_list arg_jptr) ; Действия функций vprintf (), vfprintf ( Г, vsprintf () и vsnprintf () эквивалентны действиям функций print f (), fprintff}, sprintfO и snprintf() соответственно, но список аргументов заменен указателем на список аргументов. Этот указатель должен иметь тип va_list, который определен в заголовке <stdarg. h>. В версии С99 к параметрам buf и format применен ква- лификатор restrict. Функция snprintf() добавлена в версии С99. См. также функции vscanf (), vfscanf (), vsscanf (), va_arg(), va_start() и va_end(). I vscanf, vfscanf И vsscanf | #include <stdarg.h> : ¦include <stdio.h> int vscanf(char * restrict format, • ¦¦¦.'• . va_list arg_ptr) ; int vfscanf (FILE * restrict stream, ¦'¦¦: const char * restrict format, va_list arg_ptr).; int vsscanf(char * restrict buf, 7 const char * restrict format, va_list arg_ptr) ; Эти функции добавлены в версии С99. Действия функций vscanf (), vfscanf () и vsscanf () эквивалентны действиям функций scanf (), f scanf () и Sscanf () соответственно, но список аргументов заменен указателем на список аргументов. Этот указатель должен иметь тип va_list, который определен в заголовке <stdarg. h>. См. также функции vprintf (), vfprintf (), vsprintf (), vsnprintf(), va_arg (), va_start () иva_end ().
Глава 7 Строковые и символьные функции Библиотека функций языков С и C++ включает богатый набор функций обработки строк и символов. Строковые функции работают с символьными массивами, завершающимися нулевыми символами. В языке С для использования строковых функций необходимо включить в начало модуля программы заголовочный файл <string.h>, а для символьных— заголовочный файл <ctype. h>. В языке C++ для работы со строковыми и символьными функциями используются заголовки <cstring> и <cctype.h> соответственно. В этой главе для простоты изложения используются имена С-заголовков. Поскольку в языках С и C++ при выполнении операций с массивами не предусмотрен автоматический контроль нарушения их границ, вся ответственность за переполнение массивов ложится на плечи программиста. Пренебрежение этими тонкостями может привести программу к аварийному отказу. В языках С и C++ печатаемыми являются символы, отображаемые на терминале. В ASCII-средах они расположены между пробелом @x20) и тильдой (OxFE). Управляющие символы имеют значения, лежащие в диапазоне между нулем и OxlP; к ним также относится символ DEL @x7F). Исторически сложилось так, что аргументами символьных функций являются целые значения, из которых используется только младший байт. Символьные функции автоматически преобразуют свои аргументы в тип unsigned char. Безусловно, вы вольны вызывать эти функции с символьными аргументами, поскольку символы автоматически возводятся в ранг целых в момент вызова функции. В заголовке <string.h> определен тип size_t, который является результатом применения оператора sizeof и представляет собой разновидность целого без знака. В версии С99 к некоторым параметрам нескольких функций, первоначально определенных в версии С89, добавлен
168 isalnum квалификатор restrict. При рассмотрении каждой такой функции будет приведен ее прототип, используемый в среде С89 (а также в среде C++), а параметры с атрибутом restrict будут отмечены в описании этой функции. | isalnum || tinclude <ctype.h> int isalnum(int ch); Функция isalnum() возвращает ненулевое значение, если ее аргумент ch является либо буквой, либо цифрой. Если же тестируемый символ не относится к алфавитно-цифровым, возвращается нуль. См. также функции isalphaO, iscntrlO, isdigitO, isgraph(), isprint(),ispunct() и isspace(). Iisalpha I #include <ctype.h> int isalphafint ch); Функция is alpha () возвращает ненулевое значение, если ее аргумент ch является буквой, в противном случае возвращается нуЛь. Принадлежность символа к буквам зависит от конкретного языка. Для английского языка таковыми являются прописные и строчные буквы от А до Z. См. также функции isalnumO, iscntrl(), isdigitO, isgraph(),isprint(),ispunct() иisspace(). isblank J #include <ctype.h> int isblank(int ch); Функция isblank () добавлена в версии С99. Она возвращает ненулевое, значение, если ее аргумент ch является символом, для которого функция isspace () возвра* щает значение "истина", и используется для разделения слов.
iscntrl 169 Таким образом, для английского языка пробельными символами являются пробел и символ горизонтальной табуляции. См. также функции isalriumO, isalphaO, iscntrl (), isdigit(), isgraph(), isprint(}, ispunct() и isspace(). Iiscntrl #include <ctype.h> int iscntrl(int ch); Функция iscntrl () возвращает ненулевое значение, если ее аргумент ch является управляющим символом, значение которого в ASCII-средах лежит в диапазоне между нулем и OxlF или равно 0x7F (символ DEL). В противном случае возвращается нуль. См. также функции isalnum(), isalphaO, isdigit ()>' isgraph(), isprint(),ispunct() и isspace(). !¦¦:¦"" ¦ ¦ - :¦ isif-i ¦.¦¦¦/. . .¦¦'¦" :'.:¦-'• ¦'.'--'/.->>¦*¦. ¦'¦¦:¦¦¦ '. - ' ','%- -,,,-,--: ¦¦¦ ¦ ... " -. .v. ¦ ¦¦i<;i'.1 " ¦ '4:: ¦<:-:* " Дм*1!*' ' - "¦-,¦ #include <ctype.h> • int isdigit(int ch); Функция isdigit () возвращает ненулевое значение, если ее аргумент ch является цифрой, т.е. попадает в диапазон 0- 9. В противном случае возвращается нуль. "'.,./ См. также функции isalnumO, isalphaO, iscntrl (), isgraph(), isprint(), ispunct() и isspace(). #include <ctype.h> int isgraph(int ch); Функция isgraph () возвращает ненулевое значение, если ее аргумент ch является любым печатаемым символом, но не пробелом. В противном случае возвращается нуль. Для ASCII-сред значения печатаемых символов лежат в диапазоне от 0x2-1 до 0х7Е. См. также функции isalnumO, isalphaO, iscntrl О, isdigit(), isprint(),ispunct() и isspace().
170 islower islower ¦include <ctype.h> int islower(int ch); Функция islower () возвращает ненулевое значение, если аргумент ch является строчной буквой. В противном случае возвращается нуль. См. также функцию i supper (). Iisprint | #include <ctype.h> int isprint(int ch) ; Функция isprintO возвращает ненулевое значение, если аргумент ch является печатаемым символом, включая пробел. В противном случае возвращается нуль. В ASCII-средах значения печатаемых символов лежат в диапазоне от 0x20 до 0х7Е. v См. также функции isalnum(), isalpha(), iscntrl(), ^ifi?, l"s'p\met f J' ispunct #include <ctype.h> int ispunct(int ch); Функция ispunct () возвращает ненулевое значение, если аргумент ch является знаком пунктуации. В противном случае возвращается нуль. Под знаками пунктуации подразумеваются все печатаемые символы, которые не относятся ни к алфавитно-цифровым, ни к пробельным. См. также функции isalnum(), isalpha(), iscntrl(), isdigit(), isgraph(),isprint() и isspace(). ¦include <ctype.h> int isspace(int ch);
isupper 171 Функция isspaceO возвращает ненулевое значение, если аргумент ch является пробельным символом. (К пробельным символам, помимо пробела, относятся символы горизонтальной и вертикальной табуляции, перевода страницы, возврата каретки и новой строки.) В противном случае возвращается нуль. См. также функции isalnumO, isalpha(), isblank(), iscntrl()tisdigit(}, isgraphf), ispunct() и isprint(). I isupper 1 #include <ctype.h> int isupper(int ch) ; Функция isupper () возвращает ненулевое значение, если аргумент ch является прописной буквой. В противном случае возвращается нуль. См. также функцию is lower (). [isxdigit #include <ctype.h> int isxdigit(int ch); Функция isxdigit () возвращает ненулевое значение,-если аргумент ch является шестнадцатеричной цифрой. В противном случае возвращается нуль. Шестнадцатеричная цифра должна попадать в один из следующих диапазонов: A-F, a-f или 0-9. См. также функции isalnumO, isalphaO, iscntrl (), isdigit(), isgrapht), ispunct() nisspace(). #include <string.h> void *memchr(const void *buffer, int ch, size_t count); Функция memchr () просматривает массив, адресуемый параметром buffer, чтобы отыскать первое вхождение символа ch в первых count символах.
172 memcmp • Функция memchr () возвращает указатель на первое вхождение символа ch в массиве buffer или нулевой указатель, если символ,ей не найден. -,. ; « См. также функции memcpy () и isspace (). | memcmp , #include <string.h> . int memcmp(const void *bufl, const void *buf2, size_t couht); Функция memcmp () сравнивает первые count символов массивов, адресуемых параметрами bufl и buf2. Функция memcmp () возвращает целое значение, которое интерпретируется следующим образом. Значение Результат сравнения Меньше нуля bufl меньше buf2 Нуль bufl равен buf2 Больше нуля bufl больше buf 2 См. также функции memchr (), memcpy () и strcmp (). I memcpy , ¦¦¦¦.:.> ¦¦.= . ¦::¦•' •..-,,>•?-.<> ttinclude <string.h> ' : Void ¦*ШШ;ру (void *tor const-vei.u~ *from, :»~ size_t count); Функция memcpy () копирует count символов из массива, адресуемого параметром from, в массив, адресуемый параметром to. Бели заданные массивы перекрываются, поведение функции memcopy () не определено. В версии С99 к параметрам to и froia. применен квалифи- катор restrict. ' Функция memcpy () возвращает значение указателя to. См. также функцию memmove ().
memmove 173 memmove ^include <string.h> void *memmove(void *to, const void *from, size_t count); Функция memmove () копирует count символов из массива, адресуемого параметром from, в массив, адресуемый параметром to. Если заданные массивы перекроются, процесс копирования пройдет корректно, т.е. соответствующее содержимое будет помещено в массив to, но массив from останется модифицированным. Функция memmove () возвращает значение указателя to. См. также функцию memcpy {), I memset: I вввввввввЕвававаавваввЕааавваваааввакаввваи #include <string.h> void *memset(void *buf, int ch, size_t count); Функция memset () копирует младший байт параметра ch в первые count символов массива, адресуемого параметром buf. Функция возвращает значение указателя buf. Чаще всего функция memset () используется для инициализации области памяти некоторым известным значением. См. также функции memcmp (), memcpy () и теттоуе;(). strcat J #include <string.h> char *strcat(char *strl, const char *str2); Функция-strcat () присоединяет копию строки str2 к строке strl и завершает строку strl нулевым символом. Конечный нуль-символ, первоначально завершающий строку strl, перезаписывается первым символом, строки str2. Строка str2 в результате этой операции конкатенации не модифицируется. Если заданные массивы перекрываются, поведение функции strcat О не определено. В версии С99 к параметрам strl и str2 применен квали- фикатор restrict. Функция strcat () возвращает значение указателя strl.
174 strchr Помните, что при выполнении операций с символьными массивами контроль нарушения их границ не выполняется, поэтому программист должен сам позаботиться о достаточно большом размере массива strl, позволяющем вместить как его исходное содержимое, так и содержимое массива str2. См. также функции strchr (), strcmp () и strcpy (). I strchr • I #include <string.h> char *strchr(const char *str, int ch); Функция strchr'() возвращает указатель на первое вхождение младшего байта параметра ch в строке str. Если совпадение не обнаружено, возвращается нулевой указатель. См. также функции strpbrkf), strspn(), strstr() и strtokf). iinclude <string.h> int strcmp(const char *strl, const char *str2); Функция strcmp () сравнивает в лексикографическом порядке две строки и возвращает целое значение, зависящее следующим образом от результата сравнения. Значение Результат сравнения строк Меньше нуля strl меньше str 2 Нуль strl равна str2 Больше нуля strl больше str2 См. также функции strchr (), strcpy () и strcmp (). I strcoll #include <string.h> int strcoll(const char. *strl, const char *str2);
strcpy 175 Функция strcoll() сравнивает строку strl со строкой str2. Сравнение выполняется с учетом значения параметра locale, заданного с помощью функции setlocaleO (подробности приводятся в разделе "setlocale" главы 10). Функция strcoll () возвращает целое значение, которое интерпретируется следующим образом. Значение Результат сравнения Меньше нуля strl меньше str2 Нуль strl равно str2 Больше нуля strl больше str2 См. также функции memcmp () и strcmp (). strcpy ¦include <string.h> char *strcpy(char *strl, const char *str2); : Функция strcpy () копирует содержимое строки str-2 в строку strl. Параметрstr2 должен' указыватъ^на строку с завершающим нулевым символом. Функция strcpy () возвращает значение указателя strl. Если заданные символьные массивы перекрываются, поведение функции strcpy () не определено. В версии С99 к параметрам strl и str2 применен квали- фикатор restrict. См. также функции memcpyt), strchr(), strcmp(¦) и strncmp(). (strcspn SBBBBiSBBBai #include <string.h> size_t strcspn(const char *strl, const char *str2) ; Функция strcspn() возвращает длину начальной подстроки в строке, адресуемой параметром strl, которая состоит только из символов, не содержащихся в строке, адресуемой
176 strerror параметром str2. Другими словами, функция strcspnO возвращает индекс первого символа в строке strl, который совпадает с любым из символов в строке str2. См. также функции strrehrf), strpbrkO, strstrO и strtok(). I strerror I tinclude <string.h> .char *strerror(int errnum); Функция strerror () возвращает указатель на строку, содержащую системное сообщение об ошибке, связанной со значением errnum. Ни при каких обстоятельствах не следует модифицировать эту строку. | ¦include <string.h> size_t strlen(char .* >,, Функция strl en () возвращает длину строки с завершающим нулевым символом, адресуемой параметром str. Завершающий нулевой символ не учитывается. См. также функции memcpyO, strchrO, strcmpO и strncmpO. strncat iinclude <string.h> char *strncat(char *strl, const char *str2, size_t count); Функция strncat () присоединяет не более count символов, строки, адресуемой параметром str2, к строке, адресуемой параметром strl, завершая результирующую строку strl нулевым символом. Конечный нуль-символ, первоначально завершающий строку strl, перезаписывается первым символом строки str2. Строка str2 в результате этой операции конкатенации не модифицируется. Если заданные массивы перекрываются, поведение функции strncat {} не определено.
strncmp 177 В версии С99 к параметрам strl и str 2 применен квали- фикатор restrict. Функция strncat () возвращает значение указателя strl. Помните, что при выполнении операций с символьными массивами контроль нарушения их границ не выполняется, поэтому программист должен сам позаботиться о достаточно большом размере массива strl, позволяющем вместить как его исходное содержимое, так и содержимое присоединяемого массива str2. См. также функции strcat (), strnchr (), strncmp () и strncpy(). I strncmp #include <string.h> int strncmp(const char *strl, const char *str2, size_t count); Функция strncmp () сравнивает в лексикографическом порядке не более count символов из двух строк, завершающихся нулевыми символами, и возвращает целое значение, следующим образом зависящее от результата сравнения. Значение Результат сравнения строк Меньше нуля strl меньше str2 Нуль strlравна str2 Больше нуля strl больше str2 Если в какой-нибудь из заданных строк меньше count символов, сравнение заканчивается При обнаружении первого нулевого символа. См. также функции strcmp (), strnchr () и strncpy (). I strncpy iinclude <string.h> char *strncpy(char *strl, const char *str2, size t count);
178 strpbrk Функция strncpy () копирует до count символов из строки, адресуемой параметром str2, в массив, адресуемый параметром strl. Параметр str2 должен указывать на строку с завершающим нулевым символом. В версии С99 к параметрам strl и str2 применен квали- фикатор restrict. Если заданные символьные массивы перекрываются, поведение функции strncpy () не определено. Если длина строки, адресуемой параметром str2, меньше значения count, то в конец строки-результата strl добавляются "недостающие" нулевые символы. И наоборот, если длина строки, .адресуемой параметром str2, больше значения count, результирующая строка, адресуемая параметром strl, автоматически не получит завершающего нулевого символа. Функция strncpy () возвращает значение указателя strl. См. также функции memcpy(), strchr(), strncat() и strncmp(). |strpbrk ¦include <string.h> char *strpbrk(const char *strl, const, char *str2); Функция strpbrk () возвращает указатель на первый символ в строке, адресуемой параметром strl, который совпадает с любым символом в строке, адресуемой параметром str2. Завершающие нулевые символы в расчет не берутся. Если совпадение не обнаружено, возвращается нулевой указатель. См. также функции strspnO, strrchrO, strstrO и strtokO. strrchr J ttinclude <string.h> char *strrchr(const char *str, int ch)
strspn 179 Функция strrchr () возвращает указатель на последнее вхождение младшего байта параметра ch в строке, адресуемой параметром str. Если совпадение не обнаружено, возвращается нулевой указатель. См. также функции strpbrk(), strspnf), strstrO и strtok(). Istrspn iinclude <string.h> size_t strspn(const char *strl, const char *str2); Функция strspn () возвращает длину начальной подстроки в строке, адресуемой параметром strl, которая состоит только из символов, содержащихся в строке, адресуемой параметром str2. Другими словами, функция strspn () возвращает индекс первого символа в строке strl, который не совпадает с любым из символов в строке str2. См. также функции strpbrk(), strrchr (), strstr() и strtok(). II strstr I #include <string.h> char *strstr(const char *strl, const char *str2); Функция strstr () возвращает указатель на первое вхождение в строке, адресуемой параметром strl, строки, адресуемой параметром str2. Если совпадение не обнаружено, возвращается нулевой указатель. См. также функции strchr(), strcspn(), strpbrk(), strspn(), strrchr() и strtok(). | strtok | #inelude <string.h> char *strtok(char *strl, const char *str2);
180 strxfrm Функция strtok () возвращает указатель на следующую лексему в строке, адресуемой параметром strl. Символы, образующие строку, адресуемую параметром str2, представляют собой разделители, которые определяют лексему. При отсутствии лексемы, подлежащей возврату, возвращается нулевой указатель. В версии С99 к параметрам strl и str2 применен квали- фикатор restrict. Чтобы разделить некоторую строку на лексемы, при первом вызове функции strtok () параметр strl должен указывать на начало этой строки. При последующих вызовах функции в качестве параметра strl нужно использовать нулевой указатель. В этом случае полная строка будет модифицироваться при каждом вызове функции. При каждом обращении к функции strtok () можно использовать различные наборы разделителей лексем. См. также функции strchrf), strcspn(), strpbrk(), strrchr() и strspn(). strxfrm 'КгС: ¦/.;-i:;: " :•¦•:,:,/¦У1.т;.-;/::>;:,.. -' ¦:;/¦.¦,.. "¦%:{ m ¦'¦ "¦-" '"" ¦-¦'*'•¦ • ": : -"¦¦ " •• ¦¦¦^¦¦^^¦*--ш #include <string.h> size_t strxfrm(char *strl, const char *str2, size_t count); Функция strxfrm() преобразует первые count символов строки, адресуемой параметром str2, таким образом, чтобы ее можно было использовать функцией strcmp (), и помещает результат в строку, адресуемую параметром strl. После преобразования результат вызова функции strcmpf), использующей параметр strl, будет совпадать с результатом вызова функции strcoll (), использующей исходную строку, на которую указывает параметр str2. В массив, адресуемый параметром strl, записывается не более count символов. В версии С99 к параметрам strl и str2 применен квали- фикатор restrict. Функция strxfrm () возвращает длину преобразованной строки. См. также функцию strcoll ().
strxfrm 181 Совет программисту Функция strtok () предоставляет средство, позволяющее сократить строку до составляющих ее частей. Например, следующая программа разделяет на лексемы строку "One, two, and three". ¦ include <stdio.h> '. ¦include <string.h> int main(void) { . ¦ ¦ char *p; p = strtok("One, two, and three.", ",");' printf(p); do { p = strtok(NULL, ",."); , ¦ :. if (p) printf("l%s", p); } while(p); return 0; } . Результат работы этой программы имеет следующий вид. One I two I and I three Обратите внимание, как функция strtok() сначала вызывается с исходной строкой, но в последующих ее вызовах в качестве первого аргумента используется значение NULL. Функция strtok () поддерживает внутренний указатель обрабатываемой строки. Если первый аргумент функции strtok () указывает на строку, внутренний указатель устанавливается в начало этой строки. Если первый аргумент равен значению NULL, функция strtok () продолжает процесс обработки предыдущей строки, начиная с позиции, запомненной на предыдущем шаге, и продвигает внутренний указатель по мере получения очередной лексемы. Таким образом, функция strtok () "проходит" всю строку. Также обратите внимание на то, как изменяется строка, задающая разделители, при первом и последующих вызовах функции. При каждом вызове разделители могут определяться по-разному.
182 tolower tolower #include <ctype.h> int tolower(int ch); Функция tolower () возвращает строчной эквивалент параметра ch, если ch — буква; в противном случае параметр ch не изменяется. См. также функцию toupper (). toupper #include <ctype.h> int toupper(int ch); Функция toupper () возвращает прописной эквивалент параметра ch, если ch — буква; в противном случае параметр ch не изменяется. См. также функцию tolower ().
Глава 8 Математические функции языка С В языках С и C++ определено множество разнообразных математических функций. Сначала оба языка поддерживали один и тот же набор, состоящий из 22 математических функций. Однако по мере развития языка C++ расширялся и арсенал определенных в нем функций. Затем в версии С99 размер математической библиотеки значительно увеличился. В результате этих изменений библиотеки математических функций языков С и C++ стали существенно отличаться одна от другой. Поэтому в данной главе описываются математические функции языка С (включая те, которые добавлены в версии С99), а в главе 9 уделено внимание исключительно функциям языка C++. При этом имейте в виду, что исходный набор математических функций по- прежнему поддерживается всеми версиями языков С и C++. Для использования всех математических функций в программу необходимо включить заголовок <math.h>. Помимо объявления математических функций, этот заголовок определяет один или несколько макросов. В версии С89 заголовком <math. h> определяется только макрос HUGE_VAL, который представляет собой значение типа double, сигнализирующее о возникшем переполнении. В версии С99 определены следующие макросы. HUGE_VALF float-версия макроса HUGE_VAL HUGE_VALL long double-версия макроса HUGE_VAL INFINITY Значение, представляющее бесконечность math_errhandling Содержит макросы MATH_ERRNO и/или . MATH_ERREXCEPT MATH_ERRNO Встроенная глобальная переменная errno, используемая для вывода сообщений об ошибках
184 MATH_ERREXCEPT NAN Исключение вещественного типа, возбуждаемое для вывода сообщения об ошибках Не число В версии С99 определены следующие макросы (подобные функциям), которые классифицируют значение. int fpclassify{fpval) int isfinite(fpval) int isinf(fpval) int isnan(fpval) int isnormal(fpval) int signbit(fpval) •Возвращает FP_INFINITY, FP_NAN, FP_NORMAL, FP_SUBNORMAL ИЛИ FP_ZEROB зависимости от значения аргумента fpval. Эти макросы определяются заголовком <math. h> Возвращает ненулевое значение, если fpval имеет предел Возвращает ненулевое значение, если fpval не имеет предела Возвращает ненулевое значение, если fpval — не число Возвращает ненулевое значение, если fpval является нормальным значением Возвращает ненулевое значение, если fpval отрицательно (т.е. установлен его знаковый разряд) В версии С99 определены следующие макросы сравнения, аргументами которых (а и Ь) должны быть значения с плавающей точкой. int isgreater (а, Ь) Возвращает ненулевое значение, если а больше Ъ int isgreaterequal (a, b) Возвращает ненулевое значение, если а больше или равно b int isless(a, b) Возвращает ненулевое значение, если а меньше b int islessequal (a, b) Возвращает ненулевое значение, если а меньше или равно b int islessgreater (a, b) Возвращает ненулевое значение, если а больше или меньше b
185 int isunordered(a, b) Возвращает 1, если а иЬне- упорядочены одно относительно другого. Возвращает 0, если а и Ъупорядочены Эти макросы прекрасно обрабатывают значения, которые не являются числами, не вызывая при этом исключений вещественного типа. Макросы EDOM и ERANGE также используются математическими функциями. Эти макросы определены в заголовке <errno. h>. Ошибки в версиях С89 и С99 обрабатываются по-разному. Так, в версии С89, если аргумент математической функции не попадает в домен, для которого он определен, возвращается некоторое значение, зависящее от конкретной реализации, а встроенная глобальная целая переменная errno устанавливается равной значению EDOM. В версии С99 ошибка нарушения границ домена также приводит к возврату значения, зависящего от конкретной реализации. Однако по значению math_errhandling можно судить о выполнении других действий. Если math_errhandling содержит значение MATH_ERRNO, встроенная глобальная целая переменная errno устанавливается равной значению EDOM. Если же math_errhandling содержит значение MATH_ERREXCEPT, возбуждается исключение вещественного типа. В версии С89, если функция генерирует результат, который слишком велик для возможностей представления, происходит переполнение. В этом случае функция возвращает значение HUGE_VAL, а переменная errno устанавливается равной значению ERANGE, сигнализирующему об ошибке диапазона. При обнаружении потери значимости функция возвращает нуль и устанавливает переменную errno равной значению ERANGE. В версии С99 ошибка переполнения также приводит к тому, что функция возвращает значение HUGE_VAL, а при потере значимости— нуль. Если math_errhandling содержит значение MATH_ERRNO, глобальная переменная errno устанавливается равной значению ERANGE, свидетельствующему об ошибке диапазона. Если же math_errhand- ling содержит значение MATH_ERREXCEPT, возбуждается исключение вещественного типа. В версии С89 аргументами математических функций должны быть значения типа double и значения, возвращаемые функциями, имеют тип double. В версии С99 добавлены float- и long double-варианты этих функций, которые ис-
186 acos пользуют суффиксы f и 1 соответственно. Например, в версии С89 функция sin () определена следующим образом. double sin(double arg); В версии С99 поддерживается приведенное выше определение функции sin() и добавляются еще две ее модификации— sinf() иsinl(). float sinf(float arg); long double sinl(long double arg); Операции, выполняемые всеми тремя функциями, одинаковы; различаются лишь данные, подвергаемые этим операциям. Добавление f - и 1-модификаций математических функций позволяет использовать версию, которая наиболее точно соответствует вашим данным. Поскольку в версии С99 добавлено так много новых функций, стоит отдельно перечислить функции, поддерживаемые версией С89 (они также используются в языке C++). acos cos fmod modf tan asm cosh frexp pow tanh at an exp ldexp sin atan2 f abs log sinh ceil floor loglO sqrt И еще одно: все углы задаются в радианах. | acos I #include <math.h> float acosf(float arg); double acos(double arg); long double acosl(long double arg); Функции acosf () и acosl () добавлены в версии С99. Каждая функция семейства acos () возвращает значение арккосинуса от аргумента arg. Значение аргумента должно находиться в диапазоне от -1 до 1; в противном случае возникает ошибка нарушения границ домена. См. также функции asin(), atan(), atan2 (), sin(), cos(), tan(), sinh(), cosh() и tanh().
acosh 187 acosh ttinclude <math.h> float' acoshf(float arg) ; double acosh(double arg); long double acoshldong double arg); Функции acosh(), acoshf () и acoshl () добавлены в версии С99. Каждая функция семейства acosh () возвращает значение гиперболического арккосинуса от аргумента arg. Значение аргумента должно быть больше или равно нулю; в противном случае возникает ошибка нарушения границ домена. См. также функции asinh (), atanh (), sinh (), cosh () и tanh(). #include <math.h> float asinf(float arg); double asin(double arg); long double asinl(long double arg); Функции asinf () и asinl () добавлены в версии С99. Каждая функция семейства asin() возвращает значение арксинуса от аргумента arg. Значение аргумента должно находиться в диапазоне от -1 до 1; в противном случае возникает ошибка нарушения границ домена. См. также функции acos (), atanO, atan2 (), sin(), cos(), tan(), sinh(), cosh() и tanh(). Iasinh #include <math.h> float asinhfffloat arg); d'ouble asinh (double arg); long double asinhl(long double arg);
188 atan Функции asinh(), asinhf () и asinhlO добавлены в версии С99. Каждая функция семейства asinh () возвращает значение гиперболического арксинуса от аргумента агд. См. также функции acosh (), atanh (), sinh (), cosh () и tanh (). atan #include <math.h> float atanf(float arg); double atan(double arg); long double atanldong double arg); Функции atanf () и atanl () добавлены в версии С99, Каждая функция семейства atan () возвращает значение арктангенса от аргумента агд. См. также функции asin (), acos (), atan2 (), sin (), cos(), tan(), sinh(), cosh() и tanh(). atanh #include <math.h> float atanhf(float arg); double atanh(double arg); long double atanhl(long double arg); Функции atanh(), atanhf () и atanhl () добавлены в версии С99. Каждая функция семейства atanh () возвращает значение гиперболического арктангенса от аргумента агд. Значение аргумента должно находиться в диапазоне от -1 до 1 (не включая границы); в противном случае возникает ошибка нарушения границ домена. Если агд равен 1 или -1, возможна ошибка пределов диапазона. См. также функции asinh (), acosh (), sinh (), cosh () и tanh().
atan2 189 atan2 #include <math.h> float atan2f(float a, float b); double atan2(double a, double b); long double atan21(long double a, long double b); Функции atan2f () и atan21 () добавлены в версии С99. Каждая функция семейства atan2 () возвращает значение арктангенса от alb. Для вычисления квадранта возвращаемого значения используются знаки аргументов функции. См. также функции asin(), acos (), atanO, sin(), cos(), tan(), sinh(), cosh() и tanh(). cbrt #include <math.h> float cbrtf(float пит); double cbrt(double лит); long double cbrtl(long double пит); Функции cbrt (), cbrtf () и cbrtl () добавлены в версии C99. Каждая функция семейства cbrt () возвращает значение кубического корня от аргумента num. См. также функцию sqrt (). ceil #include <math.h> float ceilf(float лит); double ceil(double пит); long double ceill(long double пит); Функции ceilf () и ceill () добавлены в версии С99. 'Каждая функция семейства ceil О возвращает наименьшее целое (представленное в виде значения с плавающей точкой), которое больше значения аргумента пит или равно ему.
190 copysign Например, при пит, равном 1,02, функция ceil ()¦ вернет значение 2,0, а при пит, равном -1,02, — значение -1. См. также функции floor () и fmod (). copysign #include <math.h> float copysignf(float val, float signval); double copysign(double val, double signval); long double copysignl(long double val, long double signval); Функции copysign (), copysignf () и copysignl () добавлены в версии С99. Каждая функция семейства copysign () наделяет аргумент val знаком, который имеет аргумент signval, и возвращает полученный результат (т.е. возвращаемое значение имеет величину, равную величине аргумента val, но его знак совпадает со знаком аргумента signval). См. также функцию f abs (). COS #include <math.h> float cosf(float arg); double cos(double arg); long double cosl(long double arg); Функции cosf () и cosl () добавлены в версии С99. Каждая функция семейства cos () возвращает значение косинуса аргумента arg. Значение аргумента должно быть выражено в радианах. См. также функции asin(), acos(), atan(), atan2 (), sin(), tan(), sinh(),cosh() и tanh(). I cosh I II " #include <math.h> float coshf(float arg);
erf 191 double cosh(double arg); long double coshlflong double arg); Функции coshf () и coshl () добавлены в версии С99. Каждая функция семейства cosh () возвращает значение гиперболического косинуса аргумента агд. См. также функции asin (), acos (), atan (), atan2 (), sin(),cos(), tan(), sinh() и tanh(). krt #include <math.h> float erff(float arg); double erf(double arg); long double erfl(long double arg); Функции erf (), erf f () и erf 1 () добавлены в версии С99. Каждая функция семейства erf () возвращает значение функции ошибок от аргумента агд. См. также функцию erf с (). I erfc iinclude <math.h> float erfcf(float arg); double erfc(double arg); long double erfcl(long double arg); Функции erfc (), er f cf () и erf cl () добавлены в версии С99. Каждая функция семейства erfc () возвращает дополнительное значение функции ошибок для аргумента агд. См. также функцию erf (). iinclude <math.h> float expf(float arg);
192 ехр2 double exp(double arg); long double expl(long double arg); Функции expf () и expl () добавлены в версии С99. Каждая функция семейства ехр () возвращает значение экспоненты от аргумента arg (число е, возведенное в степень, которая равна значению аргумента arg). См. также функции ехр2 () и log (). #include <math.h> float exp2f(float arg); double exp2(double arg); long double exp21(long double arg); Функции exp2 (), exp2 f () и exp21 () добавлены в версии C99. Каждая функция семейства ехр2 () возвращает число 2, возведенное в степень, которая равна значению аргумента arg). См. также функции ехр () и log (). #include <math.h> float expmlf(float arg); double expml(double arg) ; long double expmll(long double arg); Функции expml (), expml f () и expml 1 () добавлены в версии С99. Каждая функция семейства expml () возвращает уменьшенное на единицу значение натурального логарифма е, возведенного в степень, которая равна значению аргумента arg (т.е. возвращаемое значение равно е"я - 1). См. также функции ехр () и log ().
tabs 193 [fabs. #include <math.h> float fabsf(float nirni) ; double fabs(double пит); long double fabsl(long double пит); Функции f absf () и fabsl () добавлены в версии C99. Каждая функция семейства fabs () возвращает абсолютное значение аргумента num. См. также функцию abs (). <fdim "¦ •-¦•¦¦¦¦» #include <math.h> float fdimf(float a, float b); double fdim(double a, double b); long double fdimldong double a, long double b); Функции fdira(), fdimf {) и fdiml () добавлены в версии С99. Каждая функция семейства f dim () возвращает нуль, если значение аргумента а меньше значения аргумента b или равно ему. В противном случае возвращается результат вычисления разности а- Ь. См. также функции remainder () и remquo (). floor J #include <math.h> float floorf(float пит); double floor(double пит); long double floorl(long double пит); Функции f loorf () и f loorl () добавлены в версии С99. Каждая функция семейства floor () возвращает наибольшее целое (представленное в виде значения с плавающей точкой), которое меньше значения аргумента пит или равно
194 fma ему. Например, при лит, равном 1,02, функция floor () вернет значение 1,0, а при лит, равном -1,02, — значение -2,0. См. также функции ceil () и fmod (). #include <math.h> float fmaf(float a, float b, float c); double fma(double a, double b, double c); long double final (long double a, long double b, long double c); Функции fma (), fma () и fma () определены в версии С99. Каждая функция семейства fma () возвращает значение. а * Ь+ с. Округление выполняется только однажды, после завершения всей операции. См. также функции round (), 1 round () и 11 round (). fmax J #include <math.h> float fmaxf(float a, float b); double fmax(double a, double b); long double f maxl {long double a, long double b); Функции fmax (), fmaxf () и fmaxl () определены в версии C99. Каждая функция семейства fmax () возвращает большее из значений двух аргументов а и Ь. См. также функцию f min (). I*-1» #include <math.h> float fminf(float a, float b); double fmin(double a, double b) ; long double fminl(long double a, long double b); Функции fmin (), fminf () и fmini () определены в версии С99.
fmod 195 Каждая функция семейства f min () возвращает меньшее из значений двух аргументов а и Ь. См. также функцию f max (). I fmod #include <math.h> float fmodf(float a, float b) ; double fmod(double a, double b) ; long double fmodlflong double a, long double b); Функции fmodf () и fmodl (} определены в версии С99. Каждая функция семейства fmod () возвращает остаток от деления значений аргументов а/Ь. См. также.функции ceil (), floor () и fabs (). I fyexp #include <math.h> , ......-,. float frexpf(float лшп, int *exp); double frexp(double_num, int *exp); long double frexpl(long double лит, int *exp); Функции frexpf () и f rexpl () добавлены в версии С99. Каждая функция семейства frexp () разбивает число, задаваемое параметром пит, на мантиссу mantissa и экспоненту ехр таким образом, что значение mantissa больше или равно 0,5 и меньше 1, а целочисленное значение экспоненты присваивается переменной, адрес которой задается параметром ехр: пит = mantissa * 2<"р. Значение мантиссы возвращается функцией, а экспонента сохраняется в переменной, адресуемой параметром ехр. См. также функцию ldexp (). Ihypot 4-include Kinath. h> float hypotf(float sidel, float side2);
196 ilogb double hypot(double sidel, double side2); long double hypotldong double sidel, long double side2) ; "*" Функции hypot (), hypotf () и hypotl() определены в версии С99. Каждая функция семейства hypot () возвращает длину гипотенузы при заданных длинах двух катетов (т.е. функция возвращает значение квадратного корня из суммы квадратов значений аргументов sidel и side2). См. также функцию sqrt (). ilogb #include <math.h> int ilogbf(float пит); int ilogb(double пит); int ilogbl(long double пит); Функции ilogbO, ilogbf () и ilogbl() добавлены в версии С99. Каждая функция семейства ilogb() выделяет экспоненциальное значение аргумента пит, как если бы этот аргумент был представлен с помощью бесконечного диапазона. Возвращаемое значение имеет тип int. См. также функцию logb (). #include <math.h> float ldexpf(float пит, int exp); double ldexp(double пит, int exp); long double ldexpldong double пит, int exp); Функции ldexpf () и ldexp 1 () добавлены в версии С99. Каждая функция семейства ldexp () возвращает значение выражения пит * 2ехр. См. также функции f rexp () и modf ().
Igamma 197 1 g #include <math.h> .<•. float lgammaf(float arg) ; double Igamma(double arg); long double lgammal(long double arg); Функции Igamma (), lgammaf () и lgammal,() добавлены в версии С99. Каждая функция семейства Igamma () вычисляет абсолютное значение гамма-функции от аргумента arg и возвращает ее натуральный логарифм. См. также функцию tgamma (). Illrlnt "I #include <math.h> long long int llrintf(float arg); long long int llrint(double arg); long long int llrintlflong double arg); Функции llrint (), llrintf () Hllrintl() добавлены в версии С99. Каждая функция семейства llrint () возвращает значение аргумента arg, округленного до ближайшего целого, которое имеет тип long long int. См. также функции lrint () и rint (). llround #include <math.h> long long int llroundf(float arg); long long int llround(double arg); long long int llroundl(long double arg);. Функции llround (), llroundf () и llroundl () добавлены в версии С99. Каждая функция семейства llround() возвращает значение аргумента arg, округленное до ближайшего целого, кото-
198 log рое имеет тип long long int. Значения, отстоящие от большего и меньшего целых на одинаковую величину (например, число 3,5), округляются в сторону большего целого. См. также функции 1 round () и round (). 'log #include <math.h> float logf(float пит); double log (double лил?); long double logl(long double пит); Функции logf () и logl () добавлены в версии С99. Каждая функция семейства log О возвращает значение натурального логарифма для аргумента пил?. Если значение аргумента лил? отрицательно, возникает ошибка нарушения границ домена. Если же значение пит равно нулю, возможна ошибка пределов диапазона. См. также функции loglO () и 1од2 (). #include <math.h> float loglpf (float лил?); double loglp (double лил?) ; long .double loglpl(long double лил?); Функции loglp(), loglpf () и loglpl() добавлены в версии С99. Каждая функция семейства loglp () возвращает значение натурального логарифма для аргумента лил? + 1. Если значение аргумента лил? отрицательно, возникает ошибка нару- 'шения границ домена. Если же значение лил? равно -1, возможна ошибка пределов диапазона. См. также функции logl 0 () и 1од2 (). #include <math.h> float Iogl0f( float лип?);-
Iog2 199 \ double loglO(double num); long double loglOl(long double пит); Функции loglOf() и1од101() добавлены в версии С99. Каждая функция семейства log 10 () возвращает значение логарифма по основанию 10 для аргумента лит. Если значение аргумента лит отрицательно, возникает ошибка нарушения границ домена. Если же значение лит равно нулю, возможна ошибка пределов диапазона. См. также функции log () и 1од2 (). |1од2 #include <math.h> float Iog2f(float пит); double Iog2(double лит); long double Iog21(long double пит); Функции 1од2 (), Iog2 f () и 1од21 () добавлены в версии С99. Каждая функция семейства 1од2 () возвращает значение логарифма по основанию 2 для аргумента лит. Если значение аргумента лит. отрицательно, возникает ошибка нарушения границ домена. Если же значение лит равно нулю, возможна ошибка пределов диапазона. См. также функции log () и loglO (). 'logb #include <math.h> float logbf(float num); double logb(double num); long double logbl(long double лит); Функции logb (), logbf () и logbl () добавлены в версии С99. Каждая функция семейства logb () выделяет экспоненциальное значение аргумента лит, как если бы этот аргумент был представлен с помощью бесконечного диапазона. Возвращаемое значение является числом с плавающей точкой.
200 Irint Если значение аргумента пит равно нулю, возможна ошибка нарушения границ домена. См. также функцию ilogb(). Irint #include <math.h> long int lrintf(float arg); long int Irint(double arg) ; long int lrintl(long double arg); Функции Irint (), lrintf () и lrintlO добавлены в. версии С99. Каждая функция семейства Irint () возвращает значение аргумента arg, округленное до ближайшего целого, которое имеет тип long int. См. также функции llrint () и rint (). lround #include <math.h> long int lroundfffloat arg); long int lround (double -arg) ; lofig int lroundl (long double arg); •,! { . ¦' . "-- ¦' Функции lround-(••¦)» Iroundf () и lroundl () добавлены в версии С99. Каждая функция семейства lrourtdO возвращает значение аргумента arg, округленное до ближайшего целого, которое имеет тип long int. Значения, отстоящие от большего и меньшего целых на одинаковую величину (например, число 3,5), округляются в сторону большего целого. См. также функции 11 round () и round (). modf #include <math.h> float modff(float пит, float *i)
nan 201 double modf(double пит, double *i); long double modf1(long double пит, long double *i); Функции modf f () и modf 1 () добавлены в версии C99. Каждая функция семейства modf () разбивает аргумент пит на целую и дробную части. Функция возвращает дробную часть и размещает целую часть в переменной, адресуемой параметром i. См. также функции f rexp () и Idexp (). #include <math.h> float nanf(const char *content); double nan(const char *content); long double nanl(const char *content); Функции nan (), nanf () и nanl () добавлены в версии С99. Каждая функция семейства пап О возвращает значение, которое^не является числом и которое^^ садщщи^сдроку, адре? суемую параметром content. См. также функцию isnan (). |nearbyint ¦include <math.h> float nearbyintf(float arg); double nearbyint(double arg); long double nearbyintl(long double arg); Функции nearbyint (), nearbyintf (.) и nearbyintlO добавлены в версии С99. Каждая функция семейства nearbyint () возвращает значение аргумента arg, округленное до ближайшего целого. Однако возвращаемое число является значением с плавающей точкой. См. также функции г int () и round ().
202 nextafter nextafter #include <math.h> float nextafterf(float from, float towards); double nextafter(double from, double towards); long double nextafterl(long double from, long double towards) ; Функции nextafter(), nextafterf() и nextafterl() добавлены в версии С99. Каждая функция семейства nextafter () возвращает следующее после аргумента from значение, ближайшее к значению аргумента towards. См. также функцию nexttoward (). I next toward I #include <math.h> float nexttowardf(float from, long double towards); ..."...... double nexttoward(double from, long double towards) ; long double nexttowardl(long double from, long double towards); Функции nexttoward (), nexttowardf () и nexttowardl () добавлены в версии С99. Каждая функция семейства nexttoward () возвращает следующее после аргумента from значение, ближайшее к значению аргумента towards. Действие этих функций аналогично действию функций семейства nextafter () за исключением того, что параметр towards имеет тип long double для всех трех функций. См. также функцию nextafter ().
pow 203 #include <math.h> float powf(float base, float exp); double pow(double base, double exp); long double powldong double base, long double exp); Функции powf () и powl () добавлены в версии С99. Каждая функция семейства pow () возвращает значение аргумента base, возведенное в степень, которая равна значению аргумента ехр, т.е. baseexp. Если значение аргумента base равно нулю, а ехр меньше или равно нулю, возможна ошибка нарушения границ домена. Ее возникновение также вероятно, если значение base отрицательно, а ехр не является целым значением. При этом также возможна ошибка пределов диапазона. См. также функции ехр {), log () и sqrt (). I remainder 11 #include <math.h> float remainderf(float a, float b); double remainder(double a, double b); long double remainderl (long double a, .... ,: long double b); Функции remainder (), remainderf () и. remainder;^ () определены в версии С99. Каждая функция семейства remainder () возвращает остаток от деления значений аргументов alb. См. также функции remque (). remquo #include <math.h> float remquof(float a, float b, int *que); double remquo(double a, double b, int *gue)
204 rint long double remquol(long double a, long double b, int *gue); Функций feiriquo (J, remquof () и remquSl () определены в версии С99. Каждая функция семейства remquo () возвращает остаток от деления значений аргументов а/Ь. При этом целое, адресуемое параметром gue, будет содержать частное. См. также функции remainder (). »rlnt I #include <math.h> float rintf(float arg); double rint(double arg); long double rintl(long double arg); Функции r int (), rintf () nrintl() добавлены в версии С99. Каждая функция семейства rint () возвращает значение аргумента arg, округленное до ближайшего целого. Однако возвращаемое число является значением с плавающей точкой. Может возникнуть исключительная ситуаций вещественного типа. См. также функции nearbyint (), rint () и round (). round . . ШШ '¦-- ¦ 1 вянаавнвававвиЕвв^1^^вв1вввввва ¦include <math.h> float roundf(float arg); double round(double arg); long double roundl(long double arg); Функции round(), roundf () и roundl () добавлены в версии С99. Каждая функция семейства round () возвращает значение аргумента arg, округленное до ближайшего целого. Однако возвращаемое число является значением с плавающей точкой. Значения, отстоящие от большего и меньшего целого на одинаковую величину (например, число 3,5), округляются в сторону большего целого. См. также функции 1 round () и llround ().
scalbn 205 scalbn ¦include <math.h> ' ; float scalbnf(float val, int exp); double scalbn(double val, int exp); , long double scalbnldong double val, int exp); Функции scalbn (), scalbnf () и scalbnl () добавлены в версии С99. Каждая функция семейства scalbn () возвращает произведение параметра val и значения FLT_RADIX, возведенного в степень, которая равна значению параметра ехр, т.е. val * FLT_RADIXexp. Макрос FLT_RADIX определен в заголовке <f loat .h>, и его значение — это основание экспоненциального представления. См. также функцию scalbln {). |scalbln - 1 #include <math.h> float scalblnf(float val, long int exp); double scalbln(double val, long int exp); long double scalblnlflong double val, long int exp); Функции scalblnO, scalblnf () и scalblnK) добавлены в версии С99. Каждая функция семейства scalbln () возвращает произведение параметра val и значения FLT_RADIX, возведенного в степень, которая равна значению параметра ехр, т.е. val * FLT_RADIXew. Макрос FLT_RADIX определен в заголовке <float.h>, и его значение — это основание представления экспоненты. См. также функцию scalbn ().
206 sin LiS I #include <math.h> float sinf(float arg) ; double sin(double arg) ; long double sinl(long double arg); Функции sinf () и sinl () добавлены в версии С99. Каждая функция семейства sin О возвращает значение синуса от аргумента arg. Значение аргумента должно быть задано в радианах. См. также функции asin (), acos (), atan (), atan2 (), cos(), tan(), sinh(), cosh() и tanh(). slnh #include <math.h> float sinhf(float arg); double sinh(double arg) ; long double*siriiil [long* double arg) • "'"" * "' Функции sinhf () и sinhl () добавлены в версии С99. Каждая функция семейства sinh() возвращает значение гиперболического синуса от аргумента arg. См. также функции asin(), acos (), atan(), atan2(), sin(), cos(), tan(), eosh() и tanh(). #include <math.h> float cgrtf(float пит); double cqrt(double лит); long double cqrtldong double пит) ; Функции cqrtf () и cqrtl () добавлены в версии С99. Каждая функция семейства cqrt () возвращает значение квадратного корня от аргумента пит. Если значение
tan 207 аргумента пит отрицательно, возникает ошибка нарушения границ домена. См. также функции ехр (), log () и pow (). #include <math.h> float tanf(float arg); double tan(double arg); long double tanldong double arg); Функции tanf () и tanl () добавлены в версии С99. Каждая функция семейства tan() возвращает значение тангенса от аргумента arg. Значение аргумента должно быть задано в радианах. См. также функции asin(), acos(), atan(), atan2(), sin(), cos(), sinh(),cosh() и tanh(). tanh J #include <math.h> float tanhf(float arg); double tanh(double arg); long double tanhl(long double arg); Функции tanhf () и tanhl () добавлены в версии С99. Каждая функция семейства tanh () возвращает значение гиперболического тангенса от аргумента arg. См. также функции asinh (), acosh (), atan (), atan2 (), sin(), cos (), sinh(), cosh() Htan(). ¦include <math.h> float tgammaf(float arg); double tgamma(double arg); long double tgammal(long double arg);
208 trunc Функции tgamma (), tgammaf () и tgammal (} добавлены в версии С99. Каждая функция семейства'tgamma () возвращает значение гамма-функции от аргумента агд. См. также функцию lgamma (). fcrunc #include <math.h> float truncf(float arg); double trunc(double arg); long double trunclflong double arg); Функции trunc(), truncf () и truncl () добавлены в версии С99. д .•¦? Каждая функция семейства trunc () возвращает усеченное значение аргумента агд. См. также функцию nearbyint ().
Глава 9 Математические функции языка C++ Как было отмечено в главе 8, в языках С и C++ первоначально поддерживался один и тот же набор из 22 математических функций. Однако по мере развития языка C++ к нему добавились перегруженные версии этих оригинальных функций. Затем размер математической библиотеки версии С99 значительно увеличился, причем таким способом, который не поддерживается в языке C++. В результате этих изменений библиотеки математических функций языков С и C++ на сегодняшний день существенно отличаются одна от другой, однако исходный набор математических функций по-прежнему поддерживается всеми версиями. Ввиду значительных различий между языками С и C++ в этой области математические функции языка С (включая те, которые добавлены в версии С99) описываются в главе 8, а в данной главе внимание уделяется функциям, определенным исключительно в языке C++. Для использования математических функций в языке C++ необходимо включение в программу заголовка <cmath.h>. Этот заголовок не только объявляет математические функции, но и определяет макрос HUGE_VAL. Макросы EDOM и ERANGE также используются математическими функциями. Эти макросы определены в заголовке <cerrno.h>. Если аргумент математической функции не попадает в домен, для которого он определен, функцией возвращается некоторое значение, зависящее от конкретной реализации, а встроенная глобальная целая переменная errno устанавливается равной значению EDOM. Если функция генерирует результат, который слишком велик для возможностей представления, происходит переполнение. В этом случае функция возвращает значение HUGE_VAL, а переменная errno устанавливается равной значению ERANGE, сигнализирующему об ошибке диапазона. При обнаружении потери значимости функция возвращает нуль и устанавливает переменную errno равной значению ERANGE. В языке C++ поддерживаются оригинальные математические функции, определенные в версии С89. Однако в версии С89 аргументами математических функций должны быть щ
210 acos только значения типа double. К этим функциям в языке C++ добавились перегруженные версии, которые явно предназначены для приема значений типа float и long double. Действия, выполняемые функциями, остались теми же. Все углы задаются в радианах. Iacos Д #include <cmath.h> float acos(float arg); double acos(double arg); long double acos(long double arg); Функция acos (} возвращает значение арккосинуса от аргумента arg. Значение аргумента должно находиться в диапазоне от -1 до 1; в противном случае возникает ошибка нарушения границ домена. См. также функции asin(), atan(), atan2 (), sin(), cos(), tan(), sinh(), cosh() и tanh(). a sin #include <cmath.h> float asin(float arg); double asin(double arg); long double asin(long double arg); Функция asin () возвращает значение арксинуса от аргумента arg. Значение аргумента должно находиться в диапазоне от -1 до 1; в противном случае возникает ошибка нарушения границ домена. См. также функции acos (), atan(), atan2(), sin(), cos(), tan(), sinh(),cosh() и tanh(). 'atan #include <cmath.h> float atan(float arg); double atan(double arg); long double atan(long double arg);
atan2 211 Функция atan() возвращает значение арктангенса от аргумента arg. См. также функции asin(), acos (), atan2 (}, sin(), cos(), tan(), sinh(), cosh() и tanh(). atan2 #include <cmath.h> float atan2(float y, float x) ; double atan2(double у, double x); long double atan2(long double y, long double x) ; Функция atan2 () возвращает значение арктангенса от у/х. Для вычисления квадранта возвращаемого значения используются знаки аргументов функции. См. также функции asin(), acos (), atan(), sin(), cos(), tan(), sinh(), cosh() и tanh(). #include <cmath.h> float ceil(float пит); double ceil(double пит); long double ceil(long double пит); Функция ceil() возвращает наименьшее целое (представленное в виде значения с плавающей точкой), которое больше значения аргумента лит или равно ему. Например, при лит, равном 1,02, функция ceil () вернет значение 2,0, а при лит, равном -1,02, — значение -1. См. также функции floor () и fmod (). lcos I #include <cmath.h> float cos(float arg); double cos(double arg); long double cos(long double arg); "Функция cos () возвращает значение косинуса аргумента arg. Значение аргумента должно быть выражено в радианах.
212 cosh См. также функции asin(), acos (), atan(), atan2 (), sin(), tan(),sinh(), cosh() и tanh(). | cosh #include <cmath.h> float cosh(float arg); double cosh(double arg); long double cosh(long double arg); Функция cosh () возвращает значение гиперболического косинуса от аргумента arg. См. также функции asin (), acos (), atan (), atan2 (), sin(), cos(), tan(), sinh() и tanh(). 'exp tinclude <cmath.h> float exp(float arg); double exp(double arg); long double exp(long double arg); Функция exp () возвращает значение экспоненты от аргумента arg (число е, которое возведено в степень, равную значению аргумента arg). См. также функцию log (). 'fabs #include <cmath.h> float fabs(float пит); double fabs(double лит); long double fabs(long double пит); Функция fabs () возвращает абсолютное значение аргумента лит. См. также функцию abs (), описанную в главе 12. #include <cmath.h> float floor(float пит)
fmod 213 double floor (double num); long double floor(long double пил); Функция floor () возвращает наибольшее целое (представленное в виде значения с плавающей точкой), которое меньше значения аргумента пит или равно ему. Например, при лит, равном 1,02, функция floor () вернет значение 1,0, а при лит, равном -1,02, — значение -2,0. См. также функции ceil () и fmod (). lfmod #include <cmath.h> float fmod(float x, float y) ; double fmod(double x, double y) ; long double fmod(long double x, long double y); Функция fmod () возвращает остаток от деления значений аргументов х/у. См. также функции ceil (), floor () и f abs (). I frexp | #include <cmath.h> float frexp(float пит, int *exp); double frexp(double лит, int *exp); long double frexp(long double лит, int *exp); Функция floor () разбивает число, задаваемое параметром лит, на мантиссу mantissa и экспоненту ехр таким образом, что значение mantissa больше или равно 0,5 и меньше 1, а целочисленное значение экспоненты присваивается переменной, адрес которой задается параметром ехр: num = mantissa * 2вхе. Значение мантиссы возвращается функцией, а экспонента сохраняется в переменной, адресуемой параметром ехр. См. также функцию ldexp (). ldexp ¦include <cmath.h> float ldexp(floatnum, int exp); double ldexp(double лит, int exp); long double ldexp(long double лит, int exp);
214 log Функция ldexp () возвращает значение выражения пит 1ехр. При переполнении возвращается значение HUGE_VAL. См. также функции f гехр () и modf (). #include <cmath.h> float log(float пит); double log(double пит); long double log(long double пит); Функция log () возвращает значение натурального логарифма для аргумента пит. Если значение аргумента лит отрицательно, возникает ошибка нарушения границ домена, а если значение пит равно нулю — ошибка пределов диапазона. См. также функцию log 10 (). [log!0 #include <cmath.h> float Iogl0(float лига); double loglO(double лига); long double Iogl0(long double num); Функция log 10 () возвращает значение логарифма по основанию 10 для аргумента лил?. Если значение аргумента лшп отрицательно, возникает ошибка нарушения границ домена, а если значение лит равно нулю — ошибка пределов диапазона. См. также функцию log (). ttinclude <cmath.h> float modf(float лит, float *i); double modf(double num, double *i); long double modf(long double лит, long double *i); Функция modf () разбивает аргумент лит на целую и дробную части. Функция возвращает дробную часть и размещает целую часть в переменной, адресуемой параметром i. См. также функции f гехр () и ldexp ().
pow 215 pow tinclude <cmath.h> float pow(float base, float exp) ; float pow(float base, int exp); double pow(double base, double exp); double pow(double base, int exp); long double pow(long double base, long double exp); long double pow(long double base, int exp); Функция pow () возвращает значение аргумента base, которое возведено в степень, равную значению аргумента ехр, т.е. baseexp. Если значение аргумента base равно нулю, а ехр меньше или равно нулю, возможна ошибка нарушения границ домена. Ее возникновение также вероятно, если значение base отрицательно, а ехр не является целым значением. При переполнении возникает ошибка пределов диапазона. См. также функции ехр (), log () и sqrt (). Isin Щ #include <cmath.h> float sin(float arg); double sin(double arg); long double sin(long double arg); Функция sin () возвращает значение синуса от аргумента arg. Значение аргумента должно быть задано в радианах. См. также функции asin(), acos (), atanO, atan2 (), cos(), tan(), sinh(), cosh() и tanh(). sinh #include <cmath.h> float sinhffloat arg); double sinh(double arg); long double sinh(long double arg); •Функция sinh() возвращает значение гиперболического синуса от аргумента arg.
216 sqrt См. также функции asinO, acos(), atan(), atan2( sin(), cos(), tan(), cosh() и tanh(). #include <cmath.h> float sqrt(float пит); double sqrt(double пит); long double sqrt(long double пит); Функция sqrt () возвращает значение квадратного корня от аргумента лит. Если значение аргумента пит отрицательно, возникает ошибка нарушения границ домена. См. также функции ехр (), log () и pow (). 'tan I #include <cmath.h> float tan(float arg); double tan(double arg); long double tan(long double arg); Функция tan () возвращает значение тангенса от аргумента arg. Значение аргумента должно быть задано в радианах. См. также функции asin (), acos (), atan (), atan2 (), sin(), cos(), sinh(), cosh() и tanh(). | tanh I] #include <cmath.h> float tanh(float arg); double tanh(double arg) ; long double tanh(long double arg); Функция tanh() возвращает значение гиперболического тангенса от аргумента arg. См. также функции asinh (), acosh (), atan (), atan2 (), sin(),cos(), sinh(), cosh() и tan().
Глава 10 Функции времени, даты и геополитической среды Стандартная библиотека C/C++ включает ряд функций, работающих с датой и временем, а также функции, обрабатывающие геополитическую информацию, связанную с программой. Именно этим функциям и посвящена данная глава. В языке С использование функций даты и времени требует включения заголовка <time.h>, а в языке C++ — заголовка <ctime.h>. В этой главе для простоты изложения используются именаС-заголовков, но ссылки на заголовок <time.h> в соответствующей среде нужно заменить ссылками на заголовок <ctime.h>. В заголовке <time.h> определены три типа данных, связанных с исчислением времени: clock_t, time_t и tm. Типы clock_t и time_t предназначены для представления системного времени и даты в виде некоторого целого значения, называемого календарным временем. Тип структуры tm содержит дату и время в виде разбиения на элементы. Итак, структура tm содержит следующие члены. struct tm { int tm_sec; /* секунды, 0-61 */ int tm_min; /* минуты, 0-59 */ int tm_hour; /* часы, 0-23 */ int tm_mday; /* день месяца, 1-31 */ int tm_mon; /* месяц, начиная с января, 0-11 */ int tm_year; /* год после 1900 */ int tm_wday; /* день, начиная с воскресенья, 0-6 */ int tm_yday; /* день, начиная с 1-го января, 0-365 */ int tm_isdst /* индикатор летнего времени */ Значение tm_isdst положительно, если действует режим летнего времени (Daylight Saving Time), равно нулю, если не действует, й отрицательно, если информация об этом недоступна.
218 asctime Кроме того, в заголовке <time.h> определен макрос CLOCKS_PER_SEC, который выдает количество тиканий системных часов в секунду. Для работы с функциями геополитической среды необходимо использовать в языке С заголовок <1оса1е .h>, а в языке C++ — заголовок <clocale. h>. В этих заголовках определена структура lconv, которая приведена в описании функции localeconv (). I asctime 1 #include <time.h> char *asctime(const struct tm *ptr); Функция аз с time () возвращает указатель на строку, которая содержит информацию, сохраняемую в адресуемой параметром ptr структуре и имеющую следующую форму. день месяц число часы:минуты:секунды год\п\0 Например: Wed Jun 19 12:05:34 2005 Указатель на структуру, передаваемый" функции asctime(), обычно получают с помощью либо функции localtime (), либо функции gmtime (). Буфер, используемый функцией asctime () для хранения форматированной строки результата, представляет собой статически выделенный символьный массив, который перезаписывается при каждом вызове этой функции. Если нужно сохранить содержимое данной строки, скопируйте его в какую- нибудь другую область памяти. См. также функции localtime(), gmtime(), time() и ctime(). (clock ЕВжвввввваввввааввквввааававававваввввввваЕв ttinclude <time.h> clock_t clock(void); Функция clock () возвращает значение, которое приблизительно соответствует продолжительности времени работы вызы-
ctime 219 вающей программы. Для преобразования этого значения в секунды нужно разделить его на значение CLOCKS_PER_SEC. Если запрашиваемое время недоступно, возвращается значение -1. См. также функции asctime (), time () и ctime (). | ctime -^ ttinclude <time.h> char *ctime(const time_t *time); Функция ctime () возвращает указатель на строку вида день месяц число часы:минуты:секунды год\п\0, принимая в качестве параметра указатель на календарное время. Календарное время часто получают с помощью функции t ime (). Буфер, используемый функцией ctime () для хранения форматированной строки результата, представляет собой статически выделенный символьный массив, который перезаписывается при каждом вызове этой функции. Если нужно сохранить содержимое данной строки, скопируйте его в какую- нибудь другую область памяти. См. также функции localtime (), gmtime(), time() и asctime(). |difftime #include <time.h> double difftime(time_t time2, time_t timel); Функция dif f time () возвращает значение разности в секундах между значениями параметров timel и time2, т.е. возвращается значение выражения time2 - timel. См. также функции localtime(), gmtime(), time() и asctime().
220 gmtime Igmtime B__eBB_——— #include <time.h> struct tm *gmtime(const time_t *time); Функция gmt ime () возвращает указатель на поэлементную форму параметра time в виде структуры) tm. Значение time представлено в виде так называемого всемирного времени (Coordinated Universal Time, или UTC), которое, по сути является временем по Гринвичу (Greenwich mean time). Значение time обычно получают с помощью функции time (). Если система не поддерживает всемирное время, возвращается значение NULL. Структура, используемая функцией gmt ime () для хранения времени в поэлементной форме, выделяется статически и перезаписывается при каждом вызове этой функции. Если нужно сохранить содержимое данной структуры, скопируйте его в какую-нибудь другую область памяти. См. также функции localtime (), time () и asctime (). I localeconv iinclude <locale.h> struct lconv *localeconv(void); Функция localeconv () возвращает указатель на структуру типа lconv, которая содержит различную информацию о геополитической среде, связанную со способом форматирования чисел. Структура lconv включает следующие члены. char *decimal_point; /* Символ десятичной точки для не денежных значений. */ char *thousands_sep; /* Разделитель тысяч для не денежных значений. */ char *grouping; /* Задает группирование для не денежных значений. */ char int_curr_symbol; /* Международный символ валюты. */ char *currency_symbol; /* Местный символ валюты. */ char *mon_decimal_point; /* Символ десятичной точки для денежных значений. */
localeconv 221 char *mon_thousands_sep; char *mon_grouping; char *positive_sign; char *negative_sign; char int_frac_digits; char frac_digits; char p_cs_precedes; char p_sep_by_space; char n_cs_precedes; Разделитель тысяч для денежных значений. */ Задает группирование для денежных значений. */ Индикатор положительных чисел для денежных значений. */ Индикатор отрицательных чисел для денежных значений. */ Количество цифр, которые расположены справа от десятичной точки для денежных значений, отображаемых с использованием международного формата. */ Количество цифр, которые расположены справа от десятичной точки для денежных значений, отображаемых с использованием местного формата. */ 1, если символ валюты стоит перед положительным значением, и 0, если символ валюты стоит после значения. */ 1, если символ валюты отделяется от положительного значения пробелом, и О в противном случае. В версии С99 содержится значение, которое определяет разделитель. */ 1, если символ валюты стоит перед отрицательным значением, и 0, если символ валюты стоит после значения. */
222 localeconv char n_sep_by_space; char p_sign_posn; char n_sign_posn; 1, если символ валюты отделяется от отрицательного значения пробелом, и О в противном случае. В версии С99 содержится значение, которое определяет разделитель. */ Указывает позицию символа положительного значения. */ Указывает позицию символа отрицательного значения. */ /* Следующие члены были char _p_cs_precedes; char _p_sep_by_space; char _n_cs_precedes ; char _n_sep_by_space; char _p_sign_posn; добавлены в версии С99: */ /* 1, если символ валюты стоит перед положительным значением, и 0, если символ валюты стоит после значения. Применяется к значениям, форматируемым по международным правилам. */ /* Означает разделитель между символом валюты, знаком числа и положительным значением. Применяется к значениям, форматируемым по ' международным правилам. */ /* 1, если символ валюты стоит перед отрицательным значением, и 0, если символ валюты стоит после значения. Применяется к значениям, форматируемым по международным правилам. */ /* Означает разделитель между символом валюты, знаком числа и отрицательным значением. Применяется к значениям, форматируемым по международным правилам. */ /* Указывает позицию символа положительного значения.
localtime 223 Применяется к значениям, форматируемым по международным правилам. */ char _n_sign_posn; /* Указывает позицию символа отрицательного значения. Применяется к значениям, форматируемым по международным правилам. */ Функция localeconv() возвращает указатель на структуру Iconv. Содержимое этой структуры изменять нельзя. Для получения подробной информации, связанной с особенностями реализации структуры Iconv, обращайтесь к документации на используемый вами компилятор. См. также функцию setlocale (). |localtime #include <time.h> struct tin *localtime (const time_t *time) ; Функция localtime () возвращает указатель на поэлементную форму параметра time в виде структуры tin. Значение time представляет локальное время. Его обычно получают с помощью функции t ime (). Структура, используемая функцией localtime () для хранения времени в поэлементной форме, выделяется статически и перезаписывается при каждом вызове этой функции. Если нужно сохранить содержимое данной структуры, скопируйте его в какую-нибудь другую область памяти. См. также функции gmtime (), time () и asctime (). ImktimeI #include <time.h> time_t mktime (struct tin *time); Функция mktime () возвращает эквивалент календарного времени на основе времени, заданного в поэлементном виде и хранимого в структуре, которая адресуется параметром time.
224 mktime Элементы tm_wday и tm_yday устанавливаются самой функцией, поэтому их не нужно определять при ее вызове. Если функция mkt ime () не в состоянии представить информацию в виде допустимого календарного времени, возвращается значение -1. См. также функции gmtime(), time(), asctime() и ctime(). Совет программисту Функция mkt ime () особенно полезна, когда нужно узнать, на какой день недели выпадает конкретная дата. Например, каким днем недели будет 12 января 2012 года? Чтобы выяснить это, вызовите функцию mkt ime () с этой датой, а затем (после выполнения функции) обратитесь к члену tm_wday структуры tm. Он будет содержать день недели. Этот метод демонстрируется следующей программой. /* Определение дня недели для даты 2 января 2012 года" (January 12, 2012) . */ #include <stdio.h> #include <time.h> char day[][20] = { ¦ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" int main(void) { struct tm t; t.tm_mday = 12; t.tm_mon = 0; t.tm_year = 112; t.tm_hour = 0; t.tm_min = 0; t.tm_sec = 0; t.tm_isdst = 0;
setlocale 225 mktime(&t); /* получаем день недели */ printf("День недели %s.\n", day[t.tm_wday]); return 0; При выполнении этой программы функция mktimeO автоматически вычисляет день недели, которым в данном случае является вторник (Thursday). Поскольку значение, возвращаемое функцией mktimeO, не используется, оно попросту игнорируется. setlocale #include <locale.h> char *setlocale(int type, const char *locale); Функция setlocale () позволяет запросить или установить определенные параметры, которые зависят от геополитической среды выполнения программы. Если указатель locale нулевой, функция setlocale () возвращает указатель на строку текущей локализации. В противном случае функция попытается использовать заданную строку локализации для установки Локальных параметров в соответствии с параметром type. Для задания стандартных С-параметров региональной привязки используйте строку " С", а для задания собственных параметров среды— пустую строку (""). Чтобы получить подробную информацию о строках локализации, поддерживаемых вашим компилятором, обратитесь к документации. При вызове функции setlocale () в качестве параметра type должен быть использован один из следующих макросов (определенных в заголовке <locale. h>). LC_ALL LC_COLLATE LC_CTYPE LC_MONETARY • LC_NUMERIC LC TIME
226 strftime Макрос LC_ALL относится ко всем категориям локализации. Макрос LC_COLLATE оказывает влияние на выполнение функции strcollf). Макрос LC_CTYPE изменяет характер работы символьных функций. Макрос LC_MONETARY определяет денежный формат. Макрос LC_NUMERIC изменяет символ десятичной точки для функций форматированного ввода- вывода. Наконец, макрос LC_TIME определяет поведение функции strftime (). Функция setlocaleO возвращает указатель на строку, связанную с параметром type. См. также функции localeconv(), time(), strcoll () и strftime(). #include <time.h> size_t strftime(char *str, size_t maxsize, const char *fmt, const struct tm *time); Функция strftime () помещает информацию о времени и дате (вместе с другой информацией) в строку, адресуемую параметром str, в соответствии с командами форматирования, которые содержатся в адресуемой параметром fmt строке, и используя поэлементно заданное время time. В строку str будет помещено максимум maxsize символов. В версии С99 к параметрам str, fmt и time применен ква- лификатор restrict. Работа функции strftime () напоминает работу функции sprint f () в том, что она распознает набор команд форматирования, которые начинаются со знака процента (%), и помещает отформатированный результат в строку. Команды форматирования используются для задания точного способа представления различных данных времени и даты в параметре str. Любые другие символы, содержащиеся в строке форматирования, помещаются в строку str без изменений. Значения времени и даты отображаются в виде локального времени. Команды форматирования перечислены в следующей таблице. Обратите внимание на то, что во многих командах прописные и строчные буквы имеют различную интерпретацию.
strftime 227 Функция strftime () возвращает количество символов, которые сохранены в строке, адресуемой параметром str, или нуль при возникновении ошибки. Команда Результат форматирования %а Сокращенное название дня недели %А Полное название дня недели %Ь Сокращенное название месяца %в Полное название месяца %с Стандартная строка даты и времени %С Последние две цифры года %d День месяца в виде десятичного числа A-31) %D Дата в виде месяц/день/год (добавлено в версии С99) %е День месяца как десятичное число A-31) в 2- символьном поле (добавлено в версии С99) %F Дата в виде год-месяц-день (добавлено в версии С99) %д Последние Две цифры года с использованием понедельного года (добавлено в версий С99) %G Год с использованием понедельного года (добавлено в версии С99) %h Сокращенное название месяца (добавлено в версии С99) %Н Часы @-23) %1 Часы A-12) % j День года в виде десятичного числа A-366) %т Месяц в виде десятичного числа A-12) %М Минуты в виде десятичного числа @-59) %п Новая строка (добавлено в версии С99) %р Эквивалент индикатора A.M. или P.M. для местного времени %г 12-часовое время (добавлено в версии С99) %R Время в виде чч:мм (добавлено в версии С99)
228 strftime Команда Результат форматирования % S Секунды в виде десятичного числа @-60) % t Горизонтальная табуляция (добавлено в версии С99) ^%т Время в виде чч:мм:сс (добавлено в версии С99) %и День недели; понедельник — первый день недели A-7) (добавлено в версии С99) %U Неделя года; воскресенье — первый день недели @-53) %V Неделя года с использованием понедельного года (добавлено в версии С99) %w День недели в виде десятичного числа @-6, воскресенье — 0-й день) %W Неделя года; понедельник — первый день недели @-53) %х Стандартная строка даты %Х Стандартная строка времени %у Год в виде десятичного числа без столетия @-99) %Y Год в виде десятичного числа, включающего столетие %z Смещение относительно UTC (добавлено в версии С99) %Z Название часового пояса %% Знак процента Версия С99 позволяет в функции strftime О использовать определенные команды форматирования с модификаторами Е и О. Модификатор Е может модифицировать такие команды, как с, С, х, X, у, Y, d, е и Н. Модификатор О может модифицировать такие команды, как I, m, M, S, u, U, V, w, W и у. Использование этих модификаторов приводит к альтернативному представлению отображаемого времени и/или даты. За подробностями обращайтесь к документации на используемый вами компилятор.
time 229 Понедельный год используется командами форматирования %g, %G и %V. При таком представлении первым днем недели является понедельник, а первая неделя года должна включать день с датой  января". См. также функции time (), localtime () и gmtime (). Itime #include <time.h> time_t time(time_t *time); Функция t ime () возвращает текущее календарное время системы. Если в системе отсчет времени не производится, возвращается значение -1. Функцию t ime () можно вызывать либо с нулевым указателем, либо с указателем на переменную типа time_t. В последнем случае этой переменной будет присвоено календарное время. См. также функции localtime (), gmtime (), strftime () и ctime().
к
Глава 11 Функции динамического выделения памяти В этой главе описаны функции динамического выделения памяти C/C++. Самыми популярными из них являются malloc () и free (). При каждом вызове функции malloc () системой выделяется некоторая порция свободной памяти. При каждом вызове функции free() определенная порция памяти возвращается системе. Область свободной памяти, которая расходуется для удовлетворения запросов, называется кучей. Для программ на языке С прототипы функций динамического выделения памяти находятся в заголовке <stdlib.h>, а программы на языке C++ должны использовать заголовок <cstdlib>. В этой главе для простоты изложения употребляются имена С-заголовков, но ссылки на заголовок <stdlib.h> в соответствующей среде нужно заменить ссылками на заголовок <cstdlib>. Все компиляторы C/C++ должны включать по крайней мере следующие четыре функции динамического выделения памяти: calloc (), malloc (), free () и realloc (). Однако ваш компилятор почти наверняка содержит несколько версий этих функций, в которых учтены различные возможности и особенности среды. Поэтому вам стоит обратиться к документации на используемый вами компилятор. Несмотря на то что язык C++ поддерживает описываемые здесь функции динамического выделения памяти, они обычно не используются в С++-программах. Дело в том, что в языке C++ предусмотрены специальные операторы динамического выделения памяти new и delete, использование которых дает ряд преимуществ. Во-первых, оператор new автоматически выделяет корректный объем памяти для данных конкретного типа. Во-вторых, он возвращает корректный тип указателя на эту память. В-третьих, операторы new и delete можно перегружать. Поскольку операторы new и delete имеют преимущества перед функциями динамического выде-
232 calloc ления памяти, именно их рекомендуется использовать в программах на языке C++. (Об операторах new и delete речь идет в главе 5.) I calloc #include <stdlib.h> void *calloc(size_t лит, size_t size); Функция calloc () выделяет память, размер которой равен значению выражения пит * size, т.е. память, достаточную для массива, содержащего пит объектов размером size. Функция calloc () возвращает указатель на первый байт выделенной области. Если для удовлетворения запроса нет достаточного объема памяти, возвращается нулевой указатель. Важно всегда удостовериться, что возвращаемое значение не является нулевым указателем, причем это нужно сделать еще до попытки его использовать. См. также функции free (), malloc () и realloc (). ifree • • " • ¦ •¦¦• I iinclude <stdlib.h> void free(void *ptr) ; Функция free () возвращает куче память, адресуемую указателем pfcr, после чего эта память становится доступной для выделения в будущем. Очень важно вызывать функцию free () только с тем указателем, который был ранее назначен с помощью одной из функций динамического выделения системной памяти (либо mallocO, либо calloc ()). Вероятнее всего, использование неверного указателя в вызове функции приведет к разрушению механизма управления памятью и к полному отказу системы. При передаче нулевого указателя функция free () не выполняет никакого действия. См. также функции calloc (), malloc () и realloc ().
malloc 233 |malloc #include <stdlib.h> void *malloc(size_t size); Функция malloc () возвращает указатель на первый байт области памяти размером size, которая была выделена из кучи. Если для удовлетворения запроса нет достаточного объема памяти, возвращается нулевой указатель. Важно всегда удостовериться, что возвращаемое значение не является нулевым указателем. Попытка использовать нулевой указатель обычно приводит к полному отказу системы. См. также функции free (), calloc () и re,alloc (). Совет программисту Бели вы пишете 16-разрядные программы для семейства процессоров 8086 (например, 80486 или Pentium), то ваш компилятор, вероятно, предоставляет дополнительные функции выделения памяти,«которые учитывают модель сегментированной памяти, используемую этими процессорами при работе в 16-разрядном режиме. Например, это могут быть функции, выделяющие память FAR-кучи (которая находится вне стандартного сегмента данных). Эти функции могут назначать указатели на память, объем которой больше одного сегмента, и освобождать такую память. realloc #include <stdlib.h> void *realloc(void *ptr, size_t size); Действие функции realloc {) в версии С99 немного отличается от ее работы в языках C++ и С89, хотя основной результат совпадает. В языках C++ и С89 функция realloc () изменяет размер ранее выделенной памяти, адресуемой параметром ptr в соответствии с заданным размером size. Значение параметра size может быть больше или меньше исходного. Функция realloc () возвращает указатель на
234 realloc блок памяти, поскольку не исключена необходимость перемещения этого блока при увеличении размера памяти. В этом случае содержимое старого блока (до size байт) копируется в новый блок. В версии С99 блок памяти, адресуемый параметром ptr, освобождается, а вместо него выделяется новый блок. Содержимое нового блока совпадает с содержимым исходного (по длине, переданной в параметре size). Функция возвращает указатель на новый блок. Причем разрешается, чтобы новый и старый блоки начинались с одинакового адреса (т.е. указатель, возвращаемый функцией realloc (), может совпадать с указателем, переданным в параметре ptr). Если указатель ptr нулевой, функция realloc () просто выделяет size байт памяти и возвращает указатель на эту память. Если значение параметра size равно нулю, память, адресуемая параметром ptr, освобождается. Если в куче нет достаточного объема свободной памяти для выделения size байт, возвращается нулевой указатель, а исходный блок памяти остается неизменным. См. также функции free (), calloc () итаПос (). г
Глава 12 Функции смешанного типа Стандартная библиотека функций включает ряд полезных функций. Они осуществляют различные преобразования, обрабатывают аргументы переменной длины, выполняют сортировку и поиск, а также генерируют случайные числа. Для использования многих из описанных здесь функций в языке С необходимо включить заголовок <stdlib.h>, а в языке С+Н его эквивалент <cstdlib>. В этой главе для простоты изложения употребляются имена С-заголовков, но ссылки на заголовок <stdlib.h> в соответствующей среде нужно заменить ссылками на заголовок <cstdlib>. В заголовке <cstdlib> объявлены два типа, div_t и ldiv_t, которые используются в качестве типа значений, возвращаемых функциями div () и ldiv () соответственно. В версии С99 объявляются тип lldiv_t и функция lldiv{). Кроме того, объявляются типы size_t и wchar_t, а также следующие макросы. Макрос Значение MB_CUR_MAX Максимальная длина (в байтах) многобайтового символа NULL Нулевой указатель RAND_MAX Максимальное значение, которое может возвратить функция rand () EXIT_FAILURE Значение, возвращаемое вызывающему процессу при неудачном завершении программы EXIT_SUCCESS Значение, возвращаемое вызывающему процессу при успешном завершении программы Если для вызова некоторой функции необходимо использовать заголовок, отличный от <stdlib.h>, об этом будет специально указано в описании.
236 abort abort #include <stdlib.h> void abort(void); Функция abort () вызывает немедленное аварийное завершение программы. Как правило, буфера файлов не сбрасываются. В средах, которые поддерживают эту функцию, она возвращает вызывающему процессу (обычно им является операционная система) значение (определяемое конкретной реализацией), которое сигнализирует об отказе. См. также функции exit () и atexit(). labs L #include <stdlib.h> int abs(int пит); Функция abs () возвращает абсолютное значение целочисленного аргумента лит. См. также функцию f abs (), описанную в главе 9. assert ttinclude <assert.h> void assert(int exp); -..-; Макрос assert (), определенный в заголовках <assert .h> и <cassert>, записывает информацию об ошибке в поток stderr, а затем прекращает выполнение программы, если выражение ехр равно нулю. В противном случае макрос assert () никаких действий не выполняет. Несмотря на то что точный результат выполнения этого макроса определяется конкретной реализацией, многие компиляторы используют сообщение, подобное следующему. Assertion failed: <выражение>, file <имя_файла>, line <номер_строки> В версии С99 отображаемое сообщение также включает имя функции, содержащей макрос as sёг t (). - •
atexit 237 Макрос assert () обычно используется, чтобы убедиться в корректной работе программы, причем выражение составляется таким образом, чтобы оно было истинным только при отсутствии ошибок. После отладки программы нет необходимости в удалении операторов assert () из исходного кода, поскольку, если определен макрос NDEBUG (как и должно быть в идеале), макрос assert () игнорируется. См. также функцию abort (). atexit #include <stdlib.h> int atexit(yoid {*func) (void)); Функция atexit () при нормальном завершении программы приводит к вызову функции, адресуемой параметром func. Функция atexit () возвращает нуль, если задаваемая функция успешно зарегистрирована в качестве функции завершения, и ненулевое значение в противном случае. Может быть зарегистрировано до 32 функций завершения, которые будут вызываться в порядке, обратном порядку регистрации (т.е. функция, зарегистрированная последней, выполнится первой). См. также функции exit() и abort (). 'atof #include <stdlib.h> double atof(const char *str); Функция atof () преобразует строку, адресуемую параметром str, в значение типа double. Эта строка должна содержать допустимое число с плавающей точкой. В противном случае возвращаемое значение не определено. Число может оканчиваться любым символом, который не может быть частью допустимого числа с плавающей точкой. Имеются в виду пробельные символы, знаки препинания (но не точки) и символы, отличные от буквы "Е" или "е". Это
238 atoi значит, что, если функция atof () вызывается с аргументом 00.0 0 HELLO", будет возвращено значение 100,00. См. также функции atoi () и atol (). I atoi ¦ ' . II ¦include <stdlib.h> int atoi(const char *str); Функция atoi () преобразует строку, адресуемую параметром str, в значение типа int. Эта строка должна содержать допустимое целочисленное число. В противном случае возвращаемое значение не определено. Число может оканчиваться любым символом, который не может быть частью целого числа. Имеются в виду пробельные символы, знаки препинания (но не точки) и буквы. Это значит, что, если функция atoi () вызывается с аргументом 23.23", будет возвращено целое значение 123, а порция ". 23" будет проигнорирована. См. также функции atof () и atol (). |atol ¦include <stdlib.h> long'int atol(const char *str); Функцид atol () преобразует строку, адресуемую параметром str, в значение типа long int. Эта строка должна содержать допустимое целое число. В противном случае возвращаемое значение не определено. Число может оканчиваться любым символом, который не может быть частью целого числа. Имеются в виду пробельные символы, знаки препинания (но не точки) и буквы. Это значит, что, если функция atoi¦(') вызывается с аргументом 23.23", будет возвращено длинное целое значение 123L, а порция " . 23 " будет проигнорирована. См. также функции atof (), atoi () и atoll ().
atoll 239 atoll #include <stdlib.h> long long int atoll(const char *str); Функция atoll () добавлена в версии С99. Функция atoll () преобразует строку, адресуемую параметром str, в значение типа long long int. В остальном она аналогична функции atoi (). См. также функции atof (), atoi () и atol (). I bsearch | ttinclude <stdlib.h> void *bsearch(const void *key, const void *buf, size_t пит, size_t size, int (*compare)(const void *, const void *)); Функция bsearch () выполняет двоичный поиск в отсортированном массиве, адресуемом параметром buf, и возвращает указатель на первый член, который совпадает с ключом- значением, адресуемым параметром key. Количество элементов в массиве задается параметром пит, а размер (в байтах) каждого элемента — параметром size. Для сравнения каждого элемента массива с ключом-значением используется функция, адресуемая параметром compare. Форма записи функции compare должна иметь следующий вид. int func_name{const void *argl, const void *arg2); Она должна возвращать значения, описанные в следующей таблице. Сравнение Возвращаемое значение argl меньше агд2 Меньше нуля argl равен агд2 Нуль argl больше агд2 Больше нуля Массив должен быть отсортирован в порядке возрастания, чтобы по самому младшему адресу содержался наименьший элемент.
240 div Если массив не содержит ключа-значения, возвращается нулевой указатель. См. также функцию qsort (). aiv #include <stdlib.h> div_t div(int numerator, int denominator); Функция div () возвращает частное и остаток, полученные в результате выполнения операции numerator/denominator, в структуре типа div_t. Структура типа div_t имеет следующие два поля. int quot; /* частное */ int rem; /* остаток */ См. также функции ldiv() Hlldiv(). #include <stdlib.h> void exit(int exit_code); Функция exit() вызывает немедленное нормальное завершение программы. Это значит, что вызываются функции завершения, зарегистрированные функцией at exit (), и любые открытые файлы после сбрасывания буферов закрываются. В вызывающий процесс (обычно это операционная система) передается значение параметра exit_code, если в данной среде предусмотрена поддержка возможных значений. По соглашению, если параметр exit_code равно нулю, или значению EXIT_SUC- CESS, предполагается нормальное завершение программы. Ненулевое значение, или значение EXIT_FAILURE, используется для .индикации ошибки, определенной конкретной реализацией. См. также функции atexit (), abort () и _Exit (). Exit I #include <stdlib.h> void _Exit(int exit_code);
getenv 241 Функция _Exit () добавлена в версии С99. Действие функции _Exit() аналогично действию функции exit () за исключением следующих моментов. • Не вызываются функции завершения, зарегистрированные функцией atexit(). • Не вызываются обработчики сигналов, зарегистрированные функцией signal(). • Буфера открытых файлов необязательно сбрасываются, а сами файлы необязательно закрываются. См. также функции atexit (), abort () и exit (). getenv " #include <stdlib.h> char * getenv (const char *лал1е) ; Функция getenv () возвращает указатель на данные о среде, которая соответствует строке, адресуемой параметром name в таблице характеристик среды, определенной конкретной реализацией. Ваша программа не должна изменять содержимое этой таблицы. Среда программы может включать такие данные, как пути и электронные устройства. Их состав определяется конкретной реализацией, поэтому для уточнения деталей необходимо обратиться к руководству пользователя, прилагаемому к вашему компилятору. Если обращение к функции getenv () сделано с использованием аргумента, значение которого не совпадает ни с одним из элементов описания среды, возвращается нулевой указатель. См. также функцию system (). I labs #include <stdlib.h> long labs(long пит); \ Функция labs () возвращает абсолютное значение аргумента num. См. также функции abs () и llabs ().
242 Idiv ldiv #include <stdlib.h> ldiv_t ldiv(long int numerator, long int' denominator) ; Функция ldiv () возвращает частное и остаток, полученные в результате выполнения операции numerator/denominator, в структуре типа ldiv_t. Структура типа ldiv_t имеет следующие два поля. long int quot; /* частное */ long int rem; /* остаток */ См. также функции div () и lldiy (). 11labs ¦include <stdlib.h> long long int llabs(long long int num); Функция llabs () добавлена в версии С99. Функция llabs () возвращает абсолютное значение аргумента пит. Она аналогична функции labs (), но работает со значениями типа long long int. См. также функции abs () и labs (). #include <stdlib.h> lldiv_t lldiv(long long int numerator, long long int denominator); Функция lldiv () добавлена в версии С99. Функция lldiv () возвращает частное и остаток, полученные в результате выполнения операции numerator/denominator, в структуре типа lldiv_t. Функция lldiv () аналогична функции ldiv (), но работает со значениями типа long long int. Структура типа lldiv_t имеет следующие два поля.
longjmp 243 long long int quot; /* частное */ long long int rem; /* остаток */ См. также функции div () и ldiv {). Ilongjmp ¦include <setjmp.h> void longjmp(jmp_buf envbuf, int status); Функция longjmp () возобновляет выполнение программы с места последнего обращения к функции set jmp (). Таким образом, функции longjmp () и set jmp () предоставляют средство передачи управления между функциями. Обратите внимание на необходимость включения заголовка <set jmp.h> (в языке C++ используется заголовок <cset jmp>). Функция longjmp () восстанавливает состояние стека, сохраненное в буфере envbuf с помощью функции set jmp (). В результате выполнение программы возобновляется с оператора, следующего за вызовом функции set jmp (). Иначе говоря, компьютер вводится в "заблуждение": он считает, будто управление программой не выходило за пределы функции, которая вызвала функцию setjmpO. (Выражаясь образно, функция longjmp () "искривляет" время и пространство (памяти), чтобы вернуться в предыдущую точку программы, не выполняя нормальный процесс возврата из функции.) Буфер evnbuf имеет тип jmp_buf, который определен в заголовке <setjmp.h>. Этот буфер должен быть установлен посредством обращения к функции setjmpf) до вызова функции longjmp (). Значение параметра status становится возвращаемым значением функции set jmp (), и его можно опросить, чтобы определить "происхождение" длинного перехода. Единственным недопустимым значением является нуль. Функция set jmp () возвращает нуль в том случае, когда она вызывается непосредственно программой, а не косвенно, путем выполнения функции longjmp (). В основном, функция longjmp () используется для возврата из глубоко вложенного набора функций при возникновении ошибок. См. также функцию set jmp ().
244 mblen mblen tinclude <stdlib.h> int mblen(const char *str, size_t size); Функция mblen () возвращает длину (в байтах) многобайтового символа, адресуемого параметром str. Учету подлежат только первые size символов, количество которых не должно превышать значение MB_CUR_MAX. При ошибке функция возвращает значение -1. Функция mblen () определяет достоверность многобайтового символа в соответствии с категорией LC_CTYPE, устанавливающей текущие геополитические характеристики (имеется в виду страна и государственный язык). Если указатель str нулевой, функция mblen () возвращает ненулевое значение в случае, когда многобайтовые символы имеют кодировку, зависящую от территориально-языковых особенностей. В противном случае возвращается нуль. См. также функции mbtowc () и wctomb (). 1"=^=== ===== | mbstowcs 1 #include <stdlib.h> size_t mbstowcs(wchar_t *out, const char *in, size_t size); Функция mbstowcs О преобразует многобайтовую строку, адресуемую параметром in, в строку, состоящую из двубайтовых символов, и помещает результат в массив, адресуемый параметром out. В массиве out сохраняется только size6aUT. В версии С99 к параметрам out и in применен квалифи- катор restrict. Функция mbstowcs () возвращает количество преобразованных многобайтовых символов. При возникновении ошибки функция возвращает значение -1. См. также функции mbtowc () и wcstombs ().
mbtowc 245 mbtowc Mnclude <stdlib.h> int mbtowc(wchar_t *out, const char *in, size_.t size); Функция mbtowc () преобразует многобайтовый символ, который содержится в массиве, адресуемом параметром in, в его двубайтовый эквивалент и помещает результат в объект, адресуемый параметром out. Преобразованию подлежат только первые size символов. В версии С99 к параметрам out и in применен квалифи- катор restrict. Функция возвращает количество байтов, помещенных в объект out. При возникновении ошибки возвращается значение -1. Если указатель in нулевой, функция mbtowc () возвращает ненулевое значение в случае, когда многобайтовые символы имеют кодировку, зависящую от территориально-языковых особенностей. В противном случае возвращается нуль. См. также функции mblen () и wctomb (). ! qsort ________ #include <stdlib.h> void qsort(void *buf, size_t пит, size_t size, int (*compare) (const void *, const void *)); Функция qsort () сортирует массив, адресуемый параметром buf, с помощью алгоритма быстрой сортировки Quicksort (его разработал Ч.Э.Р. Xoap (C.A.R. Hoare)). Quicksort считается лучшим алгоритмом сортировки общего назначения. Количество элементов в массиве задается параметром пит, а размер (в байтах) каждого элемента — параметром size. Для сравнения двух элементов массива используется функция, адресуемая параметром compare. Форма записи функции compare должна иметь следующий вид. int func_name(const void *argl, const void *arg2); Она должна возвращать значения, описанные ниже.
246 raise Сравнение Возвращаемое значение argl меньше агд2 Меньше нуля argl равен агд2 Нуль argl больше агд2 Больше нуля Массив должен быть отсортирован в порядке возрастания, чтобы по самому младшему адресу содержался наименьший элемент. См. также функцию bsearch (). Совет программисту Если вы хотите с помощью функции qsort() отсортировать массив в порядке убывания (т.е. от большего к "меньшему), просто измените на противоположные условия, используемые функцией сравнения, т.е. заставьте функцию сравнения возвращать следующие значения. Сравнение Возвращаемое значение argl меньше агд2 Больше нуля argl равен агд2 Нуль argl больше агд2 Меньше нуля Кроме того, чтобы применить функцию bsearch () для массива, который отсортирован в порядке убывания, вам также придется использовать в функции сравнения условия, измененные на противоположные. raise #include <signal.h> int raise(int signal); Функция raise () посылает выполняемой программе сигнал, заданный параметром signal. При успешном выполнении возвращается нуль, в противном случае — ненулевое значение. Заметьте: функция использует заголовок <signal. h> (в среде языка C++ — <csignal>). Стандартом языка С определены следующие сигналы (не исключено, что ваш компилятор поддерживает и некоторые дополнительные сигналы).
rand 247 Макрос Значение SIGABRT Ошибка завершения SIGFPE Ошибка работы с вещественными числами SIGILL Ошибочная инструкция SIGINT Пользователь нажал комбинацию клавиш <Ctrl+C> SIGSEGV Несанкционированный доступ к памяти SIGTERM Прекратить выполнение программы См. также функцию signal (). lrand - — #include <stdlib.h> int rand(void); Функция rand () генерирует последовательность псевдослучайных чисел. При каждом обращении к функции возвращается целое в интервале между нулем и значением RAND_MAX, которое должно быть не меньше числа 32 767. См. также функцию srand (). setjmp #include <setjmp.h> int setjmp(jmp_buf envbuf); Макрос set jmp () сохраняет содержимое системного стека в буфере envbuf для использования в будущем с помощью функции long jmp (). Функция использует заголовок <setjmp.h> (в среде языка C++ — <cset jmp>). Макрос-функция setjmp () после сохранения среды стека возвращает нуль. Если макрос setjmp () выполняется в результате вызова функции longjmp (), он возвращает значение аргумента, переданного ему функцией longjmp (). А если значение аргумента функции longjmp () равно нулю, макрос setjmp () возвращает значение 1. Информация об ошибках не возвращается.
248 signal Макрос set jmp () сохраняет среду стека, которую можно впоследствии восстановить с помощью функции longjmp (). При совместном использовании функции set jmp () и longjmp () обеспечивают способ выполнения "нелокального оператора goto". Они обычно используются для передачи управления подпрограммам обработки ошибок или восстановления в ранее вызванных процедурах без использования нормального процесса вызова и возврата из процедур. См. также функцию longjmp (). I signal || #include <signal.h> void (*signal(int signal, void {*func) (int))) (int); Функция signal () регистрирует функцию, адресуемую параметром func, в качестве обработчика сигнала, который задан параметром signal (т.е. функция, адресуемая параметром func, будет вызвана в случае, когда ваша программа получит сигнал signal). Функция использует заголовок <signal.h> (в среде языка C++ — <csignal>). Значением параметра func может быть адрес функции обработчика сигнала или один из следующих макросов, определенных в заголовке <signal. h>. Макрос Значение SIG_DFL Использовать стандартную обработку сигнала SIG_IGN Игнорировать сигнал Если используется адрес функции, то при получении сигнала будет выполнен заданный обработчик. Для получения дополнительных сведений обратитесь к документации на свой компилятор. При успешном выполнении функция signal () возвращает адрес заранее определенной функции для заданного сигнала. При ошибке возвращается значение SIG_ERR (определенное в заголовке <signal. h>). См. также функцию raise ().
srand 249 Isrand #include <stdlib.h> void srand(unsigned seed); Функция srand () устанавливает стартовую точку для последовательности, генерируемой функцией rand (). (Функция rand () возвращает псевдослучайные числа.) Функция srand () часто используется, чтобы позволить при многих запусках программ работать с различными последовательностями псевдослучайных чисел путем задания различных отправных точек. И наоборот, вы можете также использовать функцию sranQ () для многократного генерирования одной и той же последовательности псевдослучайных чисел путем вызова этой функции с одинаковым начальным значением параметра seed до начала создания этой последовательности . См. также функцию rand (). Istrtod #include <stdlib.h> double strtod(const char *start, char **end); Функция strtod () преобразует строковое представление числа, которое содержится в строке, адресуемой параметром start, в значение типа double и возвращает полученный результат. В версии С99 к параметрам start и end применен квали- фикатор restrict. Функция strtod () работает следующим образом. Сначала в'строке, адресуемой параметром start, удаляется любой пробельный символ. Затем читается каждый символ, составляющий число. Любой символ, который не может быть частью числа с плавающей точкой, приведет к остановке процесса преобразования. К ним относятся пробельные символы, знаки препинания (но не точки) и символы, отличные от букв "Е" и "е". Наконец, параметр end устанавливается так, чтобы указывать на "непреобразованный" остаток исходной строки,
250 strtof если таковой существует. Это означает, что, если функция strtodO вызывается с аргументом 00.00 Pliers", то она возвратит значение 100.00, а параметр end будет указывать на пробел, предшествующий слову " Pliers". При возникновении переполнения функция strtod () возвращает либо значение HUGE_VAL, либо значение -HUGE_VAL (означающее положительное или отрицательное переполнение соответственно), а глобальная переменная errno устанавливается равной значению ERANGE, свидетельствующему об ошибке пределов диапазона. При потере точности возвращается нуль и глобальная переменная errno устанавливается равной значению ERANGE. Если параметр start не указывает на число, никакого преобразования не выполняется и функция возвращает нуль. См. также функции atof (), strtold () и strtof (). |strtof I ¦include <stdlib.h> float strtof(const char * restrict start, char restrict ** restrict end) ; Функция strtof () добавлена в версии С99. Функция strtof () аналогична функции strtod () за исключением того, что она возвращает значение типа float. При возникновении переполнения возвращается либо значение HUGE_VAL, либо значение -HUGE_VAL, а глобальная переменная errno устанавливается равной значению ERANGE, свидетельствующему об ошибке пределов диапазона. Если параметр start не указывает на число, никакого преобразования не выполняется и функция возвращает нуль. См, также функции atof (¦), strtold () nstrtod(). strtol #include <stdlib.h> long int strtol(const char *start, char **end, int radix); Функция strtol () преобразует строковое представление числа, которое содержится в строке, адресуемой параметром
strtold 251 start, в значение типа long int и возвращает полученный . результат. Основание системы счисления, в которой представлено преобразуемое число, определяется параметром radix. Если значение radix равно нулю, то основание определяется (по первым символам строки) согласно правилам, которые диктуют использование определенных спецификаций. Если значение radix не равно нулю, то оно должно находиться в диапазоне 2-36. В версии С99 к параметрам start и end применен квали- фикатор restrict. Функция strtol () работает следующим образом. Сначала в строке, адресуемой параметром start, удаляется любой пробельный символ. Затем читается каждый символ, составляющий число. Любой символ, который не может быть частью длинного целого числа, приведет к остановке процесса преобразования. К ним относятся пробельные символы, знаки препинания и символы. Наконец, параметр end устанавливается так, чтобы указывать на "непреобразованный" остаток исходной строки, если таковой существует. Это означает, что если функция strtol () вызывается с аргументом 00 Pliers", то она возвратит значение 100L, а параметр end будет указывать на пробел, предшествующий слову " Pliers". Если результат не.может быть представлен как значение типа long int, функция strtol () возвращает либо значение LONG_MAX, либо значение LONG^MIN, а глобальная переменная errno устанавливается равной значению ERANGE, свидетельствующему об ошибке пределов диапазона. Если параметр start не указывает на число, никакого преобразования не выполняется и функция возвращает нуль. См. также функции atof () и strtoll (). Istrtold tinclude <stdlib.h> long double strtold(const char * restrict start, char ** restrict end); Функция strtold () добавлена в версии С99. . Функция strtold () аналогична функции strtod{) за исключением того, что она возвращает значение типа long
252 strtoll double. При возникновении переполнения возвращается либо значение HUGE_VALL, либо значение -HUGE_VALL, а глобальная переменная errno устанавливается равной значению ERANGE, свидетельствующему об ошибке пределов диапазона. Если параметр start не указывает на число, никакого преобразования не выполняется и функция возвращает нуль. См. также функции atof (), strtod () и strtof (). || strtoll | tinclude <stdlib.h> long long int strtoll(const char * restrict start, char ** restrict end, int radix); Функция strtoll () добавлена в версии С99. Функция strtoll () аналогична функции strtol () за исключением того, что она возвращает значение типа long long int. Если результат не может быть представлен как значение типа long long int, возвращается либо значение LLONG_MAX, либо значение LLONG_MIN, а глобальная переменная errno устанавливается равной значению ERANGE, свидетельствующему об ошибке пределов диапазона. Если параметр start не указывает на число; никакого преобразования не выполняется и функция возвращает нуль. См. также функции atol () и strtol (). strtoul #include <stdlib.h> unsigned long int strtoul(const char * start, char **end, int radix) ; . Функция strtoul () преобразует строковое представление числа, которое содержится в строке, адресуемой параметром start, в значение типа unsigned long и возвращает полученный результат. Основание системы счисления, в которой представлено преобразуемое число, определяется параметром radix. Если значение radix равно нулю, то основание определяется (по первым символам строки) согласно правилам, которые диктуют использование определенных специфика-
strtoull 253 ций. Если значение radix задается и не равно нулю, то оно должно находиться в диапазоне 2-36. В версии С99 к параметрам start и end применен квали- фикатор restrict. Функция strtoul() работает следующим образом. Сначала в строке, адресуемой параметром start, удаляется любой пробельный символ. Затем читается каждый символ, составляющий число. Любой символ, который не может быть частью длинного целого числа без знака, приведет к остановке процесса преобразования. Имеются в виду пробельные символы, знаки препинания и символы. Наконец, параметр end устанавливается так, чтобы указывать на "непреобразованный" остаток исходной строки, если таковой существует. Это означает, что если функция strtoul () вызывается с аргументом 00 Pliers", то она возвратит значение 100L, а параметр end будет указывать на пробел, предшествующий слову " Pliers". Если результат не может быть представлен как длинное целое значение без знака, функция strtoul () возвращает значение ULONG_MAX, а глобальная переменная errno устанавливается равной значению ERANGE, свидетельствующему об ошибке пределов диапазона. Если параметр start не указывает на число, никакого преобразования не выполняется и функция возвращает нуль. См. также функции strtol () и strtoull (). StrtOUll #include <stdlib.h> unsigned long long int strtoull(const char *start, char **end, int radix) ; ¦ Функция strtoull () добавлена в версии С99. Функция strtoull () аналогична функции strtoul () за исключением того, что она возвращает значение типа unsigned long long int. Если результат не может быть представлен как значение типа unsigned long long int, возвращается значение ULLONG_MAX, а глобальная перемен ная errno устанавливается равной значению ERANGE, свидетельствующему об ошибке пределов диапазона. Если пара-
254 system метр start не указывает на число, никакого преобразования не выполняется и функция возвращает нуль. См. также функции strtol () и strtoul (). Д system #include <stdlib.h> int system(const char *str); Функция system () передает строку, адресуемую параметром str, в качестве команды для командного процессора операционной системы. Если функция system() вызывается с нулевым указателем, она возвращает ненулевое значение при условии существования командного процессора и нуль в противном случае. (Программы, выполняемые в специальных средах, не будут иметь доступа к командному процессору.) Во всех других случаях значение, возвращаемое функцией systemO, определяется конкретной реализацией. Но обычно возвращается нуль при успешном выполнении команды, а ненулевое значение возврата означает наличие ошибки. См. также функцию exit (). | va_arg, va_start, va_end И va_copy Д #include <stdarg.h> type va_arg(va_list argptr, type); void va_copy(va_list target, va_list source); void va_end(va_list argptr); void va_start(va_list argptr, last_parm); Макрос va_copy () добавлен в версии С99. Макросы va_arg, va_start и va_end работают вместе, чтобы сделать возможной передачу функции переменного числа аргументов. Самым распространенным примером функции, которая принимает переменное число аргументов, является функция printf(). Тип va_list определен в заголовке <stdarg. h> (а в среде языка C++ — в заголовке <cstdarg>).
va_arg, va_start, va_end и va_copy 255 Общая процедура создания функции, которая может принимать переменное количество аргументов, такова. Функция должна иметь по крайней мере один известный параметр (может и больше), указываемый до переменного списка параметров. Крайний справа известный параметр называется last_parm. Его имя используется в качестве второго параметра в обращении к макросу va_start (). Прежде чем можно будет получить доступ к любому параметру из списка параметров переменной длины, необходимо инициализировать указатель на аргумент argptr, обратившись к макросу va_start(). После этого параметры возвращаются посредством обращения к макросу va_arg () с передачей значения параметра type, которое представляет собой тип следующего параметра. Наконец после прочтения всех параметров до возвращения из функции необходимо вызвать макрос va_end (), чтобы гарантировать корректное восстановление стека. Если макрос va_end () не вызывается, высока вероятность аварийного отказа программы. Макрос va_copy() копирует список аргументов, содержащийся в параметре target, в объект source. См. также функцию vprint f (). Совет программисту Правильное использование макросов va_arg, va_start и va_end лучше всего проиллюстрировать на примере. В следующей программе применяется функция sum_series (), которая возвращает сумму ряда чисел. Первый аргумент содержит количество аргументов,' перечисленных за ним. В этом примере суммируются первые пять элементов следующего ряда чисел. 1 - 2 1 - 4 1 1 8 16 1 21 Результат равен 0.968750.. /* Пример списка аргументов переменной длины сумма ряда.*/ #include <stdio.h> #include <stdarg.h>
256 wcstombs double sum_series(int, ...); int main(void) : double d; d = sum_seriesE, 0.5, 0.25, 0.125, 0.0625, 0.03125); printf("Сумма ряда равна %f\n",d); return 0; }¦ double sum_series(int num, ...) double sum = 0.0, t; va_list argptr; . . /* Инициализируем указатель argptr. */ va_start(argptr, num); ./* Суммируем ряд. */ for(; num; num--) { . . t = va_arg(argptr, double); sum += t; }•¦-.¦• ' '..-'¦ ¦ ,¦ /* Реализуем корректное завершение. */ va_end(argptr); return sum; iwcstombs J #include <stdlib.h> int wcstombs(char *out, const wchar_t *in, size_t size); Функция wcstombs () преобразует массив двубайтовых символов, адресуемый параметром in, в его многобайтовый
wctomb 257 эквивалент и помещает результат в массив, адресуемый параметром out. Преобразованию подлежат только первые size символов. Процесс преобразования прекращается раньше в случае обнаружения завершающего нулевого символа. В версии С99 к параметрам out и in применен квалифи- катор restrict. При успешном выполнении функция wcstombs () возвращает количество байтов, помещенных в массив out. При возникновении ошибки возвращается значение — 1. См. также функции mbstowcs () и wctomb (). wctomb #include <stdlib.h> int wctomb(char *out, wchar_t in); Функция wctomb() преобразует двубайтовый символ, содержащийся в параметре in, в его многобайтовый эквивалент и помещает результат в объект, адресуемый параметром out. Массив, адресуемый параметром out, должен иметь длину не меньше MB_CUR_MAX символов. При успешном выполнении функция wctomb () возвращает количество байтов, содержащихся в многобайтовом символе. При возникновении ошибки возвращается значение -1. • Если параметр out нулевой, функция wctomb () возвращает ненулевое значение в случае, когда многобайтовый символ имеет кодировку, зависящую от территориально- языковых особенностей. В противном случае возвращается нуль. См. также функции wcstombs () и mbtowc ().
Глава 13 Функции обработки двубайтовых символов В 1995 году к стандарту С89 был добавлен ряд функций, предназначенных для обработки двубайтовых символов (wide- character functions), которые позже вошли в стандарт С99 и язык C++. Эти функции работают с символами типа wchar_t, которые занимают 16 бит. В основном, они аналогичны своим char- эквивалентам. Например, функция iswspace () является двубайтовой версией функции is space (). В целом, функции обработки двубайтовых символов используют те же имена, что и их char-эквиваленты, но добавляется буква "w" (u>ide- character, т.е. "широкоформатный" символ). В языке С функции широкоформатных символов используют заголовки <wchar. h> и <wctype. h>, а в языке C++ — заголовки <cwchar> и <cwctype>. В этой главе будут использованы имена С- заголовков, но ссылки на <wchar. h> и <wctype. h> применимы также к заголовкам <cwchar> и <cwctype> соответственно. Заголовок <wctype. h> определяет типы wint_t, wctrans_t и wctype_t. Многие функции двубайтовых символов принимают в качестве параметра символ широкого формата. Этот параметр имеет тип wint_t, который позволяет содержать символ такого увеличенного формата. Использование типа wint_t в функциях двубайтовых символов, аналогично использованию -типа int в char-ориентированных функциях. Типы wctrans_t и wctype_t — это типы объектов, используемые для преобразования символов и определения категории символа соответственно. Кроме того, в заголовке <wctype. h> определен двубайтовый признак конца файла (EOF) под именем WEOF. Помимо win_t, в заголовке <wchar.h> определены такие типы, как wchar_t, size_t и mbstate_t. Тип wchar_t создает объект двубайтового символа, a size_t — это тип значения, возвращаемого оператором sizeof. Тип mbstate_t описывает объект, который хранит состояние преобразования многобайтового объекта в символ широкого формата. Заголовок <wchar. h> также опре-
260 Функции классификации двубайтовых символов деляет макросы NULL, WEOF, WCHAR_MAX и WCHAR_MIN. Последние два макроса определяют максимальное и минимальное значения, которые могут храниться в объекте типа wchar_t. Поскольку большинство функций двубайтовых символов аналогичны своим char-эквивалентам, в этой главе приводится лишь краткое их описание. Функции классификации двубайтовых символов Заголовок <wctype.h> содержит прототипы функций двубайтовых символов, которые поддерживают классификацию символов. Эти функции устанавливают категорию символов или преобразуют регистр буквенного символа, устанавливая строчное или прописное написание. Эти функции (вместе с их char-эквивалентами, описанными в главе 7) перечислены в следующей таблице. Функция char-эквивалент int iswalnum(wint_t ch) int iswalpha(wint_t ch) int iswblank(wint_t ch) int iswcntrl(wint_t ch) int iswdigit(wint_t ch) int iswgraph(wint_t ch) int iswlower(wint_t ch) int iswprint(wint_t ch) int iswpunct(wint_t ch) int iswspace(wint_t ch) int iswupper(wint_t ch) .int iswxdigit(wint_t c,h) wint_t towlower(wint_t ch) wint_t towupper(wint_t ch) isalnum() isalpha() isblankO (Добавлена в С99.! iscntri() isdigit() isgraph() islower() isprint() ispunct() isspaceO isupper() isxdigit() : tolower() toupper() Помимо функций, приведенных выше, в заголовке <wctype. h> определена следующая функция, которая предоставляет открытые средства классификации символов. .
Функции ввода-вывода двубайтовых символов 261 wctype_t wctype(const char *attr); int iswctype(wint_t ch, wctype_t attr_ob); Функция wctype () возвращает значение, которое можно передать функции iswctype () в качестве параметра attr_ofo. Строка, адресуемая параметром attr, задает свойство, которое должен иметь символ. Это значение можно затем использовать для определения, является ли ch символом, который обладает этим свойством. Если является, т(о функция iswctype () возвращает ненулевое значение. В противном случае возвращается нуль. Для всех сред выполнения определены следующие строки свойств. ainum graph space alpha lower upper cntrl print xdigit digit punct В версии С99 также определена строка blank. Кроме того, в заголовке <wctype. h> определены функции wctrans() иtowctrans(). wctrans_t wctrans(const char *mapping); wint_t towctrans(wint_t ch, wctrans_t mapping_ob) ; Функция wctrans () возвращает значение, которое можно передать функции towctrans () в качестве параметра mappmg_ob. Строка, адресуемая параметром mapping, задает соответствие одного символа другому. Это значение затем может быть использовано функцией towctrans () для преобразования символа ch. Функция возвращает преобразованное значение. Во всех средах выполнения поддерживаются следующие строки преобразования. tolower toupper Функции ввода-вывода двубайтовых символов Некоторые функции ввода-вывода, описанные в главе 6, имеют реализации, ориентированные на работу с двубайтовыми символами. Эти функции (они перечислены в приведенной ниже таблице) используют заголовок <wchar. h>. Обратите внимание на то, что функции swprintff) и vswprintf ((требуют передачи дополнительного параметра, в котором не нуждаются их char-эквиваленты. , .
262 Функции ввода-вывода двубайтовых символов Функция char-эквивалент wchar_t *fgetws(wchar_t *str, int пит, FILE *stream) wint_t fputwc(wchar_t ch, FILE *stream) int fputws(const wchar_t *str, FILE *stream) int fwprintf (FILE * stream, const wchar_t *fmt, ... int fwscanf(FlLE *stream, const wchar_t *fmt,. . .) wint_t getwc(FILE *.stream) wint_t getwchar(void) wint_t putwc(wchar_t ch, FILE *stream) wint_t putwchar(wchar_t ch) int swprintf(wchar_t *str, size_t пит, const wchar_t *fmt, . fgets() В версии С99 к параметрам sfcrn stream применен квалификатор restrict fputc() fputs() В версии С99 к параметрам strti stream применен квалификатор restrict fprintf() В версии С99 к параметрам stream и fmt применен квалификатор restrict fscanf() В версии С99 к параметрам stream и fmt применен квалификатор restrict getc() getchar() • putc() putchar() sprintf() Обратите внимание на то, что добавлен параметр пит, который ограничивает количество символов, записываемых в массив str. В версии С99 к параметрам str и fmt применен квалификатор restrict
Функции ввода-вывода двубайтовых символов 263 Функция char-эквивалент int swscanf(const wchar_t *str, const wchar_t *fmt,... wint_t ungetwc(wint_t ch, FILE *stream) int vfwprintf(FILE *stream, const wchar_t *fmt, va_list arg) int vfwscanf( : FILE * restrict stream, const Wchar_t * restrict fmt, va_list arg); int vswprintf(wchar_t *str, size_t пит, const wchar_t *fmt, va_list arg) int vswscanf( const wchar_t * restrict str, const wchar_t * restrict fmt, va_list arg); int vwprintf(const wchar_t *fmt, va_list arg) int vwscanf( const wchar_t * restrict fmt, va_list arg); int wprintf( const wchar_t *fmt,...) int wscanf( const wchar_t *fmt, ...) sscanf() В версии С99 к параметрам str и fmt применен квалификатор restrict ungetc() vfprintf() В версии С99 к параметру fmt применен квалификатор restrict vf scanf () (Добавлена в версии С99.) vsprintf() Обратите внимание на то, что добавлен параметр лит, который ограничивает количество символов, записываемых в массив str. В версии С99 к параметрам str и fmt применен квалификатор restrict vsscanf() (Добавлена в версии С99.) vprintf() В версии С99 к параметру fmt применен квалификатор restrict vscanf () (Добавлена в версии С99.) printfO В версии С99 к параметру fmt применен квалификатор restrict scanf() В версии С99 к параметру fmt применен квалификатор restrict
264 Строковые функции двубайтовых символов Кроме того, к содержимому приведенной выше таблицы была добавлена следующая функция ввода-вывода символов широкого формата. int fwide(FILE *stream, int how); Если значение параметра how положительно, функция fwide () делает поток stream потоком широкоформатных символов. Если же значение параметра how отрицательно, то функция fwide () превращает поток stream в char-поток. А если значение how равно нулю, на поток stream никакого воздействия не оказывается. Если этот поток уже был ориентирован либо на двубайтовые, либо на обычные символы, он изменяться не будет. Функция возвращает положительное значение, если поток использует символы широкого формата, отрицательное, если он использует символы типа char, и нуль, если поток еще не ориентирован. Ориентация потока также определяется его первым использованием. Строковые функции двубайтовых символов Существуют также двубайтовые версии функций обработки строк, описанных в главе 7. Эти функции (перечисленные в следующей таблице) используют заголовок <wchar. h>. Заметьте, что функция wcstok () требует передачи дополнительного параметра, который не используется ее char-эквивалентом. Функция char-эквивалент wchar_t *wcscat (wchar_t *strl, strcat() const wchar_t *str2) В версии С99 к параметрам strl иstr2 применен квалифи- катор restrict wchar_t *wcschr(const wchar_t *str, strchrO wchar_t ch) int wcscmp(const wchar_t *strl, strcmp () const wchar_t *str2) int wcscoll(const wchar_t *strl, strcoll() const wchar_t *st-r2) size_t wcscspn(const wchar_t *strl, strcspn() const wchar_t *str2)
Строковые функции двубайтовых символов 265 Функция char-эквивалент wchar_t *wcscpy(wchar_t *strl, const wchar_t *str2) size_t wcslen(const wchar_t *str) wchar_t *wcsncpy(wchar_t *strl, constwchar_t *str2, size_t пит) wchar_t *wcsncat(wchar_t *strl, const wchar_t *str2, size_t лит) int wcsncmp(constwchar_t *strl, constwchar_t *str2, size_t пит) wchar_t *wcspbrk( const wchar_t *strl, const wchar_t *str2) wchar_t *wcsrchr( const wchar_t *strl, wchar_t ch) size_t wcsspn(const wchar_t *strl, const wchar_t *str2) wchar_t *wcstok(wchar_t *strl, const wchar_t *str2, wchar_t ** endptr) strcpy() В версии С99 к параметрам strlи str2 применен квалифи- катор restrict strlen() strncpy() В версии С99-К параметрам strl и str2 применен квалифи- катор restrict strncat() В версии С99 к параметрам strl и str2 применен квалифи- катор restrict strncmp() strpbrk() strrchr() strspn() strtokO Здесь параметр endptr является указателем, который содержит информацию, необходимую для продолжения процесса разделения строки на лексемы. В версии С99 к параметрам strl и str2применен квалификатор restrict
266 Преобразование строк двубайтовых символов Функция . char-эквивалент wchar_t *wcsstr( strstr() const wchar_t *strl, const wchar_t *str2) size_t wcsxfrm(wchar_t *strl, strxfrm() const wchar_t *str2, В версии C99 К пара- si ze_t лит) метрам strl и str2 применен квалифи- катор restrict Преобразование строк двубайтовых символов Функции, перечисленные в следующей таблице, представляют собой двубайтовые версии стандартных функций преобразования строк в числа (и обратно) и функций времени. Эти функции используют заголовок <wchar. h>. Функция char-эквивалент size_t wcsftime(wchar_t *str, ' strftime() size_t max, В версии С99 к па- const wchar_t *fmt, раметрам strl, fmt cqnst struct tm *ptrj; ирСгприменен квалификатор restrict ' ' double wcstocKconst wchar_t *start, strtod() wchar_t * * end); В версии С99 к параметрам start и end применен квалификатор restrict float wcstof( strtof () const wchar_t * restrict start, (Добавленаввер- wchar_t ** restrict end); СИИ С99.) long double wcstold( strtold() const wchar_t * restrict start, (Добавлена в вер- wchar_t ** restrict end); СИиС99.)
Работа с массивами двубайтовых символов 267 Функция char-эквивалент long int wcstol( const wchar_t *start, wchar_t **end, int radixT long long int wcstoll( const wchar_t * restrict start, wchar_t ** restrict end, int radix) unsigned long int wcstoul( const wchar_t * restrict start, wchar_t ** restrict end, int radix) unsigned long long int wcstoull( const wchar_t *start, wchar_t **end, , , int; radix) strtol ()¦ В версии С99 к параметрам start и end применен ква- лификатор restrict strtolK) (Добавлена в версии С99.) ¦ StrtQul ().; В версии С99 к параметрам start и end применен ква- лификатор restrict strtoull () (Добавлена в версии С99.) Работа с массивами двубайтовых символов Стандартные функции посимвольной обработки массивов (например, memcpy ()) также имеют двубайтовые эквиваленты. Эти функции (перечисленные в следующей таблице) используют заголовок <wchar.h>. Функция char-эквивалент wchar_t *wmemchr (const wchar_t *str, memchr () wchar_t ch, size_t пит) int wmemcmp(const wchar_t *strl, memcmp () const wchar_t *str2, size_t пит)
268 Работа с массивами двубайтовых символов Функция char-эквивалент wchar_t *wmemcpy(wchar_t *strl, const wchar_t *str2, size_t пит) wchar_t *wmemmove(wchar_t *strl, const wchar_t *str2, size_t пит) wchar_t *wmemset(wchar_t *str, wchar^t ch, size_t пит) memcpy() В версии С99 к параметрам strl и str2 применен квалификатор restrict memmove() memset() Преобразование объектов в двубайтовые символы Стандартная библиотека поддерживает различные функции, предназначенные для преобразования многобайтовых объектов в символы широкого формата (и обратно). Эти функции (перечисленные в следующей таблице) используют заголовок <wchar. h>. Многие из них представляют собой повторно запускаемые (restartable) версии обычных многобайтовых функцию Повторно' запускаемая версия использует информацию о состоянии, передаваемую ей в параметре типа mbstate_t. Если этот параметр нулевой, функция предоставит собственный объект типа mbstate t. Функция Описание win_t btowc(int ch) Преобразует параметр ch в его двубайтовый эквивалент и возвращает результат. При ошибке возвращает значение WEOF или, если ch не однобайтовый, многобайтовый символ
Преобразование объектов в двубайтовые символы 269 Функция Описание size_t mbrlen(const char *str, size_t пит, mbstate_t * state) size_t mbrtowc(wchar_t *out, const char *in, size_t пит, mbstate_t *state) int mbsinit(const mbstate_t *state) Повторно запускаемая версия функции mblen (), в которой информация о состоянии передается параметром state. Возвращает положительное число, означающее длину следующего многобайтового символа. Нуль возвращается в случае, если следующий символ — нулевой. При ошибке возвращается отрицательное значение. В версии С99 к параметрам strn state применен квалификатор restrict Повторно запускаемая версия функции mbtowc (), в которой информация о состоянии передается параметром state. Возвращает положительное число, означающее длину следующего многобайтового символа. Нуль возвращается в случае, если следующий символ — нулевой. При ошибке возвращается зна- ч чение -1 и переменной errno присваивается макрос EILSEQ. Если преобразование не завершено, возвращается число -2» В версии С99 к параметрам out, in и state применен квалификатор restrict Возвращает значение true, если параметр state представляет начальное состояние процесса преобразования
270 Преобразование объектов в двубайтовые символы Функция Описание size_t mbsrtowcs(wchar_t *out, const char **in, size_t пит, mbstate t * state) size_t wcrtotnb(char *out, wchar_t ch, mbstate_t *state) size_t wcsrtombs(char *out, :qonst wchar_t * *[in, sj.;ze_t;. пит,,,, : mbstate_t *state) int wctob(wint_t ch) Повторно запускаемая версия функции mbstowes (), в которой информация о состоянии передается параметром state. Кроме того, функция mbsrtowcs {) отличается от функции mbst owes () тем, что параметр in является косвенным указателем на исходный массив. При ошибке переменной errno присваивается макрос EILSEQ. В версии С99 к параметрам out, in и state применен квалификатор restrict Повторно запускаемая версия функции wctomb (), в которой информация о состоянии передается параметром state. При ошибке переменной errno присваивается макрос EILSEQ. В версии С99 к параметрам out и state применен квалификатор restrict Повторно запускаемая версия функции westombs (), в которой информация о состоянии передается параметром state. Кроме того, функция wcsrtombs () отличается от функции westombs() тем, что параметр in является косвенным указателем на исходный массив. При ошибке переменной errno присваивается макрос EILSEQ. В версии С99 к параметрам out» яп и state применен квалификатор restrict Преобразует параметр ch в его однобайтовый эквивалент. При сбое функция возвращает значение EOF
Глава 14 Система ввода-вы вода старого стиля в языке C++ Поскольку язык C++ полностью включает библиотеку С, он поддерживает и использование системы ввода-вывода языка С. Однако C++ также определяет собственную объектно-ориентированную, основанную на использовании классов систему ввода-вывода, которую называют библиотекой классов потоков ввода-вывода (iostream library). При написании программ на языке C++ вам стоит использовать именно собственную библиотеку C++ (iostream-библиотеку), а не С- ориентированную. На момент написания этой главы существуют две версии iostream-библиотеки, причем обе широко используются программистами: более старая, основанная на оригинальных спецификациях языка C++, и новая, определенная стандартом ANSI/ISC) Для языка C++. В настоящее время большинство компиляторов C++ поддерживают iostream-библиотеки как старого, так и нового стилей. Однако следует иметь в виду, что iostream- библиотека старого стиля уже устарела и ее не следует использовать при написании новых программ. Новые приложения должны предусматривать использование новых подходов к программированию, определенных стандартом ANSI/ISO для языка C++. Описание iostream-библиотеки старого стиля, приведенное в данной главе, предназначено для тех программистов, которые вынуждены поддерживать старые программы или хотят перевести старый код в новый стандарт. Новый подход к программированию задач ввода-вывода на языке C++ описан в главе 15. Большей частью iostream-библиотеки как старого, так и нового стилей работают в одном и том же ключе. Если вы знаете, как использовать одну библиотеку, вы сможете легко работать и с другой. Однако между ними имеется ряд существенных различий. Во-первых, оригинальные классы потоков ввода-вывода были определены в глобальном пространстве имен, а новая библиотека содержится в пространстве имен std.
272 Базовые классы потоков ввода-вывода Во-вторых, новая библиотека определена с помощью сложного набора взаимосвязанных шаблонных классов и функций, а в библиотеке старого стиля используется менее сложная иерархия классов без применения шаблонов. К счастью, имена классов, которые вы будете использовать в своих программах, остаются прежними. В-третьих, новая iostream-библиотека определяет много новых типов данных. В-четвертых, для использования старой библиотеки необходимо включать в свои программы заголовочные файлы с расширением . h, например iostream.h. В этих заголовочных файлах определяются потоковые классы старого стиля, которые относятся к глобальному пространству имен. И наоборот, для использования новой библиотеки потоковых классов включите в свою программу заголовок нового стиля <iostream>. И еще одно. Поскольку библиотека старого стиля нестандартна, ее точные реализации будут различными для разных компиляторов и она может отличаться от библиотеки, описанной здесь. Базовые классы потоков ввода- вывода В библиотеке классов потоков ввода-вывода старого стиля используется заголовочный файл iostream.h. Этот файл определяет иерархию фундаментальных классов, которая поддерживает операции ввода-вывода. Тем, кто выполняет файловые операции ввода-вывода, придется также включить в свою программу заголовочный файл fstream.h. А для использования операций ввода-вывода над массивами необходимо включить заголовочный файл strstrea. h. Класс самого нижнего уровня называется streambuf. Он обеспечивает выполнение основных операций ввода и вывода и используется, в основном, в качестве базового класса для других классов. Если вы не решитесь выводить собственные классы ввода-вывода, вам не придется использовать класс streambuf напрямую. Класс ios является базовым классом иерархии классов, который обычно используется при работе с системой ввода- вывода в среде C++. Он обеспечивает форматирование и обра-
Встроенные потоки C++ 273 ботку ошибок и предоставляет информацию о состоянии. Из класса ios выведено несколько других классов — иногда посредством промежуточных классов. Ниже перечислены классы, выведенные прямо или косвенно из класса ios, которые используются чаще всего. Класс Цель создания istream Общие операции ввода ostrearrf^ Общие операции вывода iostream Общие операции ввода-вывода i f s t rearn Ввод в файл of stream Вывод из файла f stream Файловые операции ввода-вывода istrstream Ввод, ориентированный на использование специальных массивов ostrstream Вывод, ориентированный на использование специальных массивов strstream Ввод-вывод, ориентированный на использование специальных массивов Встроенные потоки C++ Как только программа, написанная на языке C++, начинает выполняться, автоматически открываются четыре перечисленных ниже встроенных потока. Поток Значение Устройство по умолчанию cin cout cerr clog Стандартный поток ввода Стандартный поток вывода Стандартный поток вывода ошибок Буферизированная версия потока cerr Клавиатура Экран Экран Экран По умолчанию стандартные потоки используются для подключения к консоли. Однако в средах, которые поддерживают
274 Флаги форматирования возможность перенаправления ввода-вывода (например, в DOS, UNIX и Windows), стандартные потоки могут быть перенаправлены на другие устройства или в файлы. Флаги форматирования || В системе ввода-вывода C++ каждый поток связан с набором флагов форматирования, которые управляют процессом форматирования информации потоком. В классе ios определяются следующие значения (они используются для установки или очистки флагов форматирования). adjustfield basefield dec fixed floatfield oct showpoint unitbuf hex right showpos uppercase internal scientific skipws left showbase stdio Поскольку эти флаги определяются внутри класса ios, вам придется явно задавать его при использовании флагов в своей программе. Например, для ссылки на флаг left нужно записать ios::left. Когда флаг skipws установлен, ведущие пробельные символы, или символы пропуска (пробелы, символы табуляции и новой строки), отбрасываются при выполнении ввода в поток. Когда флаг skipws сброшен, пробельные символы не отбрасываются. Когда установлен флаг left, результат выравнивается по левому краю. А когда установлен флаг right, результат выравнивается по правому краю. Когда установлен флаг internal, числовое значение дополняется пробелами, чтобы заполнить поле между каким-либо знаком или базовым символом. Если ни один из этих флагов не установлен, результат выравнивается по правому краю по умолчанию. По умолчанию числовые значения выводятся в десятичной системе счисления. Однако основание системы счисления можно изменить. Установка флага oct приведет к выводу результата в восьмеричном представлении, а установка ({шага hex — в шест- надцатеричном. Чтобы при отображении результата вернуться к десятичной системе счисления, достаточно установить флаг dec.
Флаги форматирования 275 Установка флага showbase приводит к отображению обозначения основания системы счисления, служащего для представления числовых значений. Например, если используется шестнадцатеричное представление, то значение IF будет отображено как Ox IF. По умолчанию при использовании экспоненциального представления чисел отображается строчной вариант буквы "е". Кроме того, при отображении шестнадцатеричного значения используется также строчная буква "х". После установки флага uppercase отображается прописной вариант этих символов. Установка флага showpos вызывает отображение ведущего знака "плюс" перед положительными значениями. Установка флага showpoint приводит к отображению десятичной точки и хвостовых нулей для всех чисел с плавающей точкой — нужны они или нет. После установки флага scientific числовые значения с плавающей точкой отображаются в экспоненциальном представлении. Когда установлен флаг fixed, вещественные значения отображаются в обычном представлении. Если не установлен ни один флаг, компилятор сам выбирает соответствующий метод представления. При установленном флаге unitbuf буфер сбрасывается после каждой операции вставки. Если установлен флаг stdio, потоки stdout и stderr сбрасываются после каждой операции вывода. Поскольку часто приходится обращаться к полям oct, dec и hex, на них допускается коллективная ссылка ios: :basef ield. Аналогично поля left, right и internal можно собирательно назвать ios: :adjustfield. Наконец, поля scientific и fixed можно называть ios:: f loatf ield. Флаги форматирования обычно хранятся как длинные целые значения (long int), и их могут устанавливать различные функции-члены класса ios. Манипуляторы ввода-вывода Помимо прямой установки или очистки флагов форматирования, существует еще один способ изменения параметров формата любого потока. Этот второй способ реализуется посредством использования специальных функций, называв-
276 Флаги форматирования мых манипуляторами, которые можно включить в выражение ввода-вывода. Манипуляторы, определенные библиотекой iostream старого стиля, описаны в следующей таблице. Манипулятор dec endl ends flush hex oct resetiosflags (long f) setbase (int base) setfill (int ch) setiosflags (long f) setprecision (int p) setw(int w) ws Назначение Используется для представления десятичных целых Выводит символ новой строки и сбрасывает поток Вставляет в поток нулевой символ (' \0 ') Сбрасывает поток Используется для представления шестнадцатеричных целых Используется для представления восьмеричных целых Очищает флаги, заданные в переменной f Устанавливает основание системы счисления равной значению base Устанавливает символ- заполнитель равным значению переменной ch Устанавливает флаги, заданные в переменной f Устанавливает количество цифр точности (после десятичной точки) Устанавливает ширину поля равной значению переменной w Пропускает ведущие пробельные символы Функция Ввод-вывод Вывод Вывод Вывод Ввод-вывод Ввод-вывод Ввод-вывод Вывод Вывод Ввод-вывод Вывод Вывод Ввод Для получения доступа к манипуляторам, принимающим параметры, например setw{), необходимо включить в свою программу заголовочный файл iomanip. h.
Функции iostream старого стиля 277 I Функции iostream старого стиля || Ниже описаны наиболее популярные функции работы с потоками ввода-вывода старого стиля. #include <iostream.h> int bad() const; Функция bad () является членом класса ios. Функция bad () возвращает ненулевое значение, если в соответствующем потоке обнаружена фатальная ошибка ввода-вывода; в противном случае возвращается нуль. См. также функцию good (). clear #include <iostream.h> void clear(int flags = 0); Функция clear () является членом класса ios. Функция clear () очищает флаги состояния, связанные с потоком. Если значение параметра flags равно нулю (каким оно и есть по умолчанию), то очищаются, т.е. устанавливаются равными нулю, все флаги ошибок. В противном случае флаги состояния будут установлены равными значению, заданному в переменной flags. См. также функцию rdstate (). Ieatwhite #include <iostream.h> void eatwhite(); Функция eatwhite () является членом класса istream.
278 eof Функция eatwhiteO читает и отбрасывает все ведущие пробельные символы из соответствующего потока ввода и перемещает внутренний указатель ввода (get pointer) на первый непробельный символ. См. также функцию ignore (). eof #include <iostream.h> int eof() const; Функция eof () является членом класса ios. Функция eof () возвращает ненулевое значение при обнаружении конца соответствующего файла ввода; в противном случае возвращается нуль. См. также функции bad (), fail (), good (), rdstate () и clear(). I?ail ' #include <iostream.h> int fail() const; Функция f ail () является членом класса ios. Функция f ail () возвращает ненулевое значение при обнаружении в соответствующем потоке ошибки ввода-вывода; в противном случае возвращается нуль. См. также функции bad (), eof (), good (), rdstate () и clear(). [fill | #include <iostream.h> char fill() const; char fill(char ch); Функция fill () является членом класса ios. По умолчанию поле, когда его требуется заполнить, заполняется пробелами. Однако можно изменить символ заполнения с по-
flags 279 мощькьфункции f ill (), указав новый символ заполнения в переменной ch. Функция возвращает старый символ заполнения. Первая форма функции fill() возвращает текущий символ заполнения. См. также функции precision () и width (). flags I #include <iostream.h> long flags() const; long flags(long f); Функция flags () является членом класса ios. Первая форма функции f lags () просто возвращает текущие установки флагов форматирования соответствующего потока. Вторая форма функции flags () устанавливает все флаги форматирования, связанные с потоком, в соответствии со значением параметра f. При использовании этой версии двоичный код, содержащийся в параметре f, копируется в флаги форматирования соответствующего потока. Эта версия функции flags () также , возвращает предыдущие установки флагов форматирования. См. также функции unset f () nsetf (). [flush I #include <iostream.h> ostream &flush(); Функция flush () является членом класса ostream. Функция flush () выполняет физическую запись содержимого буфера, связанного с соответствующим потоком вывода, на устройство. Функция возвращает ссылку на данный поток. См. также функции put () и write (). f stream, if stream И ofstream 1 #include <fstream.h> fstream();
280 fstream, ifstream и ofstream fstreamtconst char * filename, int mode, int access=filebuf::openprot); fstream(int fd) ; fstream(int fd, char *buf, int size); ifstream(); ifstream(const char * filename, int mode=ios::in, int access=filebuf::openprot); ifstream(int fd); ifstream(int fd, char *buf, int size); ofstream(); ofstream(const char * filename, int mode-ios::out, int access=filebuf::openprot); ofstream(int fd); ofstreamfint fd, char *buf, int size); Функции fstreamt), ifstream() и ofstream() представляют собой конструкторы классов fstream, ifstream и of stream соответственно. Версии функций fstreamf), ifstream() и ofstream(), не принимающие параметров, создают поток, который не связан ни с одним файлом. Этот поток можно позже связать с файлом с помощью функции open (). Версии функций fstreamt), if stream () и ofstream(), которые принимают имя файла в качестве первого параметра, в прикладных программах используются наиболее часто. Хотя можно вполне корректно открыть файл с помощью функции open (), в большинстве случаев обходятся без нее, поскольку функции конструкторов fstream, ifstream и of stream автоматически открывают файл при создании потока. Функции конструкторов имеют те же параметры и значения, действующие по умолчанию, что и функция open (). (Подробности — в разделе "open".) Поэтому самый распространенный способ открытия файла показан в следующем примере. ifstream mystreamf"myfile"); Если по некоторым причинам файл открыть не удастся, значение переменной связанного потока будет равно нулю. Следовательно, либо использовав для открытия файла функцию конструктора, либо вызвав явным образом функцию open (), вам следует убедиться в том, что файл действительно был открыт, проверив для этого значение потока.
gcount 281 Версии функций fstream(), ifstream!) и ofstreamf), которые принимают только один параметр (уже действительный дескриптор), создают поток, а затем связывают его с дескриптором файла, заданным параметром fd. Версии функций fstreamO, ifstreamO и ofstreamO, которые принимают дескриптор файла, указатель на буфер и размер, создают поток и связывают его с дескриптором файла, заданным параметром fd. Параметр buf должен быть указателем на область памяти, которая будет служить в качестве буфера, а параметр size определяет длину буфера в байтах. (Если параметр buf оказывается нулевым указателем и/или если значение параметра size равно нулю, никакой буферизации не происходит.) См. также функции close () и open (). I gcount I явваааввавнвнававввввааввввавввававав^ввава #include <iostream.h> int gcount() const; Функция gcount () является членом класса istream. Функция gcount () возвращает количество символов, прочитанных во время последней операции ввода. См. также функции get (), get line () и read(). 'get #include <iostream.h> int get(); istream &get(char &сЛ); istream &get(char *buf, int num. char delim = '\n'); istream &get (streambuf Scbuf, char delim = '\n'); Функция get () является членом класса istream. Вообще, функция get () предназначена для чтения символов из потока ввода. Функция get (), используемая в форме без параметров, читает один символ из соответствующего потока и возвращает прочитанное значение.
282 getline Функция get (), принимающая в качестве единственного параметра ссылку на символ, читает символ из соответствующего потока и помещает прочитанное значение в переменную ch. Функция возвращает ссылку на поток. (Заметьте, что параметр ch может также иметь тип unsigned char * или signed char *.) Функция get () в форме, принимающей три параметра, читает символы в массив, адресуемый параметром buf, до тех пор, пока либо не будет прочитано лит символов, либо не встретится символ ограничителя, заданный параметром delim. После выполнения функции get () массив, адресуемый параметром buf, будет иметь завершающий нуль- символ. Если параметр delim не задан, то в качестве ограничителя по умолчанию используется символ новой строки. Обнаруженный символ ограничителя из потока ввода не извлекается. Он остается в потоке до следующей операции ввода. Эта функция возвращает ссылку на поток. (Заметьте, что параметр buf может также иметь тип unsigned char * или signed char *.) Функция get () в форме, принимающей два параметра, читает символы из потока ввода в объект класса streambuf (или производный от него объект). Символы читаются до тех пор, пока не встретится символ ограничителя, заданный параметром delim. Функция возвращает ссылку на поток. См. также функции put (), getline () и read (). I getline ввваввва #include <iostream.h> istream &getline(char *buf, int пит, char delim = '\n'); Функция getline () является членом класса istream. Функция getline () читает символы в массив, адресуемый параметром buf, до тех пор, пока либо не будет прочитано пил? символов, либо не встретится символ ограничителя, заданный параметром deli л?. После выполнения функции getline () массив, адресуемый параметром buf, будет иметь завершающий нуль-символ. Если параметр delim не задан, то в качестве ограничителя по умолчанию используется сим-
good 283 вол новой строки. Обнаруженный символ ограничителя из потока ввода извлекается, но не помещается в массив buf. Функция возвращает ссылку на поток. (Заметьте, что параметр buf может также иметь тип unsigned char * или signed char *.) См. также функции get () и read (). I good iinclude <iostream.h> int good() const; Функция good () является членом класса ios. Функция good () возвращает ненулевое значение, если в соответствующем потоке не обнаружено ни одной ошибки ввода-вывода; в противном случае возвращается нуль. См. также функции bad(), fail(), eof (), clear () и rdstate(). I ignore j ttinclude <iostream.h> istream &ignore(int пит = 1, int delim = EOF); Функция ignore () является членом класса istream. Функцию-член ignore () можно использовать для чтения и отбрасывания символов из потока ввода. Функция читает и отбрасывает символы до тех пор, пока либо не будет проигнорировано пит символов A по умолчанию), либо не встретится символ ограничителя, заданный параметром delim (EOF по умолчанию). Обнаруженный символ ограничителя удаляется из потока ввода. Функция ignore () возвращает ссылку на поток. См. также функции get () и get line ().
284 open i°pen ¦ #include <fstream.h> void open(const char * filename, int mode, int access-iilebuf::openprot); Функция ореп() является членом классов fstream, if streamn of stream. С помощью функции open () файл связывается с потоком. Параметр filename содержит имя файла и может включать спецификатор пути. Значение параметра mode определяет, в каком режиме открывается файл. Ниже перечислены возможные значения этого параметра. 1OS ios ios ios ios ios ios ios :app :ate :binary : in :nocreate :noreplace : out : trunc Используя оператор ИЛИ (OR), можно объединять в одном выражении два или больше значений (из перечисленных выше). Включив значение ios : : арр, можно обеспечивать добавление всех выводимых данных в конец заданного файла. Это значение можно использовать только с файлами, которые позволяют выполнять операцию вывода. Включение значения ios : : ate оставляет внутренний указатель в конце файла при его открытии, но несмотря на это операции ввода-вывода могут выполняться в любом месте файла. Значение ios: :binary обеспечивает возможность открывать файл для выполнения двоичных операций ввода-вывода. По умолчанию файлы открываются в текстовом режиме. Значение ios: : in указывает на способность файла к выполнению операций ввода, а значение ios: : out — операций вывода. Однако создание потока с использованием класса i f stream само по себе предполагает ввод, а с использованием класса of stream— вывод, поэтому в подобных случаях нет необходимости применять данные значения.
open 285 Использование значения ios::trunc приводит к разрушению содержимого уже существующего файла с таким же именем, а сам файл усекается до нулевой длины. Включение значения ios: :nocreate обрекает функцию open () на неудачу, если заданного файла еще не существует. Значение ios: :noreplace запрещает выполнение функции ореп(), если заданный файл уже существует, а значения ios: : ate и ios: : арр при этом не заданы. Значение параметра access определяет режим доступа к файлу. По умолчанию действует значение filebuf: ropenprot (f ilebuf — это базовый класс для классов работы с файлами), означающее обычный файл. За информацией о других возможных значениях параметра access обратитесь к документации на используемый вами компилятор. / Открывая файл, для параметров mode и access можно использовать значения, действующие по умолчанию. Открывая файл ввода, параметр mode можно по умолчанию установить равным значению ios: : in. Открывая файл вывода, параметр mode по умолчанию можно установить равным значению ios: : out. В любом случае для параметра access по умолчанию используется вариант обычного файла (normal file). Например, при выполнении следующего фрагмента программы открывается файл с именем TEST для операций вывода. out.open("test"); //по умолчанию работа с обычным // файлом для вывода Чтобы открыть поток для ввода и вывода, необходимо задать для параметра mode значения ios : : in и ios : : out, как показано ниже. mystream.open("test", ios::in | ios::out); Во многих компиляторах при открытии файлов для операций чтения/записи никаких значений, действующих по умолчанию, не предусмотрено. Во всех случаях, если функция open () выполняется неудачно, поток будет равен нулю. Следовательно, прежде чем использовать файл, необходимо убедиться в том, что он был успешно открыт. См. также функции closed, fstreamf), ifstream() и of stream().
286 open Совет программисту Чтобы выполнить чтение или запись в текстовый файл, достаточно для открытого потока использовать операторы << и >>. Например, следующая программа записывает в файл с именем TEST целое число, значение с плавающей точкой и строку, а затем читает все, что было записано. #include <iostream.h> #include <fstream.h> int main() { ofstream out("test"); if('out) { cout « "He удается открыть файл.\п"; return 1; // Выводим данные. out « 10 « " " « 123.23 « "\n"; out « "Это короткий текстовый файл.Хп"; out.close (); // Теперь читаем все, что было записано, char ch; int i ; float f; char str[80]; ifstream in("test"),• if('in) { cout << "He удается открыть файл.\п"; return 1; in » i; in » f; in >> ch; in » str; cout « "Вот эти данные: cout « i << " " << f << « ch « "\n";
peek 287 cout << str,- in.close() ; return 0; } При чтении текстовых файлов с использованием онера- тора >> имейте в виду, что могут происходить преобразования некоторых символов. Например, пробельные символы опускаются. Чтобы не допустить ненужного преобразования символов, необходимо открыть файл для двоичных операций ввода-вывода и использовать двоичные функции ввода-вывода. Ipeek вавввая tinclude <iostream.h> int peek(); Функция peek () является членом класса istream. Функция peek () возвращает следующий символ в потоке или значение EOF, если обнаружен конец файла. Ни при каких обстоятельствах функция не удаляет символ из потока. См. также функцию get (). I precision Д iinclude <iostream.h> int precision() const; int precision(int p) ; Функция precision () является членом класса ios. По умолчанию при выводе значений с плавающей точкой отображаются шесть цифр точности (после десятичной точки). Однако, используя вторую форму записи функции precision (), можно установить количество этих цифр равным значению, заданному параметром р. Функция возвращает исходное значение точности.
288 put Первая версия функции precision () возвращает текущее значение точности. См. также функции width () и fill (). [put. #include <iostream.h> ostream &put(char ch); Функция put () является Членом класса ostream. Функция put () записывает символ ch в соответствующий поток вывода. Она возвращает ссылку на этот поток. См. также функции write () и get (). I putback SSBSBSS^SBB tinclude <iostream.h> istream &putback(char ch); Функция putback () является членом класса istream. Функция putback () возвращает символ ch в соответствующий поток ввода. ПРИМЕЧАНИЕ. Параметр ch должен быть последним символом, прочитанным из потока. См. также функцию peek (). I rdstate 1 #include <iostream.h> int rdstate() const; Функция rdstate () является членом класса ios. Функция rdstate () возвращает состояние соответствующего потока. Система ввода-вывода C++ поддерживает информацию о состоянии, касающуюся результата выполнения каждой операции ввода-вывода, которая связана с активным потоком. Текущее состояние системы ввода-вывода хранится
read 289 в виде значения целочисленной переменной, в которой закодированы следующие флаги. Имя Значение ios : : goodbit He обнаружено никаких ошибок ios::eofbit Обнаружен конец файла ios: : f ailbit При выполнении операций ввода-вывода обнаружен нефатальный сбой ios : : badbit При выполнении операций ввода-вывода обнаружена фатальная ошибка Эти флаги перечислены в классе ios. Функция rdstatet) возвращает нуль (ios: :goodbit), когда не обнаружено никакой ошибки; в противном случае устанавливается бит ошибки. См. также функции eof (), good (), bad (), clear () и fail (). I read | #include <ios,tream.h> istream &read(char *buf, int пит); Функция read () является членом класса istream. Функция read () читает лют байт из соответствующего потока ввода и помещает их в буфер, адресуемый параметром buf (заметьте, что параметр buf может также иметь тип unsigned char * или signed char *). При достижении конца файла до прочтения пит символов функция read () просто прекращает работу, а в буфере содержится столько символов, сколько было прочитано в действительности. (См. раздел "gcount".) Функция read () возвращает ссылку на поток. См. также функции gcount (), get (), getline () и write (). seekgИ seekp Цвввваввввавввв #include <iostream.h> istream &seekg(streamoff offset, ios::seek_dir origin) istream kseekg(streampos position)
290 seekg и seekp ostream &seekp(streamoff offset, ios::seek_dir origin); ostream &seekp(streampos position); Функция seekg () является членом класса istream, a функция seekp () — членом класса ostream. В системе ввода-вывода C++ с помощью функций seekg () и seekp () выполняется произвольный доступ, т.е. система ввода-вывода C++ управляет двумя указателями, связанными с файлом. Один из них — это указатель ввода (get pointer), который указывает, в каком месте файла будет выполняться следующая операция ввода. А другой — указатель вывода (put pointer), который указывает, в каком месте файла будет выполняться следующая операция вывода. При каждом выполнении операции ввода или вывода соответствующий указатель автоматически перемещается, последовательно изменяя свою позицию. Однако, используя функции seekg () и seekp (), можно получить доступ к файлу непоследовательным образом. Версия функции seekg () с двумя параметрами перемещает указатель ввода на offset байт от позиции, заданной параметром origin. Версия функции seekp () с двумя параметрами перемещает указатель вывода на offset байт от позиции, заданной параметром origin. Параметр offset имеет тип streamof f, который определен в заголовке iostream.h. Объект типа streamof f способен содержать самое большое допустимое значение, которое может иметь параметр offset. Параметр origin имеет тип ios: : seek_dir и представляет собой перечисление, которое имеет следующие значения. ios: : beg Смещение от начала ios: : cur Смещение от текущей позиции ios: : end Смещение от конца Версии функций seekg () и seekp () с одним параметром перемещают указатели файлов в позиции, заданные параметром position. Это значение должно быть предварительно получено путем обращения либо к функции tellg (), либо к функции tellp() соответственно. Тип streampos определен в заголовке iostream.h. Объект типа streampos способен содержать самое большое допустимое значение, которое мо-
setf 291 жет иметь параметр position. Эти функции возвращают ссылку на соответствующий поток. См. также функции tellg () и tellp (). I setf #include <iostream.h> long setf(long flags); long setf(long flagsl, long ?lags2); Функция setf () является членом класса ios. Первая версия функции setf О устанавливает флаги форматирования, заданные параметром flags. (На все остальные флаги функция не действует.) Например, чтобы установить флаг showpos, можно использовать следующий оператор. stream.setf(ios::showpos); В данном случае stream — это поток, на который вы воздействуете. Важно понимать, что обращение к функции setf() делается относительно конкретного потока. Нет никакого смысла вызывать функцию setf () саму по себе, без указания потока. Другими словами, нет никакого смысла в глобальном статусе флагов форматирования среды C++. Каждый поток индивидуально поддерживает собственную информацию о статусе форматирования. Чтобы установить сразу несколько флагов форматирования, значения этих флагов можно объединить с помощью оператора ИЛИ (OR). Вторая версия функции setf () действует только на флаги, которые задаются параметром flags2. Соответствующие флаги сначала сбрасываются, а затем устанавливаются в соответствии с флагами, заданными параметром flagsl. Важно понимать, что даже если параметр flagsl содержит другие флаги, воздействию подвергнутся только те из них, которые заданы параметром flags2. Обе версии функции setf () возвращают предыдущие установки флагов форматирования, связанные с потоком. См. также функции unset f () и flags ().
292 setmode setmode #include <fstream.h> int setmode(int mode = filebuf::text); Функция setmode () является членом классов of stream и ifstream. Функция setmode () устанавливает режим работы соответствующего потока: двоичный или текстовый. (Текстовый устанавливается по умолчанию.) Допустимыми для параметра mode являются значения f ilebuf: : text и f ilebuf: : binary. Функция возвращает предыдущую установку режима работы потока или значение -1 при обнаружении ошибки. См. также функцию open (). #include <strstream.h> char *str(); Функция str () является членом класса strstream. Функция str () "замораживает", т.е. фиксирует динамически выделенный массив ввода и возвращает на него указатель. Но после фиксации динамический массив Нельзя использовать повторно для вывода. Следовательно, не стоит замораживать массив до тех пор, пока в него не будут выведены символы. ПРИМЕЧАНИЕ. Эта функция предназначена для выполнения операций ввода-вывода, ориентированных на использование массивов. См. также функции strstreamO, istrstreamO и ostrstream(). ..
strstream, istrstream и ostrstream 293 strstream, istrstream И ostrstream Д #include <strstream.h> strstream{); strstream(char *buf, int size, int mode); istrstream(const char *buf); istrstream(const char *buf, int size); ostrstream(); ostrstream(char *buf, int size, int mode=ios::out) Конструктор strstreamO — член класса strstream, конструктор istrstream() — член класса istrstream, и конструктор ostrstream () — член класса ostrstream. Эти конструкторы используются для создания потоков, ориентированных на работу с массивами, которые поддерживают соответствующие функции ввода-вывода C++. Для функции ostrstream () параметр buf представляет собой указатель на массив, собирающий символы, которые записаны' в поток. Размер массива передается с помощью параметра size. По умолчанию поток открывается для нормального вывода, но, используя параметр mode, можно задать и другой режим. Допустимые значения параметра mode те же, что используются для одноименного параметра в функции open (). В большинстве случаев параметр mode можно оставлять равным значению, действующему по умолчанию. Если используется версия функции ostrstream() без параметров, происходит автоматическое выделение динамического массива. Для версии функции istrstream (), принимающей один параметр, этот параметр buf является указателем на массив, который будет использован как источник символов при каждом выполнении операции ввода в поток. Содержимое массива, адресуемого параметром buf, должно иметь завершающий нулевой символ, который, однако, никогда не читается из массива. Если для ввода нужна только часть строки, используйте форму конструктора istrstream() с двумя параметрами. В этом случае будут задействованы только первые size элемен-
294 sync_with_stdio тов массива, адресуемого параметром buf. Эта строка не обязана содержать завершающий нулевой символ, поскольку ее размер определяется значением параметра size. Чтобы создать поток, ориентированный на работу с массивами и готовый ко вводу и выводу, используйте конструктор strstream(). В его параметризированной версии параметр buf указывает на строку, которая будет использована для операций ввода-вывода. Значение параметра size задает размер массива, а значение параметра mode определяет, как работает поток. Для нормальных операций ввода-вывода значение параметра mode будет равно ios : : in I ios : : out. Для операций ввода массив должен иметь завершающий нулевой символ. При использовании версии конструктора strstreamf) без параметров буфер, предназначенный для ввода-вывода, выделяется динамически, а режим устанавливается в расчете на выполнение операций чтения/записи. См. также функции str () и open (). Ii sync_with_stdio II ¦SaBSSSSSSSSSBBSBBSB^SKSSSSSSiBSSBBBK^SSSSSSal #include <iostream.h> static void sync_with_stdio() ; Функция sync_with_stdio () является членом класса ios. Вызвав функцию sync_with_stdio (), можно безопасно использовать стандартную С-подобную систему ввода-вывода в согласии с опирающейся на классы системой ввода-вывода C++. ' ¦ ••¦.-: ..¦:¦•...¦ ||tellgHtellp #include <iostream.h> streampos tellgO; streampos tellpt); Функция tellg() является членом класса istream, a функция tellp() —членом класса ostream.
unsetf 295 Система ввода-вывода C++ управляет двумя указателями, связанными с файлом. Один из них — это указатель ввода (get pointer), который указывает, в каком месте файла будет выполняться следующая операция ввода. А другой — указатель вывода (put pointer), который указывает, в каком месте файла будет выполняться следующая операция вывода. При каждом выполнении операции ввода или вывода соответствующий указатель автоматически перемещается, последовательно изменяя свою позицию. Именно с помощью функций tellgO и tellpO соответственно можно определить текущую позицию указателей ввода и вывода. Тип streampos определен в заголовке iostream.h. Он в состоянии содержать самое большое значение, которое может возвратить любая из этих двух функций. Значения, возвращаемые функциями tellg () и tellp (), можно использовать в качестве параметров функций seekg () и seekp () соответственно. См. также функции seekg () и seekp (). unsetf II #include <iostream.h> long unsetf(long flags); Функция unset f() является членом класса ios. Функция unsetf () используется для очистки одного или нескольких флагов форматирования. Флаги, заданные параметром flags, очищаются. (На все остальные флаги никакого воздействия не оказывается.) Возвращаются предыдущие установки флагов форматирования. См. также функции setf () и flags (). I width #include <iostream.h> int width() const; int width(int w); Функция width () является членом класса ios.
296 write Чтобы получить ширину поля, используйте первую форму функции width (). Эта версия возвращает текущее значение ширины поля. Чтобы установить ширину поля, используйте вторую форму. В данном случае параметр w содержит устанавливаемую ширину поля, а предыдущее ее значение возвращает функция. См. также функции precision () и fill (). write #include <iostream.h> ostream &write(const char *buf, int пит); Функция write () является членом класса ostream. Функция write()-записывает лит байт в соответствующий поток вывода из буфера, адресуемого параметром buf. (Заметьте, что параметр buf может также иметь тип unsigned char * или signed char *.) Функция возвращает ссылку на поток. • См. также функции read () и put ().
Глава 15 Классы ввода-вывода библиотеки стандарта ANSI/ISO для языка C++ Как упоминалось в предыдущей главе, в языке C++ существует две версии библиотеки iostream: библиотека старого стиля, определенная ранними версиями C++, и библиотека, определенная стандартом ANSI/ISO для языка C++ (Standard C++), в которой реализован новый подход к программированию. Библиотека старого стиля была описана в предыдущей главе, а эта глава посвящена описанию библиотеки iostream, соответствующей стандарту ANSI/ISO для языка C++. | Библиотека iostream стандарта C++ Существует два фундаментальных различия между библиотеками iostream старого стиля и соответствующей стандарту ANSI/ISO для языка C++. Во-первых, библиотека старого стиля была определена в глобальном пространстве имен, а библиотека iostream стандарта ANSI/ISO для языка C++ содержится в пространстве имен std. Во-вторых, библиотека старого стиля использует С-подобные заголовочные файлы с расширением . h, а библиотека стандарта C++ — заголовки в стиле C++ (без расширения . h). Чтобы использовать библиотеку iostream стандарта C++, включите в свою программу заголовок <iostream>. После этого вам, скорее всего, придется внести эту библиотеку в текущее пространство имен с помощью следующего оператора. using namespace std; После использования этого оператора работа как старой, так и новой библиотек во многом совпадает.
298 Классы ввода-вывода библиотеки стандарта C++ По сути, нет острой необходимости в использовании приведенного выше оператора using. Вместо него при каждой ссылке на какой-либо член классов ввода-вывода можно в явном виде использовать квалификатор пространства имен. Например, следующий оператор явным образом ссылается на поток cout. std::cout << "Это тест"; Конечно, если вы собираетесь широко использовать библиотеку iostream, включение, в программу оператора using сделает ваш труд на ниве программирования менее утомительным. Классы ввода-вывода библиотеки стандарта C++ Система ввода-вывода, соответствующая стандарту C++, построена на основе довольно сложной системы шаблонных классов. Ниже приведен список этих классов. Класс Назначение basic_ios Обеспечивает операции ввода- вывода общего назначения basic_streambuf Поддерживает нижний уровень операций ввода-вывода basic_istream ' Поддерживает операции ввода basic_ostream - Поддерживает операции вывода basic_iostream Поддерживает операции ввода- вывода basic_f ilebuf Поддерживает нижний уровень файловых операций ввода-вывода basic_if stream Поддерживает файловые операции ввода bas i c_o f s t rearn Поддерживает файловые операции вывода
Классы ввода-вывода библиотеки стандарта C++ 299 Класс Назначение basic_f stream Поддерживает файловые операции ввода-вывода basic_stringbuf Поддерживает нижний уровень строковых операций ввода-вывода basic_istringstream Поддерживает строковые операции ввода basic_ostringstream Поддерживает строковые операции вывода basic_stringstream Поддерживает строковые операции ввода-вывода Кроме того, часть иерархии классов ввода-вывода составляет нешаблонный класс ios_base. Он предоставляет определения для различных элементов системы ввода-вывода. Вся система ввода-вывода C++ построена на двух связанных, но различных иерархиях шаблонных классов. Первая выведена из класса ввода-вывода нижнего уровня basic_streambuf. Этот класс поддерживает базовые операции ввода и вывода нижнего уровня и обеспечивает основополагающую поддержку для всей системы ввода-вывода C++. Классы basic_filebuf и Ьа- sic_stringbuf выведены из класса basic_streambuf. Если вы не занимаетесь разработкой новых методов программирования ввода-вывода, вам вряд ли придется напрямую использовать класс basic_streambuf или его подклассы. В основном, вам придется работать с иерархией классов, которая выведена из класса basic_ios. Это класс ввода-вывода высокого уровня, который обеспечивает форматирование и обработку ошибок, а также предоставляет информацию о состоянии соответствующего потока ввода-вывода. Класс basic_ios используется в качестве базового для нескольких производных классов, включая такие классы, как basic_istream, basic_ostream и . ba- sic_iostream. Эти классы используются для создания потоков, способных выполнять операции ввода, вывода и ввода-вывода соответственно. Из класса basic_istream выведены классы basic_if stream и basic_istringstream, из класса Ьа- sic_ostream выведены классы basic_ofstream и basic_ost- ringstream, из класса basic_iostream выведены классы
300 Классы ввода-вывода библиотеки стандарта C++ basic_fstream и basic_stringstream. Базовым для класса basic_ios является класс ios_base. Следовательно, любой класс, выведенный из класса basic_ios, имеет доступ к членам класса ios_base. Классы ввода-вывода параметризированы для типа символов, с которыми они работают, и для характеристик этих символов. Например, вот как выглядит спецификация шаблона для класса basic_ios. template<class CharType, class Attr = char_traits<CharType> > class basic_ios: public ios_base Здесь элемент CharType задает тип символа (например, char или wchar_t), а элемент Attr определяет тип, который описывает» его атрибуты. Обобщенный тип char_traits— это класс, который определяет атрибуты, относящиеся к некоторому символу. Библиотека ввода-вывода создает две специализации описанных выше иерархий шаблонных классов: одна — для 8- разрядных, а другая — для двубайтовых символов. Ниже приводится полный список соответствия имен шаблонных классов их символьным версиям и версиям двубайтовых символов. Класс, Класс, ориентированный Шаблонный ориентированный надвубаитовые класс . ¦,. на символы символы basic_ios ios wios basic_istream istream wistream basic_ostream ostream wostream basic_iostream iostream wiostream basic_ifstream ifstream wifstream basic_ofstream ofstream wofstream basic_fstream fstream wfstream basic_istringstream istringstream wistringstream
Встроенные потоки C++ 301 Класс, Класс, . ориентированный Шаблонный ориентированный на двубайтовые класс на символы символы basic_ostringstream ostringstream wostringstream basic_stringstream stringstream wstringstream basic_streambuf streambuf wstreambuf basic_filebuf filebuf wfilebuf basic_stringbuf stringbuf wstringbuf Поскольку подавляющее большинство программистов будут использовать операции ввода-вывода, ориентированные на обработку символов, в данной главе используются именно эти имена (т.е. при ссылке на классы ввода-вывода мы будем просто использовать их "символьные" имена, а не внутренние имена шаблонов). Например, в этой главе вместо имени basic_Ios будет употребляться имя ios, вместо basic_istream— имя istreamn вместо basic_f stream— имя f stream. Помните, что для потоков, работающих с двубайтовыми символами, существуют параллельные функции, которые действуют аналогично описанным выше. | Встроенные потоки C++ || 4 Библиотека iostream стандарта C++ автоматически открывает следующие потоки. Поток Значение cin Стандартный ввод cout Стандартный вывод сегг Стандартный вывод ошибок clog Буферизированная версия потока сегг wcin Версия потока cin для двубайтовых символов wcout Версия потока cout для двубайтовых символов wcerr Версия потока сегг для двубайтовых символов we log Версия потока clog для двубайтовых символов
302 Заголовки ввода-вывода По умолчанию стандартные потоки используются для связи с консолью. Однако в средах, которые поддерживают возможность перенаправления ввода-вывода (например, в DOS, UNIX и Windows), стандартные потоки могут быть перенаправлены на другие устройства или в файлы. О Заголовки ввода-вывода I Система ввода-вывода, отвечающая стандарту C++, опирается на ряд заголовков, перечисленных в следующей таблице. Заголовок Назначение <fstream> Файлы ввода-вывода <iomanip> Параметризированные манипуляторы ввода-вывода <ios> Базовая поддержка ввода-вывода <iosfwd> Предварительные (forward) объявления, используемые системой ввода-вывода <iostream> Общие операции ввода-вывода <istream> Базовая поддержка ввода J <ostream> Базовая поддержка вывода <sstream> Потоки, ориентированные на работу со строками <streambuf> ' Поддержка операций ввода-вывода нижнего уровня Некоторые из этих заголовков используются для внутренних нужд системой ввода-вывода. А в общем случае ваша программа будет включать лишь заголовки <iostream>, <fstream>, <sstream> и <iomanip>. Флаги форматирования В системе ввода-вывода C++ каждый поток связан с набором флагов форматирования, которые управляют процессом форматирования информации. В классе ios_base объявляется перечисление f mt f 1 ag s, в котором определены следующие значения.
Флаги форматирования 303 adjustfield floatfield right skipws basefield hex scientific unitbuf boolalpha internal showbase uppercase dec left showpoint fixed oct showpos Эти значения используются для установки или очистки флагов форматирования с помощью таких функций, как setf () nunsetf (). Когда установлен флаг skipws, ведущие пробельные символы, или символы пропуска (пробелы, символы табуляции и новой строки), отбрасываются при выполнении ввода в поток. Когда флаг skipws сброшен, пробельные символы не отбрасываются. Когда установлен флаг left, результат выравнивается по левому краю. А когда установлен флаг right, результат выравнивается по правому краю. Когда установлен флаг internal, числовое значение дополняется пробелами, чтобы заполнить поле между каким-либо знаком или основным символом. Если ни один из этих флагов не установлен, результат выравнивается по правому краю по умолчанию. По умолчанию числовые значения выводятся в десятичной системе счисления. Однако основание системы счисления можно изменить. Установка флага oct приведет к выводу результата в восьмеричном представлении, а установка флага hex— в шестнадцатеричном. Чтобы при отображении результата вернуться к десятичной системе счисления, достаточно установить флаг dec. Установка флага showbase приводит к отображению обозначения основания системы счисления, служащего для представления числовых значений. Например, если используется шестнадцате- ричное представление, то значение IF будет отображено как OxlF. По умолчанию при использовании экспоненциального представления чисел отображается строчной вариант буквы "е". Кроме того, при отображении шестнадцатеричного значения используется также строчная буква "х". После установки флага uppercase отображается прописной вариант этих символов. Установка флага showpos вызывает отображение ведущего знака "плюс" перед положительными значениями.
304 Манипуляторы ввода-вывода Установка флага showpoint приводит к отображению десятичной точки и хвостовых нулей для всех чисел с плавающей точкой — нужны они или нет. После установки флага scientific числовые значения с плавающей точкой отображаются в экспоненциальном представлении. Когда установлен флаг fixed, вещественные значения отображаются в обычном представлении. Если не установлен ни один флаг, компилятор сам выбирает соответствующий метод представления. При установленном флаге unitbuf буфер сбрасывается после каждой операции вставки. Если установлен флаг stdio, потоки stdout и stderr сбрасываются после каждой операции вывода. Поскольку часто приходится обращаться к полям oct, dec и hex, на них допускается коллективная ссылка ios: : basef ield. Аналогично поля left, right и internal можно собирательно назвать ios: :adjustf ield. Наконец, поля scientific и fixed можно назвать ios:: f loatf ield. || Манипуляторы ввода-вывода Д Параметры форматирования любого потока можно изменить не только посредством прямой установки или очистки флагов форматирования, но и с помощью специальных функций, называемых манипуляторами, которые можно включить в выражение ввода-вывода. Стандартные манипуляторы описаны в следующей таблице. Манипулятор boolalpha dec endl ends flush hex Назначение Устанавливает флаг boolalpha Устанавливает флаг dec Выводит символ новой строки и сбрасывает поток Вставляет в поток нулевой символ('\0') Сбрасывает поток Устанавливает флаг hex Функция Ввод-вывод Ввод-вывод Вывод Вывод Вывод Ввод-вывод
Манипуляторы ввода-вывода 305 Манипулятор internal left noboolalpha noshowbase noshowpoint noshowpos noskipws nounitbuf nouppercase oet resetiosflags „(fmtflags f) right scientific setbase (int base) setfill (int ch) setiosflags (fmtflags f) setprecision (int p) setwfint w) showbase showpoint showpos Назначение Устанавливает флаг internal Устанавливает флаг left Сбрасывает флаг boolalpha Сбрасывает флаг showbase Сбрасывает флаг showpoint Сбрасывает флаг showpos Сбрасывает флаг skipws Сбрасывает флаг uni tbuf Сбрасывает флаг uppercase Устанавливает флаг oct Очищает флаги, заданные в переменной f Устанавливает флаг right Устанавливает флаг scientific Устанавливает основание системы счисления равной значению base Устанавливает символ- заполнитель равным значению переменной ch Устанавливает флаги, заданные в переменной f Устанавливает количество цифр точности (после десятичной точки) Устанавливает ширину поля равной значению- переменной w Устанавливает флаг showbase Устанавливает флаг showpoint Устанавливает флаг showpos Функция Вывод Вывод Ввод-вывод Вывод Вывод Вывод Ввод Вывод Вывод Ввод-вывод Ввод-вывод Вывод Вывод Вывод Вывод Ввод-вывод Вывод Вывод Вывод Вывод Вывод
306 Манипуляторы ввода-вывода Манипулятор Назначение Функция skipws Устанавливает флаг skipws Ввод unitbuf Устанавливает флаг unitbuf Вывод uppercase Устанавливает флаг Вывод uppercase ws Пропускает ведущие пробель- Ввод ные символы , Для использования манипуляторов, которые принимают параметры, необходимо включить в свою программу заголовок <iomanip>. Совет программисту Одним из самых интересных флагов форматирования, добавленных в новую библиотеку iostream, является флаг boolalpha. Его можно установить либо напрямую, либо путем использования манипуляторов boolalpha () и noboolalpha (). Дело в том, что установка флага boolalpha позволяет вводить и выводить булевы значения с помощью ключевых слов true и false. Обычно нужно было вводить число 1 для значения истины и число О для значения лжи. Рассмотрим, например, следующую программу. // Демонстрация использования-флага форматирования boolalpha. #include <iostream> using namespace std; int main() { bool b; ' • cout « "Перед установкой флага boolalpha: "; b = true; cout << b << " "; b = false; cout << b << endl; cout << "После установки флага boolalpha: "; b = true;
О некоторых типах данных 307 cout « boolalpha << b « " "; b = false; cout << b << endl; cout << "Введите булево значение: "; cin >> boolalpha >> b; cout << "Вы ввели " << b; return 0; } Вот пример работы этой программы. Перед установкой флага boolalpha: 1 О После установки флага boolalpha: true false Введите булево значение: true Вы ввели true Очевидно, что после установки флага boolalpha логические (булевы) значения вводятся и выводятся с помощью слов true и false. Как видно из текста этой программы, флаг boolalpha необходимо установить для потоков cin и cout отдельно. Как и установка всех флагов форматирования, установка флага boolalpha для одного потока не означает, что он установлен и для другого. IО некоторых типах данных || Помимо уже использованного выше типа данных fmtflags, система ввода-вывода стандарта C++ определяет ряд других типов. ТИПЫ streamsize И streamof f Объект типа streamsize в состоянии хранить самое большое число байтов, которое будет передано во время любой одной операции ввода-вывода. Это разновидность целого типа данных. Объект типа streamof f способен содержать значение, которое указывает позицию смещения внутри потока. Это также разновидность целого типа данных. Данные типы определены в заголовке <ios>, который автоматически включается системой ввода-вывода.
308 О некоторых типах данных Типы streampos И wstreampos Объект типа streampos способен содержать значение, которое представляет позицию внутри потока символов типа char. Объект типа wstreampos способен содержать значение, которое представляет позицию внутри потока символов типа wchar_t. Эти типы определены в заголовке <ios_fwd>, который автоматически включается системой ввода-вывода. ТИПЫ pos_type И of f _type Типы pos_type и of f_type создают объекты (обычно целочисленные), которые способны содержать значения, представляющие позицию и смещение соответственно внутри потока. Эти типы определены в классе ios (и других классах) и по сути аналогичны типам streamof f и streampos (или их эквивалентам, работающим с символами широкого формата). Тип open_mode Тип open_mode определяется в классе ios_base и описывает, как будет открыт файл. Объект этого типа может принимать одно или несколько из следующих значений. арр Добавление в конец файла ate Переход в конец файла при открытии binary Открытие файла для двоичных операций in Открытие файла для ввода out Открытие файла для вывода trunc Очистка файла при условии его существования используя оператор ИЛИ (OR), можно объединять в одном выражении два или больше значений (из перечисленных выше). ТИП iostate Текущее состояние потока ввода-вывода описывается объектом типа iostate, который представляет собой перечисление, определенное в классе ios_base и включающее следующие члены. goodbit He обнаружено никаких ошибок eofbit Обнаружен конец файла f ailbit Обнаружена нефатальная ошибка ввода-вывода badbi t Обнаружена фатальная ошибка ввода-вывода
Перегруженные операторы « и » 309 Тип seekdir Тип seekdir описывает, как будет происходить операция произвольного доступа к файлу. Этот тип определен в классе ios_base, а его допустимые значения перечислены ниже. bed cur end Начало файла Текущая позиция Конец файла Класс failure В классе ios_base определен тип исключения failure. Он служит в качестве базового класса для типа исключений, которые могут быть сгенерированы системой ввода-вывода. Этот класс наследует класс exception (стандартный класс исключений). Класс failure имеет следующий конструктор. explicit failure(const string &str); Здесь str— сообщение, которое описывает ошибку. Это сообщение может быть получено из объекта failure путем вызова его функции what (). virtual const char *what() const throw(); [| Перегруженные операторы << и >> | Следующие классы перегружают операторы « и >>, связанные со всеми встроенными типами данных. basic_istream basic_ostream basic_iostream Операторы << и >> наследуют любые классы, производные от перечисленных выше классов. Функции ввода-вывода стандарта C++ В остальной части этой главы описываются функции ввода-вывода общего назначения, определенные стандартом
310 bad ANSI/ISO для языка C++. Как уже упоминалось, система ввода-вывода, соответствующая стандарту C++, построена на сложной иерархии шаблонных классов. Многие члены классов нижнего уровня не используются для прикладного программирования, поэтому они и не будут описаны в этой главе. 1^2 I iinclude <iostream> bool bad() const; Функция bad () является членом класса ios. Функция bad () возвращает значение true, если в соответствующем потоке обнаружена фатальная ошибка ввода- вывода; в противном случае возвращается значение false. См. также функцию good (). I clear #include <iostream> void clear(iostate flags = goodbit); , Функция clear () является членом класса ios. Функция clear () очищает флаги состояния, связанные с потоком. Если параметр flags равен значению goodbit (каким оно и устанавливается по умолчанию), то очищаются, т.е. устанавливаются равными нулю, все флаги ошибок. В противном случае флаги состояния будут установлены равными значению, заданному в переменной flags. См. также функцию rdstate (). Гео? ttinclude <iostream> bool eof() const; Функция eof () является членом класса ios.
exceptions 311 Функция eof () возвращает значение true при обнаружении конца соответствующего файла ввода; в противном случае возвращается значение false. См. также функции bad (), fail (), good (), rdstate () и clear(). Id exceptions 1 вввваивавввввввавввввввввквввнш #include <iostream> iostate exceptions() const; void exceptions(iostate flags); Функция exceptions () является членом класса ios. Первая форма функции exceptions () возвращает объект типа iostate, который показывает, какие флаги- вызывают исключение. Вторая форма функции устанавливает эти значения. См. также функцию rdstate (). [fail. ¦include <iostream> bool failO const; Функция fail () является членом класса ios. Функция fail() возвращает значение true при обнаружении в соответствующем потоке ошибки ввода-вывода; в противном случае возвращается значение false. См. также функции bad (), eof (), good (), rdstate () и clear(). ¦include <iostream> char fill() const; char fill(char ch); Функция fill О является членом класса ios.
312 flags По умолчанию поле, когда его требуется заполнить, заполняется пробелами. Однако можно изменить символ заполнения с помощью функции fill (), указав новый символ заполнения в переменной ch. Функция возвращает старый символ заполнения. Первая форма функции f ill () возвращает текущий символ заполнения. См. также функции precision () и width (). [flags #include <iostream> fmtflags flags() const; fmtflags flags(fmtflags f) ; Функция flags () является членом класса ios (производного от класса ios_base). Первая форма функции flags () просто возвращает текущие установки флагов форматирования соответствующего потока. Вторая форма функции flags () устанавливает все флаги форматирования, связанные с потоком, в соответствии со значением параметра f. При использовании этой версии двоичный код, содержащийся в параметре f, копируется в флаги форматирования соответствующего потока. Эта версия функции flags () также возвращает значения предыдущих установок флагов форматирования. См. также функции unset f () и setf (). I, ? 111 sh. УК 'Ж^-ШШЗЖ^ #include <iostream> ostream &flush(); Функция flush () является членом класса ostream. Функция flush () выполняет физическую запись содержимого буфера, связанного с соответствующим потоком вывода, на устройство. Функция возвращает ссылку на данный поток. См. также функции put () и write ().
fstream, ifstream и ofstream 313 I f stream, if stream И of stream 1 ttinclude <fstream> fstream(); explicit fstream(const char * filename, ios::openmode mode = ios::in | ios::out); ifstream(); explicit ifstream(const char * filename, ios::openmode mode = ios::in); ofstream(); explicit ofstream(const char * filename, ios::openmode mode=ios::out | ios::trunc); Функции fstreamf), ifstream() и ofstream() представляют собой конструкторы классов fstream, ifstream и ofstream соответственно. Версии функций fstreamf), ifstream() и ofstream(), которые не принимают параметров, создают поток, не связанный ни с одним файлом. Этот поток можно позже связать с нужным файлом с помощью функции open (). Версии функций f stream(), ifstream() и ofstream(), которые принимают имя файла в качестве первого параметра, используются в прикладных программах наиболее часто. Хотя вполне корректно можно открыть файл с помощью функции open (), в большинстве случаев обходятся без нее, поскольку эти функции конструкторов fstream, ifstream и ofstream автоматически открывают файл при создании потока. Функции конструкторов имеют те же параметры и значения, действующие по умолчанию, что и функция open (). (Подробности — в разделе "open".) Например, самый распространенный способ открытия файла показан в следующем примере. ifstream mystreamf"myfile"); Если по некоторым причинам файл открыть не удастся, переменная связанного потока будет равна значению false. Следовательно, либо использовав для открытия файла функцию конструктора, либо вызвав явным образом функцию open (), вам следует убедиться в том, что файл действительно был открыт, проверив для этого значение потока. См. также функции close () и open ().
314 gcount Совет программисту В библиотеке iostream старого стиля конструктор f stream не содержит задаваемого по умолчанию значения для параметра mode. Это значит, что он не открывает автоматически поток для операций ввода и вывода. Поэтому при использовании библиотеки iostream старого стиля для открытия потока на ввод и вывод оба значения ios: : in и ios: : out должны задаваться явным образом. Имейте это в виду, если обратная совместимость с библиотекой iostream старого стиля является для вас важным фактором. ! gcount ——j—-———нв #include <iostream> streamsize gcount() const; Функция gcount () является членом класса istream. Функция gcount () возвращает количество символов, прочитанных во время последней операции ввода. См. также функции get (), get line () и read (). lget #include <iostream> int get(); istream &get(char-&ch); istream &get(char *buf, streamsize пит); istream &get(char *buf, streamsize пит, char delim); istream &get (streambuf Scbuf) ; istream &get(streambuf &buf, char delim); Функция get () является членом класса istream. Вообще, функция get () предназначена для чтения символов из потока ввода. Функция get (), используемая без параметров, читает один символ из соответствующего потока и возвращает прочитанное значение. Функция get (char &ch) читает символ из соответствующего потока и помещает прочитанное значение в переменную ch. Функция возвращает ссылку на поток.
getline 315 Функция get (char *buf, streamsize пит) читает символы в массив, адресуемый параметром buf, до тех пор, пока либо не будет прочитано пит-1 символов, либо не встретится символ новой строки, либо не обнаружится конец файла. После выполнения функции get () массив, адресуемый параметром buf, будет иметь завершающий нуль-символ. Обнаруженный символ новой строки из потока ввода не извлекается. Он остается в потоке до следующей операции ввода. Эта функция возвращает ссылку на поток. Функция get (char *Jbuf, streamsize nura, char delim) читает символы в массив, адресуемый параметром buf, до тех пор, пока либо не будет прочитано пит-1 символов, либо не встретится символ ограничителя, заданный параметром delim, либо не обнаружится конец файла. После выполнения функций get () массив, адресуемый параметром buf, будет иметь завершающий нуль- символ. Обнаруженный символ ограничителя из потока ввода не извлекается. Функция возвращает ссылку на поток. Функция get (streambuf Scbuf) читает символы из потока ввода в объект streambuf. Символы читаются до тех пор, пока либо не встретится символ новой строки, либо не обнаружится конец файла. Обнаруженный символ новой строки из потока ввода не извлекается. Функция возвращает ссылку на поток. Функция get (streambuf Scbuf, char delim) читает символы из потока ввода в объект streambuf. Символы читаются до тех пор, пока либо не встретится символ ограничителя, заданный параметром del im, либо не обнаружится конец файла. Обнаруженный символ ограничителя из потока ввода не извлекается. Функция возвращает ссылку на поток. См. также функции put (), getline () и read(). Igetline | #include <iostream> istream &getline(char *buf, streamsize пит); istream &getline(char *buf, streamsize пит, char delim); Функция getline () является членом класса istream. Функция getline (char *buf, streamsize пит) читает символы в массив, адресуемый параметром buf, до тех пор, пока либо не будет прочитано пит-1 символов, либо не ветре-
316 good тится символ новой строки, либо не обнаружится конец файла. После выполнения функции getline() массив, адресуемый параметром buf, будет иметь завершающий нуль- символ. Обнаруженный символ новой строки из потока ввода извлекается, но в массив buf не помещается. Функция возвращает ссылку на поток. Функция getline(char *buf, streamsize лит, char delim) читает символы в массив, адресуемый параметром buf, до тех пор, пока либо не будет прочитано niim-1 символов, либо не встретится символ ограничителя, заданный параметром delim, либо не обнаружится конец файла. После выполнения функции get line () массиву адресуемый параметром buf, будет иметь завершающий нуль-символ. Обнаруженный символ ограничителя из потока ввода извлекается, но не помещается в массив buf. Функция возвращает ссылку на поток. См. также функции get () и read (). I good #include <iostream> bool good() const; Функция good () является членом класса ios. Функция good() возвращает значение true, если в соответствующем потоке не обнаружено ни одной ошибки ввода- вывода; в противном случае возвращается значение false. См. также функции bad(), fail(), eof(), clear() и rdstate(). (ignore #include <iostream> istream Signore(streamsize пит = 1, int delim = EOF); Функция ignore () является членом класса istream. Функцию-член ignore () можно использовать для чтения и отбрасывания символов из потока ввода. Функция читает и отбрасывает символы до тех пор, пока либо не будет проигнориро-
open 317 вано num символов A по умолчанию), либо не встретится символ ограничителя, заданный параметром del im (EOF по умолчанию). Обнаруженный символ ограничителя удаляется из потока ввода. Функция ignore () возвращает ссылку на поток. См. также функции get ()и getline (). Iopen #include <fstream> void fstream::open(const char * filename, ios::openmode mode = ios::in I ios::out); void ifstream::open(const char * filename, ios :': openmode mode = ios: : in); void ofstream::open(const char * filename, ios::openmode mode = ios::out I ios::trunc); Функция ореп() является членом классов fstream, ifstream и ofstream. С помощью функции open () файл связывается с потоком. Параметр filename содержит имя файла и может включать спецификатор пути. Значение параметра mode определяет, в каком режиме открывается файл. Ниже перечислены возможные значения этого параметра. 1OS ios ios ios ios ios :app :ate :binary : in :out :t rune Используя оператор ИЛИ (OR), можно объединять в одном выражении два или больше значений (из перечисленных выше). Включив значение ios: :app, можно обеспечить добавление всех выводимых данных в конец заданного файла. Это значение можно использовать только с файлами, которые позволяют выполнять операции вывода. Включение значения ios: : ate оставляет внутренний указатель в конце файла при его открытии, но несмотря на это операции ввода-вывода могут выполняться в любом месте файла.
318 peek Значение ios: : binary обеспечивает возможность открывать файл для выполнения двоичных операций ввода-вывода. По умолчанию файлы открываются в текстовом режиме. Значение ios:: in указывает на способность файла к выполнению операций ввода, а значение ios:: out — операций вывода. Однако создание потока if stream само по себе предполагает ввод, создание потока of stream— вывод, а открытие файла с использованием потока f stream—как ввод, так и вывод. Использование значения ios: : trunc приводит к разрушению содержимого уже существующего файла с таким же именем, а сам файл усекается до нулевой длины. Во всех случаях, если функция open () выполняется неудачно, поток равен значению false. Следовательно, прежде чем использовать файл, необходимо убедиться в том, что он был успешно открыт. См. также функции close(), fstream(), ifstream() и ofstream(). peek #include <iostream> int peek(); Функция peek () является членом класса istream. Функция peek () возвращает следующий символ в потоке или значение EOF, если обнаружен конец файла. Ни при каких обстоятельствах функция не удаляет символ из потока. См. также функцию get (). | precision | #include <iostream> streamsize precision!) const; streamsize precision(streamsize p); Функция precision () является членом класса ios (производного от класса ios_base).
precision 319 По умолчанию при выводе значений с плавающей точкой отображаются шесть цифр точности (после десятичной точки). Однако, используя вторую форму записи функции precision (), можно установить количество этих цифр равным значению, заданному параметром р. Функция возвращает исходное значение точности. Первая версия функции precision () возвращает текущее значение точности. См. также функции width () и fill (). Совет программисту Существует две разновидности манипуляторов: без параметров и с параметрами. Поскольку создание параметризованных манипуляторов выходит за рамки этой книги, следует отметить, что создание собственных манипуляторов, не имеющих параметров, — задача совсем несложная. Все не имеющие параметров манипуляторы вывода имеют следующую структуру. ostream &тапip-name(ostrearn ^Stream) ' { // Текст программы, return stream; } Здесь manip-name — имя манипулятора. Обратите внимание, что манипулятор ¦ возвращает ссылку на поток типа ostream. Это необходимо в случае, если манипулятор должен использоваться как часть большого выражения ввода- вывода. Важно понимать, что, хотя манипулятор использует в качестве своего единственного параметра ссылку на поток, с которым он работает, при вставке манипулятора в операцию вывода аргументы у него отсутствуют. , - Все не имеющие параметров манипуляторы ввода имеют следующую структуру. istream Scmanip-name(istream Scstream) { // Текст программы, return stream; } Манипулятор ввода получает ссылку на поток, для ко- торого он был вызван. Этот манипулятор должен вернуть
320 put ссылку на "свой" поток. Вот пример простого манипулятора вывода с именем setup (). Он устанавливает выравнивание по левому краю, делает ширину поля равной значению 10 и задает в качестве символа заполнителя знак доллара. #include <iostream> #include <iomanip> using namespace std; ostream &setup(ostream &stream) { stream.setf(ios::left); stream « setwA0) « setfill('$'); return stream; int main() { cout << 10 << " " << setup << 10; return 0; } . ' ' Помните: ваш манипулятор должен возвращать поток stream. В противном случае его нельзя использовать в ряде операций ввода и вывода. put #include <iostream> ostream &put(char ch); Функция put () является членом класса ostream. Функция put () записывает символ ch в соответствующий поток вывода. Она возвращает ссылку на этот поток. См. также функции write () и get ().
putback 321 putback #include <iostream> istream &putback(char ch); Функция putback () является членом класса istream. Функция putback () возвращает символ ch в соответствующий поток ввода. См. также функцию peek (). Irdstate SSB|SS9SBSSBB8SSB3SSS #include <iostream> iostate rdstate() const; Функция rdstate () является членом класса ios. Функция rdstate () возвращает состояние соответствующего потока. Система ввода-вывода C++ поддерживает информацию о состоянии, касающуюся результата выполнения каждой операции ввода-вывода, связанной с активным потоком. Текущее состояние системы ввода-вывода хранится в виде объекта типа iostate, в котором определены следующие флаги. Имя флага Значение ~ goodbit He обнаружено никаких ошибок ео f bi t Обнаружен конец файла f ailbi t При выполнении операций ввода-вывода обнаружен нефатальный сбой badbit При выполнении операций ввода-вывода обнаружена фатальная ошибка Эти флаги перечислены в классе ios (посредством класса ios_base). Функция rdstate {) возвращает значение goodbit, когда не обнаружено никакой ошибки; в противном случае устанавливается бит ошибки. См. также функции eof(), good(), bad(), clear (), setstate() и fail ().
322 read read ¦include <iostream> istream &read(char *buf, streamsize лига); Функция read () является членом класса istream. Функция read () читает лит байт из соответствующего потока ввода и помещает их в буфер, адресуемый параметром buf. При достижении конца файла до прочтения лит символов функция read () просто прекращает работу и устанавливает флаг f ailbit, а в буфере содержится столько символов, сколько было прочитано в действительности. (См. раздел "gcount".) Функция read () возвращает ссылку на поток. См. также функции gcount(), readsome(), get(), getlineO nwrite(). readsome iinclude <iostream> streamsize readsome(char tbuf, streamsize пит) ; Функция readsome() является членом класса istream. Функция readsome () читает лит байт из соответствующего потока ввода и помещает их в буфер, адресуемый параметром buf. Если поток содержит меньше чем лит символов, считыва- ется именно это число символов. Функция readsome () возвращает число прочитанных символов. Разница между функциями read () и readsome () состоит в том, что функция readsome () не устанавливает флаг failbit, если число доступных символов меньше значения параметра лит. См. также функции gcount (), read {) и write (). Iseekg И seekp ¦include <iostream> istream &seekg(off_type offset, ios::seek_dir origin) istream &seekg(pos_type position)
seekg и seekp 323 ostream &seekp(off_type offset, ios::seek_dir origin); ostream &seekp(pos_type position); Функция seekg () является членом класса istream, a функция seekp () — членом класса ostream. В системе ввода-вывода C++ с помощью функций seekg () и seekp () выполняется произвольный доступ, т.е. система ввода-вывода C++ управляет двумя указателями, связанными с файлом. Один из них— это указатель ввода (get pointer), который указывает, в каком месте файла будет выполняться следующая операция ввода. А другой — указатель вывода (put pointer), который указывает, в каком месте файла будет выполняться следующая операция вывода. При каждом выполнении операции ввода или вывода соответствующий указатель автоматически перемещается, последовательно изменяя свою позицию. Однако, используя функции seekg() и seekp(), можно получить доступ к файлу непоследовательным образом. Версия функции seekg () с двумя параметрами перемещает указатель ввода на offset байт от позиции, заданной параметром origin. Версия функции seekp () с двумя параметрами перемещает указатель вывода на offset байт от позиции, заданной параметром origin. Параметр offset имеет тип of f_type. Объект типа of f_type способен содержать самое большое допустимое значение, которое может иметь параметр offset. Параметр origin имеет тип seek_dir и представляет собой перечисление, которое имеет следующие значения. ios : : beg Смещение от начала ios: : cur Смещение от текущей позиции ios: : end Смещение от конца Версии функций seekg () и seekp (•) с одним параметром перемещают указатели файлов в позиции, заданные параметром position. Это значение должно быть предварительно получено путем обращения либо к функции tellg (), либо к функции tellpt) соответственно. Тип pos_type позволяет содержать самое большое допустимое значение, которое мо-
324 self жет иметь параметр position. Эти функции возвращают ссылку на соответствующий поток. См. также функции tellg(') и tellp(). #include <iostream> fmtflags setf(fmtflags flags); fmtflags setf(fmtflags flagsl, fmtflags flags2); Функция setf() является членом класса ios (выведенного из класса ios_base). Функция setf () устанавливает флаги форматирования, связанные с потоком. О флагах форматирования речь шла выше в этой главе. Первая версия фуцдции setf() устанавливает флаги форматирования, заданные параметром flags. (На все остальные флаги функция не действует.) Например, чтобы установить флаг showpos для потока cout, можно использовать следующий оператор. cout.setf(ios::showpos); : При необходимости установки сразу нескольких флагов их значения можно объединить с помощью оператора ИЛИ. Важно понимать, что обращение к функции setf () делается относительно конкретного потока; Нет никакого смысла вызывать функцию set f () саму по себе, без указания потока. Другими словами, нет никакого смысла в глобальном статусе флагов форматирования среды C++. Каждый поток индивидуально поддерживает собственную информацию о статусе форматирования. Вторая версия функции set f () действует только на флаги, которые задаются параметром flags2. Соответствующие флаги сначала сбрасываются, а затем устанавливаются в соответствии с флагами, заданными параметром flagsl. Важно понимать, что даже если параметр flagsl содержит другие флаги, воздействию подвергнутся только те из них, которые заданы параметром flags2. Обе версии функции setf () возвращают предыдущие установки флагов форматирования, связанные с потоком. См. также функции unset f () и flags ().
setstate 325 setstate #include <iostream> void setstate(iostate flags) const; Функция setstate () является членом класса ios. Функция setstate () устанавливает состояние соответствующего потока в соответствии с содержимым параметра flags. Подробности приводятся в описании функции rdstate(). См. также функции clear () и rdstate(). lstg ' • ¦¦ • #include <sstream> string str() const; void str(string &s); Функция str () является членом классов stringstream, istringstreamn ostringstream. Первая форма функции str () возвращает объект класса string, заполненный текущим содержимым потока, который ориентирован на работу со строками. Вторая форма функции str() освобождает строку, содержащуюся в данный момент в строковом потоке, и заменяет строку, на которую ссылается параметр s. См. также функции strstream(), istrstreamf) и ostrstream{). stringstream, istringstreamM ostringstream #include <sstream> explicit stringstream(ios::openmode mode = ios::in I ios::out); • . explicit stringstream(const string &str,
326 sync_with_stdio ios::openmode mode = ios::in I ios::out); explicit istringstream(ios::openmode mode = ios::in); explicit istringstream(const string str, ios::openmode mode = ios::in); explicit ostringstream(ios::openmode mode = ios::out); explicit ostringstream(const string str, ios::openmode mode = ios::out); Функции stringstream(), istringstream() и ostringstream () представляют собой конструкторы классов string- stream, istringstream и ostringstream соответственно. Они создают потоки, связанные с обработкой строк. Те версии функций stringstreamf), istringstream() и ostringstream (), которые задают только параметр типа openmode, создают пустые потоки. А версии, которые принимают параметр типа string, инициализируют строковый поток. См. также функцию str (). |sync_with_stdio I ¦include <iostream> bool sync_with_stdio(bool sync = true); Функция sync_with_stdio () являетсячленом класса lbs (выведенного из класса ios_base). Вызвав функцию sync_with_stdio (), можно безопасно использовать стандартную С-подобную систему ввода-вывода в согласии с опирающейся на классы системой ввода-вывода C++. Чтобы отключить синхронизацию, передайте функции sync_with_stdio() значение false. Функция возвращает предыдущую установку: значение true означает синхронизацию, а значение false— её отсутствие. По умолчанию стандартные потоки синхронизированы. Эта функция достоверна только в случае, если она вызывается до выполнения любых других операций ввода-вывода.
tellQ и tellp 327 ItellgИtellp #include <iostream> pos_type tellgO; pos_type tellpO; Функция tellg О является членом класса istream, a функция tellp () — членом класса ostream. Система ввода-вывода C++ управляет двумя указателями, связанными с файлом. Один из них — это указатель ввода (get pointer), который указывает, в каком месте файла будет выполняться следующая операция ввода. А другой — указатель вывода (put pointer), который указывает, в каком месте файла будет выполняться следующая операция вывода. При каждом выполнении операции ввода или вывода соответствующий указатель автоматически перемещается, последовательно изменяя свою позицию. Именно с помощью функций tellg () и tellpt) соответственно можно определить текущую позицию указателей ввода и вывода. Тип pos_type позволяет содержать самое большое значение, которое может возвратить любая из этих двух функций. Значения, возвращаемые функциями tellg () й tellp (), можно использовать в качестве параметров функций seekg () HseekpO соответственно. См. также функции seekg () и seekp(). | unsetf , Д #include <iostream> void unsetf(fmtflags flags); Функция unsetf () является членом класса ios (выведенного из класса ios_base). Функция unsetf () используется для очистки одного или нескольких флагов форматирования. Флаги, заданные параметром flags, очищаются. (На все остальные флаги никакого воздействия не оказывается.) См. также функции setf () и flags ().
328 width I width #include <iostream> streamsize width() const; streamsize width(streamsize w); Функция width () является членом класса ios (выведенного из класса ios_base). Чтобы получить ширину поля, используйте первую форму функции width(). Она возвращает текущее значение ширины поля. Чтобы установить ширину поля, используйте вторую форму. В данном случае параметр w содержит устанавливаемую ширину поля, а предыдущее ее значение возвращает функция. См. также функции precision () и fill (). iinclude <iostream> ostream &write(const char *buf, streamsize лит); Функция write () является членом класса ostream. Функция write () записывает пит байт в соответствующий поток вывода из буфера, адресуемого параметром buf. Функция возвращает ссылку на поток. См. также функции read () и put ().
Глава 16 Стандартная библиотека шаблонов C++ Значительную часть библиотеки классов C++ составляет стандартная библиотека шаблонов (Standard Template Library — STL). Библиотека STL предоставляет шаблонные классы и функции общего назначения, которые реализуют многие популярные и часто используемые алгоритмы и структуры данных. Например, она включает поддержку векторов, списков, очередей и стеков, а также определяет различные процедуры, обеспечивающие доступ к этим объектам. Поскольку библиотека STL состоит из шаблонных классов, алгоритмы и структуры данных могут быть применены к данным практически любого типа. STL — это большая библиотека, и поэтому не все ее возможности полностью рассмотрены в настоящей книге. Кроме того, описанная здесь версия библиотеки STL определена стандартом ANSI/ISO C++. Более старые компиляторы могут представлять версию STL, которая несколько отличается от стандартной. | Обзор STL Ядро стандартной библиотеки шаблонов составляют три основных элемента: контейнеры, алгоритмы и итераторы. Они работают совместно один с другим, предоставляя тем самым готовые решения различных проблем программирования. Контейнеры Контейнеры—это объекты, содержащие другие объекты. Существует несколько различных типов контейнеров. Например, класс vector определяет динамический массив, класс queue создает двустороннюю очередь, а класс list обеспечивает работу с линейным списком. Эти контейнеры называются последовательными контейнерами, поскольку в терминологии STL последовательность представляет собой линейный список. Помимо базовых контейнеров, библиотека STL определяет ассоциативные кон-
330 Обзор STL тейнеры, которые позволяют эффективно находить нужные значения на основе заданных ключевых значений (ключей). Например, класс тар обеспечивает доступ к значениям с уникальными ключами, т.е. хранит пару "ключ/значение",и предоставляет возможность находить значение по заданному ключу. Каждый контейнерный класс определяет набор функций, которые можно применять к данному контейнеру. Например, контейнер списка включает функции, предназначенные для выполнения вставки, удаления и объединения элементов. А стек включает функции, которые позволяют помещать значения в стек и извлекать значения из стека. Алгоритмы Алгоритмы действуют в контейнерах. Они включают возможности инициализации, сортировки, поиска и преобразования содержимого контейнеров. Многие алгоритмы работают с группой (или диапазоном) элементов внутри контейнера. Итераторы Итераторы — это объекты, которые в той или иной степени являются указателями. Они позволяют циклически опрашивать содержимое контейнера практически так же, как это делает указатель для циклического опроса элементов массива. Существует пять типов итераторов. Итераторы Разрешаемый доступ Произвольного Сохраняют и считывают значения; доступа позволяют организовать произволь- (random access) ный доступ к элементам Двунаправленные Сохраняют и считывают значения; (bidirectional) обеспечивают инкрементно- декрементное перемещение Однонаправленные Сохраняют и считывают значения; (forward) обеспечивают только инкрементное перемещение Входные (input) Считывают, но не записывают значений; обеспечивают только инкрементное перемещение Выходные (output) Записывают, но не считывают значения; обеспечивают только инкрементное перемещение
Обзор STL 331 В общем случае итератор, который имеет большие возможности доступа, можно использовать вместо итератора с меньшими возможностями. Например, однонаправленным итератором можно заменить входной итератор. Итераторы обрабатываются аналогично указателям. Их можно инкрементировать и декрементировать. К ним можно применять оператор разыменования адреса *. Итераторы объявляются с помощью типа iterator, определяемого различными контейнерами. Библиотека STL поддерживает реверсивные итераторы, которые являются либо двунаправленными, либо итераторами случайного доступа, т.е. позволяют перемещаться по последовательности в обратном направлении. Следовательно, если реверсивный итератор указывает на конец последовательности, то после инкрементирования он будет указывать на элемент, расположенный перед концом последовательности. При ссылке на различные типы итераторов в описаниях шаблонов в этом разделе будут использованы следующие термины. Термин Представляемый итератор Bilter Двунаправленный Forlter " Однонаправленный Inlter Входной Outlter Выходной Randlter Произвольного доступа Другие элементы библиотеки STL STL опирается не только на контейнеры, алгоритмы и итераторы, но и на другие стандартные компоненты. Основными из них являются распределители памяти, предикаты, функции сравнения и объекты-функции. Каждый контейнер имеет свой распределитель памяти (allocator). Распределители управляют выделением памяти при создании нового контейнера. Стандартный распределитель— это объект класса allocator, но при необходимости (в специализированных приложениях) можно определять собственные распределители. В большинстве случаев стандартного распределителя вполне достаточно. Некоторые алгоритмы и контейнеры используют специальный тип функции, называемый предикатом (predicate). Суще-
332 Обзор STL ствует два варианта предикатов: унарный и бинарный. Унарный предикат принимает один аргумент, а бинарный— два. Эти функции возвращают результаты "истина/ложь", но точные условия, которые заставят их вернуть значение истины или лжи, определяются программистом. В остальной части этой главы, когда потребуется унарная функция-предикат, на это будет указано с помощью типа UnPred. При необходимости использования бинарного предиката будет применяться тип BinPred. В бинарном предикате аргументы всегда расположены в порядке первый, второй относительно функции, которая вызывает этот предикат. Как для унарного, так и для бинарного предикатов аргументы будут содержать значения, тип которых совпадает с типом объектов, сохраняемых данным контейнером. Некоторые алгоритмы и классы используют специальный тип бинарного предиката, который сравнивает два элемента. Функции сравнения возвращают значение true, если их первый аргумент меньше второго. Функции сравнения идентифицируются с помощью типа Сотр. Помимо заголовков, требуемых различными классами STL, стандартная библиотека C++ включает заголовки <utility> и <functional>, которые обеспечивают поддержку STL. Например, в заголовке <utility> определяется шаблонный класс pair, который может хранить пару значений. Шаблоны в заголовке <?unctional> позволяют создавать объекты, которые определяют функцию operator (). Эти объекты называются объектами-функциями, и их во многих случаях можно использовать вместо указателей на функции. Существует несколько встроенных объектов-функций, объявленных в заголовке <functional>. plus minus multiplies divides modulus negate equal_to not_equal_to greater greater_equal less less_equal logical_and logical_or logical_not Возможно, самой широко используемой объектом- функцией является less, которая определяет, когда один объект меньше другого. Объекты-функции можно использовать вместо реальных указателей на функции в алгоритмах STL, "о которых пойдет речь ниже. Используя объекты- функции вместо указателей на функции, библиотека STL генерирует более эффективный программный код.
Обзор STL 333 "Обитателями" библиотеки STL являются и такие сущности, как связка (binder) и инвертор (negator). Связка связывает аргумент с объектом-функцией, а инвертор возвращает дополнение предиката. Наконец, следует познакомиться еще с одним термином: адаптер (adaptor). По логике библиотеки STL адаптер преобразует один объект в другой. Например, контейнер queue (который создает стандартную очередь) является адаптером для контейнера deque. Совет программисту Контейнеры, алгоритмы и итераторы работают "в одной команде". Чтобы понять, как это происходит, рассмотрим пример. В следующей программе демонстрируется использование контейнера vector, который аналогичен массиву. Однако контейнер имеет одно преимущество, заключающееся в том, что он автоматически обрабатывает собственные потребности в памяти, наращивая при необходимости свои объемы. Вектор предоставляет методы, позволяющие определять его размер, а также добавлять новые или удалять ненужные элементы. Итак, следующая программа иллюстрирует использование класса vector. // Короткая программа демонстрации // работы класса vector, ¦include <iostream> #include <vector> using namespace std; int main() { vector<int> v; // создаем вектор нулевой длины int i; // Отображаем исходный размер объекта v. cout « "размер = " « v.size() « endl; /* Помещаем значения в конец вектора: вектор будет расти по мере необходимости. */ for(i=0; i<10; i++) v.push_back(i);
334 Обзор STL /./ Отображаем текущий размер объекта v. cout « "размер сейчас = " « v.sizeO « endl; / ' // Доступ к содержимому вектора можно полу- - чить, используя индексы. for(i=0; i<10; i++) cout « v[i] « " "; cout « endl ; // Доступ к первому и последнему элементам // вектора. cout « "первый = " « v.front() « endl; cout « "последний = " « v.back() « endl; ¦-// Доступ через итератор. vector<int>::iterator p = v.begin(); while(p != v.endO) { cout « *p « " "; P++; return 0; } Ниже показан результат работы этой программы. размер = 0 ' ; размер сейчас = 10 " • 0123456789 первый =0 ' ' последний = 9 0123456789 В этой программе вначале создается вектор нулевой длины. Функция-член push_back () помещает значения в конец вектора, увеличивая тем самым его размер по мере необходимости. Функция size () отображает текущий размер вектора. Вектор может быть индексирован подобно обычному массиву. К его содержимому можно также получить доступ с помощью итератора. Функция begin () возвращает итератор в начало вектора, а функция end () — в конец вектора. И еще одно: обратите внимание на объявление итератора р. Тип iterator определяется несколькими контейнерными классами.
Контейнерные классы 335 | Контейнерные классы Ниже приведены контейнеры, определенные библиотекой STL. Требуемый Контейнер Описание заголовок bitset Битовое множество <bitset> deque Дек (двусторонняя очередь, <deque> или очередь с двусторонним доступом) list Линейный список <list> map Отображение. Хранит пары <тар> "ключ/значение", в которых каждый ключ связан только с одним значением multimap Мультиотображение. Хранит <тар> пары "ключ/значение", в которых каждый ключ может быть связан с двумя или более значениями multiset Множество, в котором каждый <set> элемент необязательно уникален .; (мультимножество) priority_queue Приоритетная очередь <queue> queue Очередь <queue> ; set Множество, в котором <set> : каждый элемент уникален stack Стек <stack> vector Динамический массив <vector> В последующих разделах подробно рассмотрен каждый из контейнеров. Поскольку контейнеры реализованы с помощью шаблонных классов, это значит, что вы можете использовать различные типы данных. В приведенных ниже описаниях обобщенный тип Т представляет тип данных, сохраняемых контейнером. Поскольку имена типов в шаблонных классах произвольны, контейнерные классы объявляют typedef-версии этих типов, что конкретизирует имена типов. Некоторые из наиболее популярных имен typedef приведены ниже.
336 bitset size_type reference 1.const_reference difference_type iterator const_iterator reverse_iterator const_reverse_iterator value_type allocator_type key_type key_compare mapped_type value_compare value_type pointer const_pointer container_type Некоторый целочисленный тип, приблизительно эквивалентный Timysize_t Ссылка на элемент const-ссылка на элемент Может представлять разность между двумя адресами Итератор const-итератор Реверсивный итератор Константный реверсивный итератор Тип значения, сохраняемого в контейнере (то же самое, что и обобщенный тип т) Тип распределителя Тип ключа Тип функции, которая сравнивает два ключа Тип значения, сохраняемого в отображении (то же самое, что и обобщенный тип т) Тип функции, которая сравнивает два значения Тип обрабатываемых значений (то же самое, что и обобщенный тип Т) Тип указателя Тип константного указателя Тип контейнера bitset Класс bitset поддерживает операции на множестве битов. Спецификация его шаблона имеет следующий вид.
bitset 337 template <size_t N> class bitset; Здесь элемент N задает длину (в битах) битового множества. Класс имеет следующие конструкторы. bitset( ); bitset(unsigned long bits); explicit bitset(const string &s, size_t i ¦= 0, size_t пит = npos); Первая форма конструктора создает пустое битовое множество. Вторая форма создает битовое множество, биты которого установлены в соответствии с заданными значениями битов параметра Ы ts. Третья форма создает битовое множество с помощью строки s, начиная с позиции i. Строка должна содержать только единицы и нули. Используется только лит или s.size()-i значений (выбирается меньшее число). Константа npos — это значение, достаточно большое для описания максимальной длины строки s. Для класса bitset определены операторы вывода << и ». Класс bitset содержит следующие функции-члены. Функция-член Назначение boolany() const; size_typecount() const; bitset<N> &f lip(); bitset<N> &flip(size_t i) bool none () const; bool operator !=(const bitset<N> &.op2) const; Возвращает истину, если в исследуемом битовом множестве установлен (т.е. равен 1) хотя бы один бит; в противном случае возвращает ложь Возвращает количество единичных битов Меняет на противоположное (переключает) состояние всех битов битового множества и возвращает значение *this Переключает состояние бита в позиции i используемого битового множества и возвращает значение *this Возвращает истину, если в используемом битовом множестве не установлен ни один бит Возвращает истину, если используемое битовое множество отличается от другого битового множества, заданного в правой части оператора ор2
338 bitset Функция-член Назначение bool operator == (const bitset<N> &op2) const; bitset<N> &operator &=(const bitset<N> &.op2) ; bitset<N> &operator Л=(const bitset<N> bitset<N> ^operator I=(const bitset<N> Uop2) bitset<N> &operator const; bitset<N> koperator <<=(size_t пит); bitset<N> &operator >>=(size_t пит); Возвращает истину, если используемое битовое множество совпадает с другим битовым множеством, заданным в правой части оператора ор2 Выполняет логическую операцию И (AND) с каждым битом используемого битового множества и соответствующим битом битового множества в ор2 и оставляет результат в первом; возвращает значение *this Выполняет логическую операцию исключающего ИЛИ (XOR) с каждым битом используемого битового множества и соответствующим битом битового множества в ор2 и оставляет результат в первом; возвращает значение *this Выполняет логическую операцию ИЛИ (OR) с каждым битом используемого битового множества и соответствующим битом битового множества в ор2 и оставляет результат в первом; возвращает значение* this Меняет на противоположное (переключает) состояние всех битов битового множества и возвращает результат Сдвигает влево на лит позиций каждый бит используемого битового множества, в котором и оставляет результат; возвращает значение *this Сдвигает вправо на пит позиций каждый бит используемого битового множества, в котором и оставляет результат; возвращает значение *this
deque 339 Функция-член Назначение reference operator [](size_type i); bitset<N> Preset(); bitset<N> &reset (size_t bitset<N> &set(); bitset<N> &set(size_t int val = 1); size_t size() const; bool test(size_t i); string to_string() const; unsigned long to_ulongl const; Возвращает ссылку на бит i в используемом битовом множестве Очищает все биты в используемом битовом множестве и возвращает значение *this Очищает бит в позиции i используемого битового множества и возвращает значение *this Устанавливает все биты в используемом битовом множестве и возвращает значение * thi s Устанавливает бит в позиции i используемого битового множества равным значению, заданному параметром val, и возвращает значение *this. Любое ненулевое значение параметра val принимается за 1 Возвращает количество битов, которое может содержать данное битовое множество Возвращает состояние бита в позиции i Возвращает строку, которая содержит представление двоичного кода в используемом битовом множестве Преобразует данное битовое множество в длинное целое без знака (deque Класс deque поддерживает очередь с двусторонним доступом (дек). Спецификация его шаблона имеет следующий вид. template <class T, class Allocator = allocator<T>> class deque
340 deque Здесь Т — тип данных, сохраняемых в деке. Класс deque имеет следующие конструкторы. explicit deque(const Allocator &a = Allocator{) ); explicit deque(size_type пит, const T &val = T (), const Allocator &a = Allocator()); deque(const deque<T, Allocator> bob); template <class Inlter> deque(Inlter start, Inlter end, const Allocator &a = Allocator()); Первая форма конструктора создает пустой дек. Вторая создает дек, который имеет лит элементов со значением val. Третья создает дек, который содержит те же элементы, что и объект ob. Четвертая создает очередь, которая содержит элементы в диапазоне, заданном параметрами start и end. Для класса deque определены следующие операторы сравнения: ==,<,<=, !=,> и >=. Класс deque содержит следующие функции-члены. Функция-член Назначение template <class Inlter> void assign(Inlter start, Inlter end); void assign(size_type пит, const T ScwaD ; reference at (size_type i) ; const_reference at(size_type i) const; reference back(); const_reference back() const; iterator begin(); const_iterator begin() const; void clear(); bool empty() const; Помещает в дек последовательность, определяемую параметрами start и end- Помещает в дек пит элементов со значением val Возвращает ссылку на элемент, заданный параметром i Возвращает ссылку на последний элемент в деке Возвращает итератор для первого элемента в деке Удаляет все элементы из дека Возвращает значение истины, если используемый дек пуст, и значение лжи в противном случае
deque 341 Функция-член Назначение const_iterator end () const; iterator end () ; iterator erase( iterator i) ; iterator erase( iterator start, iterator end); reference front(); const_reference front() const; allocator_type get_allocator() const; iterator insert( iterator i, const T bval = T()); void insert(iterator i, size_type лит, const T &val) ; template <class Inlter> void insert( iterator i, Inlter start, Inlter end); size_type max_size() const; reference operator[](size_type i) const; •const_reference operator[](size_type i) const; Возвращает итератор для конца дека Удаляет элемент, адресуемый итератором i; возвращает итератор для элемента, расположенного после удаленного элемента Удаляет элементы в диапазоне, задаваемом параметрами start и end; возвращает итератор для элемента, расположенного за последним удаленным элементом Возвращает ссылку на первый элемент в деке Возвращает распределитель дека Вставляет значение val непо^ средственно перед элементом, заданным параметром i; возвращает итератор для этого элемента Вставляет пит копий значения val сразу перед элементом, заданным параметром i Вставляет в дек последовательность, определяемую па?, раметрами start и end, сразу перед элементом, заданным параметром i Возвращает максимальное число элементов, которое может содержать дек Возвращает ссылку на i-й элемент
342 list Функция-член Назначение void pop_back(); void pop_front(); void push_back( const T kval) ; void push_front( const T bval) ; reverse_iterator rbegin() const_reverse_iterator rbegin() const; reverse_iterator rend(); const_reverse_iterator rendO const; void resize(size_type пит, T val = T( ) ) ; size_type size() const; void swap(deque<T, Allocator> &ob) ; Удаляет последний элемент в деке Удаляет первый элемент в деке Добавляет элемент со значением, заданным параметром val, в конец дека ' Добавляет элемент со значением, заданным параметром val, в начало дека Возвращает реверсивный итератор для конца дека Возвращает реверсивный итератор для начала дека Устанавливает размер дека равным значению, заданному параметром лит. Если дек для этого нужно удлинить, то в конец дека добавляются элементы со значением, заданным параметром val Возвращает текущее количество элементов в деке Выполняет обмен элементами данного дека и дека оЬ list Класс list поддерживает работу списка. Спецификация его шаблона выглядит следующим образом. template <class T, class Allocator = allocatorxT» class list Здесь T — тип данных, сохраняемых в списке. Класс list имеет следующие конструкторы. explicit list(const Allocator &a = Allocator() ); explicit list(size_type пит, const T bval = T (), const Allocator &a = Allocator()); list (const list<T, Allocator> Scob) ;
list 343 template <class Inlter>list(Inlter start, Inlter end, const Allocator &a = Allocator()); Первая форма конструктора создает пустой список. Вторая создает список, который содержит пит элементов со значением val. Третья создает список, который содержит те же элементы, что и объект ob. Четвертая создает список, который содержит элементы в диапазоне, заданном параметрами start и end. Для класса list определены следующие операторы сравнения: ==,<,<=,!=,> и >=. Класс list содержит следующие функции-члены. Функция-член Назначение template <class Inlter> void assign(Inlter start, Inlter end); void assign(size_type пит, const T Scval); reference back(); const_reference back() const; iterator begin(); const_iterator begin() const; void clear(); bool empty() const; iterator end(); const_iterator end() const; iterator erase( iterator i); Функция-член Помещает в список последовательность, определяемую параметрами start и end Помещает в список лит элементов со значением val Возвращает ссылку на последний элемент в списке Возвращает итератор для первого элемента в списке Удаляет все элементы из списка Возвращает значение истины, если используемый список пуст, и значение лжи в противном случае Возвращает итератор для конца списка Удаляет элемент, адресуемый итератором i; возвращает итератор для элемента, расположенного после удаленного элемента Назначение iterator erase( Удаляет элементы в диапазо-
344 list iterator start, iterator end) ; reference front(); const_reference front() const; allocator_type get_allocator() const; iterator insert( iterator i, const T &vaJ = T() ) ; void insert(iterator i , size_type пит, const T bval); template <class Inlter> void insert( iterator i, Jnlter start, Inlter end) ; size_type max_size() const; void merge(list<T, Allocator> &ob); template -cclass Comp> void merge( list<T, Allocator> bob, Comp cmpfn); не, задаваемом параметрами start и end; возвращает итератор для элемента, расположенного за последним удаленным элементом Возвращает ссылку на первый элемент в списке Возвращает распределитель списка Вставляет значение val непосредственно перед элементом, заданным параметром i; возвращает итератор для этого элемента Вставляет пит копий значения val непосредственно перед элементом, заданным параметром i Вставляет в список последовательность, определяемую параметрами start и end, непосредственно перед элементом, заданным параметром i Возвращает максимальное число элементов, которое может содержать список Объединяет упорядоченный список, содержащийся в объекте оЪ, с данным упорядоченным списком. Результат также упорядочивается. После объединения список, содержащийся в ob, остается пустым. Во второй форме может быть задана функция сравнения, которая определяет, когда один элемент меньше другого
list 345 Функция-член Назначение void pop_back{) ; void pop_front() ; void push_back( const T &val); void push_front( const T Scval) ; reverse_iterator rbegin(); const_reverse_iterator rbegin{) const; reverse_iterator rend(); const_reverse_iterator rend() const; void remove(const T bval); template <class UnPred> voidremove_if (UnPred pr) ; void resize(size_type пит, T val = TO); void reverse(); size_type size() const; void sort( ); template <class Comp> void sort(Comp cmpfn) Удаляет последний элемент в списке Удаляет первый элемент в списке Добавляет элемент со значением, заданным параметром val, в конец списка Добавляет элемент со значением, заданным параметром val, в начало списка Возвращает реверсивный итератор для конца списка Возвращает реверсивный итератор для начала списка Удаляет из списка элементы со значением val Удаляет элементы, для которых унарный предикат рг равен значению true Устанавливает размер списка равным значению, заданному параметром num. Если список для этого нужно удлинить, то в конец списка добавляются элементы со значением, заданным параметром val Реверсирует список Возвращает текущее количество элементов в списке Сортирует список. Вторая форма сортирует список с помощью функции сравне- ,ния cmpfn, чтобы определять, когда один элемент меньше другого
346 map Функция-член Назначение void splice( iterator i, list<T, Allocator» bob); void splice( iterator i, list<T, Allocator> bob, iterator el); void splice( iterator i, list<T, Allocator> Scob, iterator start, iterator end); void swap(list<T, Allocator> Scob) ; void unique() ; template <class BinPred> void unique (BinPred pr) ;. Вставляет содержимое списка ob в данный список в позиции, указанной итератором i. После выполнения этой операции список ob остается пустым Удаляет из списка ob элемент, адресуемый итератором el, и сохраняет его в данном списке в позиции, адресуемой итератором i Удаляет из списка ob диапазон, определяемый параметрами start и end, и сохраняет его в данном списке, начиная с позиции, адресуемой итератором i Выполняет обмен элементами данного списка и списка ob Удаляет из списка элементы-дубликаты. Вторая форма для определения уникальности использует предикат рг тар Класс тар поддерживает ассоциативный контейнер, в котором уникальным ключам соответствуют определенные значения. Спецификация его шаблона имеет следующий вид. template <class Key, class T, class Comp = less<Key>, class Allocator = allocator<pair<const Key, T> > > class map Здесь Key — тип данных ключей, Т — тип сохраняемых (отображаемых) значений, a Comp — функция, которая сравнивает два ключа. Класс тар имеет следующие конструкторы.
map 347 explicit map (coast Comp Sccmpfn = Comp(), const Allocator &a = Allocator()); mapfconst map<Key, T, Comp, Allocator> &.ob) ; template <class Inlter> maptlnlter start, Inlter end, const Comp Sccmpfn = Comp () , const Allocator &a = Allocator()); Первая форма конструктора создает пустое отображение. Вторая создает отображение, которое содержит те же элементы, что и отображение ob. Третья создает отображение, которое содержит элементы в диапазоне, заданном параметрами start и end. Функция, заданная параметром cmpfn (и если она задана), определяет упорядочение отображения. Для класса тар определены следующие операторы сравнения: ==, <, < = , ! =, > и >=. Класс тар содержит перечисленные ниже функции-члены. В приведенных в следующей таблице описаниях элемент key_type представляет тип ключа, а элемент value_type — пару элементов pair<Key, Т>. Функция-член Назначение iterator begin(); const_iterator begin(J const; void clear(); size_type count( const key_type &Jc) const; bool emptyf) const; iterator end(); const_iterator end() canst, pair<iterator, iterator> equal_range( const key_type Sck) ; pair<const_iterator, const_iterator> equal_range( const key_type Sck) const; Возвращает итератор для первого элемента в отображении Удаляет все элементы из отображения Возвращает число вхождений ключа к в отображении A илиО) Возвращает true, если данное отображение пустое, и false в противном случае Возвращает итератор, указывающий на конец отображения Возвращает пару итераторов, которые указывают на первый и последний элементы в отображении, содержащие заданный ключ
348 map Функция-член void erase(iterator i); void erase(iterator start, iterator end) ; size_type erase( const key__type Ьк) ; iterator find( const key_type &k) ; const_iterator find( const key_type &k) const; allocator_type get_allocator() const; iterator insert( iterator i, const value_type Scval) ; template <class Inlter> void insert(Inlter start, Inlter end) ; pair<iterator, bool> insert( const value_type &val); key_compare key_comp() const; Назначение Удаляет элемент, на который указывает итератор i Удаляет элементы в диапазоне, заданном параметрами 'start и end Удаляет из отображения элементы, ключи которых имеют значение к Возвращает итератор для заданного ключа. Если ключ не обнаружен, возвращает итератор для конца отображения Возвращает распределитель отображения Вставляет значение val в позиции или после элемента, заданного итератором i. Возвращает итератор на этот элемент Вставляет элементы заданного диапазона Вставляет значение val в используемое отображение. Возвращает итератор для данного элемента. Элемент вставляет только в том случае, если его еще нет в отображении. Если элемент был вставлен, возвращает пару pair-citerator, true>. В противном случае возвращает пару pair<iterator, false> Возвращает объект-функцию, которая сравнивает ключи
map 349 Функция-член iterator lower_bound(const key_type Sck) ; const_iterator lower_bound( const key_type &^c) const; s i z e_type max_s i z e() const; reference operator!] ( const key_type &i) ; reverse_iterator rbegint); const_reverse_iterator rbegin() const; reverse_iterator rend(); const_reverse_iterator rend() const; size_type size() const; void swap(map<Key, T, Comp, Allocator> Scob) ; iterator upper_bound( const key_type &Jc) ; const_iterator upper_bound( const key_type Sck) const; value_compare value_comp(] const; Назначение Возвращает итератор для первого элемента в отображении, ключ которого равен значению к или больше этого значения Возвращает максимальное число элементов, которое может содержать данное отображение Возвращает ссылку на элемент, заданный параметром i. Если этого элемента не существует, вставляет его в отображение Возвращает реверсивный итератор для конца отображения Возвращает реверсивный итератор для начала отображения Возвращает текущее число элементов в отображении Выполняет обмен элементами данного отображения и отображения ob Возвращает итератор для первого элемента в отображении, ключ которого больше заданного значения к Возвращает объект-функцию, которая сравнивает значения
350 multimap Imultimap Класс multimap поддерживает ассоциативный контейнер, в котором неуникальным (в общем случае) ключам соответствуют определенные значения. Спецификация его шаблона имеет следующий вид. template <class Key, class T, class Comp = less<Key>, class Allocator = allocator<pair<const Key, T> > > class multimap Здесь Key — тип данных ключей, Т — тип сохраняемых (отображаемых) значений, a Comp — функция, которая сравнивает два ключа. Класс mul t imap имеет следующие конструкторы. explicit multimap(const Comp bcmpfn = Comp(), const Allocator &a = Allocator()); multimap(const multimap<Key, T, Comp, Allocator> bob) ; template <class Inlter> multimap(Inlter start, Inlter end, const Comp Sccmpfn = Comp () , const Allocator &a = Allocator()); Первая форма конструктора создает пустое мультиотображе- ние. Вторая создает мультиотображение, которое содержит те же элементы, что и мультиотображение ob. Третья создает мультиотображение, которое содержит элементы в диапазоне, заданном параметрами start и end. Функция, заданная параметром cmpfn (если она задана), определяет упорядочение мультиотображения. Для класса multimap определены следующие операторы сравнения: ==, <,<=, !=,> и >=. Класс multimap содержит перечисленные ниже функции- члены. В приведенных в следующей таблице описаниях элемент key_type представляет тип ключа, а элемент value_type — пару элементов pair<Key, Т>. Функция-член Назначение iterator begin О; Возвращает итератор для первого const_iterator begin О элемента в мультиотображении const; void clear () ; Удаляет все элементы из мультиотображения
multimap 351 Функция-член Назначение size_type count( const key_type &.k) const; bool empty() const; iterator end(); const_iterator end() const; pair<iterator, iterator> equal_range( const key_type &к); pair<const_iterator, const_iterator> equal_range( const key_type &.k) const; void erase(iterator i) ; t void erase(iterator start, iterator end); size_type erase( const key_type Sck) ; iterator find( const key_type S*.k) ; const_iterator find( const key_type kk) const; allocator_type get_allocator() const; iterator insert( iterator i, const value_type bval) ; template <class Inlter> void insert(Inlter start, Inlter end); Возвращает число вхождений ключа к в мультиотображении Возвращает true, если данное мультиотображение пустое, и false в противном случае Возвращает итератор для конца мультиотображения Возвращает пару итераторов, которые указывают на первый и последний элементы в мультиотображении, которые содержат заданный ключ Удаляет элемент, на который указывает итератор i Удаляет элементы в диапазоне, заданном параметрами start и end Удаляет из мультиотображения элементы, ключи которых име- * ют значение к Возвращает итератор для заданного ключа. Если ключ не обнаружен, возвращает итератор для конца мультиотображения Возвращает распределитель мультиотображения Вставляет значение val в позиции или после элемента, заданного итератором i. Возвращает итератор для этого элемента Вставляет элементы заданного диапазона
352 multimap Функция-член Назначение iterator insert( const value_type hval) key_compare key_comp() const; iterator lower_bound( const key_type &.k) ; const_iterator lower_bound( const key_type Ьк) const; size_type max_size() const; reverse_iterator rbegin(); const_reverse_iterator rbegin() const; reverse_iterator rend() const_reverse_iterator rend() const; « size_type size() const; void swap(multimap<Key, T, Comp, Allocator> bob); iterator upper_bound( const key_type &.k) ; const_iterator upper_bound( const key_type Ьк const; value_compare value_comp() const; Вставляет значение val в используемое мультиотображение Возвращает объект-функцию, которая сравнивает ключи Возвращает итератор для первого элемента в мультиотображении, ключ которого равен значению к или больше этого значения Возвращает максимальное число элементов, которое может содержать данное мультиотображение Возвращает реверсивный итератор для конца мультиотображе- ния Возвращает реверсивный итератор для начала мультиотобра- жения Возвращает текущее число элементов в мультиотображении Выполняет обмен элементами данного мультиотображения и мультиотображения оЪ Возвращает итератор для первого элемента в мультиотображении, ключ которого больше заданного значения к Возвращает объект-функцию, которая сравнивает значения
multiset 353 I multiset __________ Класс multiset поддерживает множество, в котором неуникальным (в общем случае) ключам соответствуют определенные значения. Спецификация его шаблона имеет следующий вид. template xclass Key, class Comp = less<Key>, class Allocator = allocator<Key> > class multiset Здесь Key — тип данных ключей, a Comp — функция, которая сравнивает два ключа. Класс multiset имеет следующие конструкторы. explicit multiset (const Comp Sccmpfn = Comp () , const Allocator &a = Allocator()); multiset(const multiset<Key, Comp, Allocator> bob); template <class Inlter> multiset(Inlter start, Inlter end, const Comp Sccmpfn = Comp () , const Allocator &a = Allocator()); Первая форма конструктора создает пустое мультимножество. Вторая создает мультимножество, которое содержит те жеэлемен- ты, что и мультимножество ob. Третья создает мультимножество, которое содержит элементы в диапазоне, заданном параметрами start и end. Функция, заданная параметром cmpfn (если она задана), определяет упорядочение мультимножества. Для класса multiset определены следующие операторы сравнения: ==,<,<=, !=, > и >=. Класс multiset содержит перечисленные ниже функции- члены. В приведенных в следующей таблице описаниях элементы key_type и value_type получены в результате применения оператора typedef для типа данных Key. Функция-член Назначение iterator begin (); Возвращает итератор для перво- const_iterator begin () го элемента в мультимножестве const; void clear (); Удаляет все элементы из мультимножества
354 multiset Функция-член Назначение size_type count( const key_type Sck) const; bool empty() const; iterator end(); const_iterator end() const; pair<iterator, iterator> equal_range( const key_type Sck) const; void erase(iterator i); void erase(iterator^ start, iterator end) ; size_type erase( const key_type Sck) ; iterator find( const key^type &k) ; allocator_type get_allocator() const; iterator insert( iterator i, const value_type Scval) ; template <class Inlter> void insert(Inlter start, Inlter end); iterator insert( const value_type &vaJ); Возвращает число вхождений значения к в мультимножестве Возвращает true, если мультимножество пустое, и false в противном случае Возвращает итератор для конца мультимножества Возвращает пару итераторов, которые указывают на первый и последний элементы в мультимножестве, которые содержат заданный ключ Удаляет элемент, на который указывает итератор i Удаляет элементы в диапазоне, заданном параметрами start и end Удаляет из мультимножества элементы, ключи которых имеют значение к Возвращает итератор для заданного ключа. Если ключ не обнаружен, возвращает итератор для конца мультимножества Возвращает распределитель мультимножества Вставляет значение val в позиции или после элемента, заданного итератором i. Возвращает итератор для этого элемента Вставляет элементы заданного диапазона Вставляет значение val в используемое мультимножество. Возвращает итератор для вставленного элемента
queue 355 Функция-член Назначение key_compare key_comp() const; iterator lower_bound( const key_type &.k) const; s i z e_type max_s i z e() const; reverse_iterator rbegin(); const_reverse_iterator rbeginO const; reverse_iterator rend () ; const_reverse_iterator rend() const; size_type size() const; void swap(multiset<Key, T, Comp, Allocator> &ab) iterator upper_bound(const key_type &k) const; value_compare value_comp() const; Возвращает объект-функцию, которая сравнивает ключи Возвращает итератор для первого элемента в мультимножестве, ключ которого равен значению к или больше этого значения Возвращает максимальное число элементов, которое может содержать данное мультимножество Возвращает реверсивный итератор для конца мультимножества Возвращает реверсивный итератор для начала мультимножества Возвращает текущее число элементов в мультимножестве Выполняет обмен элементами данного мультимножества и мультимножества оЬ Возвращает итератор для первого элемента в мультимножестве, ключ которого больше заданного значения к Возвращает объект-функцию, которая сравнивает значения queue Класс queue поддерживает очередь с односторонним доступом. Спецификация его шаблона имеет следующий вид. template <class T, class Container = deque<T>> class queue Здесь T — тип данных, сохраняемых в очереди, a Container — тип контейнера'^ • используемого для реализации очереди. Класс queue имеет следующий конструктор.
356 priority_queue explicit queue(const Container &cnt = Container()); Конструктор queue () создает пустую очередь. По умолчанию в качестве контейнера используется дек (deque), но к очереди можно получить доступ только по принципу "первым вошел — первым вышел". Можно также в качестве контейнера для очереди использовать список (list). Контейнер содержится в защищенном объекте с именем с типа Container. Для класса queue определены следующие операторы сравнения: ==,<,<=, !=, > и >=. Класс queue содержит перечисленные ниже функции-члены. Функция-член Назначение value_type &back(); const value_type &back() const; bool empty() const; value_type &front() const value_type &front() const; void pop(); void push(const T bval) ; size_type size(> const; Возвращает ссылку на последний элемент в очереди Возвращает true, если данная очередь пустая, и false в противном случае Возвращает ссылку на первый элемент в очереди Удаляет первый элемент в очереди Добавляет в конец очереди элемент, значение которого задано параметром val Возвращает текущее количество элементов в очереди (priority_gueue Класс priority_queue поддерживает приоритетную очередь с односторонним доступом. Спецификация его шаблона имеет следующий вид. template <class T, class Container = vector<T>, class Comp = less<Container::value_type» ' class priority_queuei
set 357 Здесь Т — тип данных, сохраняемых в приоритетной очереди, Container —тип контейнера, используемого для реализации очереди, а класс Сотр задает функцию сравнения, которая определяет, когда один член приоритетной очереди меньше другого по приоритету. Класс priority_gueue имеет следующие конструкторы. explicit priority_queue(const Comp kcmpfn ='Comp(), Container &cnt = Container()); template <class Inlter> priority_queue(initer start, Initer end, const Comp Sccmpfn = Comp () , Container &cnt = Container()); Первый конструктор priority_queue () создает пустую приоритетную очередь. Второй создает приоритетную очередь, которая содержит элементы, заданные границами диапазона start и end. По умолчанию в качестве контейнера используется вектор (vector). Можно также в качестве контейнера для приоритетной очереди использовать дек (deque). Этот контейнер хранится в защищенном объекте с именем с типа Container. Класс priority_queue содержит перечисленные ниже функции-члены. Функция-член Назначение bool empty () const,- ч Возвращает true, если данная приоритетная очередь пустая, и false в противном случае void pop (); Удаляет первый элемент в приоритетной очереди void push (const т Добавляет в приоритетную оче- &val); редь элемент, значение которого задано параметром val s i z e_type s i z e () cons t; Возвращает текущее количество элементов в приоритетной очереди const value_type &top() Возвращает ссылку на элемент с const; наивысшим приоритетом. Этот элемент не удаляется lset I Класс set поддерживает множество, в котором неуникальным (в общем случае) ключам соответствуют определенные значения. Спецификация его шаблона имеет следующий вид.
358 set template <class Key, class Comp = less<Key>, class Allocator = allocator<Key> > class set Здесь Key — тип данных ключей, a Comp — функция, которая сравнивает два ключа. Класс set имеет следующие конструкторы. explicit set (const Comp Sccmpfn = Comp () , const Allocator &a = Allocator()); set(const set<Key, Comp, Allocator> bob); template -cclass Inlter> set(lnlter start, Inlter end, const Comp Sccmpfn = Comp () , const Allocator &a = Allocator()); Первая форма конструктора создает пустое множество. Вторая создает множество, которое содержит те же элементы, что и множество оЪ. Третья создает множество, которое содержит элементы в диапазоне, заданном параметрами start и end. Функция, заданная параметром cmpfn (если она задана), определяет упорядочение множества. Для класса set определены следующие операторы сравнения: ==, <, <=, ! =, > и >=. Класс multiset содержит перечисленные ниже функции- члены. Функция-член Назначение iterator begin(); const_iterator begin() const; void clear(); size_type count (... , const key_type &k) const; bool empty() const; iterator end() ; . ¦ . ;,, const_iterator end (.) const; pair<iterator, iterator> equal_range( const key_type Ьк) const,- Возвращает итератор для первого элемента в множестве Удаляет все элементы из множества Возвращает число вхождений значения к» множестве Возвращает true, если данное множество пустое, и false в противном случае Возвращает итератор для конца множества Возвращает пару итераторов, которые указывают на первый и последний элементы в множестве, содержащие заданный ключ
set 359 Функция-член Назначение void erase(iterator i); void erase(iterator start, iterator end); size_type erase( const key_type &.k) ; iterator find( const key_type allocator_type get_allocator() const; iterator insert( iterator i, const value_type &val) template <class Inlter> void insert(Inlter start, Inlter end); pair<iterator, bool> insert(const value_type bval); Удаляет элемент, на который указывает итератор i Удаляет элементы в диапазоне, заданном параметрами start и end Удаляет из множества элементы, ключи которых имеют значение к. Возвращает количество удаленных элементов Возвращает итератор для заданного ключа. Если этот ключ не обнаружен, возвращает итератор для конца множества Возвращает распределитель множества Вставляет значение val в позиции или после элемента, заданного итератором i. Элементы-дубликаты не вставляет. Возвращает итератор для этого элемента Вставляет элементы заданного диапазона. Элементы-дубликаты не вставляет Вставляет значение val в используемое множество. Возвращает итератор для вставленного элемента. Элемент вставляет только в том случае, если его еще нет в отображении. Бели элемент был вставлен, возвращает пару pair<iterator, true>. В противном случае возвращает пару pair<iterator, false>
360 stack Функция-член Назначение key_compare key_conp() const; iterator lower_bound( const key_type Sck) const; size_type max_size() const; reverse_iterator rbegin(); const_reverse_iterator rbeginf) const; reverse_iterator rend(); const_reverse_iterator rend() const; size_type sizeO const; void swap(set<Key, T, Comp, Allocator> iterator upper_bound( const key_type const; value_compare value_comp() const; Возвращает объект- функцию, которая сравнивает ключи Возвращает итератор для первого элемента в множестве, ключ которого равен значению к или больше этого значения Возвращает максимальное число элементов, которое может содержать данное множество Возвращает реверсивный итератор для конца множества Возвращает реверсивный итератор для начала множества Возвращает текущее число элементов в множестве Выполняет обмен элементами данного множества и множества оЪ Возвращает итератор для первого элемента в множестве, ключ которого больше заданного значения к Возвращает объект- функцию, которая сравнивает значения I stack Класс stack поддерживает стек. Спецификация его шаблона имеет следующий вид. template <class T, class Container = deque<T>> class stack
vector 361 Здесь Т — тип данных, сохраняемых в стеке, a Container — тип контейнера, используемого для реализации стека. Класс stack имеет следующий конструктор. explicit stack(const Container &cnt = Container()); Конструктор stack () создает пустой стек. По умолчанию в качестве контейнера используется дек (deque), но к стеку можно получить доступ только по принципу "последним вошел — первым вышел". Можно также в качестве контейнера для стека использовать вектор (vector) или список (list). Контейнер содержится в защищенном объекте с именем с типа Container. Для класса stack определены следующие операторы сравнения: ==, <,<=, !=,> и >=. Класс stack содержит перечисленные ниже функции- члены. Функция-член Назначение bool empty() const; void pop(); void push(const T size_type size() const; value_type &top() const value_type &top() const; Возвращает true, если данный стек пуст, и false в противном случае Удаляет верхний элемент в стеке, который формально является последним элементом в контейнере Помещает элемент, значение которого задано параметром val, в конец стека. Последний элемент в контейнере представляет вершину стека Возвращает текущее количество элементов в стеке Возвращает ссылку на вершину стека, что эквивалентно последнему элементу в контейнере. Этот элемент не удаляется vector Класс vector поддерживает динамический массив. Спецификация его шаблона имеет следующий вид.
362 vector template <class T, class Allocator = allocator<T» class vector Здесь T — тип сохраняемых данных, a Allocator задает распределитель. Класс vector имеет следующие конструкторы. explicit vector(const Allocator &a = Allocator()); explicit vector(size_type пит, const T &val = T(), const Allocator &a = Allocator()); vector(const vector<T, Allocator> bob); template <class Inlter> vector(Inlter start, Inlter end, const Allocator &a = Allocator()); Первая форма конструктора создает пустой вектор. Вторая создает вектор, который содержит пит элементов со значением val. Третья создает вектор, который содержит те же элементы, что и вектор оЪ. Четвертая создает вектор, который содержит элементы в диапазоне, заданном параметрами start и end. Для класса vector определены следующие операторы сравнения:==,<,<=, !=,> и >=. Класс vector содержит следующие функции-члены. Функция-член , Назначение template <class Inlter> Помещает в вектор после- void assign! довательность, определяе- Inlter start, мую параметрами start и Inlter end); end void assign (size_type nura, Помещает в вектор пит const T Scval) ; элементов со значением val reference at(size_type i); Возвращает ссылку на эле- const_ref erence мент, заданный параметром i at(size_type i) const; reference back () ; Возвращает ссылку на по- const_ref erence back () следний элемент в векторе const; iterator begin (); Возвращает итератор для const_iterator begin () первого элемента в векторе const;
vector 363 Функция-член Назначение size_type capacity() const; void clear! bool empty() const; const_iterator end() const; iterator end'() ; iterator erase(iterator i) ; iterator erase( iterator start, iterator end) ; reference front(); const_reference front() const; allocator_type get_allocator() const; iterator insert( iterator i, const T Stval = T() Возвращает текущую емкость вектора, которая представляет собой количество элементов, способное храниться в векторе до того, как возникнет необходимость в выделении дополнительной памяти Удаляет все элементы из вектора Возвращает значение истины, если используемый вектор пуст, и значение лжи в противном случае Возвращает итератор для конца вектора Удаляет элемент, адресуемый итератором i; возвращает итератор для элемента, расположенного после удаленного элемента Удаляет элементы в диапазоне, задаваемом параметрами start и end; возвращает итератордля элемента, расположенного за последним удаленным элементом Возвращает ссылку на первый элемент в векторе Возвращает распределитель вектора Вставляет значение val непосредственно перед элементом, заданным параметром i; возвращает итератор для этого элемента
364 vector Функция-член Назначение void insert(iterator i, size_type лит, const.T template <class Inlter> void insert( iterator i, Inlter start, Inlter ел<3) ; size_type max_size() const; reference operator[](size_type i) const; const_reference operator[](size_type i) const; void pop_back(); void push_back( const T &val) ; reverse_iterator rbeginf); const_reverse_iterator rbegin() const; reverse_iterator rend(); const_reverse_iterator rend() const; void reserve ( size_type лит); void resize(size_type пит, T val = T());" Вставляет пит копий значения val непосредственно перед элементом, заданным параметром i Вставляет в вектор последовательность, определяемую параметрами start и end, непосредственно перед элементом, заданным параметром i Возвращает максимальное число элементов, которое может содержать вектор Возвращает ссылку на элемент, заданный параметром i Удаляет последний элемент в векторе Добавляет в конец вектора элемент со значением, заданным параметром val Возвращает реверсивный итератор для конца вектора Возвращает реверсивный итератор для начала вектора Устанавливает емкость вектора равной не менее заданного значения пит Устанавливает размер вектора равным значению, заданному параметром num. Если вектор для этого нужно удлинить, то в его конец добавляются элементы со значением, заданным параметром val
Алгоритмы библиотеки STL 365 Функция-член Назначение size_type 'size () const; Возвращает текущее количество элементов в векторе void swap(deque<T, Выполняет обмен элемен- Allocator> Scob) ; тами данного вектора и вектора оЪ В библиотеке STL также содержится специализированная версия класса vector для булевых значений. Она включает все функции класса vector и добавляет еще два члена. void flip(); Инвертирует значения всех битов в векторе static void swap ( Переставляет местами би- reference i, ты, заданные параметрами reference j) ; iuj I Алгоритмы библиотеки STL ^ В данной книге рассматриваются алгоритмы, определенные стандартной библиотекой шаблонов. Эти алгоритмы работают с данными, содержащимися в контейнерах, посредством итераторов. Все алгоритмы представляют собой шаблонные функции. Ниже перечислены описания обобщенных имен типов, используемых в алгоритмах. Обобщенное имя Что представляет Bilter Двунаправленный (bidirectional) итератор For 11 er Однонаправленный (forward) итератор Inl t er Входной (input) итератор Outlter Выходной (output) итератор Randl t er Итератор произвольного доступа (random access) T Некоторый тип данных Size Некоторый тип целочисленных данных Func Некоторый тип функции Generator Функция, генерирующая объекты
366 adjacentjind Обобщенное имя Что представляет ¦BinPred Бинарный предикат UnPred Унарный предикат Сотр Функция сравнения Д adj acent_find template <class Forlter> Forlter adjacent_findfForlter start, Forlter end); template <class Forlter, class BinPred> Forlter adjacent_findfForlter start, Forlter end, BinPred pfn); Алгоритм adjacent_f ind() выполняет поиск совпадающих смежных элементов внутри последовательности, заданной параметрами start и end, и возвращает итератор для первого элемента. Если ни одной такой смежной пары не обнаружено, возвращается значение end. Первая версия предназначена для поиска эквивалентных элементов. Вторая же позволяет задать собственный метод определения совпадающих элементов. |binary_search ",,:. ,V :,:::::*:"; ¦•"¦я|Щ|^:-:<!;II template <class Forlter, class T> bool binary_search(Forlter start, Forlter end, const T Scval) ; template <class Forlter, class T, class Comp> bool binary_search(Forlter start, Forlter end, const T &.val, Comp cmpfn) ; Алгоритм binary_search() выполняет двоичный поиск значения, заданного параметром val, внутри упорядоченной последовательности, границы которой заданы параметрами start и end. Алгоритм возвращает значение true, если значение val было найдено, и false в противном случае. Первая версия предназначена для поиска в заданной последовательности элементов, которые равны заданному значению. Вторая версия позволяет задать собственную функцию сравнения.
copy 367 template <class Inlter, class Outlter> Outlter copy(Inlter start, Inlter end, Outlter result); Алгоритм copy (} копирует последовательность, границы которой заданы параметрами start и end, и помещает результат в последовательность, адресуемую параметром result. Алгоритм возвращает указатель на конец результирующей последовательности. Диапазон копируемой последовательности не должен перекрывать диапазон последовательности, заданной параметром result. copy_backward template <class Bilterl, class Bilter2> Bilter2 copy_backward(Bilterl start, Bilterl end, Bilter2 result); Алгоритм cqpy_backward () аналогичен алгоритму copy (), за исключением того, что копирование происходит в обратном порядке, т.е. сначала перемещаются элементы, находящиеся в конце последовательности. (count 1 sssssssssssa^ssssssssBSBasBsaasESSSEsssasai template <class Inlter, class T> e_t count(Inlter start, Inlter end, const T Алгоритм count () возвращает количество элементов со значением val в последовательности, границы которой заданы параметрами start и end. _^_^_х_ | count_if I template <class Inlter, class UnPred> size_t count(Inlter start, Inlter end, UnPred pfn);
368 equal Алгоритм count_if(), действуя в последовательности, границы которой заданы параметрами start и end, возвращает количество элементов, для которых унарный предикат pfn возвращает значение true. ! equal ВВВЕВВВВВ template <class Inlterl, class Inlter2> bool equal(Inlterl start 1, Inlterl endl, Inlter2 start2); template <class Inlterl, class Inlter2, class BinPred> bool equal(Inlterl startl, Inlterl endl, Inlter2 start2, BinPred pfn); Алгоритм equal () определяет, одинаковы ли два диапазона. Диапазон, заданный параметрами startl и endl, сравнивается с последовательностью, адресуемой параметром start2. Если диапазоны одинаковы, возвращается значение true, в противйом случае — значение false. Вторая форма позволяет задать бинарный предикат, определяющий, в каком случае считать равными два элемента. |equal_range SB^ESiaBssiBSBsaB template <class Forlter, class T> pair<ForIter, Forlter> equal_range{Forlter start, Forlter end, const T &vaJ) ; template -cclass Forlter, class T, class Comp> pair<ForIter, Forlter> equal_range(Forlter start, Forlter end, const T &.val, Comp cmpfn); Алгоритм equal_range () возвращает диапазон, в который можно вставить элемент, не нарушая порядок некоторой последовательности. Область, в которой ведется поиск такого диапазона, определяется параметрами start и end. Значение вставляемого элемента передается посредством параметра
fill и fil1_n 369 val. Для задания собственного критерия задайте функцию сравнения с помощью параметра cmpfn. Шаблонный класс pair — это класс, который может хранить пару объектов в своих членах first и second. template <class Forlter, class T> void fill(Forlter start, Forlter end, const T Scval) ; template <class Forlter, class Size, class T> void fill_n(Forlter start, Size пит, const T Scval) ; Алгоритмы f i 11 () и fil l_n () заполняют диапазон значением, заданным параметром val. Для версии fill() диапазон задается параметрами start и end. Для версии f ill_n () начало диапазона задается параметром start, после чего в операции заполнения участвуют пит элементов. |_find_ template <class Inlter, class T> Inlter find(Inlter start, Inlter end, const T Алгоритм find() в диапазоне, заданном параметрами start и end, выполняет поиск значения, заданного параметром val. Алгоритм возвращает итератор для первого вхождения элемента или для конца диапазона (end), если искомое значение не обнаружено в заданной последовательности. I f ind_endI template <class Forlterl, class Forlter2> Fwdlterl find_end(Forlterl startl, Forlterl endl, Forlter2 start2, Forlter2 end2); template <class Forlterl, class Forlter2, class BinPred>
370 find_first_of Fwdlterl find__end(Forlterl startl, -Forlterl endl, Forlter2 start2, Forlter2 end2, BinPred pfn) ; Алгоритм find_end() выполняет поиск последнего итератора последовательности, заданной параметрами start2 и end2 внутри диапазона, заданного параметрами startl и endl. Если последовательность найдена, возвращается итератор для последнего элемента в этой последовательности. В противном случае возвращается итератор endl. Вторая форма позволяет задать бинарный предикат, который определяет принцип совпадения элементов. I find first of I 1 " template <class Forlterl, class Forlter2> Fwdlterl find_first_of(Forlterl startl, Forlterl endl, Forlter2 start2, Forlter2 end2); template <class Forlterl, class Forlter2, class BinPred> Fwdlterl find_first_of(Forlterl startl, Forlterl endl, Forlter2 start2, Forltef2 end2, BinPred pfn); Алгоритм f ind_f irst_of () выполняет поиск первого элемента внутри последовательности, определенной параметрами startl и endl, который совпадает с любым элементом внутри диапазона, заданного параметрами start2 и end2. Если совпадения элементов не обнаружено, возвращается итератор endl. Вторая форма позволяет задать бинарный предикат, который определяет принцип совпадения элементов. |find_if | template <class Inlter, class UnPred> Inlter find_if(Inlter start, Inlter end, UnPred pfn); Алгоритм find () в диапазоне, заданном параметрами start и end, выполняет поиск элемента, для которого унарный преди-
for_each 371 кат pfn возвращает значение true. Алгоритм возвращает итератор для первого вхождения элемента или значение end, если искомого значения нет в данной последовательности. for_each I template <class Inlter, class Funo Func for_each(Inlter. start, Inlter end, Func fn); Алгоритм f or_each () применяет функцию fn к диапазону элементов, заданному параметрами start и end. Алгоритм возвращает функцию fn. I generate И generate_n I template <class Forlter, class Generator> void generate(Forlter start, Forlter end, Generator fngen); template <class Forlter, class Size, class Generator> void generate_n(OutIter start, Size пит, Generator fngen); Алгоритмы generate {) и generate_n() присваивают значения, возвращаемые некоторой генерирующей функцией, элементам из диапазона, задаваемого параметрами алгоритма. Для алгоритма generate () диапазон задается граничными параметрами start и end. А для алгоритма generate_n () задается начало диапазона (параметр start) и указывается количество участвующих в операции элементов (параметр пил?). Функция- генератор передается посредством параметра fngen, причем она не имеет параметров. includes Ц template <class Inlterl, class Inlter2> bool includes(Inlterl startl, Inlterl endl, Inlter2 start2, Inlter2 end2); template <class Inlterl, class Inlter2, class Comp> bool includes(Inlterl startl, Inlterl endl,
372 inplacejnerge Inlter2 start2, Inlter2 end2, Comp cmpfn); Алгоритм includes () устанавливает факт включения всех элементов последовательности, заданной параметрами start2 и end2, последовательностью, заданной параметрами startl и endl. Алгоритм возвращает значение true, если все элементы одной заданной последовательности обнаружены в другой, и значение false в противном случае. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. Iinplace_merge template <class Bilter> void inplace_merge(Bilter start, Bilter mid, Bilter end); template <class Bilter, class Comp> void inplace_merge(Bilter start, Bilter mid, Bilter end, Comp cmpfn); Внутри одной последовательности алгоритм inplace_merge () объединяет диапазон, заданный параметрами start и mid, с диапазоном, заданным параметрами mid и end. Оба диапазона должны быть отсортированы в порядке возрастания. После выполнения алгоритма полученная последовательность сортируется в порядке возрастания. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. |iter_swap template «cclass Forlterl, class Forlter2> void iter_swap(Forlterl i, Forlter2 j); Алгоритм iter_swap () меняет местами значения, адресуемые итераторами, которые передаются в качестве параметров.
lexicographicaLcompare 373 Ilexicographical_compare template <class Inlterl, class Inlter2> bool lexicographical_compare(Inlterl startl, Inlterl endl, Inlter2 start2, Inlter2 end2); template <class Inlterl, class Inlter2, class Comp>- , bool lexicographical_compare(Inlterl startl,' Inlterl endl, Inlter2 start2, Inlter2 end2, Comp cmpfn); Алгоритм lexicographical_compare () сравнивает последовательность, заданную параметрами startl и endl, с последовательностью, заданной параметрами start2 и end2. Алгоритм возвращает значение true, если первая последовательность лексически меньше второй (т.е. если первая последовательность опережает вторую с учетом алфавитного порядка). Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. 8 lower bound I template «class Forlterl, class T> Forlter lower_bound(ForIter start, Forlter end, const T Scval) ; template <class Forlterl, class T, class Comp> Forlter lower_bound(Forlter start, Forlter end, const T &val, Comp cmpfn); Алгоритм lower_bound () выполняет поиск первого элемента в последовательности, заданной параметрами start и end, значение которого не меньше заданного значения val. Алгоритм возвращает итератор для этого элемента. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого.
374 mdke_heap |make_heap I template <class Randlter> void make_heap(Randlter start, Randlter end); template <class Randlter, class Comp> void make_heap(Randlter start, Randlter end, Comp cmpfn); Алгоритм make_heap () создает кучу из последовательности, заданной параметрами start и end. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. I max template <class T> const T &max(const T &i, const T &j); template <class T, class Comp> , const T &max(const T &i, const T &j, Comp cmpfn); Алгоритм max () возвращает максимальное из двух значений. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. max element template <class Forlter> Forlter max_element(Forlter start, Forlter last); template <class Forlter, class Comp> Forlter max_element(Forlter start, Forlter last, Comp cmpfn); Алгоритм max_element () возвращает итератор для максимального элемента внутри диапазона, заданного параметрами start и last. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого.
merge 375 merge template <class Inlterl, class Inlter2, class Outlter> Outlter merge(Inlterl startl, Inlterl endl, Inlter2 start2, Inlter2 end2, Outlter result); template <class Inlterl, class Inlter2, class Outlter, class Comp> Outlter merge(Inlterl startl, Inlterl endl, Inlter2 start2, Inlter2 end2, Outlter result, Comp cmpfn); Алгоритм merge () объединяет две упорядоченные последовательности, помещая результат в третью последовательность. Объединяемые последовательности задаются параметрами startl, endl и start2, end2. Результат помещается в последовательность, адресуемую параметром result. Возвращается итератор, указывающий на конец результирующей последовательности. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. min template <class T> const T &min(const T &i, const T &j); template <class T, class Comp> , const T & min(const T &i, const T &j, Comp cmpfn); Алгоритм min () возвращает минимальное из двух значений. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. min element template <class Forlter> Forlter min_element(Forlter start, Foriter last); template <class Forlter, class Comp>
376 mismatch Forlter min_element(Forlter start, Forlter last, Comp cmpfn); Алгоритм min_element () возвращает итератор для минимального элемента внутри диапазона, заданного параметрами start и last. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. Д mismatch template <class Inlterl, class Inlter2> pair<lnlterl, Inlter2> mismatch(Inlterl startl, Inlterl endl, Inlter2 start2); template <class Inlterl, class Inlter2, class BinPred> pair<lnlterl, Inlter2> mismatch(Inlterl startl, Inlterl endl, Inlter2 start2, BinPred pfn); Алгоритм mismatch () выполняет поиск первого несовпадения элементов в двух последовательностях. Возвращаются итераторы для этих двух элементов. Если несовпадения не обнаружено, возвращаются итераторы last! и start2 + (lastl- startl). Вторая форма позволяет задать бинарный предикат, который определяет, когда один элемент равен другому. Шаблонный класс pair содержит два данных-члена с именами first и second, которые предназначены для хранения пары значений. II^==-J==,^_^^====O==^^^^=__=====__^^___==_=_^^__=_=_=_ next_permutation I template <class Bilter> bool next_permutation(BiIter start, Bilter end); template <class Bilter, class Comp> bool next_permutation(Bilter start, Bilter end, Comp cmpfn);
nth_element 377 Алгоритм next_permutation () создает следующую перестановку заданной последовательности. Перестановка генерируется в предположении, что последовательность, отсортированная от меньшего к большему, представляет собой первую перестановку. Если следующей перестановки не существует, алгоритм next_permutation() сортирует последовательность в виде ее первой перестановки и возвращает значение false. В противном случае возвращается значение true. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. nth_element template <class Randlter> void nth_element(Randlter start, Randlter element, Randlter end); template <class Randlter, class Comp> • void nth_element(Randlter start, Randlter element, Randlter end, Comp cmpfn); Алгоритм nth_element () упорядочивает последовательность, заданную параметрами start и end, таким образом, чтобы все элементы, значения которых меньше значения element, размещались перед этим элементом, а все элементы, значения которых больше значения element, размещались после него. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. partial_sort template <class Randlter> void partial_sort(Randlter start, Randlter mid, Randlter end); template <class Randlter, class Comp> void partial_sort(Randlter start, Randlter mid, Randlter end, Comp cmpfn); Алгоритм partial_sort () сортирует диапазон, заданный параметрами start и end. Однако после выполнения алго-
378 partial_sort_copy * ритма отсортированными будут только элементы из диапазона, определяемого параметрами start и mid. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. !partial_sort_copy I вввввввввва=ваваЕввввввваввв1 template <class Inlter, class Randlter> Randlter partial_sort_copy(Inlter start, Inlter end, Randlter res_start, Randlter res_end); template <class Inlter, class Randlter, class Comp> Randlter partial_sort_copy(Inlter start, Inlter end, Randlter res_start, Randlter res_end, Comp cmpfn); Алгоритм partial_sort_copy () сортирует диапазон, заданный параметрами start и end, а затем копирует столько элементов, сколько может поместиться в результирующую последовательность, которая задана параметрами res_start и res_end. Алгоритм возвращает итератор для последнего элемента, скопированного в результирующую последовательность. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. [partition | template <class Bilter, class UnPred> Bilter partition(Bilter start, Bilter end, UnPred pfn); Алгоритм partition () сортирует последовательность, заданную параметрами start и end, таким образом, чтобы все элементы, для которых заданный параметром pfn предикат возвращает значение true, размещались перед теми элементами, для которых этот предикат возвращает значение false. Алго-
pop_heap 379 ритм возвращает итератор, указывающий на начало диапазона элементов, для кот.орых предикат равен 3Ha4eHHiofalse. |pop_heap —В——g_———__— template <class Randlter> void pop_heap(Randlter start, Randlter end); template <class Randlter, class Comp> void pop_heap(Randlter start, Randlter end, Comp cmpfn); Алгоритм pop_heap () меняет местами элементы start и end - 1, а затем перестраивает кучу, используя диапазон, определяемый параметрами start и end - 1. Таким образом, первый элемент исходной кучи удаляется и создается новая куча, состоящая из оставшихся элементов. Хотя элемент из кучи удален, он по-прежнему присутствует в контейнере. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. II prev_permutation I аавкввввввацнвЕВВЕВ^вваввввававввввввввавв! template <class Bilter> bool prev_permutation(BiIter start, Bilter end); template <class Bilter, class Comp> bool prev_permutation(Bilter start, Bilter end, Comp cmpfn) ; Алгоритм prev_permutation() создает предыдущую перестановку последовательности. Перестановка генерируется в предположении, что последовательность, отсортированная от меньшего к большему, представляет собой первую перестановку. Если следующей перестановки не существует, алгоритм prev_permutation() сортирует последовательность в виде ее заключительной перестановки и возвращает значение false. В противном случае возвращается значение true. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого.
380 push_heap Ipush_heap template <class Randlter> void push_heap(Randlter start, Randlter end); template <class Randlter, class Comp> void push_heap(Randlter start, Randlter end, Comp cmpfn); Алгоритм push_heap () помещает элемент в конец кучи. Предполагается, что диапазон, заданный параметрами start и end, представляет действительную кучу. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. random shuffle template <class Randlter> .void random_s.huf fie (Randlter start, Randlter end); template <class Randlter, class Generator> void random_shuffie(Randlter start, Randlter end, Generator rand_gen); Алгоритм random_shuf f le () рандомизирует (т.е. придает случайный характер) последовательность, заданную параметрами start и end. Вторая форма позволяет задать генератор случайных чисел. Эта функция должна иметь следующую общую форму. rand_gen(num) ; Она должна возвращать случайное число в диапазоне между нулем и значением пил?. remove, remove_if, remove_copy И remove codv if remove_copy_if template <class Forlter, class T> Forlter remove(Forlter start, Forlter end, const T Uval) ; template <class Forlter, class UnPred>
eplace, replace_copy, replacejf и replace_copy_if 381 Forlter remove_if(Forlter start; Forlter end, UnPred pfn); template <class Forlter, class Outlter, class T> Outlter remove_copy(Inlter start, Inlter end, Outlter result, const T kval) ; template <class Forlter, class Outlter, class UnPred> Outlter remove_copy_if(Inlter start, Inlter end, Outlter result, UnPred pfn); Алгоритм remove () удаляет из заданного диапазона элементы, которые равны значению val. Он возвращает итератор, указывающий на конец оставшихся элементов. Алгоритм remove_i f () удаляет из заданного диапазона элементы, для которых предикат pfn равен значению true. Алгоритм возвращает итератор, указывающий на конец оставшихся элементов. Алгоритм remove_copy () копирует из заданного диапазона элементы, которые равны значению val, и помещает результат в последовательность, адресуемую параметром result. Алгоритм возвращает итератор, указывающий на конец результата. Алгоритм remove_copy_if () копирует из заданного диапазона элементы, для которых предикат pfn равен значению true, и помещает результат в последовательность, адресуемую параметром result. Алгоритм возвращает итератор, указывающий на конец результата. replace,replace_copy, replace_if И replace_copy_if template <class Forlter, class T> void replace(Forlter start, Forlter end, const T Scold, Const T,SiJiew); template <class Forlter, class UnPred, class T> void replace_if (Forlter start, Forlter еле?, UnPred pfn, Const T knew); template <class Forlter, class Outlter, class T> Outlter replace_copy(Inlter start, Inlter end, Outlter result, const T Scold, Const T knew) ;
382 reverse и reverse_copy template <class Forlter, class Outlter, class UnPred, class T> Outlter replace__copy_if(Inlter start, Inlter end, Outlter result, UnPred pfn, Const T Scnew) ; Внутри заданного диапазона алгоритм replace () заменяет элементы, которые имеют значение old, элементами, имеющими значение new. Внутри заданного диапазона алгоритм replace_if {) заменяет элементы, для которых предикат pfn равен значению true, элементами, имеющими значение new. Внутри заданного диапазона алгоритм replace_.copy (} копирует элементы в последовательность, адресуемую параметром result. В процессе копирования происходит замена элементов, которые имеют значение old, элементами, имеющими значение new. Исходный диапазон не изменяется. Алгоритм возвращает итератор, указывающий на конец последовательности, адресуемой параметром result. Внутри заданного диапазона алгоритм replace_copy_if () копирует элементы в последовательность, адресуемую параметром resul t. В процессе копирования происходит замена элементов, для которых предикат pfn равен значению true, элементами, имеющими значение new. Исходный диапазон не изменяется. Алгоритм возвращает итератор, который указывает на конец последовательности, адресуемой параметром resul t. I reverse И reverse_copy I template <class Bilter> void reverse(Bilter start, Bilter end); template <class Bilter, class Outlter> Outlter reverse_copy(Bilter first, Bilter last, Outlter result); Алгоритм reverse () меняет порядок следования элементов в диапазоне, заданном параметрами start и end, на противоположный. Алгоритм reverse_copy () копирует в обратном порядке диапазон, заданный параметрами start и end, и сохраняет результат в последовательности, заданной параметром result. Алго-
rotate и rotate_copy 383 ритм возвращает итератор, указывающий на конец result- последовател ьности. rotate И rotate_copy template <class Forlter> void rotate(Forlter start, Forlter mid, Forlter end); template <class Forlter, class Outlter> Outlter rotate_copy(Forlter start, Forlter mid, Forlter end, Outlter result); Алгоритм rotate () выполняет циклический сдвиг влево элементов в диапазоне, заданном параметрами start и end, таким образом, чтобы элемент, заданный параметром mid, стал новым первым элементом. Алгоритм rotate_copy () копирует элементы в диапазоне, заданном параметрами start и end, в последовательность, адресуемую параметром result. В процессе копирования выполняется циклический сдвиг влево элементов таким образом, чтобы элемент, заданный параметром mid, стал новым первым элементом. Алгоритм возвращает итератор, указывающий на конец resul t-последовательности. search template <class Forlterl, class Forlter2> Forlterl search(Forlterl startl, Forlterl endl, Forlter2 start2, Forlter2 end2); template <class Forlterl, class Forlter2, class BinPred> Forlterl search(Forlterl startl, Forlterl endl, Forlter2 start2, Forlter2 end2, BinPred pfn); Алгоритм search () выполняет поиск одной последовательности внутри другой. Последовательность, внутри которой производится поиск, задается параметрами startl и endl, а искомая последовательность— параметрами start2 и end2. Если искомая последовательность найдена, возвра-
384 search_n щается итератор, указывающий на ее начало. В противном случае возвращается итератор endl. Вторая форма позволяет задать бинарный предикат, который определяет, когда один элемент равен другому. I search__n template <class Forlter, class Size, class T> Forlter search-_n(Forlter start, Forlter end, Size пит, Const T &val) ; template <class Forlter, class Size, class T, class BinPred> Forlter search_n(Forlter start, Forlter end, Size пит, Const T &val, BinPred pfn); Алгоритм search_n() внутри некоторой последовательности выполняет поиск другой последовательности, которая состоит из пит элементов, равных значению val. Последовательность, внутри которой производится поиск, задается параметрами start и end. Если искомая последовательность найдена, возвращается итератор, указывающий на ее начало. В противном случае возвращается итератор endl. Вторая форма позволяет задать бинарный предикат, который определяет, когда один элемент равен другому. Д set_difference template <class Inlterl, class Inlter2, class Outlter> - Outlter set_difference(Inlterl startl, Inlterl endl, Inlter2 start2, Inlter2 end2, Outlter result); template <class Inlterl, class Inlter2, class Outlter, class Comp> Outlter set_difference(Inlterl startl, Inlterl endl, Inlter2 start2, Inlter2 end2, Outlter result, Comp cmpfn);
setjntersection 385 Алгоритм set_difference() создает последовательность, которая содержит разность между двумя упорядоченными множествами, определяемыми параметрами startl, endl и start2, end2, т.е. множество, задаваемое параметрами start2, end2, вычитается из множества, задаваемого параметрами startl, endl. Результат упорядочивается и помещается в последовательность, адресуемую параметром result. Алгоритм возвращает итератор, указывающий на конец результата. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. |set_intersection вввввввввввввввввввввввввввввввввввввввва template <class Inlterl, class Inlter2, class Outlter> " - ¦ ' Outlter set_intersection(Inlterl startl, Inlterl endl, Inlter2 start2, Inlter2 end2, Outlter result^); template <class Inlterl, class Inlter2, class Outlter, class Comp> Outlter set_intersection(Inlterl startl, Inlterl endl, Inlter2 starts, Inlter2 end2, Outlter result, Comp cmpfn); Алгоритм set_intersection() создает последовательность, которая содержит пересечение двух упорядоченных множеств, определяемых параметрами startl,' endl и starts, end2, т.е. создаваемая последовательность будет включать только те элементы, которые принадлежат обоим множествам. Результат упорядочивается и помещается в последовательность, адресуемую параметром result. Алгоритм возвращает итератор, указывающий на конец результата. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. I set_syinmetric_dif f erence I template <class Inlterl, class Inlter2, class Outlter> Outlter set_symmetric_difference(Inlterl startl,
386 set_union Inlterl endl, Inlter2 start2, Inlter2 end2, Outl'ter result) ; template <class Inlterl, class Inlter2, class Outlter, class Comp> Outlter set_symmetric_difference(Inlterl startl, Inlterl endl, Inlter2 start2, Inlter2 end2, Outlter result, Comp cmpfn); Алгоритм set_symmetric_difference() создает последовательность, которая содержит симметричную разность между двумя упорядоченными множествами, определяемыми параметрами startl, endl и start2, end2, т.е. создаваемая последовательность будет включать только те элементы, которые не являются общими для обоих множеств. Результат упорядочивается и помещается в последовательность, адресуемую параметром result. Алгоритм возвращает итератор, указывающий на конец результата. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. I set_union ш template <class Inlterl,_ class Inlter2, class Outlter> Outlter set_union(Inlterl startl, Inlterl endl, Inlter2 start2, Inlter2 end2, Outlter result); template <class Inlterl, class Inlter2, class Outlter, class Comp> Outlter set_union(Inlterl startl, Inlterl endl, Inlter2 start2, Inlter2 end2, Outlter result, Comp cmpfn); Алгоритм set_union () создает последовательность, которая содержит объединение двух упорядоченных множеств, определяемых параметрами startl, endl и start2, end2, т.е. создаваемая последовательность будет включать элементы обоих множеств. Результат упорядочивается и помещается в последовательность, адресуемую параметром result. Алгоритм возвращает итератор, указывающий на конец результата.
sort 387 Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. lsort • template <class Randlter> void sort(Randlter start, Randlter end); template <class Randlter, class Comp> void sort(Randlter start, Randlter end, Comp cmpfn); Алгоритм sort (} сортирует диапазон, заданный параметрами start и end. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. |sort_heap template <class Randlter> void sort_heap(Randlter start, Randlter end); template <class Randlter, class Comp> void sortjieap(Randlter start, Randlter end, Comp cmpfn); , Алгоритм sort_heap () сортирует кучу внутри диапазона, задаваемого параметрами start и end. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. stable partition template <class Bilter, class BinPred> Bilter stable_j?artition(Bilter start, Bilter end, BinPred pfn); Алгоритм stable_partition() упорядочивает последовательность, заданную параметрами start и end, таким образом, что все элементы, для которых заданный параметром pfn предикат возвращает значение true, будут размещаться перед элементами, для которых этот предикат возвращает значение false. Такое разбиение являетсястаб. ильном, Это рз^чает.сохранение от-
388 stable_sort носительного упорядочения последовательности. Алгоритм возвращает итератор, указывающий на начало элементов, для которых задаваемый предикат равен значению false. |stable_sort template <class Randlter> void stable_sort(Randlter start, Randlter end); template <class Randlter, class Comp> void stable_sort(Randlter start, Randlter end, Comp cmpfn); Алгоритм stable_sort () выполняет устойчивую сортировку диапазона, заданного параметрами start и end. Это значит, что равные элементы не переставляются. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого. | swap template <class T> void swap(T &i, T &j) ; - ": Алгоритм swap () меняет местами значения, заданные ссылками i и j. „ template <class Forlterl, class Forlter2> Forlter2 swap_ranges(Forlterl start!, Forlterl endl, Forlter2 start2); Алгоритм swap_ranges () выполняет обмен элементов в диапазоне, заданном параметрами startl и endl, и элементов из последовательности, начало которой задается параметром start2. Алгоритм возвращает указатель на конец последовательности, заданной параметром start2. I transform 11 template <class Inlter, class Outlter, class Func> ¦traHs-fQ?sa(~In-I-ter, start;, ...Inlter .,?
transform 389 Outlter result, Func unaryfunc); template <class Inlterl, class Inlter2, class Outlter, class Funo Outlter transform(Inlterl startl, Inlterl endl, Inlter2 start2, Outlter result, Func binary func) -, Алгоритм transformO применяет функцию к диапазону элементов и сохраняет результат в последовательности, заданной параметром result. В первой форме диапазон задается параметрами start и end. Применяемая функция задается параметром unary func. Она принимает значение элемента в качестве параметра и должна возвратить преобразованное значение. Во второй форме алгоритма преобразование применяется с использованием бинарной функции, которая принимает значение элемента из последовательности, предназначенного для преобразования, в качестве первого параметра и элемент из второй последовательности в качестве второго параметра. Обе версии возвращают итератор, указывающий на конец результирующей последовательности. Совет программисту Одним из самых интересных алгоритмов является алгоритм trans form (), поскольку он модифицирует каждый элемент из заданного диапазона в соответствии с предоставленной вами функцией. Например, в следующей программе используется простая функция преобразования xform(), предназначенная для возведения в квадрат содержимого списка. Обратите внимание, что результирующая последовательность сохраняется в том же списке, в котором содержится и исходная. // Пример использования алгоритма преобразования transformO . #include <iostream> #include <list> ¦include <algorithm> using namespace std; // Простая функция преобразования. int xform(int i) { , _ return i * i; // квадрат исходного значения >¦
390 transform int main() list<int> xl; int i; // Помещаем значения в список. for(i=0; i<10; i++) xl.push_back(i); cout « "Исходное содержимое списка xl: "; list<int>::iterator p = xl.begin(); while(p != xl.endO ) { COUt « *p << " "; P++; cout « endl; // Преобразуем список xl. p = transform(xl .begin() , xl.endO, xl.begin() , xform); cout << "Преобразованное содержимое списка xl: "; . . -....• • p - xl.begin(); j.whilefp != xl.endO) { •. COUt « *p «"";¦" . •,...; ' ¦ return 0; . - } Ниже представлен результат работы этой программы. Исходное содержимое списка xl: 01234567. 8 9 Преобразованное содержимое списка xl: 0 14 9 16 25 36 49 64 81 Как видите, каждый элемент в списке xl возведен в квадрат.
unique и unique_copy 391 (unique И unique_copy ssBBBBasBBBassssMBSBSBBBSBi template <class Forlter> Forlter unique(Forlter start, Forlter end); template <class Forlter, class BinPred> Forlter unique(Forlter start, Forlter end, BinPred pfn); template <class Forlter, class Outlter> Outlter unique_copy(Forlter start, Forlter end, Outlter result); template <class Forlter, class Outlter, class BinPred> Outlter unique_copy(Forlter start, Forlter end, Outlter result, BinPred pfn); Алгоритм unique () удаляет повторяющиеся элементы из заданного диапазона. Вторая форма позволяет задать бинарный предикат, который определяет, когда один элемент равен другому. Алгоритм unique () возвращает итератор, указывающий на конец диапазона. Алгоритм unique_copy () копирует диапазон, заданный параметрами startl и endl, удаляя в процессе копирования повторяющиеся элементы. Результат помещается в последовательность, заданную параметром result. Вторая форма позволяет задать бинарный предикат, который определяет, когда один элемент равен другому. Алгоритм unique_copy () возвращает итератор, указывающий на конец диапазона. Iupperjbound I template <class Forlter, class T> Forlter upper_bound(Forlter start, Forlter end, const T &val); template <class Forlter, class T, class Comp> Forlter upper_bound(Forlter start/ Forlter end, const T Scval, Comp cmpfn);
392 upper_bound Алгоритм upper_bound () находит последний элемент в последовательности, заданной параметрами start и end, который не больше заданного значения val. Алгоритм возвращает итератор для этого элемента. Вторая форма позволяет задать функцию сравнения, которая определяет, когда один элемент меньше другого.
Глава 17 Строки, исключения и классы арифметики комплексных чисел в языке C++ Помимо библиотек iostream и STL, стандартная библиотека C++ определяет еще несколько классов. В то время как многие из них являются классами специального назначения, существуют три широко используемых класса, предназначенных для поддержки строк, исключений и комплексной арифметики. Именно этим трем классам и посвящена данная глава. [ Строки В языке C++ поддержка строк осуществляется двумя способами. Первый состоит в использовании символьного массива, завершающегося нулевым символом. Такой массив иногда называется С-строкой. Второй способ подразумевает работу с объектом класса типа basic_string. Существует две специализации типа basic_string: тип string, который поддерживает символьные строки, и тип wstring, который поддерживает строки, образованные двубайтовыми символами. Чаще всего используются строковые объекты типа string. Для использования строковых классов C++ необходимо включить в программу заголовок <string>. Класс basic_string по сути является контейнером. Это значит, что итераторы и алгоритмы STL могут обеспечить работу со строками. Однако строки обладают дополнительными возможностями. Тип basic_string использует класс char_traits, который определяет ряд атрибутов символов, составляющих строку. Важно понимать, что, поскольку большинство строк состоит из символов либо типа char, либо типа wchar_t, класс basic_string в состоянии обработать любой объект, который может быть использован для представления текстового символа.v
394 Строки Спецификация шаблона для класса basic_string имеет следующий вид. template <class CharType, class Attr = char_traits<CharType>, class Allocator = allocator<T>> class basic_string ,. Здесь CharType — тип используемого символа, Attr — класс, в котором описаны атрибуты этого символа, и класс Allocator задает распределитель. Класс basic_string имеет следующие конструкторы. explicit basic_string( const Allocator &a = Allocator()); basic_string(size_type len, CharType ch, const Allocator &a = Allocator()); basic_string(const CharType *str; const Allocator &a = Allocator()); basic_string(const CharType *str; size_type len, const Allocator &a = Allocator()); basic_;String(const basic_string &str, size_type indx = 0, size_type len=npos, const Allocator &a = Allocator()); template <class Inlter> basic_string(Inlter start, Inlter end, const Allocator &a = Allocator()); Первая форма конструктора создает пустую строку. Вторая форма создает строку, которая содержит len символов со значением ch. Третья создает строку, которая содержит такие же элементы, как и строка str. Четвертая формирует строку, которая содержит подстроку str, начинающуюся с нулевого (по счету) символа, и имеет длину, равную 2 ел символов. Пятая создает строку из другого класса basic_string, используя подстроку, которая начинается с символа indx и имеет длину, равную len символов. Наконец, шестая форма создает строку, которая содержит элементы в диапазоне, заданном параметрами start и end. Для класса basic_string определены следующие операторы сравнения: ==, <, <=, !=, >и >=.
Строки 395 Также определены оператор +, выполняющий конкатенацию двух строк, и операторы ввода-вывода « и >>, которые можно использовать для ввода и вывода строк. Оператор + можно использовать для конкатенации одного строкового объекта с другим или строкового объекта со строкой, созданной в С-стиле. Другими словами, поддерживаются следующие операции. строка + строка строка + С-строка С-строка + строка Оператор + можно использовать для добавления символа в конец строки. В классе basic_string определена константа npos, которая обычно равна -1. Она представляет размер строки максимально возможной длины. В приведенных ниже описаниях обобщенный тип CharType представляет тип символа, сохраняемого строкой. Поскольку имена типов в шаблонном классе являются произвольными, в контейнерных классах объявляются typedef-версии этих типов, что конкретизирует имена типов. Ниже перечислены часто используемые типы, определенные в классе basic_string. size_type Некоторый целый тип, эквивалентный типу size_t reference - Ссылка на символ const_reference const-ссылка на символ iterator Итератор const_iterator const-итератор reverse_iterator Реверсивный итератор const_reverse_iterator Реверсивный const-итератор value_type Тип символа, сохраненного в строке allocator_type Тип распределителя pointer Указатель на символ внутри строки const_pointer const-указатель на символ внутри строки
396 Строки traits_type difference_type typedef-имя для char_traits<CharType> Тип, который может хранить разность двух адресов В следующей таблице приведены функции-члены, определенные в классе basic_string. Поскольку подавляющее большинство программистов используют char-строки (в том числе в целях упрощения описания), в таблице использован тип string, но следует помнить, что эти функции также применяются к объектам типа wstring (или любого другого типа, определенного в классе basic_string). Функция-член Назначение string &append( const string &str); string &append( const string &str, size_type indx, size_type len); string &append( const CharType *str); string &append( const CharType *_str, size_type пит); string &append( size_type len, char CharType ch); template<class Inlter> string & app end( ' Inlter start, ' Inlter end); Добавляет подстроку str в конец данной строки. Возвращает указатель * t hi s Добавляет подстроку str в конец данной строки. Добавляемая подстрока начинается с позиции indx и имеет длину J ел символов. Возвращает указатель *this Добавляет подстроку str в конец данной строки. Возвращает указатель* this Добавляет первые лит символов из строки str в конец данной строки. Возвращает указатель* this Добавляет 1ел символов, заданных параметром ch, в конец данной строки. Возвращает указатель* this Добавляет последовательность, заданную параметрами start и end, в конец данной строки. Возвращает указатель *this
Строки 397 Функция-член Назначение string &assign( const string &str); string &assign( const string &str, size_type indx, size_type Jen); string &assign( const CharType *str); string &assign( const CharType *str, size_type 2ел); string &assign( size_type len, CharType-ch); template<class Inlter> string &append( Inlter start, Inlter end); reference at( size_type indx); const_reference at( size_type indx) const; iterator begin(); const_iterator begin() const; const CharType *c_str() const; Присваивает подстроку str данной строке. Возвращает указатель *this Присваивает подстроку str данной строке. Присваиваемая подстрока начинается с позиции indx и имеет длину J en символов. Возвращает указатель* this Присваивает подстроку str данной строке. Возвращает указатель * this Присваивает данной строке первые len символов из строки str. Возвращает указатель *this Присваивает данной строке 1 еп символов, заданных параметром ch. Возвращает указатель *this Присваивает данной строке последовательность, заданную параметрами start и end. Возвращает указатель *this Возвращает ссылку на символ, заданный параметром indx Возвращает итератор для первого элемента в строке Возвращает указатель на версию данной строки в С-стиле (т.е. с завершающим нулевым символом)
398 Строки Функция-член Назначение size_type capacity () const; int compare( const string &str) const; int compare( size_type indx, size_type len, const string &str) const; int compare( size_type indx, size_type len, const string &str, size_type indx2, size_type Ien2) const; int compare( const char CharType *str) const; Возвращает текущую емкость строки — число символов, которое она может содержать до того, как ей придется запросить дополнительную память Сравнивает строку str с данной строкой. Возвращает одно из сле- дующих-значений: меньше нуля, если * this < str, нуль, если* this == str; больше нуля, если* this > str Сравнивает строку str с подстрокой внутри данной строки. Эта подстрока начинается с позиции indxvi содержит len символов. Возвращает одно из следующих значений: меньше нуля, если * this < str; нуль, если *this == str; больше нуля, если* this > str Сравнивает подстроку в строке str с подстрокой внутри данной строки. Подстрока в данной строке начинается с позиции indx и содержит len символов. Подстрока в строке str начинается с позиции indx2 и содержит 1 еп2 символов. Функция возвращает одно из следующих значений: меньше нуля, если* this < str; нуль, если * this == str; больше нуля, если * this > str Сравнивает строку str с данной строкой. Функция возвращает одно из следующих значений: меньше нуля, если * this < str; нуль, если * this == str; больше нуля, если *this > str
Строки 399 Функция-член Назначение int compare(.. size_type indx, size_type len, const char CharType *str, size_type Ien2 = npos) const; s i z e_type с ору( CharType *str, size_type len, size_type indx = 0) const; const CharType *data() const; bool empty() const; iterator end(); const_iterator end() const; iterator erase (iterator i) iterator erase( iterator start, iterator end); Сравнивает подстроку в строке str с подстрокой внутри данной строки. Подстрока в данной строке начинается с позиции indx и содержит 2 en символов. Подстрока в строке str начинается с нулевой позиции и содержит 1еп2 символов. Функция возвращает одно из следующих значений: меньше нуля, если* this < str; нуль, если * this == str; больше нуля, если *this >str Начиная с позиции indx, копирует 2 en символов из данной строки в символьный массив, адресуемый параметром str. Возвращает количество скопированных символов Возвращает указатель на первый символ в данной строке Возвращает true, если данная строка пуста, и false в противном случае Возвращает итератор, указывающий на конец строки Удаляет символ, адресуемый параметром i. Возвращает итератор для символа, расположенного за удаленным символом Удаляет символы в диапазоне, задаваемом параметрами start и end. Возвращает итератор для символа, расположенного за последним удаленным символом
400 Строки Функция-член Назначение string & erase( size_type indx = 0, size_type len = npos) size_type find( const string Scstr, size_type indx = 0) const; size_type find( const CharType *str, size_type indx = 0) const; s i z e_type f ind( const CharType *str, size_type indx, size_type len) const; size_type find( CharType ch, size_type indx = 0) const; size_type find_first_of( const string &str, size_type indx = 0) const; Начиная с позиции indx, удаляет len символов из данной строки. Возвращает указатель *this Возвращает индекс первого вхождения строки str внутри данной строки. Поиск начинается с индекса indx. Если совпадения не обнаружено, возвращает значение npos Возвращает индекс первого вхождения строки str внутри данной строки. Поиск начинается с индекса indx. Если сов-, падения не обнаружено, возвращает значение npos Возвращает индекс первого вхождения первых J еп символов строки str внутри данной строки. Поиск начинается с индекса indx. Если совпадения не обнаружено, возвращает значение npos Возвращает индекс первого вхождения символа ch внутри данной строки. Поиск начинается с индекса indx. Если совпадения не обнаружено, возвращает значение npos Возвращает индекс первого символа внутри данной строки, который совпадает с любым символом в строке str. Поиск начинается с индекса indx. Если совпадения не обнаружено, возвращает значение npos
Строки 401 Функция-член Назначение size_type find_first_of( const CharType *str, size_type indx = 0) const; size_type find_first_of( const CharType *str, size_type indx, size_type Jen) const; size_type find_first_of( CharType ch, size_type indx = 0) const; size_type find_first_not_of( const string &str, size_type indx = 0) const; size_type find_first_not_of( const CharType *str, size_type indx =0) const; Возвращает индекс первого символа внутри данной строки, который совпадает с любым символом в строке str. Поиск начинается с индекса indx. Если совпадения не обнаружено, возвращает значение npos Возвращает индекс первого символа внутри данной строки, который совпадает с любым символом в первых 1 ел символах строки str. Поиск начинается с индекса indx. Если совпадения не обнаружено, возвращает значение npos Возвращает индекс первого вхождения символа ch внутри данной строки. Поиск начинается с индекса indx. Если совпадения не обнаружено, возвращает значение npos Возвращает индекс первого символа внутри данной строки, который не совпадает ни с каким символом в строке str. Поиск начинается с индекса indx. Если несовпадения не обнаружено, возвращает значение npos Возвращает индекс первого символа внутри данной строки, который не совпадает ни с каким символом в строке str. Поиск начинается с индекса indx. Если несовпадения не обнаружено, возвращает значение npos
402 Строки Функция-член Назначение size_type find_first_not_of( const CharType *str, size_type indx, size_type len) const size_type find_first_not_of( CharType ch, size_type indx = 0) const; size_type find_last_of( const string &str, size_type indx = npos) const; size_type find_last_of const CharType *str, size_type indx = npos) const; size_type find_last_of const CharType *str, size_type indx, size_type len) const Возвращает индекс первого символа внутри данной строки, который не совпадает ни с одним символом в первых len символах строки str. Поиск начинается с индекса indx. Если несовпадения не обнаружено, возвращает значение npos Возвращает индекс первого символа внутри данной строки, который не совпадает с символом ch. Поиск начинается с индекса indx. Если несовпадения не обнаружено, возвращает значение npos Возвращает индекс последнего символа внутри данной строки, который совпадает с любым символом в строке str. Поиск начинается с индекса indx. Если совпадения не обнаружено, возвращает значение npos Возвращает индекс последнего символа внутри данной строки, который совпадает с любым символом в строке str. Поиск начинается с индекса indx. Если совпадения не обнаружено, возвращает значение npos Возвращает индекс последнего символа внутри данной строки, который совпадает с любым символом в первых Jen символах строки stir. Поиск начинается с индекса indx. Если совпадения не обнаруже- " но, возвращает значение npos
Строки 403 Функция-член Назначение size_type find_last_ofi CharType ch, size_type indx = npos) const; size_type find_last_not_of( const string &str, size_type indx = npos) const; size_type . find_last_not_of( const CharType *str, size_type indx = npos) const; size_type find_last_not_of( const CharType *str, size_type indx, size_type len) const; size_type find_last_not_of( CharType ch, size_type indx = npos) const; allocator_type , get_allocator() const; Возвращает индекс последнего вхождения символа ch внутри данной строки. Поиск начинается с индекса indx. Если совпадения не обнаружено, возвращает значение проз Возвращает индекс последнего символа внутри данной строки, который не совпадает ни с одним символом в строке str. Поиск начинается с индекса indx. Если несовпадения не обнаружено, возвращает значение npos Возвращает индекс последнего символа внутри данной строки, который не совпадает ни с одним символом в строке str. Поиск начинается с индекса indx. Если несовпадения не обнаружено, возвращает значение npos Возвращает индекс последнего символа внутри данной строки, который не совпадает ни с одним из первых 1 вп символов строки str. Поиск начинается с индекса indx. Если несовпадения не обнаружено, возвращает значение npos Возвращает индекс последнего символа внутри данной строки, который не совпадает с символом ch. Поиск начинается с индекса indx. Если несовпадения не обнаружено, возвращается значение npos Возвращает распределитель строки
404 Строки Функция-член Назначение iterator insert( iterator i, ¦•¦ const CharType ScCh) ; string &insert( size_type indx, const string &str); string &insert( size_type indxl, const string &str, size_type indx2, size_type len); string &insert( size_type indx, const CharType *str); string &insert( size_type indx, const CharType *str, size_type len); string &insert( size_type indx, size_type len, CharType ch); void insert( iterator i, size_type len, const CharType &сЛ); template <class Inlter> void insert(iterator i, Inlter start, Inlter end) ; Вставляет символ ch непосредственно перед символом, заданным итератором i. Возвращает итератор для этого символа Вставляет строку str в данную строку в позиции, заданной индексом indx. Возвращает указатель *this Вставляет подстроку строки str в данную строку в позиции, заданной индексом indxl. Подстрока начинается с позиции, заданной индексом indx2, и содержит 1 еп символов. Возвращает указатель *this Вставляет строку str в данную строку в позиции, заданной индексом indx. Возвращает указатель * this Вставляет первые 1 еп символов строки str в данную строку в позиции, заданной индексом indx. Возвращает указатель *this Вставляет 1 еп символов со значением ch в данную строку в позиции, заданной индексом indx. Возвращает указатель *this Вставляет len копий символа ch непосредственно перед элементом, заданным итератором i Вставляет последовательность, заданную параметрами start и end, непосредственно перед элементом, заданным итератором i
Строки 40$ Функция-член Назначение size_type length!) const; s i z e_type max_s i z e() const; reference operator[](size_type indx) const; const_reference operator[](size_type indx) const; string &operator=( const string &str); string &operator=( const CharType *str); string &operator=( CharType ch); string &operator+=( const string &str); string &operator+=( const CharType *str); string &operator+=( CharType ch); reverse_iterator .rbegin(); const_reverse_iterator rbegin() const; reverse_iterator rend () ; const_reverse_iterator rend() const; string &replace( size_type indx, size_type 2en, const string &str); Возвращает количество символов в строке Возвращает максимальное количество символов, которое может содержаться в строке Возвращает ссылку на символ, заданный параметром indx Присваивает заданную строку или символ данной строке. Возвращает указатель *this Добавляет заданную строку или символ в конец данной строки. Возвращает указатель *this Возвращает реверсивный итератор, указывающий на конец строки Возвращает реверсивный итератор, указывающий на начало строки Заменяет до 2 en символов в данной строке, начиная с позиции indx, строкой str. Возвращает указатель *this
406 Строки Функция-член Назначение string breplace ( size_type indxl, size_type lenl, const string &str, size_type indx2, size_type Ien2); string &replace( size_type indx, size_type len, const CharType *str); string &replace( size_type indxl, size_type lenl, const CharType *str, size_type Ien2); string &replace( size_type indx, size_type lenl, size_type Ien2, CharType ch); string &replace( iterator start, iterator end, const string &str); string fireplace ( iterator start, iterator end, const CharType *str); string &replace( iterator start, iterator end, const CharType *str, size_type len); Заменяет до lenl символов в данной строке, начиная с позиции indxl, символами (в количестве 1еп2) строки str, начиная с позиции indx2. Возвращает указатель *this Заменяет до 1 еп символов в данной строке, начиная с позиции indx, строкой str. Возвращает указатель *this Заменяет до lenl символов в данной строке, начиная с позиции indxl, символами (в количестве 1еп2) строки str, начиная с позиции indx2. Возвращает указатель *this Заменяет до lenl символов в данной строке, начиная с позиции indx, символами (в количестве 1еп2), заданными параметром ch. Возвращает указатель * this Заменяет диапазон, заданный параметрами start и end, строкой str. Возвращает указатель *this Заменяет диапазон, заданный параметрами start и end, строкой str. Возвращает указатель *this Заменяет диапазон, заданный параметрами start и end, первыми 1 еп символами строки str. Возвращает указатель * thi s
Строки 407 Функция-член Назначение string kreplace( iterator start, iterator end, size_type Jen, CharType ch); template <class Inlter> string &replace( iterator startl, iterator endl, inlter start2, Inlter end2); void reserve(size_type nuffl = 0) ; void resize(size_type пит) ; void resize(size_type пит, CharType ch); size_type rfind( const string &str, size_type indx = npos) const; size__type rfind( const CharType *str, size_type indx = npos) const; size_type rfind( const CharType *str, size_type indx, size_type 2ел) const; Заменяет диапазон, заданный параметрами start и end, символами (в количестве 1еп), заданными параметром ch. Возвращает указатель *this Заменяет диапазон, заданный параметрами startl и endl, символами из диапазона, заданного параметрами start2 и end2. Возвращает указатель *this Устанавливает емкость строки равной не менее значения пит Изменяет размер строки, делая его равным значению, заданному параметром пит. Чтобы строку (при необходимости) удлинить, в ее конец следует добавить элементы со значением, заданным параметром ch Возвращает индекс последнего вхождения строки str внутри данной строки. Поиск начинается с позиции, заданной индексом indx. Если совпадения не обнаружено, возвращает значение npos Возвращает индекс последнего вхождения строки str внутри данной строки. Поиск начинается с позиции, заданной индексом indx. Если совпадения не обнаружено, возвращает значение npos Возвращает индекс последнего вхождения первых 1еп символов строки str внутри данной строки. Поиск начинается с позиции, заданной индексом indx. Если совпадения не обнаружено, возвращает значение npos
408 Строки Функция-член Назначение size_type rfind( CharType ch, size_type indx = npos) const; size_type size() const; i string substr( size_type indx = 0, size_type len = npos) const; void swap(string &str); Возвращает индекс последнего вхождения символа ch внутри данной строки. Поиск начинается с позиции, заданной индексом indx. Если совпадения не обнаружено, возвращает значение npos Возвращает текущее количество символов в строке Возвращает подстроку (внутри данной строки), состоящую из len символов, начиная с позиции indx Выполняет обмен символов данной строки и символов строки str Совет программисту Если с традиционными, созданными в С-стиле строками было всегда легко работать, то строковые классы C++ делают обработку строк совершенно простой. Например, с помощью объектов string можно использовать оператор присваивания (для назначения строковым объектам заключенных в кавычки строк), операторы отношений (для сравнения строк), а также множество функций обработки строк, которые значительно облегчают операции с подстроками. Рассмотрим, например, следующую программу. // Демонстрация работы со строками. #include <iostream> #include <string> using namespace std; . int main() { . \ ' string strl = "abcdefghijklmnopqrstuvwxyz"; string str2; "string str3(strl); str2 = strl.substrA0, 5);
Строки 409 cout << "strl: " << strl << endl; cout « "str2: " << str2 << endl; cout << "str3: " << str3 « endl; strl.replace(S, 10, "") ; cout « "strl.replaeeE, 10, \"\"): " « strl « endl; strl = "one"; str2 = "two"; str3 = "three"; cout << "strl.compare(str2): "; cout « strl.compare(str2) << endl; if(strl<str2) cout << "strl меньше str2\n"; string str4 = strl + " " + str2 + " " + str3; cout << "str4: " « str4 << endl; int i = str4.find("wo"); cout << "str4.substr(i): " « str4.substr(i); return 0; } Ниже приведен результат работы этой программы. Strl: abcdefghijklmnopqrstuvwxyz str2: klmno '¦"... str3: abcdefghijklmnopqrstuvwxyz strl.replaceE, 10, ""): abcdepqrstuvwxyz ../ strl.compare(str2) : -1 "/' ', strl меньше str2 , .¦'"•' str4: one two three . • str4.substr(i): wo three Обратите внимание на простоту выполнения обработки строк. Например, оператор + используется для конкатена-" ции, а оператор < — для сравнения двух строк. Чтобы выпол-; нить эти операции со строками с завершающими нулевыми символами в С-стиле, потребуется сделать менее удобные вызовы функций strcat () и strcmp (). Поскольку в языке C-N- объекты string можно свободно смешивать со строками с за-. вершающими нулевыми символами в С-стиле, от их пример- нения в программе нет никакого ущерба— наоборот, сле^дует ожидать значительного выигрыша. ', ."
410 Исключения Исключения В стандартной библиотеке C++ определены два заголовка, которые имеют отношение к обработке исключительных .ситуаций, или исключений: <exception> и <stdexcept>. Исключения используются для сигнализации об ошибочных условиях. Рассмотрим эти заголовки подробнее. <exception> Заголовок <exception> определяет классы, типы и функции, которые связаны с обработкой исключений. Вот как выглядят определения классов. class exception ( public: exception() throwO ; except ion (const bad_exception &ob) throwO; virtual -exception() throwO; exception &operator=(const exception &ob) throw(); virtual const char *what(() const throw(); class bad_exception: public exception { public: bad_exception() throw(); bad_exception(const bad_exception &ob) throw(); virtual ~bad_exception() throwO; bad_exception &operator=(const bad_exception &ob) throw(); virtual const char *what ( () const throwO; }; Класс exception — это базовый класс для всех исключений, определенных стандартной библиотекой C++. Класс bad_exception представляет собой тип исключения, генерируемого функцией unexpected О . В каждом из этих классов функция-член what () возвращает указатель на строку с за-
Исключения 411 вершающим нулевым символом, которая описывает соответствующее исключение. Из класса exception выведен ряд других важных классов. Класс bad_alloc используется в случае неудачного выполнения оператора new. Класс bad_typeid оказывается полезным при попытке выполнения недопустимого выражения typeid. Наконец, класс bad_cast ирпользуется при попытке выполнить неверную операцию динамического приведения типа. Эти классы содержат те же члены, что и класс exception. Ниже приводятся типы, определенные в заголовке <exception>. Тип Значение terminate_handler unexpected_handler typedef void(*terminate_handler)( typedef void(*unexpected_handler) В следующей таблице перечислены функции, определенные в заголовке <exception>. Функция Назначение terminate_handler set_terminate( terminate_handler fn) throw(); unexpected_handler set_unexpected( unexpected_handler fn) throw(); void terminate)); Устанавливает функцию, заданную параметром fn, в качестве обработчика завершения работы. Возвращает указатель на прежний обработчик завершения Устанавливает функцию, заданную параметром fn, в качестве обработчика непредвиденного исключения. Возвращает указатель на прежний обработчик непредвиденного исключения Вызывает обработчик завершения, когда не обработано фатальное исключение. По умолчанию вызывает функцию abort ()
412 Исключения Функция Назначение bool uncaught_exception(); Возвращает значение true, если исключение не перехвачено void unexpected (); Вызывает обработчик непредвиденного исключения, если функция генерирует неразрешенное исключение. По умолчанию вызывает функцию terminate() <stdexcept> Заголовок <stdexcept> определяет ряд стандартных исключений, которые могут быть сгенерированы библиотечными функциями C++ и/или системой времени выполнения. Существует два общих типа исключений, определяемых заголовком <stdexcept>: логические ошибки и ошибки времени выполнения (динамические ошибки). Логические ошибки обязаны своим существованием программистам. Динамические ошибки возникают из-за наличия ошибок в библиотечных функциях или системе времени выполнения и не подвластны контролю со стороны программиста. Определенные в языке C++ стандартные исключения, вызываемые логическими ошибками, выведены из базового класса logic_error. Они приведены в следующей таблице. Исключение Причина возникновения domain_error Возникла ошибка домена invalid_argument В вызове функции использован неверный аргумент length_error Была предпринята попытка создания слишком большого объекта out_of_range Аргумент функции не попал в требуемый диапазон Перечисленные ниже динамические исключения выведены из базового класса runtime_error.
Классы арифметики комплексных чисел 413 Исключение Причина возникновения overf low_error Возникло арифметическое переполнение range_error Возникла ошибка внутреннего диапазона underf low_error Возникла потеря значимости Классы арифметики комплексных чисел Заголовок <complex> определяет класс complex, который представляет комплексные числа. Он также определяет ряд функций и операторов, которые работают с объектами типа complex. Спецификация шаблона для класса complex имеет следующий вид. template <class T> class complex Здесь элемент т задает тип, используемый для хранения компонентов комплексного числа. Существуют три встроенные специализации класса complex. class complex<float> class complex<double> class complex<long double> Класс complex имеет следующие конструкторы. complex(const T Ureal = T(), const T = ^.imaginary = T()); complex(const complex bob); template <class Tl> complex(const complex<Tl> bob); Первая форма конструктора создает объект класса complex с вещественной составляющей (real) и мнимой частью (imaginary). По умолчанию эти значения, если они не заданы, устанавливаются равными нулю. Вторая форма создает копию комплексного числа ob. Третья создает комплексный объект из объекта ob. Для комплексных объектов определены следующие операции.
414 Классы арифметики комплексных чисел + - * / += /= *= Операторы, не выполняющие операцию присваивания, перегружаются для следующих трех видов операций: для операций, в которых объект класса complex участвует слева, а скалярный объект справа; затем для операций, в которых скалярный объект участвует слева, а объект класса complex справа, и наконец, для операций с двумя объектами класса complex. Например, разрешены следующие типы операций. complex_ob + скаляр скаляр + complex_ob complex_ob + complex_ob *^ Операции, включающие скалярные величины, оказывают воздействие только на вещественную составляющую. В классе complex определены две функции-члена: real () и imag(). Т real() const; Т imag() const; Функция real () возвращает вещественную составляющую вызывающего объекта, а функция imag () — мнимую. Для объектов класса complex также определены следующие функции. Функция-член Назначение template <class T> Возвращает абсолютное т abs (const complex<T> &о?>); значение объекта ob template <class T> Возвращает аргумент Т arg(const complex<T> bob); комплексного объекта ob template <class T> complex<T> Возвращает сопряжен- conj (const complex<T> bob); ную величину объекта ob template <class T> complex<T> Возвращает значение cos (const complex<T> &oi>) ; косинуса объекта ob template <class T> complex<T> Возвращает значениеги- cosh(const complex<T> bob); перболическогокосинуса объекта ob
Классы арифметики комплексных чисел 415 Функция-член Назначение template <class T> oomplex<T> ехр(const complex<T> bob); template <class T> T imag (const complex<T> Scob) ; template <class T> complex<T> log(const complex<T> Hob); template <class T> complex<T> loglO (const complex<T> &ob) ; template <class T> T norm (const complex<T> Scob) ; template <class T> complex<T> polar(const T &v, const T &fcheta=0); template <class T> complex<T> pow(const complex<T> &b, int e) ; template <class T> complex<T> pow(const complex<T> &b, const T &e); template <class T> complex<T> pow(const complex<T> &i>, const complex<T> &e); template <class T> complex<T> pow (const T &.b, const complex<T> &e) ; template <class T> T real (const complex<T> Scob) ; template <class T> complex<T> sin(const complex<T> bob); template <class T> complex<T> sinh(const complex<T> Hob); Возвращает значение ob e Возвращает мнимую составляющую объекта ob Возвращает значение натурального логарифма объекта ob Возвращает значение логарифма по основанию 10 объекта ob Возвращает значение модуля объекта ob Возвращает комплексное число, которое задано модулем v и аргументом theta Возвращает значение Ьв Возвращает значение Ье Возвращает значение Ье Возвращает значение Ьв Возвращает вещественную составляющую объекта ob Возвращает значение синуса объекта ob Возвращает значение гиперболического синуса объекта ob
416 Классы арифметики комплексных чисел Функция-член Назначение template <class T> complex<T> sqrt(const complex<T> bob); template <class T> complex<T> tan]const complex<T> &о?>); template <class T> complex<T> tanh(const complex<T> Lob); Возвращает значение квадратного корня из объекта оЬ Возвращает значение тангенса объекта оЪ Возвращает значение гиперболического тангенса объекта оЪ
Глава 18 Библиотечные средства, добавленные в версии С99 В стандарте С99 расширены возможности библиотеки языка С, причем это сделано двояким образом. Во-первых, добавлены новые функции в заголовки, ранее определенные в версии С89. Например, значительно расширена математическая библиотека, поддерживаемая заголовком <math.h>. Эти дополнительные функции описывались в предыдущих главах. Во-вторых, созданы новые категории функций, начиная поддержкой арифметики комплексных чисел и заканчивая макросами обобщенного типа, а также новые заголовки, предназначенные для поддержки таких функций. Эти новые библиотечные элементы и описываются в данной главе. Следует иметь в виду, что ни одно из рассматриваемых здесь средств не поддерживается языком C++. || Библиотека комплексных чисел | В версии С99 расширен язык С: теперь появилась возможность работать с комплексными числами. С самого начала важно отметить, что математическая библиотека комплексных чисел в версии С99 совершенно отличается от библиотеки классов комплексных чисел, определенной в языке C++. Если вы собираетесь программировать на языке C++, вам обязательно стоит использовать библиотеку комплексных чисел C++. Библиотека комплексных чисел версии С99 предназначена только для программистов, которые ограничены рамками языка С. Библиотека комплексных чисел версии С99 поддерживается заголовком «complex. h>. В нем определены следующие макросы. Макрос Расширение complex _Complex imaginary _Imaginary
418 Библиотека комплексных чисел Макрос Расширение _Complex_I (const float_Complex) i _Imaginary_I (const float imaginary) i I _Imaginary_I (или _Complex_I, если не поддерживаются мнимые типы) Здесь i представляет мнимое значение, которое равно квадратному Корню из -1. Поддержка мнимых типов необязательна. В версии С99 вместо ключевых слов complex и imaginary определены ключевые слова _Complex и „.Imaginary, поскольку во многих существующих программах С89 уже определены пользовательские типы комплексных данных с помощью имен complex и imaginary. Использование в версии С99 слов _Complex и ...Imaginary позволяет избежать нарушения работоспособности созданного ранее программного кода. Однако в новые программы лучше всего включить заголовок <complex.h>, а затем использовать макросы complex и imaginary. Ниже приведены математические функции, предназначенные для работы с комплексными числами. Обратите внимание на определение float complex-, double complex- и long double complex-версий для каждой функции. В float complex-версии используется суффикс f, а в long double complex-версии — суффикс 1. Следует также учитывать, что углы измеряются в радианах. Функция Назначение float cabsf(float complex arg) ; Возвращает абсо- double cabs(double complex arg); лютноезначение long double cabsl( параметра arg long double complex arg) ; float complex cacosff Возвращает ком- float complex arg); плексноезначение double complex cacos( арккосинуса от double complex arg); параметра arg long double complex cacos1( long double complex arg) ; float complex cacoshf ( Возвращает ком- float complex arg); плексноезначение double complex cacosh( гиперболического double, complex arg); арккосинуса от long double complex cacoshl( параметра arg long double complex arg);
Библиотека комплексных чисел 419 Функция Назначение float cargf(float complex arg); double carg(double complex arg); long double cargl( long double complex arg) ; float complex casinff float complex arg); double complex casin( double complex arg); long double complex casinl( long double complex arg); float complex casinhf( float complex arg); double complex casinhf double complex arg); long double complex casinhl( long double complex arg); float complex catanf( float complex arg); double complex catanf double complex arg); long dovible complex catanl ( long double complex arg); float complex catanhf( fldat complex arg); double complex catanh( double complex arg); long double complex catanhl( long double complex arg); float complex ccosf( float complex arg); double complex ccos( double complex arg); long double complex ccoslf long double complex arg) ; float complex ccoshf( ¦float complex arg) ; double complex ccosh( double complex arg) ; long double¦¦ complex ccoshl ( long double complex arg); Возвращает значение аргумента комплексного числа arg Возвращает комплексное значение арксинуса от параметра arg Возвращает комплексное значение гиперболического арксинуса от параметра arg Возвращает комплексное значение арктангенса от параметра arg Возвращает комплексное значение гиперболического арктангенса от параметра arg Возвращает комплексное значение косинуса от параметра arg Возвращает комплексное значение гиперболического косинуса от параметра arg
420 Библиотека комплексных чисел Функция Назначение float complex cexpf( float" complex arg) ; double complex cexp( double complex arg); long double complex cexpl( long double complex arg); float cimagf(float complex arg); double cimag(double complex arg), long double cimagl( long double complex arg); float complex clogf ( float complex arg); double complex clog( double complex arg); long double complex clogl( long double complex arg); float complex conjf( float complex arg); double complex conj( double complex arg); long double complex conjl( long double complex arg); float complex cpowf( float complex a, long double complex b); double complex cpowf double complex a, double complex b); long double complex cpowl( . ,. long double complex a, long double complex b); float complex cprojf( float complex arg); double complex cproj( double complex, arg),;. ,-,. , ¦• long double complex cproj1( long double complex arg) ; float crealf(float complex arg); double creal(double complex arg) long double creall( long double complex arg); Возвращает комплексное значение earer, где е — основание натурального логарифма Возвращает мнимую часть параметра arg Возвращает комплексное значение натурального логарифма от параметра arg Возвращает комплексно- сопряженное значение параметра arg Возвращает комплексное значение ь а Возвращает проекцию параметра arg на сферу Ри- мана Возвращает вещественную часть параметра arg
Библиотека вычислений с плавающей точкой 421 Функция Назначение float complex csinf( float complex arg); double complex csinf double complex arg); long double complex csinl( long double complex arg); float complex csinhf( float complex arg); double complex csinh( double complex arg); long double complex csinhl( long double complex arg); float complex csqrtf( float complex arg) ; double complex csqrt{ double complex arg); long double complex csqrtl( long double complex arg); float complex ctanf( float complex arg); double complex ctanf double complex arg); long double complex ctanl( - long double complex arg) ; float complex ctanhf( float complex arg); double complex ctanhf double complex arg); long double complex ctanhl( long double complex arg); Возвращает комплексное значение синуса от параметра arg Возвращает комплексное значение гиперболического синуса от параметра arg Возвращает комплексное значение квадратного корня из параметра arg Возвращает комплексное значение тангенса от параметра arg Возвращает комплексное значение гиперболического тангенса от параметра arg Библиотека вычислений с плавающей точкой В заголовке <fenv.h> версии С99 объявляются функции, которые имеют доступ к среде вычислений с плавающей точкой. Эти функции описаны ниже.
422 Библиотека вычислений с плавающей точкой Функция Назначение void feclearexcept(int ex); void fegetexceptflag( fexcept_t *fptr, int ex); void feraiseexcept(int ex); void fesetexceptflag( fexcept_t *fptr, int ex); int fetestexcept(int ex); int fegetround(void); int fesetround( int direction) void fegetenv( fenv_t *envptr) Очищает исключения, заданные параметром ex Сохраняет в переменной, адресуемой указателем fptr, состояние флагов исключений среды вычислений с плавающей точкой, заданное параметром ех Возбуждает исключения, заданные параметром ех Устанавливает флаги состояния исключений среды вычислений с плавающей точкой, заданные параметром ех, в соответствии с состоянием флагов в объекте, адресуемом параметром fptr Выполняет операцию поразрядного ИЛИ для исключений, заданных параметром ех, и текущих флагов состояния исключений среды вычислений с плавающей точкой. Возвращает результат этой операции Возвращает значение текущего направления округления Устанавливает значение текущего направления округления с помощью параметра direction. При успешном выполнении возвращается нуль Объект, адресуемый параметром envptr, принимает конфигурацию среды вычислений с плавающей точкой
Библиотека вычислений с плавающей точкой Л2У Функция Назначение int feholdexcept( fenv_t * envptr) , void fesetenv( fenv_t *envptr) void feupdateenv( : fenv_t *envptr) Вызывает безостановочную обработку исключения, возникшего при выполнении вычислений с плавающей точкой. Сохраняет конфигурацию среды вычислений с плавающей точкой в переменной, адресуемой параметром envptr, и очищает флаги состояния. При успешном выполнении возвращает нуль., • Устанавливает конфигурацию среды вычислений с плавающей точкой равной значению переменной, адресуемой параметром envptr, но не возбуждает исключения с плавающей точкой. Этот объект должен быть получен путем вызова либо функции f egetenv (), либо функции feholdexcept() Устанавливает конфигурацию среды вычислений с плавающей точкой равной значению переменной, адресуемой параметром envptr. Сначала сохраняет любые текущие исключения и возбуждает эти исключения после установки конфигурации среды в соответствии со значением переменной, адресуемой параметром envptr. Этот , объект должен быть получен путем вызова либо функции f egetenv (), либо функции f eholdexcept ()
424 Заголовок <stdint.h> Заголовок <fenv.h> также определяет типы fenv_t и f except_t, которые представляют конфигурацию среды вычислений с плавающей точкой и флаги состояния исключений среды вычислений с плавающей точкой соответственно. Макрос FE_DFL_ENV задает указатель на действующую по умолчанию конфигурацию среды вычислений с плавающей точкой, определяемую в начале выполнения программы. Определены также следующие макросы исключений, возникающих при работе с числами с плавающей точкой. FE_DIVBYZERO FE_INEXACT FE_INVALID FE_OVERFLOW FE_UNDERFLOW ' FE_ALL_EXCEPT Все комбинации этих макросов, полученные с помощью оператора ИЛИ, можно сохранять в объекте типа int. Определены и следующие макросы направления округления. FE_DOWNWARD FE_TONEAREST FE_TOWARDZERO FE_UPWARD Эти макросы определяют метод, используемый для округления значений. Для тестирования флагов среды вычислений с плавающей точкой необходимо установить специальную директиву для компилятора FENV_ACCESS. Разрешен ли доступ к этим флагам по умолчанию, зависит от конкретной реализации компилятора. Заголовок <stdint .h> II В заголовке <stdint .h> версии С99 не объявлено ни одной функции, но он определяет множество целочисленных типов и макросов. Целочисленные типы используются для объявления целых значений известного размера или значений, несущих информацию о некоторых специальных атрибутах. Макросы, имеющие вид intw_t, определяют целое значение длиной N бит. Например, макрос intl6_t задает 16- разрядное целое со знаком. Макросы, имеющие вид uintw_t, определяют целое значение без знака с N бит. Например, макрос uint32_t задает 32-разрядное целое без знака. Макросы, в имени которых N равно 8, 16, 32 или 64, будут доступны
; , -.. : Заголовок <stdint.h> 425 во всех средах, работающих с целыми числами перечисленных длин. Макросы, имеющие вид int_leastAf_t, определяют целое значение длиной не менее N бит. Макросы, имеющие вид uint^leastflLt, определяют целое значение без знака с не менее чем N бит. Макросы, в имени которых N равно 8, 16, 32 или 64, будут доступны во всех средах, работающих с целыми числами перечисленных длин. Например, макрос int_leastl6_t — это допустимый тип значения. Макросы, имеющие вид int_f astw_t, определяют самый быстродействующий целочисленный тип значения длиной не Л менее N бит. Макросы, имеющие вид uint_f astW_t, определяют самый быстродействующий целочисленный тип значения без знака с не менее чем N бит. Макросы, в имени которых N равно 8, 16, 32 или 64, будут доступны во всех средах, работающих с целыми числами перечисленных длин. Например, макрос int_fast32_t — это допустимый тип значения для всех известных сред. Тип intmax_t определяет целое значение максимальной длины со знаком, а тип uintmax_t — целое значение максимальной длины без знака. Также определены типы intptr_t и uintptr_t. Их можно использовать для создания целых значений, которые способны хранить-указатели. Эти типы необязательны. В заголовке <stdlnt. h> определен ряд макросов, вид которых подобен виду функций, которые расширяются до констант заданного целочисленного типа. Эти макросы имеют следующую общую форму. INTW_C(значение) UINTW_C(значение) Здесь N — длина в битах желаемого типа. Каждый макрос создает константу длиной не менее N бит, которая содержит заданное значение. Также в этом заголовке определены следующие макросы. INTMAX_C(значение) UINTMAX_C(значение) Они создают константы максимальной длины заданного значения.
426 Функции преобразования целого формата Функции преобразования целого формата В версии С99 добавлен ряд специализированных функций преобразования целочисленного формата, которые позволяют преобразовывать целые значения максимальной длины. Эти функции поддерживает заголовок <inttypes.h>, который включает заголовок <stdint.h>. Заголовок <inttypes.h> определяет один тип: структуру imaxdiv_t, которая хранит значение, возвращаемое функцией imaxdiv (). Ниже перечислены функции преобразования целых значений. Функция Описание intmax_t imaxabs( *¦¦¦¦¦¦¦-' : se ;. intmaxifc arg) ; imaxdiv_t imaxdiv( intmax_t numerator, intmax_t denominator); intmax_>t strtoimaxf const char * restrict start, char ** restrict end, int base); uintmax_t strtoumax( const char * restrict start, char ** restrict end, int base); intmax_t wcstoimax( const char * restrict start, char ** restrict end, int base); uintmax_t wcstoumax( const char * restrict start, char ** restrict end, int base); Возвращает абсолютное значение параметра агд Возвращает структуру imaxdiv_t, которая содержит результат numerator/denominator (числитель/знаменатель). Частное занимает поле quot, а остаток — поле rem. Как поле quot, так и поле rem имеют тип intmax_t < Версия функции strtol () для целочисленных параметров максимальной длины Версия функции strtoul () для целочисленных параметров максимальной длины Версия функции wcstolO для целочисленных параметров максимальной длины Версия функции wcstoul () для целочисленных параметров максимальной длины
Математические макросы обобщенного типа 427 В заголовке <inttypes.h> также определено множество макросов, которые можно использовать в вызовах функций семейств print f () и scanf () для задания различных целочисленных преобразований. Макросы функции print ? () начинаются с префикса PRI, а макросы функции scanf () ¦— с префикса SCN. За этими префиксами стоит такой спецификатор преобразования, как d или и, затем следует имя типа (например, N, MAX, PTR, РАЭТАГили LEASTW, где N задает количество битов). Точный список поддерживаемых макросов преобразования лучше всего узнать, обратившись к соответствующей документации на используемый вами компилятор. Математические макросы обобщенного типа В стандарте С99 определены три версии для большинства математических функций: одна — для параметров типа float, другая — для параметров типа double и третья — для параметров типа long double. Например, в стандарте С99 определены следующие функции для операции вычисления синуса. double sin( double arg); float sinf(float arg); long double sinlflong double arg); Все три функции выполняют одну и ту же операцию, разница лишь в типе принимаемых ими данных. Причем для всех функций версия, работающая с типом double,— это оригинальная функция, определенная в стандарте С89, a float- и long double-версии добавлены в стандарте С99. В именах float- версий используется суффикс f, а в именах long double- версий — суффикс 1. (Необходимость в применении различных имен вызвана тем, что язык С не поддерживает перегрузки функций.) Предоставляя три различные функции, стандарт С99 позволяет вызвать ту, которая более точно соответствует конкретным условиям. Как упоминалось выше в данной главе, по тем же причинам каждая из функций математики комплексных чисел также представлена тремя версиями. Несмотря на очевидную полезность наличия трех версий математических функций и функций комплексных чисел, работать с ними не совсем удобно. Во-первых, при передаче данных определённого типа нужно не забыть приписать к имени
428 Математические макросы обобщенного типа функции надлежащий суффикс. Это и утомительно, и повышает вероятность возникновения ошибок. Во-вторых, если в процессе разработки проекта изменить тип данных, передаваемых одной из таких функций, нужно не забыть изменить и суффикс в имени функции. А это, опять-таки, очень способствует "размножению" ошибок и действует угнетающе на самого программиста. Чтобы справиться с этими (и другими) проблемами, в стандарте С99 определен набор макросов обобщенного типа, которые можно использовать вместо математических или комплексных функций, Эти макросы автоматически выполняют преобразование в соответствующую функцию в зависимости от типа аргумента. Макросы обобщенного типа определены в заголовке <tgmath.h>, который автоматически включает заголовки <math. h> и <complex. h>. Для макросов обобщенного типа используются те же имена, что и для double-версий математических или комплексных функций, в которые они преобразуются. (Эти имена также совпадают с именами функций, определенными в стандарте, С89 и языке C++.) Следовательно, макрос обобщенного типа для функций sin (), sinf () и sinl () использует имя sin(). Макрос обобщённого типа для функций csin(), csinf () и csinl() также использует имя sin(). Как уже упоминалось, соответствующая функция вызывается в зависимости от типа аргумента. Например, в программе определены следующие переменные. long double Idbl ; float complex fcmplx; ¦•: Тогда вызов cos (Idbl) ¦-. . ¦<¦ преобразуется в вызов cosl(ldbl), а вызов cos(fcmplx) преобразуется в вызов ccosf(fcmplx). Как проиллюстрировано в приведенных выше примерах, использование макросов обобщенного типа предоставляет про-
Заголовок <stdbool.h> 429 граммисту на С удобство без потери производительности, точности или совместимости (переносимости) программного кода. ПРИМЕЧАНИЕ. Если вы программируете на языке C++, в использовании макросов обобщенного типа нет никакой необходимости, поскольку язык C++ предоставляет перегруженные версии математических и комплексных функций. I Заголовок < s tdbool. h> ~J| В стандарт С99 добавлен заголовок <stdbool .h>, который поддерживает тип данных _Воо1. Хотя в нем не определено ни одной функции, он определяет следующие четыре макроса. Макрос bool true false bool_true_false are_defined Расширение _Bool 1 0 1 В версии С99 вместо ключевого слова bool определено ключевое слово _Воо1, поскольку во многих существующих С-программах уже определены собственные пользовательские версии типа bool. Определение в версии С99 булева типа в виде ключевого слова _Воо1 позволяет избежать нарушения работоспособности созданного ранее программного кода. То же объяснение касается ключевых слов true и false. Однако при написании новых программ лучше всего включить в них заголовок <stdbool .h>, а затем использовать макросы bool, true и false. В этом случае вы сможете создавать программы, совместимые с языком C++.
#define, 79 #elif, 82 #else, 81 #error, 81 #if, 81 #ifdef, 81 #if ndef, «2 #include, S3 #line, S4 #pragma, 85 #undef, 86 cplusplus, 88 _J)ATE__,88 FILE ,84 LINE ,84 __STDC ,88 __STDC_HOSTED , 89 __STDCJEC_559 ,89 __STDC_lEC 559 COMPLEX _,89 __STDC_ISO_10646__, 89 _ _STDC_VERSION , 89 TIME__,88 __VA_ARGS__,00 _Bool, 21; 40; 93; 429 „Complex, 21; 95; 418 _Exit(), 240 „Imaginary, 21; 104;, 418 _Pragma, 85 A abort(), 236 abs(), 236 acos(), 210 acos(), acosf() и acoslQ, 186 acosh(), acoshf() и acoshl(), 187 adaptor, 333 adjacent_find, 366 allocator, 331 asctimeO, 218 asin(), 210 asin(), asinf() и asinl(), 187 asinh(), aslnhf() и asinhl(), 187 asm, 92 assert(), 236 &tan{),210 atan(), atanf() и atanl(), 188 atan2(), 211 atan2(), atan2f() и atan21(), 189 atanh(), atanhf() и atanhl(), 188 atexit(), 237 atof(), 237 atoi(), 238 atol(), 238 atoll(), 239 auto, 33; 92 В bad(), 277; 310 binary_search, 366 Binder, 333 bitset, 336 bool, 22; 92 break, 93 bsearchO, 239 btowc(), 268 С calloc(),232 case, 94 catch, 94; 123 cbrt(), cbrtf() и cbrtlQ, 1,89 ceil(), 211 ceil(),ceilf()Hceill(), 189 cerr, 273 char, 21; 22; 94 cin, 273 class, 29; 94 clear(), 277; 310 clearerrO, 132 c\oc\l(),218 clog, 273 const, 35; 95 const_cast, 72; 96 continue, 96 copy, 367 copy_backward, 367 ¦'¦
copysign(), copysignf () и copysignl(), 190 cos(), 211 cos(), cosf() и cosl(), 190 cosh(), 212 cosh(), coshf() и coshl(), 190 count, 367 count_if, 367 cout, 273 CPU, 112 ctime(), 219 С-строка, 393 D default, 96 define, 82 delete, 97 deque, 339 difftime(), 219 div(), 240 do, 97 double, 21; 22; 97 dynamic_cast, 72; 98 E eatwhiteO, 277 else»98 enum, 32; 98 eoi(),278;310 equal, 368 equal_range(), 368 erf(),erff()Herfl(), 191 erfc(), erfcf() и erfcl(), 191 exceptions(), 311 exit(), 24V EXIT_FAILURE, 240 EXrr_SUCCESS, 240 expQ,212 exp(),expf()Hexpl(), 191 exp2(), exp2f() и ехр21(), 192 explicit, 56; 99 expml(), expmlf () и expmll(), 192 export, 99 extern, 33; 57; 99 F fabsO, 212 fabs(), fabsf() и fabsl(), 193 lailQ, 278; 311 false, 40; 100; 429 fclose(), 133 fdim(), fdimf () и fdiml(), 193 feof(), 133 ferror(), 134 fflush(), 134 fgetc(), 135 fgetpos(), 135 fgets(), 136 fgetws(), 262 НПО, 278; 311:369 < fill_n, 369 find, 369 find_end, 369 find_first_of, 370 ,': find_if, 370 i flags(), 279; 312 ПоеЛ, 21; 22; 100 floor(), 212 floor(), floorf() и floorlO, 193 flush(), 279; 312 fma(), fma() и f ma(), 194 fmax(), fmaxf() и fmaxl(), 194 fmin(), fminf() и fminl(), 194 fmod(), 2/3 fmod(), fmodf() и fmodl(), 195 fopen(), 136 ¦ FOPEN_MAX, 139; 163 for, 100 for_each, 371 fprintf(), 139 fputc(), /39 fputs(), 140 fputwc(),262 fputwsO, 262 fread(), 141 free(), 232 freopen(), 141 frexp(), 213 frexpO, frexpf() и frexpl(), 195 friend, 101 fscanf(), 142 fseek(), 142 fsetpos(), 143 fstreamO, 279; 313 ftell(), 144 fwide(), 264 fwprintfO, 262 fwrite(), 144 fwscanf(), 262
G gcount(), 281,314 generate, 371 generate_n, 371 getQ, 281; 314 getc(), 145 getchar(), 145 getenv(), 241 getline(), 282; 315 gets(), 146 getwc(), 262 getwchar(), 262 gmtime(), 220 good(), 283; 316 goto, 101 H HUGEJVAL, 185; 250 HUGE_VALL, 252 hypot(), hypotf() и hypotl(), 195 I if, 103 ifstream(), 2 79; 313 ignore(), 283; 316 ilogb(), ilogbf() и ilogbl(), 196 includes, 371 inline, 56; 104 inplace_merge, 372 int, 21; 22; 105 iostream, 271 isalnum(), 168 isalpha(), 168 isblank(), 168 iscntrlO, 169 isdigit(), 169 isgraph(), 169 islower, / 70 isprint(), 170 ispunctO, / 70 isspace(), / 70 istringstream(), 325 istrstream(), 293 isupper(), 171 isxdigit(), 171 iterswap, 372 L " labs(), 241 ldexp(), 213 ldexp(), ldexpf() и ldexpl(), 196 ldiv(), 242 lexicographical_compare, 373 lgamma(), lgammaf() и lgammal(), 197 list, 342 llabs(), 242 lldiv(), 242 LLONG_MAX, 252 LLONGJVHN, 252 llrint(), llrintf()Hllrintl(), 197 llround(), llroundf() и llroundl(), 197 localeconv(), 220 localtimeO, 223 log(), 214 log(), logf() и logl(), 198 loglO(), 214 loglOO, loglOf() и Iogl01(), 198 loglp(), loglpf() и loglpl(), 198 Iog2(), Iog2f() и Iog21(), 199 logb(), logbf() и logbl(), 199 long, 22; 105 long double, 23 long int, 23 long long int, 23 LONG_MAX, 251 LONGJMIN, 251 longjmp(), 243 lower_bound, 373 lrint(), lrintf () и lrintlO, 200 lround(), lroundf() и Iroundl(), 200 M make_heap, 374 malloc(), 233 map, 346 max, 374 max_element, 374 MB_CUR_MAX, 244; 257 mblen(), 244 mbrlenO, 269 mbrtowcO, 269 mbsinit(), 269 mbsrtowcsO, 270 mbstowcs(), 244 mbtowc(), 245 memchrO, 171 memcmpO, / 72 memcpyO, 172 memmoveO, 173
memset(), 173 merge, 375 min, 375 min_element, 375 mismatch, 376 mktime, 223 modf(), 214 modf(), modff() и modfl(), 200 multimap, 350 multiset, 353 mutable, 33; 105 N namespace, 31; 50; 105 nan(), nanf() и nanl(), 201 nearbyint(), nearbyintf () и nearbyintl(), 201 negator, 333 new, 107 r next_permutation, 376 nextafter(), nextafterf() и nextafterl(), 202 nexttoward(), nexttowardf() и nexttowardlO, 202 npos, 395 nth_element, 377 NULL, 163; 235 О ofstreamO, 279; 313 open(), 284; 317 operator, 77; 108 ostringstreamO, 325 ostrstreamO, 293 overload, 91 P partial_sort, 377 partial_sort_copy, 378 partition, 378 peek(), 287; 318 perrori(), 146 POD, 32 pop_heap, 379 pow(), 215 pow(), powf() и powl(), 203 precision(), 287; 318 predicate, 331 prev_permutation, 379 printfO, 148 priorityqueue, 356 private, 109 protected, 27; 110 public, 26;/Л pushjheap, 380 put(), 288; 320 putback(), 288; 321 putc(), 152 putchar(), 153 puts(), 153 putwc(), 262 putwchar(), 262 Q qsort(), 245 queue, 355 Quicksort, 245 R raise(), 246 rand(), 247 RAND_MAX, 247 random_shuffle, 380 rdstate(), 288; 321 read(), 289; 322 readsome(), 322 reallocO, 233 register, 33; 112 reinterpret_cast, 72; 112 remainderO, remainderf() и remainderlO, 203 removeO, 154; 380 remove_copy, 380 .. ¦ ; remove_copy_if, 380 remove_if, 380 remquo(), remquof () и remquol(), 203 renameX), 154 replace, 381 replace_copy, 381 replace_copy_if, 381 replace_if, 381 restrict, 113; 132 return, 114 reverse, 382 reverse_copy, 382 rewind(), 154 rint(), rintf() и rintl(), 204 rotate, 383 rotate_copy, 383 round(), roundf() и roundl(), 204
s scalbln(), scalblnf() и scalblnK), 205 scalbn(), scalbnf () и scalbnl(), 205 setud(),154 - Scanset, 158 search, 383 search_n, 384 seekg(), 289; 322 seekp(), 289; 322 set, 357 set_difference, 384 set_intersection, 385 set_symmetric_difference, 385 set_union, 386 setbuf(), 160 settQ.291,324 setjmp{), 247 setlocale(), 225 setmode(), 292 setstate(), 325 setvbuf(), 109 short, 22; 114 short int, 23 SIG_ERR, 248 signalO, 248 signed, 22; 115 signed char, 23 signed int, 23 signed long int, 23 signed long long int, 23 signed short int, 23 sin(), 215 sin(), sinf() и sinl(), 206 sinh(), 215 sinh(), sinhf() и sinhl(), 206 sizeof, 72; 115 snprintJfO, 161 sort, 387 eort_heap, 387 sprintf(), 161 sqrtO, 216 sqrt(), cqrtf () и cqrtl(), 206 srand(), 249 sscanfO, 162 stable_partition, 387 stable_sort, 388 stack, 360 Standard Template Library, 60 static, 31; 33; 50; 115 static_cast, 72; 116 std, 61; 271 STL, 60; 329 str(), 292; 325 i ,,.. strcat(), 173 strchrO, 174 strcmpO, 174 strcolK), 174 strcpyO, 175 л . strcspn(), 175 :; iJ strerror(), 176 ¦•¦ ¦-. strftimeO, 226 stringstream(), 325 ¦•-.¦: strlen(), i 76 strncat(), 176 strncmpO, 177 strncpyO, 177 ¦ ' - ¦ strpbrk(), 178 ! strrchr(), i 78 strspn(), 179 strstr(), 179 strstream(), 293 strtodO, 249 strtof (), 250 strtokO, 179 strtolO, 250 strtoldO, 251 strtollO, 252 strtouK), 252 strtoullO, 253 struct, 29; 116 strxfrmO, 180 swap, 388 swapranges, 388 switch, 117 swprintfO, 262 swscanfO, 263 sync_with_stdio(), 294; 326 system(), 254 T tan(), 216 tan(),tanf() и tanl(), 207 tanh(), 216 tanh(), tanhf() и tanhl(), 207 tellg(), 294; 327 tellpO, 294; 327 template, 27; 99; 118 tgamma(), tgammaf() и tgammal(), 207 this, 101; 109; 123
throw, 123 time(), 229 TMPJMAX, 163 tmpfileO, 163 tmpnam(), 163 tolower(), 182 toupper(), 182 transform, 388 true, 40; 126; 429 trunc(), truncf() и trunclQ, 208 try, 123; 126 typedef, 38; 126 typeid, 126; 411 typename, 127 и ULLONG_MAX, 253 ULONG_MAX, 253 ungetc(), 164 ungetwc(), 263 union, 30; 127 unique, 391 unique_copy, 39/ unsetf(), 295; 327 unsigned, 22; 128 unsigned char, 23 unsigned int, 23 ,. unsigned long int, 23 unsigned long long int, 23 unsigned short int, 23 upper_bound, 391 using, 61; 106; 128 '¦'¦' XJTC, 220; 228 V va_arg(), 254 va_copy(), 254 ' ¦ va_end(), 254 va_start()( 254 vector, 361 vfprintf(), 164 vfscanf(), 165 vfwprintf(), 263 ,,, vfwscanf(), 263 '""' virtual, 56; 128 void, 21; 22; 48; 129 volatile, 35; 129 vprintf(), 164 vscanf(), 165 vsnprintfO, 164,, ,,.,.,,. vsprintfO, 164 T-\ 'j\v\ [¦¦¦¦'¦-'.¦-. vsscanf(), 165 vswprintf(), 263 vswscanf(), 263 vwprintf(), 263 vwscanf(), 263 w wchar_t, 22; 130 wcrtombO, 270 wcscaM), 264 wcschrO, 264 wcscmp(), 264 wcscolK), 264 wcscpyO, 265 wcscspn(), 264 wcsftime(), 266 wcslenO, 265 wcsncatO, 265 ,. wcsncmpO, 265 wcsncpy(), 265 wcspbrk(), 265 wcsrchrO, 265 wcsrtombs(), 270 wcsspn(), 265 wcsstr(), 266 wcstodO, 266 wcstof(), 266 wcstokO, 265 wcstol(), 267 wcstold(), 266 wcstollO, 267 ; wcstombs(), 256 ! wcstoulO, 267 wcstoull(), 267 wcsxfrmO, 266 wctobQ, 270 wctomb(), 257 WEOF, 259 while, 130 width(), 295; 328 wmemchrO, 267 wmemcmp{), 267 wmemcpyO, 268 wmemmove(), 268 wmemsetO, 268 wprintf(), 263 writeO, 296; 328 wscanf(), 263 A Абстрактные классы, 129 -: i: :
Адаптер, 333 Алгоритм adjacent_find(), 366 binary_search(), 366 сору(), 367 copy_backward(), 367 count(), 367 count_if{), 368 equal(), 368 equal_range(), 368 fill(), 369 fill_n(), 369 find(), 369; 370 find_end(), 370 flnd_firat_of(), 370 for_each(), 371 generate(), 371 generate_n(), 371 includes(), 372 inplace_merge{), 372 iter_swap(), 372 lexicographical_compare(), 373 lower_bound(), 373 makeheapQ, 374 max(), 374 max_element(), 374 merge(), 375 min(), 375 min_element(), 376 mismatchO, 376 next_permutation(), 377 nth_element(), 377 partial_sort(), 377 partial_sort_copy(), 378 partitionO, 378 popJieapO, 379 prev_permutation(), 379 push_heap(), 3*0 random_shuffle(), 380 removeO, 381 remove_copy(), 381 remove_copy_if(), 381 remove_il(), 381 replace(), 382 replace_copy(), 382 replace_copy_if(), 382 replace_if(), 382 reverseO, 382 reverse_copy(), 382 rotate(), ЗвЗ rotate_copy(), 383 search(), 383 search_n(), 384 set_differenceO, 385 set_intersection(), 385 set_symmetric difference(), 386 set_union(), 386 sortQ, 387 sort_heap(), 387 stablejjartitionO, 387 stable_sort(), 388 swap(), 388 swap_ranges(), 388 transform(), 389 unique(), 391 unique_copy(), 391 upper_bound(), 392 быстрой сортировки Quicksort, 245 Алгоритмы, 330; 3