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

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

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

char fio[ 30 ];// ФИО

//Номер группы

char

group_name[ 7 ];

 

 

 

char

date[

9 ];//

Дата поступления студента в ВУЗ

float

stip;

 

//

Размер стипендии

 

 

} current;

 

//

Имя структурного объекта

 

Как

и массивам^

структурам может быть

приписан

любой

класс хранения, за исключением класса

register.

Тем самым

будут

определены область

действия и время

жизни структурированного

объекта. Структуры, как и массивы, можно инициализировать. Дополнительно отметим, что для элемента структуры статиче­

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

Для ссылки на элементы

структурного объекта current

следует

использовать операцию "точка". Эту операцию называют

квалифи­

кацией элемента.

 

 

 

/ / Символ, начинающий название факультета

 

current.fak_name[

О ]

 

 

current.stip

// Размер стипендии студента

 

Сколько байтов памяти занимает current? Точный размер этого

объекта можно определить с помощью операции sizeof:

 

s±zeo£( current

) или sizeof ( struct STUDENT__INFO ) ИЛИ

 

sizeof(

STUDENT_INFO )

 

Последний вариант допустим только в языке C++.

Имена элементов структуры не конфликтуют с такими же име­ нами других объектов, имеющих отличающиеся типы:

Int

stip;

//

правильно

struct

STUDENT__INFO

 

 

currentl;

// Тоже правильно

Объекты stip и currentl.stip располагаются в разных областях памяти и имеют разный смысл: с ними можно работать независимо.

Как уже указывалось, структурные объекты можно инициали­ зировать по тем же синтаксическим правилам, что и массивы:

/*

Объявление структурного типа и определение структурирован­ ного объекта с его инициализацией

90

struct

STUDENT_INFO

//

Тэг структуры

{

 

 

 

 

//

Факультет

 

 

сЬяг

fak_name[

30

];

char

fio[ 30 ];//

ФИО

//Номер группы

cbatr

group__name [ 7 ] ;

char

date[

9 ];//

Дата поступления студента в ВУЗ

float

stip;

//

Размер стипендии

} current =

 

//

Имя структурного объекта

{

 

 

 

"ФТК", "Иванов И. И. " , "1081/4", "01-09-97" , 100 000,Of

};

//Можно создавать массив структур, например: struct STUDENT_INFO

group[

12

];

group[ 5],stip

//

Стипендия шестого студента группы

3.9.5. Структуры в качестве аргументов функций

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

Файл Р14.СРР Однофайловый программный проект с двумя функциями. Пример

иллюстрирует передачу структуры в функцию по значению V (следует заметить, что этот способ не рекомендуется)

iinclude <stdlo.h>

// Для функций ввода-вывода

/*

Объявление структурного типа, определение и инициализация структурированного объекта

V

struct

STUDENT_INFO //

Сведения о студенте

{

Факультет

 

//

 

char

fak__name[ 30

];

91

char

fiol 20 ];// ФИО

//Группа

 

char

 

 

group^^name

[

7

];

поступления

 

в

университет

 

char

 

 

date[

9 ];//

Дата

 

 

float

=

 

stlp;

 

 

//

Размер

 

стипендии

 

 

current

 

 

 

 

//

Определение

 

объекта

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

"ФТК:",

 

 

 

 

 

 

 

 

 

 

 

 

 

 

"Иванов

И. И.

 

 

 

 

 

 

 

 

 

 

 

 

 

"1081/4",

 

 

 

 

 

 

 

 

 

 

 

 

 

 

"01-09-97",

 

 

 

 

 

 

 

 

 

 

 

 

 

 

100000,Of

 

 

 

 

 

 

 

 

 

 

 

 

 

 

};

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//

Прототип:

обратите

внимание,

 

как

 

записывается

параметр

//

структура

при

его

передаче

 

по

значению.

 

В

принципе,

//

здесь

прототип

не

обязателен,

 

так

как

файл

содержит

//

определение

функции

 

 

 

 

 

 

 

 

 

 

 

void

dlsplay_s

 

( struct

STUDENT_INFO ) ;

 

 

 

 

 

int

main (

void

)

 

 

//

Возвращает

0

при

успехе

{

// Вызов

функции,

печатающей

строки

массива:

обратите

 

 

//

внимание,

как

записывается

 

 

аргумент-структура

 

d±splay_s

(

current

)

;

 

 

 

 

 

 

 

 

 

 

 

retvLrn

О;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//

Печать

элементов

структуры

 

 

 

 

 

 

 

 

 

void

display_s

 

(

 

 

 

 

 

 

 

 

 

 

 

 

 

 

struct

STUDENT_INFO

//

Структура

для

печати:

передается

 

 

 

 

S )

 

 

//

 

по

значению,

 

т.е.

копируется

{

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

printf(

 

"\п

Факультет:

%s

 

S.fak

 

name

)

;

 

 

printf(

(

"\n

ФИО: %s

",

s.fio

%s

) ;

s.group_name

) .

 

printf

"\n

Номер

группы:

",

 

printf(

 

"\n

Дата поступления:

%s

",

s.date

)

;

 

printf(

 

"\n

Размер

стипендии:

%f

",

s.stip

)

;

 

return;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

/*

Файл

P15.CPP

программный

проект

с двумя

функциями.

Пример

Однофайловый

иллюстрирует

передачу

структуры

в

функцию

по

ссылке.

Такой

способ

передачи

структуры

в функцию

рекомендуется

в

качестве

основного

 

 

 

 

 

 

 

 

 

 

*/

 

 

 

 

 

 

 

 

 

 

^include

 

<stdio.h>

//

Для

функций

ввода-вывода

 

92

Объявление

структурного

типа, определение

и

инициализация

структурного

объекта

 

 

 

 

 

V

 

 

 

 

 

 

 

struct

STUDENT

INFO

// Сведения

о

студенте

 

{

//

cha,r char

//

сЬа.г char float current

{

};

Факультет

fak__name[ 30 ]; fio[ 20 ];// ФИО

Группа

 

7 ];

group__name [

date[

9 ];//

Дата

stip;

//

Размер

=

//

Определение

поступления

в

университет

стипендии

 

 

объекта

"ФТК:", "Иванов И. И. "1081/4", "01-09-97", 100000,Of

//

Прототип:

обратите

внимание,

как

записывается

параметр

//

 

структура

при

его

передаче

по

ссылке.

 

 

void

display_s

 

( struct

STUDENT_INFO

& ) ;

 

 

 

int

main

( void

)

 

 

//

Возвращает

0

при

 

успехе

{

//

Вызов

функции,

печатающей

 

строки

 

массива:

обратите

 

 

 

 

//

 

внимание,

как

записывается

 

 

 

 

аргумент-структура

 

display_s(

 

current

)

;

 

 

 

 

 

 

 

 

 

return

 

0;

 

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//

Печать

элементов

 

структуры

 

 

 

 

 

 

 

void

 

display__s

(

 

 

 

 

 

 

 

 

 

 

 

 

struct

 

STUDENT__INFO

//

Структура

для

печати:

передается

 

 

 

 

 

&S

)

 

//

по

ссылке,

 

т.е.

не

копируется

 

printf(

 

"\п

Факультет:

 

%s ",

s.fak_name

 

)

;

 

 

printf(

 

"\n

ФИО: %s

", s.fio

)

;

 

 

 

 

 

 

print

f (

"\n

Номер

группы:

%s

",

s.group_name

 

) ;

 

printf(

 

"\n

Дата поступления:

 

%s

",

s.date

)

;

 

printf(

 

"\n

Размер

стипендии:

 

%f

",

s.stip

)

;

return;

}

3.9.6Упражнения для самопроверки

1.В текстовом файле "ctrl4.dat" имеется 15 строк, каждая из кото­ рых имеет следующий формат:

93

число_ 1

число_2

Здесь "число_Г' определяет вид геометрической фигуры (1 - квадрат, 2 - круг), а "число_2" - параметр фигуры (при "число 1" — 1 - длина сторо­ ны, а при "число_2" = 2 - радиус).

1.1.Написать определение массива структур для хранения ука­ занных сведений о геометрических фигурах. Каждый элемент массива должен иметь следующие поля:

имя фигуры;

длина стороны или радиус;

площадь фигуры.

1.2.Написать фрагмент программы для чтения из файла на маг­ нитном диске "ctrl4.dat" информации о геометрических фигурах.

1.3.Написать фрагмент программы, вычисляющий площади геометрических фигур.

1.4.Написать фрагмент программы, печатающий в файл "ctrl4.out" параметры геометрических фигур. Сведения об отдельных фигурах располагаются в отдельной строке и имеют вид:

круг: радиус= . . . , площадь^ . . .

квадрат: длина стороны= . . . , площадь= . . .

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

4. ОПЕРАТОРЫ И УПРАВЛЕНИЕ ИХ ИСПОЛНЕНИЕМ

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

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

выбор (ветвление);

итерация (цикл).

Вы уже знакомы с несколькими различными операторами язы­ ка Си, которые реализуют эти конструкции. К ним относятся опера­ торы z/, while, do-while и for.

Однако кроме элементарных конструкций в языках Си/С-н+ существуют и другие операторы, которые помогают облегчить про­ граммирование. Перечень операторов языков Си/С++ в форме син­ таксической диаграммы показан на рис. 31.

4.1. Пустой оператор

Пустой оператор состоит из одного символа — ";". Он не вы­ полняет никаких действий. Тогда возникает вопрос - а зачем он ну­ жен?

Пустой оператор используется как заполнитель в других, более сложных операторах, например, в операторах z/, for, while. По этой причине пустой оператор будет обсуждаться при рассмотрении ука­ занных операторов и им подобных.

4.2. Операторы-выражения

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

95

Оператор

->( return V

->^ break ->r continue

- ^ goto J

'^

AL ^V ' У ^

'

^

Выражение

 

L

^

 

< < >

 

Выражение

4'>

^

^

^

^ь Идентификатор

jf

^switch

Блок

^do-while

while

for

u i ic;|^a 1 Kjyj

Рис. 31. Перечень операторов

4.3. Операторы break и continue

Эти операторы (break - прервать, continue - продолжить), по­ добно пустому оператору, используются в составе других операто­ ров: switch, while, do-while и for. Как и в случае пустого оператора будем касаться их по мере обсуждения тех операторов, в состав ко­ торых они могут входить.

4.4. Блок операторов

Как уже указывалось выше, блок (иногда называемый состав­ ным оператором), состоит из определений объектов (данных), за ко­ торыми следует последовательность операторов. Блок заключается в

96

фигурные скобки. Повторно

отметим,

что

в языке

C++ определе­

ния объектов и операторы

могут чередоваться,

но

определения

объектов долэюны всегда предшествовать

их

использованию.

Обратите также внимание на то, что в описании

синтаксиса

языков Си/С++ всюду, где указан "оператор", в качестве

последнего

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

 

 

 

 

4.5. Оператор return

Этот оператор имеет следующие две формы:

return ( выражение ) ; ИЛИ эквивалентно return,

выражение;

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

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

4.6. Оператор if

Этим оператором уже ранее пользовались и достаточно интен­ сивно. Это объясняется тем, что // один из основных структуриро­ ванных операторов языка Си. Синтаксическая диаграмма этого опе­ ратора представлена на рис. 32.

Работа этого оператора состоит в том, что вначале вычисляет­ ся значение заключенного в скобки "выражения". Если его значение отлично от нуля (!0, "истина"), то выполняется "оператор_1". Если использовано служебное слово else (иначе) и значение "выражения" равно нулю (=0, "ложь"), то выполняется "оператор_2", указанный после служебного слова else. После выполнения "оператора 1" или

97

"оператора_2" управление передается следующему за if оператору программы.

dXIH Выражение

!=0

Оператор_1

 

= 0

•Г

else V ^ Оператор_2

Рис. 32. Синтаксическая диаграмма оператора if

Если значение "выражения" равно нулю, но служебное слово else отсутствует, то управление сразу же передается следующему оператору программы. Обратите внимание, что если вычисление значения "выражения" дает нецелый тип, то полученное значение перед анализом преобразуется к целому типу. Как обычно, в качест­ ве операторов "оператор_1" или "операторе" можно использовать блоки операторов:

±£( а > Ь ) так = а;

else

max = b;

Обратите также внимание на местоположение символов ';'. На­ личие этих символов необходимо потому, что в качестве "оператора_Г' и "оператора_2" используются операторы-выражения, кото­ рые должны заканчиваться ';' (см. рис. 31).

/ / Эквивалентная

запись

±f(a>b)

 

 

 

{

 

 

 

так

=

а;

 

}

 

 

 

else

 

 

 

{

 

 

 

max

=

b;

 

)

 

 

 

В соответствии с синтаксической диаграммой для операторов, приведенной на рис. 31, после операторов-блоков символ ";" не ста­ вится. По этой причине символ "точка с запятой" отсутствует после символов " } " , завершающих блоки.

Поскольку в качестве "оператора 1" и "оператора_2" можно, в частном случае, использовать и оператор if то операторы if могут быть вложенными:

98

char

 

 

 

ch;

 

±f(

ch -=

'a ' ;

 

 

 

index

=

1;

'b ' ;

else

±f(

ch ==

 

index

 

=2;

 

 

else

±f(

ch

==

'y'

)

else

index

=

25;

' z '

)

±f(ch==

26;

else

index

=

 

 

index

=

0;

 

 

 

 

 

В этом примере при значении ch, отличном от одной из строч­ ных букв латинского алфавита, переменной index будет присвоено нулевое значение. Обратите внимание на местоположение вложен­ ных операторов if. Хороший стиль программирования рекомендует помещать вложенный if в охватывающий г^после else\

//

Пример

с

"подводными

камнями"

dovble

 

 

 

а

=

77.

7;

int

 

 

 

 

i

-

5;

 

if(i<3)

i

^=

2

)

 

 

 

 

±f(

 

 

 

 

else

a

=

1.1;

 

 

 

 

a

=

2.2;

 

 

 

//

Здесь

=

7 7.7

 

имеем

a

/ /

Другой

 

пример

=

77. 7/

double

 

 

 

a

int

 

 

 

 

i

=

5;

 

if(i<3)

 

 

 

 

 

 

 

{

±f(

i

-=

2

)

 

 

 

 

 

 

 

I

 

a

=

1.1;

 

 

 

 

 

 

 

 

 

 

 

else

 

2.2;

 

 

 

 

 

//

a =

 

 

a

 

=2.2

 

Здесь

 

имеем

 

 

Почему получены такие результаты? Потому, что языки Си/С++ следуют обычному правилу, согласно которому служебное слово else связывается с ближайшим предыдущим //, с которым еще не было связано else. Иной порядок, как следует из рассмотренного примера, может быть установлен с помощью фигурных скобок.

99