- •2. Оператор цикла while.
- •Билет 2.
- •Билет 3
- •2. Оператор цикла for
- •Билет 4
- •Билет 5
- •1. Константы
- •1.1 Целые Константы
- •1.3 Символьные Константы
- •1.4 Строки
- •2. Оператор if
- •Билет 6
- •Билет 7
- •1.1 Описания Функций
- •1.2 Определения Функций
- •1.3 Описания
- •2.1.1 Область Видимости
- •2.1.2 Объекты и Адреса (Lvalue)
- •2.1.3 Время Жизни
- •2. Логические операции.
- •Билет 8
- •1. Указатели. Использование указателей при работе с массивами
- •2. Оператор Goto
- •Билет 9
- •2. Указатели и операции над ними.
- •Билет 10
- •Билет 11
- •1. Оператор if
- •2. Строки
- •Билет 12
- •1. Увеличение и уменьшение
- •Билет 13
- •1. Побитовые логические операции
- •2. Функция scanf
- •Билет 14
- •Основные сведения о функциях
- •2. Функции operator new() и operator delete()
- •Билет 15
- •1. Объединения
- •2. Форматный вывод - функция printf
- •Билет 16
- •1. Оператор Выражение
- •2. Области видимости объектов
- •Билет 17
- •1.1 Оператор Return
- •1.2 Оператор Break
- •1.3 Оператор Continue
- •2. Ввод-вывод текстового файла: getc( ), putc( )
- •Билет 18
- •Билет 19
- •1. Аргументы функции main()
- •2. Операции Отношения
- •Билет 20
- •1. Стандартный ввод и вывод - функции getchar и putchar
- •2.1 Оператор typedef
- •Билет 21
- •1. Глобальные переменные
- •2. Открытие файла: fopen( )
- •Закрытие файла: fclose( )
- •Билет 22
- •2. Директивы Препроцессора
- •2.1. Директива #include
- •2.2. Директива #define
- •2.3. Директива #undef
- •Билет 23
- •1. Преобразование типов.
- •2. Операция Запятая
- •Билет 24
- •1. Определение
- •2. Арифметические Преобразования
- •Билет 25
- •Билет 26
- •1. Передача Параметров
- •Билет 27
- •1. Преобразования символов
- •2. Массив и константный указатель
- •Билет 28
- •2. Операции Отношения
- •Билет 29
- •1. Оператор return. Точка вызова и точка возврата
- •Билет 30
- •2. Рекурсивная функция
- •Билет 31
- •2. Функция. Прототип
- •Билет 32
- •2. Генерация случайных чисел
- •Билет 33
- •2. Шаблоны функций и шаблонные функции
Билет 12
1. Увеличение и уменьшение
Операция ++ используется для явного выражения приращения вместо его неявного выражения с помощью комбинации сложения и присваивания. По определению ++lvalue означает lvalue+=1, что в свою очередь означает lvalue=lvalue+1 при условии, что lvalue не вызывает никаких побочных эффектов. Выражение, обозначающее (денотирующее) объект, который должен быть увеличен, вычисляется один раз (только). Аналогично, уменьшение выражается операцией --. Операции ++ и -- могут применяться и как префиксные, и как постфиксные. Значением ++x является новое (то есть увеличенное) значение x. Например, y=++x эквивалентно y=(x+=1). Значение x++, напротив, есть старое значение x. Например, y=x++ эквивалентно y=(t=x,x+=1,t), где t - переменная того же типа, что и x.
Операции приращения особенно полезны для увеличения и уменьшения переменных в циклах. Например, оканчивающуюся нулем строку можно копировать так:
inline void cpy(char* p, const char* q)
(*
while (*p++ = *q++) ;
*)
Напомню, что увеличение и уменьшение арифметических указателей, так же как сложение и вычитание указателей, осуществляется в терминах элементов вектора, на которые указывает указатель p++ приводит к тому, что p указывает на следующий элемент. Для указателя p типа T* по определению выполняется следующее:
long(p+1) == long(p)+sizeof(T);
2. Структуры
Вектор есть совокупность элементов одного типа, struct является совокупностью элементов (практически) произвольных типов. Например:
struct address (* // почтовый адрес
char* name; // имя "Jim Dandy"
long number; // номер дома 61
char* street; // улица "South Street"
char* town; // город "New Providence"
char* state[2]; // штат 'N' 'J'
int zip; // индекс 7974
*)
определяет новый тип, названный address (почтовый адрес), состоящий из пунктов, требующихся для того, чтобы послать кому-нибудь корреспонденцию (вообще говоря, address не является достаточным для работы с полным почтовым адресом, но в качестве примера достаточен). Обратите внимание на точку с запятой в конце; это одно из очень немногих мест в С++, где необходимо ставить точку с запятой после фигурной скобки, поэтому люди склонны забывать об этом.
Переменные типа address могут описываться точно также, как другие переменные, а доступ к отдельным членам получается с помощью операции . (точка). Например:
address jd;
jd.name = "Jim Dandy";
jd.number = 61;
Запись, которая использовалась для инициализации векторов, можно применять и к переменным структурных типов. Например:
address jd = (*
"Jim Dandy",
61, "South Street",
"New Providence", (*'N','J'*), 7974
*);
Однако обычно лучше использовать конструктор (#5.2.4). Заметьте, что нельзя было бы инициализировать jd.state строкой "NJ". Строки оканчиваются символом '\0', поэтому в "NJ" три символа, то есть на один больше, чем влезет в jd.state.
К структурным объектам часто обращаются посредством указателей используя операцию ->. Например:
void print_addr(address* p)
(*
cout << p->name << "\n"
<< p->number << " " << p->street << "\n"
<< p->town << "\n"
<< chr(p->state[0]) << chr(p->state[1])
<< " " << p->zip << "\n";
*)
Объекты типа структура можно присваивать, передавать как параметры функции и возвращать из функции в качестве результата. Например:
address current;
address set_current(address next)
(*
address prev = current;
current = next;
return prev;
*)
Остальные осмысленные операции, такие как сравнение (== и !=) не определены. Однако пользователь может определить эти операции, см. Главу 6. Размер объекта структурного типа нельзя вычислить просто как сумму его членов. Причина этого состоит в том, что многие машины требуют, чтобы объекты определенных типов выравнивались в памяти только по некоторым зависящим от архитектуры границам (типичный пример: целое должно быть выравнено по границе слова), или просто гораздо более эффективно обрабатывают такие объекты, если они выравнены в машине. Это приводит к "дырам" в структуре. Например, (на моей машине) sizeof(address) равен 24, а не 22, как можно было ожидать.
Заметьте, что имя типа становится доступным сразу после того, как оно встретилось, а не только после того, как полностью просмотрено все описание. Например:
struct link(*
link* previous;
link* successor;
*)
Новые объекты структурного типа не могут быть описываться, пока все описание не просмотрено, поэтому
struct no_good (*
no_good member;
*);
является ошибочным (компилятор не может установить размер no_good). Чтобы дать возможность двум (или более) структурным типам ссылаться друг на друга, можно просто описать имя как имя структурного типа. Например:
struct list; // должна быть определена позднее
struct link (*
link* pre;
link* suc;
link* member_of;
*);
struct list (*
link* head;
*)
Без первого описания list описание link вызвало бы синтаксическую ошибку.