Открыть Электронные книги
Категории
Открыть Аудиокниги
Категории
Открыть Журналы
Категории
Открыть Документы
Категории
Архангельский
O+Builder 6
СПРАВОЧНОЕ ПОСОБИЕ
Книга 1
Язык C++
Москва
ЗАО «Издательство БИНОМ»
2002
УДК 004.43
ББК 32.973.26-018.1
А87
Архангельский А.Я.
C++Builder 6. Справочное пособие. Книга 1. Язык C++. -- М.: Бином-
Пресс, 2002 г. — 544 с.: ил.
В книге даются исчерпывающие справочные сведения по языку C++ в
C++Builder 6: синтаксис языка, все операции и операторы, все типы данных. Подроб-
но рассматривается работа с исключениями, с текстовыми и двоичными файлами, со
строками разных типов, массивами, множествами, структурами, классами. Обсуждает-
ся обработка и генерация сообщений Windows. Рассматривается около 650 функций С,
C++, API Windows, из них более 300 с подробными описаниями и примерами.
Рассматривается стандартная библиотека шаблонов STL: все типы контейнеров,
итераторов, все алгоритмы и функции-объекты.
Представленный в книге справочный материал снабжен подробными коммента-
риями и примерами, что позволяет читателю изучать его практически с нуля.
Как справочник книга полезна пользователям любой квалификации: от начинаю-
щих до опытных разработчиков.
WM_CANCELMODE .228
WM_CLOSE 228
WM_GETMINMAXINFO 228
WM_GETTEXT 229
WM_SETFONT 230
WM_SETTEXT 230
3.1.6 AnsiString — тип строк 231
3.1.7 Тип данных TDateTime 235
3.1.8 TStringFloatFormat - тип 236
3.2 Математические функции 237
3.2.1 Константы, используемые в математических выражениях 237
3.2.2 Арифметические и алгебраические функции 238
3.2.3 Тригонометрические функции 241
3.2.4 Генерация псевдослучайных чисел 243
3.2.5 Функции обработки статистических данных 244
3.2.6 Функции управления FPU 246
3.3 Преобразование типов данных 247
3.3.1 Функции взаимного преобразования чисел и строк 247
3.3.1.1 Функции взаимного преобразования чисел и строк типа char * 247
3.3.1.2 Функции взаимного преобразования чисел и строк,
описанные в файле SysUtils.hpp 249
3.3.2 Функции преобразования дат и времени . : 252
3.3.3 Функции преобразования типов 261
3.4 Строки и символы 262
3.4.1 Функции обработки символов 262
3.4.2 Функции обработки строк 264
3.4.2.1 Функции работы с областями памяти и строками 264
3.4.2.2 Функции обработки строк с нулевым символом в конце 265
3.4.2.3 Функции обработки строк типа AnsiString 272
3.5 Потоки и файлы 275
3.5.1 Атрибуты и флаги файлов, стандартные файлы 275
3.5.2 Управление потоками и файлами, описываемыми структурами FILE . . . 277
3.5.3 Управление потоками и файлами, связанными с дескрипторами . . . . 281
3.5.4 Функции ввода/вывода 284
3.5.5 Функции обработки имен файлов 290
3.5.6 Управление каталогами и файлами на дисках 293
3.6 Управление процессами 302
3.6.1 Функции управления текущим процессом 302
3.6.2 Функции выполнения порождаемых процессов 304
3.6.3 Сообщения об ошибках при запуске внешних програм 306
3.7 Функции различного назначения 307
3.7.1 Функции динамического распределения памяти 307
3.7.2 Функции вызова диалоговых окон с сообщениями 311
3.7.3 Функции воспроизведения звуков 314
3.7.4 Некоторые вспомогательные функции C++и C++Builder 317
3.7.5 Некоторые вспомогательные функции API Windows 322
3.8 Работа с сообщениями Windows 323
Глава 4. Описания функций 325
abort — функция завершения выполнения 325
Abort — функция генерации исключения 325
abs и другие функции вычисления модуля 326
AnsiCompareStr и другие функции сравнения строк 326
AnsiCompareText —сравнение строк без учета регистра 327
AnsiLowerCase и другие функции преобразования строки к нижнему регистру 327
AnsiPos и другие функции поиска подстроки 328
AnsiStrComp — сравнение строк 329
AnsiStrlComp — сравнение строк 330
AnsiStrLower — преобразование строки к нижнему регистру 331
AnsiStrPos — поиск подстроки 331
AnsiStrUpper — преобразование строки к верхнему регистру 331
Содержание 9
// функция main
WINAPI WinMain (HINSTANCE, HINSTANCE, LPSTR, int)
try
Application->Initialize () ;
Application->CreateForm( _ classid (TForml) , SForml)
20 Глава 1
а
,.4 .
типа TButton). Подробные комментарии в этом тексте поясняют, куда и что в этот
код вы можете добавлять.
Заголовочный файл:
//
tfifndef UnitlH
#define UnitlH
//
#include «Classes.hpp>
#include <Controls.hpp>
tinclude <StdCtrls.hpp>
#include <Forms.hpp>
// сюда могут помещаться дополнительные директивы
// препроцессора (в частности, include),
// не включаемые в файл автоматически
//
// объявление класса формы TForml
class TForml : public TForm
{
published: // IDE-managed Components
// размещенные на форме компоненты
TButton *Buttonl;
TLabel *Labell;
void fastcall ButtonlClick(TObject *Sender);
Заголовочный файл:
//
#ifndef UnitlH
tfdefine UnitlH
// , .
#include <Classes.hpp>
tinclude <Controls.hpp>
tinclude <StdCtrls.hpp>
tinclude <Forms.hpp>
//
class TForml : public TForm
{
published: // IDE-managed Components
TLabel *Labell;
TButton *Buttonl;
void fastcall ButtonlClick(TObject *Sender);
tpragma hdrstop
#include "Unitl.h"
//
tpragma package(smart_init)
#pragma resource "*.dfm"
TForml *Forml;
//
fastcall TForml::TForml(TComponent* Owner)
: TForm(Owner)
{
}
//
// Глобальная переменная Ch3 и функция F4 доступны в пределах
// данного модуля; переменная СЬЗ доступна в других модулях,
// если определена там со спецификацией extern;
// функция F4 доступна в других модулях, если там содержится
// ее прототип
char Ch3;
void F4(char Ch)
f
Forml->Labell->Caption = Forml->Labell->Caption + Ch +
Forml->Chl;
)
// . ,
void fastcall TForml::Fl(char Ch)
{
Labell->Caption = Labell->Caption + Ch + Chi;
}
//
void f a s t c a l l T F o r m l : : F 2 ( c h a r Ch)
{
Labell->Caption = Labell->Caption + Ch + Chi;
)
//
шем примере Ch2 и Ch3) так и остаются в одном экземпляре. А переменные, опи-
санные в классе (в нашем примере СЫ), тиражируются столько раз, сколько объ-
ектов данного класса создано. Т.е. в каждом объекте класса TForml будет своя пе-
ременная Chi, и все они друг с другом никак не будут связаны. Таким образом,
в переменную, описанную внутри класса, можно заносить какую-то информацию,
индивидуальную для каждого объекта данного класса. А переменная, описанная
в модуле вне описания класса, может хранить только одно значение.
Отметим без детальных пояснений еще одну особенность, которую вы уже, ве-
роятно, заметили в приведенных текстах файлов. Перед именами функций-эле-
ментов класса ставится опция компилятора fastcall. He вдаваясь в детали, ска-
жем, что эта опция влияет на процесс компиляции и обеспечивает передачу пара-
метров функции в быстрые регистры, что ускоряет вызов функции. Для функ-
ций-элементов классов эту опцию следует указывать всегда. Для других функций
ее можно указывать, а можно и не указывать. Впрочем, эту опцию целесообразно
указывать и для функций, не являющихся элементами класса (в приведенном
примере это не сделано, просто чтобы подчеркнуть различие между функция-
ми-элементами и прочими функциями).
В заключение просуммируем изложенные правила.
• В реализацию функций-элементов должна добавляться ссылка на класс с по-
мощью операции разрешения области действия (::).
• Функции-элементы объявляются и описываются с применением опции компи-
лятора fastcall.
• В функциях-элементах обращение к другим функциям-элементам и дан-
ным-элементам того же класса может осуществляться без указания на объект.
• В функциях, не являющихся элементами класса данного объекта, доступ
к функциям-элементам (методам) и данным-элементам (свойствам) осуществ-
ляется через указатель на объект с помощью операции стрелка (—>) или (зна-
чительно реже) с помощью разыменования указателя на объект и операции
точка (.).
Рис. 1.2
Окно компиляции и компоновки
| Project DA..Л
[Compiling: Untt2.<
Cancel
Это, конечно, удобно, но не всегда. Дело в том, что фоновая компиляция осуществ-
ляется медленнее. Кроме того, по завершении компиляции в фоновом режиме
окно компилятора исчезает, и при этом не показываются результаты компиляции:
прошла ли она успешно, или имеются замечания. Поэтому, если у вас нет каких-то
работ в ИСР, которые можно выполнять во время компиляции, лучше отключить
фоновый режим компиляции. Это можно сделать, выполнив команду Tools | Environ-
ment Options и выключив на странице Preferences опцию Background Compilation.
Если фоновый режим компиляции отключен, то после окончания компиля-
ции рассмотренными командами (кроме Run) в окне рис. 1.2.во второй строке появ-
ляется одно из трех итоговых сообщений: "Done: Make" "Результат: выполне-
но", "Done: There are errors" "Результат: имеются ошибки", "Done: There are
warnings" "Результат: имеются предупреждения".
Более подробные сведения о компиляции и компоновке проектов в C++Builder
и рекомендации по настройке и ускорению этих процессов вы найдете в книге [1].
-
Справочные данные по языку C++ 35
double circ(double x)
{
return 3.14159 * x * x;
)
и вызывать ее оператором:
S = circ(a + Ь);
Таким образом, возникает вопрос, что выгоднее использовать: макросы или
функции.
Вызов функции сопряжен с накладными расходами и затягивает выполнение
программы. Это соображение работает в пользу использования макросов. С другой
стороны, макрос расширяется во всех местах текста, где используется его вызов.
Если таких мест в программе много, то это увеличивает размер текста и, соответст-
венно, размер выполняемого модуля. Так что функции позволяют сокращать объ-
ем выполняемого файла, а макросы — сокращать скорость выполнения. Правда,
макросы тоже могут быть связаны с дополнительными накладными расходами.
В приведенном примере значение параметра а + Ъ вычисляется дважды, в то вре-
мя, как в функции это вычисление осуществляется только один раз. Конечно, для
таких простых вычислений это не существенно. Но если в качестве параметра пе-
редается сложное выражение, обращающееся в свою очередь к каким-нибудь
сложным функциям, то эти дополнительные накладные расходы могут стать за-
метными и затянуть вычисления.
Недостатком макросов является отсутствие встроенного контроля согласова-
ния типов аргументов и формальных параметров. Отсутствие соответствующих
предупреждений компилятора может приводить к ошибкам программы, которые
трудно отлавливать. Но наиболее существенный недостаток макросов — возмож-
ность появления побочных эффектов, если в качестве аргумента в макрос переда-
ется некоторое выражение. Например, если описанный выше макрос CIRC, вычис-
ляющий площадь круга, вызвать следующим образом:
S = CIRC(a++)
предполагая рассчитать площадь и затем операцией постфиксного инкремента (см.
разд. 1.9.2) увеличить радиус на 1, то макрос будет расширен так:
S = (3.14159 * (а++) * ( а + + ) ) ;
При этом площадь будет вычислена верно, но постфиксный инкремент вычис-
лится два раза. В результате значение радиуса а будет увеличено не на 1, а на 2.
Если же это макрос вызвать следующим образом:
S = CIRC(++a)
предполагая увеличить радиус на 1 и вычислить площадь круга с таким увеличен-
ным радиусом, то макрос будет расширен так:
S = (3.14159 * (++а) * ( + + а ) ) ;
При этом площадь будет определена неверно, так как в процессе вычислений
радиус будет увеличен дважды и выражение окажется эквивалентным следующему:
S = (3.14159 * (а + 1) * (а + 2 ) ) ;
Всех этих побочных эффектов не будет, если вместо макроса использовать опи-
санную выше функцию circ.
При выборе реализации вычислений функцией или макросом надо обеспечи-
вать компромисс между скоростью вычислений и затратами памяти. Для неболь-
ших функций, возможно, наилучшим решением является применение встраивае-
мых функций (inline — см. разд. 1.7.6). Для них проблемы оптимальной реализа-
ции решает компилятор, и делает это он, вероятно, не хуже нас с вами.
36 Глава 1
tundef MyConst
// Здесь константу MyConst использовать нельзя
#define MyConst 64
// Здесь константа MyConst равна 64
#endif
и
#if defined Size
... I
#endif
эквивалентны.
Можно использовать более сложные конструкции условных директив препро-
цессора при помощи директив #elif (эквивалент else if в обычной структуре if)
и #else (эквивалент else в структуре if). Например, в коде
#if условие 1
фрагмент кода 1
#elif условие 2
фрагмент кода 2
#else
фрагмент кода 3
#endif
фрагмент кода 1 будет компилироваться, если выполняется условие 1, фрагмент
кода 2 будет компилироваться, если выполняется условие 2, а фрагмент кода 3 бу-
дет компилироваться, если не выполняется ни одно из предыдущих условий.
Условная компиляция может быть полезна во многих случаях. Например, не-
редко в процессе отладки приложения в него полезно ввести различные отладоч-
ные печати, позволяющие следить за ходом выполнения программы. Если вы не
хотите, чтобы эти печати оставались в окончательном варианте программы, вы мо-
жете в разных местах приложения ввести конструкции вида
#ifdef Debug
операторы отладки
#endif
Тогда, если в начале программы вы введете директиву
#define Debug
операторы отладки будут компилироваться и выполняться. Но когда вы уберете
или закомментируете эту директиву #define, определяющую введенный вами
идентификатор Debug, все операторы отладки исчезнут из текста. Можно посту-
пить даже проще, ничего не изменяя в тексте, а оперируя опцией Conditionals на
странице Directories/Conditionals диалогового окна, вызываемого командой Project
Options.
Конечно, вы могли бы поступить иначе: ввести переменную булева типа
Debug, задать ей в начале выполнения приложения значение true и оформлять от-
ладки следующим образом:
#if (Debug)
(
операторы отладки
}
Если в дальнейшем заменить задаваемое значение Debug на false, то операто-
ры отладки перестанут выполняться. Отличие этого подхода от использования ди-
ректив препроцессора заключается в том, что коды операторов отладки в этом слу-
38 Глава 1
A n s i S t r i n g Ыате="Неизвестный";
void f 1 ( v o i d )
(
if (! InputQuery("Пожалуйста, представьтесь",
"Укажите, как в дальнейшем обращаться к Вам", Name))
ShowMessage("Вы не представились, господин неизвестный");
else ShowMessage("Здравтвуйте, господин " + Name + " !");
}
void f2(void)
(
ShowMessage("Начало работы");
}
Выполните это приложение. Вы увидите, что прежде, чем откроется его глав-
ная форма, будет вызвана функция fl и пользователю будет показано диалоговое
окно с просьбой представиться. Вид этого окна вы можете посмотреть в гл. 4 в опи-
сании функции InputQuery. Введенное пользователем имя записывается в гло-
бальную переменную Name и может использоваться при выполнении программы
для формирования обращений к пользователю.
После вызова fl последует вызов функции f2, сообщающей о начале работы,
и только после этого пользователь увидит главную форму приложения.
Если вы замените директиву вызова f 1 на
#pragma startup fl 101
то сначала будет вызвана функция f2, имеющая по умолчанию приоритет 100,
и только после этого вызовется функция fl.
Справочные данные по языку C++ 41
1.5 Константы
1.5.1 Неименованные константы
Константы могут использоваться непосредственно в тексте программы в лю-
бых операторах и выражениях. Имеется 4 типа констант: целые, с плавающей за-
пятой, символьные (включая строки) и перечислимые. Например: 25 и -5 — целые
константы, 4.8, 5е15, 5Е15, -5.1е8 — константы с плавающей запятой, 'А', '\0',
'\п', '007' — символьные константы, "Это строка" - строковая константа.
Целые константы могут быть десятичные, восьмеричные и шестнадцатерич-
ные. Восьмеричные начинаются с символа нуля, после которого следуют восьме-
ричные цифры (от 0 до 7). Например: 032. Запись константы вида 08 будет воспри-
нята как ошибка, поскольку 8 не является восьмеричной цифрой. Восьмеричные
константы не могут превышать значения 037777777777. Значения, большие этой
величины, усекаются.
Шестнадцатеричные константы начинаются с символов нуля и X или х, после
которых следуют Шестнадцатеричные цифры (от 0 до F, можно записывать в верх-
нем или нижнем регистрах). Например: OXF01. Шестнадцатеричные константы не
могут превышать значения OxFFFFFFFF. Значения, большие этой величины, усека-
ются.
Символьные константы должны заключаться в одинарные кавычки. Эти кон-
станты хранятся как char, signed char или unsigned char.
Строковые константы заключаются в двойные кавычки. Они хранятся как по-
следовательность символов, завершающаяся нулевым символом '\0'. Пустая стро-
ка содержит только нулевой символ.
Если две строковые константы разделены в тексте только пробельным симво-
лом, они склеиваются в одну строку. Например:
"Это начало строки, " "а это ее продолжение"
ИЛИ
42 _ Глава 1
1.6 Переменные
1.6.1 Объявление переменных
Переменная является идентификатором, обозначающим некоторую область
в памяти, в которой хранится значение переменной. Это значение может изме-
няться во время выполнения приложения.
Объявление переменной имеет вид:
тип список идентификаторов_переменных;
Список идентификаторов может состоять из идентификаторов переменных,
разделенных запятыми. Например:
int x l , х2;
Одновременно с объявлением некоторые или все переменные могут быть ини-
циализированы. Например:
int xl = 1, х2 = 2;
Для инициализации можно использовать не только константы, но и произ-
вольные выражения, содержащие объявленные ранее константы и переменные.
Например:
int xl = 1, х2 = 2 * xl;
Объявление переменных может быть отдельным оператором или делаться
внутри таких операторов, как, например, оператор цикла:
for ( int i = 0; i < 10; i++)
1.7 Функции
1.7.1 Объявление и описание функций
Функции представляют собой программные блоки, которые могут вызываться
из разных частей программы. При вызове в них передаются некоторые перемен-
ные, константы, выражения, являющиеся аргументами, которые в самих процеду-
рах и функциях воспринимаются как формальные параметры. При этом функции
возвращают значение определенного типа, которое замещает в вызвавшем выра-
жении имя вызванной функции.
Например, оператор
I = 5 * F(X) ;
вызывает функцию F с аргументом X, умножает возвращенное ею значение на 5
и присваивает результат переменной I.
Допускается также вызов функции, не использующий возвращаемого ею зна-
чения. Например:
F(X) ;
В этом случае возвращаемое функцией значение игнорируется.
Функция описывается следующим образом:
тип_возвращаемого_эначения имя_функции(список_параметров)
(
операторы тела функции
}
Первая строка этого описания, содержащая тип возвращаемого значения, имя
функции и список параметров, называется заголовком функции. Тип возвращае-
мого значения может быть любым, кроме массива и функции. Могут быть также
функции, не возвращающие никакого значения. В заголовке таких функций тип
возвращаемого значения объявляется void.
Если тип возвращаемого значения не указан, он по умолчанию считается рав-
ным int. Впрочем, можно посоветовать не злоупотреблять этой возможностью.
Лучше всегда указывать тип возвращаемого функцией значения, кроме главной
функции main. Указание типа делает программу более наглядной и предотвращает
возможные ошибки, связанные с неправильным преобразованием типов.
Список параметров, заключаемый в скобки, в простейшем случае (более слож-
ные формы задания списка параметров будут рассмотрены позднее) представляет
собой разделяемый запятыми список вида
тип параметра иденификатор_параметра
Например, заголовок:
double FSum(double X I , d o u b l e X 2 , int A)
объявляет функцию с именем FSum, с тремя параметрами XI, Х2 и А, из которых
первые два имеют тип double, а последний — int. Тип возвращаемого результа-
та — double. Имена параметров XI, Х2 и А — локальные, т.е. они имеют значение
только внутри данной функции и никак не связаны с 'именами аргументов, пере-
данных при вызове функции. Значения этих параметров в начале выполнения
функции равны значениям аргументов на момент вызова функции. Подробнее эти
вопросы будут рассмотрены в разд. 1.7.2.
Ниже приведен заголовок функции, не возвращающей никакого значения:
void S P r i n t ( A n s i S t r i n g S)
Она принимает один параметр типа строки и, например, отображает его в ка-
ком-нибудь окне приложения.
Справочные данные по языку C++ 49
Обратите внимание на то, что роль пустого списка параметров функции в C++
существенно отличается от аналогичного списка в языке С. В С это означает, что
все проверки аргументов отсутствуют (т.е. вызов функции может передать любой
аргумент, который требуется). А в C++ пустой список означает отсутствие аргу-
ментов. Таким образом, программа на С, использующая эту особенность, может со-
общить о синтаксической ошибке при компиляции в C++.
Как правило (хотя формально не обязательно), помимо описания функции
в текст программы включается также прототип функции — ее предварительное
объявление. Прототип представляет собой тот же заголовок функции, но с точкой
с запятой ";" в конце. Кроме того, в прототипе можно не указывать имена парамет-
ров. Если вы все-таки указываете имена, то их областью действия является только
этот прототип функции. Вы можете использовать те же идентификаторы в любом
месте программы в любом качестве. Таким образом, указание имен параметров
в прототипе обычно преследует только одну цель — документирование программы,
напоминание вам или сопровождающему программу человеку, какой параметр что
именно обозначает.
Примеры прототипов приведенных выше заголовков функций:
double FSum(double XI,double Х 2 , int А ) ;
void S P r i n t ( A n s i S t r i n g S ) ;
void F l ( v o i d ) ;
ИЛИ
double FSum(double, double, int);
void S P r i n t ( A n s i S t r i n g ) ;
void Fl () ;
Введение в программу прототипов функций преследует несколько целей.
Во-первых, это позволяет использовать в данном модуле функцию, описанную
в каком-нибудь другом модуле. Тогда из прототипа компилятор получает сведе-
ния, сколько параметров, какого типа и в какой последовательности получает дан-
ная функция. Во-вторых, если в начале модуля вы определили прототипы функ-
ций, то последовательность размещения в модуле описания функций безразлична.
При отсутствии прототипов любая используемая функция должна быть описана до
ее первого вызова в тексте. Это прибавляет вам хлопот, а иногда при взаимных вы-
зовах функций друг из друга вообще невозможно. И, наконец, прототипы, разме-
щенные в одном месте (обычно в начале модуля), делают программу более нагляд-
ной и самодокументированной. Особенно в случае, если вы снабжаете прототипы
хотя бы краткими комментариями.
Если предполагается, что какие-то из описанных в модуле функций могут ис-
пользоваться в других модулях, прототипы этих функций следует включать в за-
головочный файл. Тогда в модулях, использующих данные функции, достаточно
будет написать директиву #include (см. разд. 1.4.1), включающую данный заголо-
вочный файл, и не надо будет повторять прототипы функций.
Обычно функции принимают указанное в прототипе число параметров указан-
ных типов. Однако могут быть функции, принимающие различное число парамет-
ров (например, библиотечная функция printf) или параметры неопределенных за-
50 Глава 1
ранее типов. В этом случае в прототипе вместо неизвестного числа параметров или
вместо параметров неизвестного типа ставится многоточие "...". Многоточие мо-
жет помещаться только в конце списка параметров после известного числа пара-
метров известного типа или полностью заменять список параметров. Например:
int prf (char * f o r m a t , . . .) ;
Функция с подобным прототипом принимает один параметр format типа char
* (например, строку форматирования) и произвольное число параметров произ-
вольного типа. Функция с прототипом
void Fp ( . ' . . ) ;
может принимать произвольное число параметров произвольного типа.
Если в прототипе встречается многоточие, то типы соответствующих парамет-
ров и их количество компилятором не проверяются.
Объявлению функции могут предшествовать спецификаторы класса памяти
extern или static. Спецификатор extern предполагается по умолчанию, так что за-
писывать его не имеет смысла. К функциям, объявленным как extern, можно по-
лучить доступ из других модулей программы (см. заключительную часть
разд. 1.8.1). Если же объявить функцию со спецификатором static, например
s t a t i c void F ( v o i d ) ;
то доступ к ней из других модулей невозможен. Это надо использовать в крупных
проектах во избежание недоразумений при случайных совпадениях имен функций
в различных модулях.
Теперь рассмотрим описание тела функции. Тело функции пишется по тем же
правилам, что и любой код программы, и может содержать объявления типов, кон-
стант, переменных и любые выполняемые операторы. Не допускается объявление
и описание в теле других функций. Таким образом, функции не могут быть вложе-
ны друг в друга.
Надо иметь в виду, что все объявления в теле функции носят локальный ха-
рактер. Объявленные переменные доступны только внутри данной функции. Если
их идентификаторы совпадают с идентификаторами каких-то глобальных пере-
менных модуля, то эти внешние переменные становятся невидимыми и недоступ-
ными. В этих случаях получить доступ к глобальной переменной можно, поставив
перед ее именем два двоеточия "::", т.е. применив унарную операцию разрешения
области действия.
Локальные переменные не просто видны только в теле функции, но по умолча-
нию они и существуют только внутри функции, создаваясь в момент вызова функ-
ции и уничтожаясь в момент выхода из функции. Если требуется этого избежать,
соответствующие переменные должны объявляться со спецификацией static (под-
робнее см. в разд. 1.6.2).
Выход из функции может осуществляться следующими способами. Если
функция не должна возвращать никакого значения, то выход из нее происходит
или по достижении закрывающей ее тело фигурной скобки, или при выполнении
оператора return. Если же функция должна возвращать некоторое значение, то
нормальный выход из нее осуществляется оператором
return выражение
где выражение должно формировать возвращаемое значение и соответствовать
типу, объявленному в заголовке функции.
Например:
double FSum(double XI,double X 2 , int A)
{
return A * (XI + Х 2 ) ;
Справочные данные по языку C++ 51
(
*а *= *а; // Изменение значения параметра
)
Вызов подобной функции может осуществляться, например, следующим обра-
зом:
int xl = 2;
square(Sxl);
void a v e r a g e ( A n s i S t r i n g m e s s , . . . )
{
double A = 0;
int i = 0,arg;
va_list ap;
va_start(ap, m e s s ) ;
while ( ( a r g = v a _ a r g ( a p , i n t ) ) != 0)
{
i++;
A += arg;
}
Forml->Labell->Caption = mess + "N = " + I n t T o S t r ( i ) +
", среднее = "+FloatToStr(A/i);
va_end(ap);
}
Вызов функции может быть, например, таким:
average("Результаты экзамена: " , 4 , 2 , 3 , 5 , 4 , 0 ) ;
В результате функция выдаст в метку Labell сообщение:
Результаты экзамена: N = 5, среднее = 3 , 6
Функцию average можно было бы организовать иначе, не вводя специальную
конечную метку в список (в приведенном примере — 0), а предваряя список аргу-
ментов параметром N, указывающим размер списка:
void a v e r a g e ( A n s i S t r i n g m e s s , i n t N , . . . )
{
double A = 0;
va list ap;
v a _ s t a r t ( a p , N) ;
for (int i = 0; i < N; i++)
A += va arg ( a p , i n t ) ;
Forml->Labell->Caption = mess + "N = " -UntToStr (N) +
", среднее = " + F l o a t T o S t r ( A / N ) ;
va_end(ap);
}
Вызов функции может быть, например, таким:
, average("Результаты экзамена: " , 5 , 4 , 2 , 3 , 5 , 4 ) ;
Справочные данные по языку C++ 57