Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_СП_2004_1_00.doc
Скачиваний:
69
Добавлен:
04.11.2018
Размер:
882.69 Кб
Скачать

3. Инициализация переменных и массивов

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

= expression

где expression - произвольное константное выражение. Например:

char sym = 0x73, slash = '/';

int x = 10, y = 15;

float alpha = 4.7, pi = 3.1415, fi = pi/4;

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

= {initializer-list}

где initializer-list - список константных выражений, разделенных запятыми. Например:

int set[4] = { 3, 7, 9, 13 };

char string[6] = { 's', 't', 'r', 'i', 'n', 'g' };

float tab[10] = { 3.5, 6.7, 5.3 };

Заметим, что инициализация массивов допустима лишь при их описании на внешнем уровне программы, т. е. вне тела какой бы то ни было функции, или при явном назначении класса памяти static. Более детальная информация по этому вопросу будет приведена в пятой и седьмой лекциях. Те переменные или элементы массивов, для которых начальные значения явным образом не заданы, инициализируются нулем при их определении на внешнем уровне или при наличии описателя класса памяти static, и остаются неопределенными для автоматических и регистровых переменных. Исключение составляет случай, когда размерность массива не указана:

int mas[] = { 1, 2, 3 };

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

char str[] = "hello";

что эквивалентно описанию

char str[] = { 'h', 'e', 'l', 'l', 'o', '\0' };

В первом случае длина массива полагается равной количеству символов в строке плюс один, а во втором равна количеству элементов в списке инициализации. С другой стороны, описание

char line[80] = "This is a string";

объявляет массив, состоящий из 80 элементов типа char, но лишь 16 из них отличны от нуль- символа. Используемое в этом параграфе понятие классов памяти будет подробно рассмотрено в Лекции 7.

4. Управляющие конструкции языка си

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

4.1. Условный оператор if-else

Условный оператор является простейшим и эффективным средством, позволяющим программировать разветвленные алгоритмы. Его формальный синтаксис задается следующей формулой:

if (expression)

statement1

else

statement2

причем else-часть не является обязательной и может быть опущена. Здесь if и else - ключевые слова языка Си; expression - произвольное выражение, приводимое к логическому значению; statement1 и statement2 - простые или составные операторы. Семантика. Прежде всего вычисляется значение выражения, стоящего в скобках, и полученный результат сравнивается с нулем, что соответствует его интерпретации в терминах "истина"/"ложь". Если результатом является логическое значение "истина" (выражение отлично от нуля), то выполняются действия, отвечающие statement1. В противном случае осуществляется переход к statement2 в else-части условного оператора, а при ее отсутствии - к оператору, непосредственно следующему за оператором if.

В приведенном ниже примере

if (i > 0)

y = x/i;

else

{ x = i/2; y = x + 4; }

оператор y = x/i; будет выполнен, если значение i больше нуля. В противном случае выполняется группа операторов x = i/2; y = x + 4; Замечание. В конструкциях вида

if (n > 0)

if (a > b)

z = a;

else

z = b;

где один оператор if вложен в другой, else-часть связывается с ближайшим предыдущим оператором if. Чтобы изменить это соглашение, необходимо использовать фигурные скобки:

if (n > 0)

{ if (a > b)

z = a; }

else

z = b;

4.2. Оператор-переключатель switch

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

switch (expression)

{

case const-expression: statements

. . .

. . .

default: statements

. . .

. . .

case const-expression: statements

}

где любая case- или default-часть может отсутствовать, а также могут быть опущены statements в любой из этих частей. Здесь switch, case и default - ключевые слова языка Си; expression - произвольное выражение целого типа; const-expressi- on - константное выражение, обрабатываемое в период компиляции программы; state- ments - группа операторов. Семантика. Предварительно вычисленное значение выражения в круглых скобках сравнивается с const-expression во всех вариантах case и управление передается той группе операторов statements, которая соответствует найденному значению. В том случае, когда значение ни одного из константных выражений не совпало со значением выражения expression, выполняются операторы, связанные с меткой default, а при ее отсутствии - оператор, непосредственно следующий за оператором switch. Никакие два константные выражения в одном операторе-переключателе не могут иметь одинаковых значений. В следующем примере значение переменной operation, имеющей тип char, определяет ту арифметическую операцию, которая должна быть выполнена над переменными x и y:

switch (operation)

{

case '+':

z = x + y;

break;

case '-':

z = x - y;

break;

case '*':

z = x*y;

break;

case '/':

z = x/y;

}

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

switch (key)

{

case '0':

case '1':

case '2':

case '3':

case '4':

case '5':

case '6':

case '7':

case '8':

case '9':

printf ("Это цифра");

}

4.3. Оператор цикла while

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

while (expression)

statement

где while - ключевое слово языка Си; expression - произвольное выражение, приводимое к логическому значению (условие продолжения итераций); statement - простой или составной оператор (тело цикла). Семантика. Если значение выражения expression истинно (отлично от нуля), то тело цикла выполняется до тех пор, пока это выражение не станет ложным (равным нулю), причем проверка производится всякий раз перед началом очередной итерации цикла. Если же значение выражения ложно в момент инициализации цикла, то тело цикла не выполняется ни разу и управление передается оператору, следующему за оператором while.

В качестве примера использования оператора цикла с предусловием, рассмотрим фрагмент программы, определяющей длину строки символов string:

count = 0;

while (string[count] != '\0')

count++;

После окончания работы этого фрагмента, значение переменной count равно количеству символов в строке string, не считая завершающего нуль- символа.

4.4. Оператор цикла do-while

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

do

statement

while (expression);

где do и while - ключевые слова языка Си; statement - простой или составной оператор (тело цикла); expression - произвольное выражение, приводимое к логическому значению (условие продолжения итераций). Семантика. После однократного выполнения тела цикла вычисляется значение выражения expression. Если найденное значение истинно (отлично от нуля), то выполняется очередная итерация цикла. Этот процесс повторяется до тех пор, пока значение выражения не станет ложным (равным нулю), после чего управление передается оператору, непосредственно следующему за оператором do-while. Таким образом, тело цикла всегда будет выполнено хотя бы один раз. В качестве примера использования цикла с постусловием, приведем фрагмент программы, выполняющей копирование строки символов string1 в строку string2:

count = 0;

do

string2[count] = string1[count];

while (string1[count++]);

4.5. Оператор цикла for

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

expression1

while (expression2)

{ statement

expression3; }

Общая форма записи оператора цикла for такова:

for (expression1; expression2; expression3)

statement

где for - ключевое слово языка Си; expression1, expression2 и expression3 - произвольные выражения, причем второе из них приводится к логическому значению; statement - простой или составной оператор (тело цикла). Любое из трех выражений, входящих в заголовок цикла, может быть опущено при сохранении следующей за ним точки с запятой. Семантика. Перед началом выполнения цикла вычисляется значение инициализирующего выражения expression1 и значение выражения expression2, играющего роль условия продолжения итераций. Если expression2 истинно (отлично от нуля), то выполняется оператор statement тела цикла, вычисляется корректирующее выражение expression3 и вновь проверяется истинность выражения expression2. Этот процесс повторяется до тех пор, пока условие продолжения итераций не станет ложным (равным нулю), после чего управление передается оператору, следующему за оператором for. В случае отсутствия выражения expression2 ему условно присваивается постоянное значение "истина", что равносильно бесконечному циклическому процессу. В следующем программном фрагменте, вычисляющем сумму элементов числового массива, оператор цикла for используется для организации последовательного доступа ко всем элементам этого массива:

s = 0;

for (i = 0; i < n; i++)

s = s + a[i];

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

for (i = 0, j = n-1; i < j; i++, j--)

{ buf = a[i]; a[i] = a[j]; a[j] = buf; }

4.6. Оператор завершения break

В ряде случаев возникает необходимость завершить выполнение какого-либо оператора цикла или оператора-переключателя раньше, чем это произойдет в соответствии с принятой семантикой этих операторов. Для этой цели служит оператор break, прекращающий выполнение ближайшего вложенного оператора while, do-while, for или switch и передающий управление оператору, следующему за заканчиваемым. Идентификатор break является ключевым словом языка Си. Пусть, например, необходимо найти сумму элементов числового массива до первого отрицательного элемента. Эту задачу можно решить с помощью следующего программного фрагмента:

s = 0;

for (i = 0; i < n; i++)

if (a[i] >= 0)

s = s + a[i];

else

break;

Заметим, что появление оператора break вне одного из операторов while, do-while, for или switch приводит к ошибке на этапе компиляции программы.

4.7. Оператор продолжения continue

При возникновении необходимости прекратить выполнение текущей итерации ближайшего внешнего оператора while, do-while или for и перейти к началу следующей итерации, может быть использован оператор continue. В случае операторов while и do-while очередная итерация начинается с вычисления и проверки истинности выражения expression (см. пп. 1.3. и 1.4.), а в операторе for - с вычисления значения корректирующего выражения expression3 (см. п. 1.5.). Идентификатор continue является ключевым словом языка Си. Пусть в примере п 1.6. теперь необходимо найти сумму всех положительных элементов числового массива. Используя оператор continue, это можно сделать следующим образом:

s = 0;

for (i = 0; i < n; i++)

{ if (a[i] < 0)

continue;

s = s + a[i]; }

4.8. Оператор перехода goto

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

goto label;

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

x = 17;

for (i = 0; i < n; i++)

for (j = 0; j < n; j++)

if (a[i][j] == x)

goto L01;

/* Действия, выполняемые в случае,

если элемент x не найден */

....................................

....................................

....................................

L01: ....................................

4.9. Оператор возврата return

Оператор return прекращает выполнение текущей функции и возвращает управление той функции, из которой была вызвана текущая. В общем случае он имеет следующий формат:

return expression;

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

Если же выражение в операторе return отсутствует, то возвращаемое текущей функцией значение считается неопределенным. Замечание. В случае использования оператора return в главной функции (т.е. функции, имеющей имя main), его действие приводит к прекращению выполнения программы и передаче управления операционной системе. Более подробно этот оператор будет рассмотрен в Лекции 5, посвященной функциям в языке Си.