Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Давыдов В.Г. - Программирование и основы алгоритмизации - 2003

.pdf
Скачиваний:
839
Добавлен:
13.08.2013
Размер:
9.55 Mб
Скачать

5. Пусть определен массив

±nt

а[ 25

];

Напишите фрагмент Си-программы, который напечатает с новой строки значения элементов массива "а" по пять элементов в строке и по десять позиций на элемент. Решить задачу с помощью цикла while.

6. При каких исходных значениях "А:" приведенный ниже цикл бу­ дет выполняться бесконечно?

±zit

к;

wh±lG(

к < 5 ) к+ + ;

5.ВЫРАЖЕНИЯ И ОПЕРАЦИИ

Вязыках Си/С++ предусмотрен богатый набор операций. В дополнение к традиционным арифметическим, логическим операци­ ям, операциям отношения и присваивания предусмотрены сокра­ щенные версии этих операций, побитовые операции и операции над адресами (указателями). Рассмотрим операции и выражения, ис­ пользующие их, кроме операций над адресами и побитовых опера­ ций, которые будут рассмотрены ниже.

Можно выделить шесть категорий операций:

ссылки;

унарные операции;

бинарные операции;

тернарные операции;

присваивания;

операция "запятая".

Операции ссылки используются, в основном, для доступа к элементам массивов и структур.

Унарные операции воздействуют на одно значение или выра­ жение.

В бинарных операциях участвуют два выражения, а в тернар­ ных - три.

Приоритеты операций в порядке их убывания и порядок вы­ полнения операций с одинаковым приоритетом указаны в табл. 16. Из приведенной таблицы следует, что в особый класс бинарных операций выделены операции присваивания.

Табл. 16. Приоритеты и порядок выполнения операций

Наименование

Знаки операций

Порядок

операций

 

выпол­

 

 

нения

Разрешение области

 

Нет

видимости

 

 

Ссылочные

[ ] - доступ по индексу: адрес_начала[ выражение ]

Слева -

 

или выражение[ адрес_начала ])

направо

 

( ) — управление порядком выполнения операций в

 

 

выражении; вызов функции:

 

 

имя_функции( списокпараметров );

 

 

конструирование значения:

 

 

тип(списокпараметров)

 

 

. — выбор члена класса посредством объекта:

 

 

объект, членкласса

 

 

-> - выбор члена класса посредством указателя:

 

 

указатель->член класса

 

111

Наименование

операций

Унарные

Мультипликативные

бинарные

Аддитивные бинарные

Сдвига бинарные

продолжение табл. 16

Знаки операций

Порядок

 

выпол­

 

нения

++ - постфиксный инкремент: lvalue++

Нет

— постфиксный декремент: lvalue-

 

new - динамически создать объект (выделить

 

динамическую память): new type или

 

new type( списоквыражений)

 

delete — уничтожить объект (освободить

 

динамическую память): delete указа-

 

гел ьнаобъект

 

delete[ ] - уничтожить массив объектов:

 

delete указательнамассивобъектов

 

++- префиксный инкремент: -ь+lvalue

префиксный декремент: —lvalue

*- разадресация (разименование): * выражение

&- получение адреса объекта: & lvalue

+- унарный плюс: + выражение

- унарный минус: - выражение

!- логическое отрицание (not): !выражение '- - поразрядное дополнение: -выражение sizeof - размер в байтах: 812еоГ(объект) или sizeof(THn)

typeidO - идентификация типа времени выполнения: typeid(type)

(type) - приведение типа: (type)выpaжeниe - приведение типа выражения к типу в скобках (старый стиль), выполняется справа-налево

COnst_cast — константное преобразование типа: const_cast<type>(выpaжeниe)

dynamic_cast - преобразование типа с проверкой во время выполнения:

dynamiccast <1уре>(выражение) reinterpret__cast - преобразование типа без проверки: reinteфret_cast<type>(выpaжeниe)

static__cast — преобразование типа с проверкой во время компиляции: static cast<type>(выpaжeниe)

.* - выбор члена класса посредством объекта: объект. *указатель_на_член_класса, выполняется слева-направо

->* - выбор члена класса посредством указателя на объект:

указатель на объект ->* указатель на член класса,

выполняется слева-направо

* - умножение: выражение * выражение

Слева -

/ - деление: выражение / выражение

| направо

% - остаток от деления (деление по модулю):

 

выражение % выражение

 

 

+ - сложение: выражение -^ выражение

Слева -

- - вычитание: выражение - выражение

направо

«

- сдвиг влево: выражение «

выражение

Слева -

»

- сдвиг вправо: выражение »

выражение

направо

112

Продолжение табл. 16

1

Наименование

 

Знаки операций

Порядок

 

 

операций

 

 

 

выпол­

 

 

Отношения бинарные

 

 

 

нения

 

 

< - меньше: выражение < выражение

Слева —

 

 

 

> - больше: выражение > выражение

направо

 

 

 

<= - меньше или равно: выражение <= выражение

 

 

 

Отношения бинарные

>= - больше или равно: выражение >= выражение

Слева —

 

 

== - равно: выражение == выражение

 

 

 

!= - не равно: выражение != выражение

направо

|

 

Поразрядная "И"

& - поразрядное умножение:

Слева -

 

 

бинарная

выражение & выражение

направо

 

 

Поразрядная

^ - выражение '^ выражение

Слева -

 

 

"ИСКЛЮЧАЮЩЕЕ

 

 

 

направо

 

 

ИЛИ" бинарная

 

 

 

 

 

 

Поразрядная

1 - выражение | выражение

Слева -

 

 

"ВКЛЮЧАЮЩЕЕ

 

 

 

направо

 

 

ИЛИ" бинарная

 

 

 

Слева -

 

 

Логическая "И"

&& - логическое умножение:

 

 

бинарная(and)

выражение && выражение

направо

 

1

Логическая "ИЛИ"

ii - логическое умножение: выражение || выражение

Слева -

 

 

бинарная (or)

 

 

 

направо

 

 

Условная тернарР1ая

?: - выражение ? выражение : выражение

Справа-

 

 

 

 

 

 

налево

 

 

Простое присваивание

= - lvalue = выражение

Справа —

 

 

 

 

 

 

налево

 

 

Совмещенное

*= - выражение *= выражение

Справа —

 

 

присваивание

/= - выражение /= выражение

налево

 

 

 

%= - выражение %= выражение

 

 

 

 

+= - выражение += выражение

 

 

 

 

-= - выражение -= выражение

 

 

 

 

« =

- выражение « =

выражение

 

 

 

 

» =

- выражение » =

выражение

 

 

 

 

&= - выражение &= выражение

 

 

 

 

1= - выражение |= выражение

 

 

Генерация исключения

^= - выражение ^= выражение

Нет

 

throw - throw выражение

 

 

Запятая

, - выражение , выражение

Слева -

 

 

(последовательность)

 

 

 

направо

|

5.1. Операции ссылки

Порядок выполнения операций (раньше - позже) определяется их приоритетом. Операции с одинаковым приоритетом могут вы­ полняться в порядке их появления в выражении слева - направо или справа - налево. В этом плане операции ссылки после операции раз­ решения области видимости имеют наивысший приоритет и выпол­ няются слева - направо (табл. 16).

Имеются следующие разновидности операций ссылки:

• ссылка на элемент массива [ ];

113

ссылка на элемент структуры .;

ссылка на элемент структуры с помощью указателя ->.

Особое место в этой группе занимает операция "()", служащая для управления порядком выполнения операций в выражении. Объ­ ясняется это тем, что данная операция, как и другие операции ссыл­ ки, имеет наивысший приоритет.

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

^define

N100

 

//

Размер

массива

 

 

±nt

 

 

 

arr[ N ]; //

Определение

массива

целого

типа

. . .

агг[

i+2

J

//

из N

элементов

массива

 

//

Ссылка

на

элемент

 

. . .

arrf

12

]

//

Ссылка

на

элемент

массива

 

Повторно напомним, что у массива, содержащего N элементов, значения индекса изменяются в диапазоне от О до Л^-1. Имя массива, записанное без операции ссылки, означает адрес первого элемента массива:

агг эквивалентно <&агг/" О ]

Алгоритм выполнения ссылки на элемент массива следующий (например, для агг[ i+2 ]):

1. Вычислить значение выражения, которое служит индексом. Пусть, например, результат s = i+2.

2. Преобразовать s в сдвиг в массиве элемента с индексом /+2 относительно начала массива. Для этого следует умножить s на раз­ мер отдельного элемента массива:

shift = S '* s±zeof( ±nt )

 

3.

Вычислить адрес элемента массива по формуле:

 

 

adr

=

arr+shift

= arr+s*slzeof

(int)

= &arr

[ 0] -hs'^slzeof

(int)

 

Эта функция

получила название

функции

индексации.

В

ней

агг

= 8сагг[ О ] означает адрес первого элемента массива (адрес

на­

чала массива).

 

 

 

 

 

 

 

4.

Извлечь значение, находящееся по этому адресу.

 

 

 

Нетрудно заметить, что для доступа к элементам одномерного

массива нужно выполнить довольно много работы - одно умножение

114

и одно сложение. Поэтому работа с массивом по сравнению со ci^- лярными объектами происходит существенно медленнее и это сле­ дует иметь в виду.

Получим функцию индексации для двумерного массива. Дву­ мерный массив (в математике его называют матрицей) располагает­ ся в оперативной памяти по строкам - сначала располагаются эле­ менты первой строки матрицы в порядке возрастания индексов и адресов оперативной памяти, затем - второй строки и т.д.

#define

N10

 

 

 

//

Строчный

размер

матрицы

(массива)

#define

М 9

 

 

 

//

Столбцовый

размер

массива

 

//

Определение

двумерного

массива

 

 

 

 

 

 

short

±nt

 

two_arr[

N ][

М

]/

 

 

 

 

 

 

//

Функция

индексации

для

элемента

массива

two__arr[i]

[j] :

//

1.

Вычисляем

значения

индексных

выражений,

указанных

в

//

квадратных

скобках

данном

случае

этого

не требуется) .

//

2.

Вычисляем

сдвиг

указанного

 

элемента

относительно

начала

//

массива

shift

= (i*M+j)

*s±zeo£(shoirb

int) .

 

//

3,

Тогда

функция

индексации,

 

дающая

адрес

оперативной

//

памяти,

по

которому

находится

 

элемент

 

массива

 

//

two__aгг

[i ] [j ] ,

имеет следующий

вид:

 

(i*M+j)

 

//

adr

= two_arr-hshift

=

8ctwo_arr[0]

[0] +

 

//

*3±zeof(

short

i n t

; .

 

 

 

 

 

 

 

 

 

Для доступа к элементам двумерного массива вычислительной работы еще больше - на каждый элемент два умножения и два сло­ жения. Поэтому для повышения быстродействия надо избегать ис­ пользования массивов вообще и особенно массивов высокой раз­ мерности.

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

current .stip (см. подразд. 3.9.3 о структурах)

представляет значение элемента stip структуры current. Так как структуры могут быть вложенными, то вложенность распространя­ ется и на ссылку на элемент структуры. Например,

bigstr.smallstr.elem

представляет элемент elem структуры smallstr^ которая, в свою оче­ редь, является элементом структуры bigstr.

Операция ссылки на элемент структуры с помощью указателя выглядит следующим образом:

115

STUDENT__INFO

s_data,

//

 

Структура

 

 

*ps_data

=

&s__data;

на эту же структуру

 

 

//

Указатель

. . . s_data.stlp

/* эквивалентно

*/

ps__data->stlp

5.2. Унарные операции

Приоритет унарных операций ниже, чем операций ссылок и выполняются они справа налево (см. табл. 16). Унарные операции представлены в табл. 17.

Табл.17. Унарные операции

-

Инвертирование знака

f

Логическое отрицание

++ —

Увеличение, уменьшение

sizeo/{ имя типа )

Размер в байтах

(спецификация типа)выражение

Преобразование типа

~

Поразрядная инверсия (обсуждается ниже в

& *

разделе "Поля битов и побитовые операции")

Адресация, разадресация (обсуждается ниже

 

в разделе "Указатели")

Унарный минус. Является обычной арифметической операци­ ей изменения знака и может использоваться в выражении любого арифметического типа.

При использовании операции "-" тип результирующего значе­ ния тот же, что и тип операнда, над которым выполняется операция.

Логическое отрицание. Операция отрицания "!" изменяет значение "истина" на значение "ложь", а значение "ложь" - на значе­ ние "истина". Напомним, что значению "истина" соответствует не­ нулевое целое значение, а значению "ложь" - нуль.

Увеличение и уменьшение. Операции "++" и "—" могут пред­ шествовать операнду (префиксные операции) или следовать за ним (постфиксные операции). Эти операции соответственно добавляют или вычитают единицу из значения операнда и присваивают ему по­ лученный результат:

 

 

X

=

X

-h

1;

/'^

эквивалентно

*•/

++х;

 

 

 

у

=

у

-

1;

/*

эквивалентно

V

--у;

 

X

=

X

+

1;

 

 

/*

эквивалентны

 

= arrf

-h-i-x 7/

а

=

а г г

[

X

];

 

 

 

 

 

116

а

=

arr

[ X ];

/* эквивалентны

*/

а = arr [ к + + ];

к

=

к

+ 1;

 

 

 

При использовании "++" и "—" тип результирующего значения тот же, что и тип операнда, над которым выполняется операция.

Преобразование

типа. В языке

предусмотрено средство для

явного изменения типа выражения:

 

(

спецификация_типа

)выражение

"Спецификациятипа" может быть любым служебным словом, задающим спецификацию типа, например, int, short, long, float и т.д.

int

 

 

 

 

1

=

11000,

 

w =

4;

 

 

 

 

long

 

 

 

a;

 

 

 

 

 

 

 

 

//

Если целое

занимает 2

байта

(разрядность

процессора

16

//

 

 

бит),

то

здесь

возникает

ошибка при

умножении:

 

//

=

1

44000

>

32767.

Как

быть?

 

 

 

 

 

а

"^ w;

) (

1

* W ) ;

//

И

здесь

возникает

ошибка

при

а

=

(

long

а

=

(

long

)1

*

w;

 

//

 

умножении:

44000

> 32 767

 

//

Так

правильно!

 

 

Другим распространенным примером использования автома­ тического преобразования типа является преобразование типов ар­ гументов при вызове библиотечных функций языка Си. И еще одно важное замечание. В вызовах таких функций аргументы с типом float автоматически преобразуются к типу double, а аргументы с ти­ пом char преобразуются к типу int.

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

Пример.

±пЬ

count,

iarrayl

10

];

) / sizeof

( ±nt

 

 

for( count

= 0; count

< slzeof(

 

larray

)

;

count++

)

= %d\n",

count,

iarrayl

count

]

) ;

printf(

"iarray[%d]

Применение операции sizeof всюду, rjxQ это возможно, счита­ ется хорошим стилем программирования.

117

5.3. Бинарные операции

п р и о р и т е т и порядок выполнения бинарных операций пред­ ставлены в табл. 16. Бинарные операции воздействуют на два выра­ жения:

выражение Ыпор выражение

Здесь Ыпор - одна из бинарных операций, приведенных в табл.

18.

Табл. 18. Бинарные операции

 

, /, %

Умножение, деление, взятие остатка от деления целого на целое

 

Сложение, вычитание

»

Операции сдвига (обсуждаются в разделе "Поля битов и побитовые

операции")

 

Больше, меньше

 

Больше или равно

 

Меньше или равно

 

Равно

&, м

Не равно

Поразрядные логические операции (обсуждаются в разделе "Поля битов

и побитовые операции")

&&,

Логическое И, логическое ИЛИ

Арифметические

операции:

"*", "/", "%", "+" и "-". Эти опе­

рации задают обычные действия над операндами

арифметического

типа. Операция "%" означает получение

остатка

от деления одного

г^елого числа на другое:

 

 

 

1

% j

дает значение

i -

( i/j )

* j

Примеры.

12 % 6 дает О, 13 % 6 дает

1, 3 % 6 дает 3 и т.д.

Если арифметическая операция или операция отношения со­ держит операнды различных типов, то компилятор выполняет авто­ матическое преобразование их типов, если замена типов явно не указана. Такое преобразование производится путем "продвижения"

значений операндов к "наибольшему" типу:

 

 

long

double

(наибольший

тип)

 

 

double

 

 

 

 

 

float

 

 

 

 

unsigned

long

int

 

 

 

 

long

int

 

 

 

 

unsigned

int

 

 

 

 

 

int

 

 

 

 

unsigned.

char

или unsigned

 

short

int

ciiax- или

short

int

(наименьший

тип)

118

Алгоритм выполнения очередной бинарной арифметической операции ("*", "/", "+", "-") или операции отношения ("<", ">", ">=", "<=", "==", "!=") состоит в следующем.

1. Если один операнд имеет тип long double, то и второй опе­ ранд преобразуется к типу long double и выполняется операция. Иначе производится переход к п. 2.

2.Все операнды с типом float преобразуются к типу double и производится переход к п. 3.

3.Если один операнд имеет тип double, то и второй операнд преобразуется к этому же типу и выполняется операция. Иначе вы­ полняется п. 4.

4.Если один операнд имеет тип unsigned long int, то и второй операнд преобразуется к этому же типу и выполняется операция. Иначе выполняется п. 5.

5.Если один операнд имеет тип long int, то и второй операнд преобразуется к этому же типу и выполняется операция. Иначе вы­ полняется п. 6.

6.Если один операнд имеет тип unsigned int, то и второй опе­ ранд преобразуется к этому же типу и выполняется операция. Иначе выполняется п. 7.

7.Если операнды имеют тип unsigned char и/или unsigned short int, то они преобразуются к типу unsigned int и выполняется опера­ ция. Иначе выполняется п. 8.

8.Если операнды имеют тип char и/или short int, то они пре­ образуются к типу int и выполняется операция.

Далее по такому же алгоритму выполняется следующая из пе­ речисленных выше арифметических операций и операций отноше­ ний.

Результат арифметической операции имеет такой же тип, как и тип операндов после преобразования. Результат операции отноше­ ния всегда имеет тип int (О - "ложь", "нет" и 1 - "истина", "да").

И еще раз повторим важное замечание. В вызовах функций ар­ гументы с типом float автоматически преобразуются к типу double, а аргументы с типом char преобразуются к типу int.

Операции отношения. Приоритеты и порядок выполнения операций отношения "<", ">", "<=", ">=", == и "!=** указаны в табл. 16. Операция "==" выполняет проверку на равенство, а операция "!=" - проверку на неравенство. Смысл остальных операций отноше­ ния очевиден.

Запись операции отношения имеет вид:

операнд!

операция__отношения

опера нд2

119