Программирование для карманных компьютеров
Шрифт:
//переменной mm, обращаясь к глобальной переменной при помощи оператора
//разрешения области видимости::
strcat(mm,mm);
mbstowcs(mstr, mm, 256);
szStr = mstr;
}
Комментарии в тексте поясняют действие кода. После запуска программы нужно нажать клавишу 4. На экран будет выведено следующее сообщение:
Hello, Local Word! Hello, Global Word!
Поскольку ошибки, связанные с ненамеренным замещением имен трудно обнаружить, особенно в большой программе, следует придерживаться следующих правил.
? Чем более глобальное имя было создано, тем более описательный характер, позволяющий понять функциональную нагрузку имени и область, оно должно носить.
? Имена из локальной области видимости хорошо делать однобуквенными.
? Чем чаще используется имя, тем короче его надо делать.
? Имя должно отображать смысл использования объекта, а не детали его представления.
? Нужно записывать имена макросов заглавными буквами.
? Следует отделять слова внутри имени символом подчеркивания.
Объекты и lvalue (левые значения)
Когда для хранения тех или иных данных выделяется некоторая непрерывная область памяти, эта операция создает объект. В С++ разработчик может создавать области памяти и хранить там данные, не присваивая этим объектам имен. Но если вы такому объекту все же присваивается имя, то этим создается так называемое lvalue , то есть нечто, что может быть использовано в левой части оператора присваивания. Когда вы создаете переменную, вы создаете модифицируемое lvalue . При создании константы
Объект, объявленный в функции, создается в момент его определения и живет до выхода из функции. Такого рода объекты называются автоматическими или локальными . Глобальные объекты, а также статические объекты, объявленные в функциях и классах, живут до тех пор, пока не закончится программа.
Объекты, созданные явно при помощи оператора new, уничтожаются оператором delete, и программист непосредственно управляет временем их жизни. Такие объекты называются динамическими .
typedef
Объявление, начинающееся с ключевого слова typedef, вводит новое имя для типа.typedef char* Pchar;
Эта конструкция создает новое имя для уже имеющегося типа «указатель на символ». Таким образом, ключевое слово typedef позволяет создавать синонимы уже имеющимся типам.
Выражения
Выражения – это операторы, операнды и разделители, определяющие некоторое вычисление и возвращающие значение. В следующем разделе будут рассматриваться основные операторы языка С++, а в этом разделе нужно коснуться приоритета выполнения операторов в выражениях. Правильное понимание того, в каком порядке будут выполняться операторы, поможет избежать многих досадных ошибок, которые не в состоянии обнаружить компилятор. В справочной системе, в разделе, посвященном языку C/C++, есть страница Operator Precedence and Associativity, посвященная этому вопросу. На этой странице указаны практически все операторы языка C++.
Операторы
Операторы – это лексемы, которые производят некоторые вычисления, если их применить к переменным или другим объектам внутри выражения.
Арифметические операторыАрифметические операторы используются для математических вычислений. Они приведены в табл. 4.1.
Инкремент и декремент могут быть как постфиксными, так и префиксными.
Это демонстрирует следующий фрагмент кода:
int x=1, y=0;
y = x++; //Сначала y получит значение x (1), затем x будет увеличен на 1
y = ++x; //Сначала x будет увеличен на 1, затем полученное значение будет
//увеличено на единицуБудет иметь смысл и выражение ++x = 5. А вот выражение x++ = 5 не имеет смысла, поскольку мы пытаемся присвоить значение 5 операции инкремента. Таблица 4.1. Арифметические операторы
Битовые операторы приведены в следующем списке.
? & – побитовое И. Если оба бита равны 1, то результат тоже будет равен 1, иначе результат будет равен 0.
? | – побитовое ИЛИ. Оператор сравнивает два бита и возвращает 1, если хотя бы один из битов равен 1, иначе результат будет равен 0.
? ^ – побитовое исключающее ИЛИ. Оператор сравнивает два бита и возвращает 1 только тогда, когда один из битов равен 0, а другой – 1, иначе результат будет равен 0.
? ~ – побитовая инверсия, при которой значение каждого бита меняется на противоположное.
«– побитовый сдвиг вправо. В этом случае последний бит теряется, для беззнакового значения слева вдвигается 0, для знакового – расширяется знак.
? «– побитовый сдвиг влево. В этом случае левый бит теряется, а справа вдвигается ноль.
Тернарный условный оператор Оператор? имеет три операнда. Пример его применения показан ниже.Е1?Е2:ЕЗ
Первым выполняется операнд Е1. Если результат его выполнения равен true, то выполняется операция Е2, а ЕЗ игнорируется. Если результат выполнения Е1 равен false, то выполняется ЕЗ, а Е2 игнорируется. Например, в коротком выражении а = (х>у)?х: у переменная а всегда будет получать большее значение. Операторы сравнения и равенства
Операторы сравнения и равенства приведены в табл. 4.2.
Выполнение этих операторов между двумя операндами возвращает логический результат true, если условие выполняется, или значение false, если оно не выполняется. Операторы == и!= могут быть использованы для сравнения указателей, в то время как остальные операторы для этого использовать нельзя.
Таблица 4.2. Операторы сравнения и равенстваЛогические операторы языка C++ приведены в табл. 4.3.
Таблица 4.3. Логические операторыОператор * предназначен для объявления указателя. Указатель содержит в себе адрес блока памяти, на который он указывает. Этот же оператор разыменовывает указатель, то есть позволяет получить доступ к содержимому объекта, на который создан указатель.
Оператор & (адрес) предназначен для получения адреса, по которому содержится значение конкретной переменной. Когда мы обращаемся к переменной по имени, мы всегда получаем доступ к ее значению, но не к области памяти, в которой это значение хранится. Иногда надо знать, в какой конкретно области памяти хранится тот или иной объект. В этом случае следует использовать оператор разыменования.
Другие операторы? – скобки. Они позволяют группировать выражения, обеспечивая им высший приоритет исполнения, выделять выражения проверки условия в операторах ветвления или цикла. Также скобки показывают, что определенное имя является функцией и заключают в себе параметры функций. Иногда скобки обозначают операцию явного приведения типа.
? {} – фигурные скобки. Они предназначены для обозначения начала и конца составного выражения, объединяющего несколько простых выражений.
? [] – квадратные скобки служат для объявления массивов.
? sizeof – возвращает число типа int, показывающее объем памяти в байтах, занимаемый операндом. Операнд может быть любым выражением, именем типа или объекта.
?. – точка, предназначена для выбора члена структуры или объединения в выражении типа s.m, где s – объект класса структуры или объединения, а m – член структуры или объединения.
? – > стрелка, предназначена для выбора члена структуры или объединения в выражении типа s->m, где s – указатель на объект класса структуры или объединения, а m – член структуры или объединения.
Специфичные операторы C++?:: доступ к объекту-владельцу данного объекта, классу-владельцу данного члена или разрешение области видимости. Доступ к объекту-владельцу данного объекта для динамических объектов или к классу-владельцу для статических объектов будет рассматриваться позже.
?.* – разыменование указателя на член класса.
? – >* – разыменование указателя на указатель члена класса.
? const_cast – добавляет или удаляет из имени указателя модификатор const, когда указатель, имеющий такой модификатор, надо передать в качестве аргумента функции.
? dynamic_cast – во время выполнения программы проверяет, может ли быть указатель приведен к определенному типу или выполняет такое приведение.
? reinterpret_cast – преобразует типизированный указатель в указатель на пустой тип и обратно.
? static_cast – преобразует любой тип, известный на момент компиляции в любой другой тип, также полностью известный на момент компиляции. В том случае, если преобразование может быть выполнено другими средствами языка (например, приведение типа intк типу double), результат применения static_cast будет тем же самым.
? typeid – получает идентификатор времени исполнения для любого выражения-операнда.
? new – осуществляет динамический захват памяти во время исполнения.
? delete – динамически освобождает память, захваченную командой new.
? this –
оператор указания на объект, для которого была вызвана данная функция.? ~ – деструктор класса.
Инструкции
В группу инструкций в С++ выделено все, что влияет на ход выполнения программы и порядок выполнения выражений. В том числе инструкцией считается последовательность выражений, оканчивающаяся точкой с запятой. Таким образом, в число инструкций попадают выражения присваивания и вызовы функций. Особым случаем инструкции является пустая инструкция, которая ничего, кроме точки с запятой, не содержит. Функционально такая инструкция особой пользы не несет, но может быть полезна при отладке или, к примеру, в организации бесконечного цикла.
if…else Эта инструкция позволяет выполнять некоторые выражения только в случае, когда выполняется некоторое условие. Имеет две формы: сокращенную и полную. Синтаксис сокращенной формы приведен ниже.if (<condition>) <statement1>;
Полная форма выглядит несколько иначе.
if (<condition>) <statement1>; else <statement2>;
Если (if) условие в скобках (<condition>) в результате вычисления дает результат типа bool со значением true, то выполняется выражение <statement1>, иначе будет выполнено выражение <statement2>. Пример использования этой конструкции приведен в листинге 4.10. Листинг 4.10
void fother {
char mstr[20];
mstr[0]= \0;
int a = 5;
if (a>5) //Если a>5
{
strcat(mstr, «a>5»); //содержимым строки будет «a>5»
}
else //иначе
{
if (a =5) //Если а=5
{
strcat(mstr, «a=5»); //содержимым строки будет «a=5»
}
else //иначе
{
strcat(mstr, «a<5»); //содержимым строки будет «a<5»
};
};
}Приведенный пример демонстрирует применение инструкций if…else. В листинге показано, что инструкции могут быть вложенными. Следует обратить внимание, что если в качестве выражений фигурируют блоки, то точка с запятой ставится только в конце инструкции. switch (переключатель)
Эта инструкция предназначена для того, чтобы переключить ход выполнения программы на одну из ветвей в соответствии со значением переменной на входе.
Ее синтаксис приведен ниже:switch (<switch variable>) {
case <constant expression>: <statement>; [break;]
default: <statement>;
}В этом определении показано, как переменная передается инструкции switch. Если значение переменной соответствует одному из значений константы case, то выполняется соответствующее выражение, которое может быть завершено инструкцией. Если не было найдено значения переменной, соответствующее одной из констант case, то выполняется ветвь default. Каждую из ветвей желательно завершать инструкцией break, иначе возможно выполнение сразу нескольких ветвей. Ветвь default может отсутствовать в конструкции switch. Работа оператора switch проиллюстрирована в блоке 11 рассматриваемого примера. При помощи этого оператора происходит выполнение той или иной функции в зависимости от того, какая клавиша была нажата на клавиатуре. while Инструкция while предназначена для организации цикла, в котором тело цикла может ни разу не быть выполнено. Это зависит от значения переменной продолжения цикла. Синтаксис этой инструкции приведен ниже.
while (<condition>) <statement>
Инструкция statement будет выполняться до тех пор, пока будет оставаться верным условие condition. Пример подобного цикла приведен ниже.
while (*p == ) p++; do while Инструкция do while предназначена для организации цикла, в котором тело цикла будет выполнено хотя бы один раз. Синтаксис этой инструкции приведен ниже.
do <statement> while (<condition>)
Инструкция statement будет выполняться до тех пор, пока будет выполняться условие condition. for Инструкция for предназначена для организации параметрического цикла. Синтаксис этой инструкции приведен ниже.
for (<initialization>]; <condition>]; <increment>]) <statement>
В секции <initialization> выполняется инициализация переменной цикла, в секции <condition> устанавливается условие, а в секции <increment> обуславливается механизм изменения переменной цикла. Блок инструкций <statement> является телом цикла. Пока условие соблюдается <condition>, цикл будет выполняться. Пример инструкции for приведен ниже.
for (int i = 0; i < 10; i++){
sprintf(nn, «%d», i);
strcat(mm, nn);
strcat(mm, " ");
}
breakИнструкция break прерывает выполнение инструкций switch, for, while или do и передает управление следующему блоку инструкций.
continueЭта инструкция прерывает только текущую итерацию цикла и передает управление следующей итерации.
goto Инструкция goto предназначена для передачи управления на произвольную инструкцию программы, которая должна быть помечена соответствующей меткой. Это может быть в том числе и инструкция объявления имени. Заметим, что метка может быть только локальной, в качестве метки может выступать любое необъявленное до сих пор имя с двоеточием после него. Синтаксис конструкции приведен ниже.identifier:
…
goto <identifier>;
return Эта инструкция предназначена для выхода из текущей функции и возврата в то место, откуда эта функция была вызвана. При необходимости она может возвращать значение. Синтаксис этой конструкции приведен ниже.return [<expression>];
Пример этой инструкции выглядит достаточно просто.
double sqr(double x)
{
return (x*x);
}
Указатели
Указатель – это объект, хранящий в себе адрес некоей области памяти, в которой располагается переменная или иной объект. Но кроме адреса указатель еще хранит в себе тип объекта, на который указывает. Обычно различают указатели на объекты и указатели на функции. Оба типа указателей – специальные объекты для хранения адресов памяти. Эти два класса имеют различающиеся свойства, назначения и правила манипуляции ими.
Указатели на функции используются для того, чтобы осуществлять доступ к функциям и передавать функции как параметры для других функций. Для указателей на функции нельзя использовать арифметику указателей. Для указателей на объект , напротив, постоянное уменьшение и увеличение являются стандартной операцией для сканирования массивов и других структур данных в памяти.
В С++ указатель всегда имеет тип. Указателя без типа не может существовать. Указатель всегда указывает или на функцию, или на объект какого-то типа. Даже если указатель нетипизирован, он должен иметь тип void*.
Может быть нулевой указатель, который гарантированно указывает на адрес в памяти, который не может указать ни один другой указатель. То есть нулевой указатель ни на что не указывает. Присвоение указателю константы 0 делает его нулевым указателем.
Синтаксис объявления указателя достаточно прост.type *ptr;
После того как указатель будет объявлен, его обязательно нужно инициализировать. В этом случае type может быть любым типом, в том числе и пользовательским. Получившийся указатель будет трактоваться как указатель на объект типа, и после инициализации к этому указателю будут применимы все правила относительно видимости и времени жизни того объекта, на который он указывает.
Также один указатель можно присвоить другому. Правила этой операции достаточно просты и перечислены в следующем списке.
? Указателю типа void можно присвоить любой другой указатель.
? Никакому указателю не может быть присвоен указатель типа void.
? Указатель на объект и указатель на функцию не могут быть присвоены один другому.
? Указатели на объекты одного типа могут быть присвоены один другому.
? Указатели на объекты разного типа могут быть присвоены один другому только при соблюдении некоторых условий.
Помимо этого существует несколько правил арифметики указателей. Они, конечно, не являются обычными переменными, но язык C++ позволяет выполнять некоторые операции, которые приведены в следующем списке.
? Над указателями можно выполнять операцию инкремента и декремента. В этом случае указатель будет увеличиваться на размер объекта, на который он указывает.
? Указатели можно вычитать, но только в том случае, если это указатели на элементы одного и того же массива.
? Указатели можно сравнивать.
Массивы
Синтаксис объявления массива достаточно прост.