Программирование для карманных компьютеров - Владимир Волков 13 стр.


? 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++ позволяет выполнять некоторые операции, которые приведены в следующем списке.

? Над указателями можно выполнять операцию инкремента и декремента. В этом случае указатель будет увеличиваться на размер объекта, на который он указывает.

? Указатели можно вычитать, но только в том случае, если это указатели на элементы одного и того же массива.

? Указатели можно сравнивать.

Массивы

Синтаксис объявления массива достаточно прост.

type declarator <constant-expression>]

Эта конструкция объявляет массив, состоящий из constant-expression элементов типа type. Следующий фрагмент кода можно рассматривать как пример объявления массивов.

float v[3]; //массив из трех элементов с плавающей точкой v[0], v[1], v[2] char* а[32]; //массив из 32 указателей на char а[0]…а[31]

Количество элементов массива не может изменяться после объявления. При необходимости объявить многомерный массив он объявляется массивом массивов, как это показано ниже.

int d[10][20];

Эта команда объявляет массив d из десяти массивов по 20 элементов типа int в каждом из них. Начальное значение массиву можно присвоить через указание списка значений.

int v1[] = {1, 3, 5, 7}; char v2[] = {\'a\',\'b\',\'d\',\'l\',0};

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

Массив удобно инициализировать строковым литералом. В C++, как и в С, в строковом литерале на один символ больше, чем используется при записи, таким образом, в строковом литерале "???" будет 4 символа.

Имя массива является указателем на его первый элемент. При направлении в строку массива символов, туда помещается содержащаяся в массиве строка. Если же мы отправим в строку массив, то туда будет помещен адрес первого элемента массива, а при разыменовании массива будет получено значение его первого элемента.

ВНИМАНИЕ! Можно также получить адрес элемента массива, следующего за последним. Компилятор C++ спокойно пропускает такой код. Мало того, можно получить как адрес, так и указатель на любой из элементов массива, выходящий за пределы массива как угодно далеко, и даже можно записать туда значение, что рано или поздно приводит к вторжению в "чужую" память и ошибке доступа к памяти с аварийным завершением работы программы или даже всей операционной системы. Поскольку массивы не хранят в себе информации о количестве элементов массива, при такого рода операциях ответственность за не выход за диапазон возложена целиком на программиста.

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

Упражнение 4.1 (продолжение)

20. В конец файла MyExp.cpp нужно добавить код, приведенный в листинге 4.11. Указанную функцию нужно объявить в заголовочном файле. Также потребуется добавить еще одну ветку case.

Листинг 4.11

//Блок 17

void f5(){

mm[0] = \0;

//Объявляем массив символов и инициализируем его строкой из 9 элементов

char p[]="Crocodile!";

//Выводим в строку значения элементов массива как символы

for (int i = 0;i<10; sprintf(nn,"%c", p[i]), strcat(mm, nn), i++);

strcat(mm,"\n");

//Устанавливаем указатель на первый элемент массива и, последовательно

//перебирая элементы (увеличивая значение указателя), получаем значения,

//записанные в них в виде целых чисел

for (char* t=p;*t!=0; sprintf(nn,"%u", *t), strcat(mm, nn), strcat(mm," "), t++);

strcat(mm,"\n");

//Устанавливаем указатель на первый элемент массива и, последовательно

//перебирая элементы массива, получаем в строку их адреса

for (char* s=p;*s!=0; sprintf(nn,"%p", s), strcat(mm, nn), strcat(mm,"\n"), s++);

mbstowcs(mstr, mm, 256);

szStr = mstr;

}

Вся функциональность достаточно хорошо описана в комментариях. Но также следует обратить внимание на то, как оформлены циклы. Оказывается цикл for можно весь уложить в одну строку, записав все необходимые операции в заголовок.

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

Структуры

Структуры в С++ – это определенные пользователем именованные коллекции данных разного типа. Структура объявляется при помощи ключевого слова struct, как это показано ниже.

struct mystruct {… };

Членами структуры могут быть данные любого типа и битовые поля , которые не могут использоваться только в структурах, объединениях или классах. Обработка структур в С++ практически ничем не отличается от обработки классов. После объявления структуры определенного типа разработчик может объявить переменную этого типа, как это показано в следующем примере.

struct mystruct{… } s, *ps, arrs[10]; mystruct s1;

Возможно также объявление неименованной структуры. Оно имеет смысл только тогда, когда тут же объявляются переменные этого типа. Для неименованной структуры невозможно объявить переменные этого типа в другом месте. Этот механизм демонстрирует следующий фрагмент кода:

struct {… } s, *ps, arrs[10];

Есть возможность создать typedef для неименованной структуры, как это показано ниже.

typedef struct {… } MYSTRUCT; MYSTRUCT s, *ps, arrs[10];

Оператор typedef можно использовать и для именованной структуры, если согласно логике программы в этом есть какой-то смысл.

Внутри скобок для объявления членов структуры используется стандартный синтаксис для объявления соответствующих типов. При этом структура не может иметь в качестве своего члена объект того же типа, что и сама структура, но указатель на такой объект может быть членом структуры. Членом структуры в C++ может быть функция.

Битовые поля структур Битовые поля это определенное количество именованных или не именованных битов, которое является членом структуры (объединения, класса). Объявляется битовое поле следующим образом:

type-specifier <bitfield-id>: width;

В С++ спецификатором типа может быть любое беззнаковое целое.

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

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

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

? Доступ к битовому полю х при помощи выражения вроде mystruct.x корректен, а получение адреса & mystruct.x невозможно в принципе, поскольку mystruct.x не хранится в байте.

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

В следующем примере будет объявлена структура, членами которой являются указатель на эту структуру, функция и битовое поле.

Упражнение 4.1 (продолжение)

21. Добавить новый блок в основную рабочую последовательность, код которого приведен в листинге 4.12.

Листинг 4.12

//Блок 18

void f6(){

mm[0] = \0;

struct mystruct {

int d;

double e;

unsigned short mybit: 2;

mystruct* s;

int myfunc(int g)

{return g*g;};} mystr;

mystruct* pmy = &mystr;

mystr.s = pmy;

mystr.d = 100;

pmy->e = 300.00;

mystr.mybit = 3;

sprintf(nn,"%f", pmy->e);

strcat(mm, nn);

strcat(mm, " – pmy->e\n");

sprintf(nn,"%d", mystr.d);

strcat(mm, nn);

strcat(mm, " – mystr.d\n");

sprintf(nn,"%p", mystr.s);

strcat(mm, nn);

strcat(mm, " – mystr.s\n");

sprintf(nn,"%d", mystr.myfunc(12));

strcat(mm, nn);

strcat(mm, " – mystr.myfunc(12)\n");

sprintf(nn,"%d", pmy->myfunc(12));

strcat(mm, nn);

strcat(mm, " – pmy->myfunc(12)\n");

sprintf(nn,"%d", mystr.mybit);

strcat(mm, nn);

strcat(mm, " – mystr.mybit\n");

mbstowcs(mstr, mm, 256);

szStr = mstr;

}

Этот код будет выполняться при нажатии клавиши 6 на клавиатуре.

Объединения

Объединение объявляется при помощи ключевого слова union. Объединения очень похожи на структуры, и главное их отличие от структур заключается в том, что разработчик может пользоваться только одним из членов объединения в конкретный момент времени. Практически мы можем трактовать объединение как своего рода объект с переключающимся типом или переменную типа variant. В тот момент, когда одному из членов объединения присваивается значение, остальные члены объединения содержат непредсказуемые значения и обращаться к ним не стоит. Результат этого действия нельзя будет предсказать.

Но это не означает, что каждый раз результат будет неверным. Просто память для объединения выделяется по размеру его большего члена и далее для членов объединения распределяется динамически при каждом присваивании только для того члена, которому присваивается значение, внутри одного и того же участка памяти. Значение остальных членов не гарантированно. Оно может сохраниться, а может и перезаписаться новым значением.

Среда разработки eMbedded Visual C++ 3.0

Несмотря на то, что среда eVC предназначена для разработки программ для "маленьких" компьютеров, сама среда – вполне серьезный инструмент. Знакомство со средой стоит начать со структуры экрана.

Окна

Главное окно среды представляет собой окно в стиле SDI, когда все прочие документы и окна открываются в главном окне и не могут покинуть его пределы. Таким образом, главное окно является контейнером для других окон. На нем размещены панель инструментов и главное меню (рис. 4.1).

Назад Дальше