Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Условные выражения и условные операторы




Управление вычислениями

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

 

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

 

if (Check_For_Connection() == TRUE)

{

Transmit = 1;

}

else

{

Transmit = 0;

}

 

То же самое будет если мы вспомним, что функция Check_For_Connection() сама имеет логическое значение.

 

if (Check_For_Connection())

{

Transmit = 1;

}

else

{

Transmit = 0;

}

 

Или, используя условное присваивание:

 

Transmit = Check_For_Connection()?1:0;

 

и, наконец,

 

Transmit = Check_For_Connection();

 

В последнем случае мы «вспомнили», что логическое значение «истинно» представляется в Си единицей, а «ложно» нулём. Мы специально не воспользовались средствами приведения (преобразования) типа, чтобы добиться максимальной лаконичности записи.

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

С точки зрения понимания того, что делается в программе, первая запись является наиболее удачной. Она же наиболее пригодна для тестирования, так как ветви вычислений в ней явно разделены. Кроме того, даже возвращаемое функцией Check_For_Connection() значение проверяется в отдельной операции сравнения, что позволяет проконтролировать его отдельно, как результат вызова процедуры, перед сравнением с константой TRUE (1).

 

Операторы цикла

 

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

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

Действия цикла могут вообще не начаться, если инвариант сразу ложен.

Давайте посмотрим на фрагмент программы, определяющий есть ли в строке, хранящейся в массиве char Str_In[20] стоящие подряд повторяющиеся символы. Напомним, что признаком конца строки в Си является символ с кодом '\0'.

 

int i, Yes;

char Ch;

i = 0; Ch = Str_In[i]; Yes = 0;

while (Ch!= '\0')

{ if (Ch == Str_In[++i])

Yes = 1;

Ch = Str_In[i];

}

 

Такой цикл будет работать до тех пор пока не «наткнётся» на конец строки. И значение переменной Yes равное единице покажет нам, встречались ли в строке стоящие подряд одинаковые символы. Но цикл можно прекратить и раньше, если в инвариант включить проверку значения переменной Yes.

 

int i, Yes;

char Ch;

i = 0; Ch = Str_In[i]; Yes = 0;

while (Ch!= '\0' && Yes == 0)

{ Yes = (Ch == Str_In[++i]);

Ch = Str_In[i];

}

 

Теперь цикл будет прекращаться, как только в строке встретится пара одинаковых символов. В этом случае и тело удалось упростить, так как если соседние символы равны, то переменная Yes становится истинной и цикл прекращается.

Используя форму цикла do-while или, как его ещё называют, цикл с постусловием, можно ещё более сократить текст подобного фрагмента программы:

 

int i, Yes;

char Ch;

i = 0; Ch = Str_In[i];

do

{ Yes = (Ch == Str_In[++i]);

Ch = Str_In[i];

}

while (Ch!= '\0' && Yes == 0);

 

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

Ещё один вид цикла имеет заголовок определяющий более сложные правила выполнения тела. Это цикл for. В заголовке этого цикла в круглых скобках записываются три оператора. Первый (инициализация цикла) выполняется один раз перед началом работы. Второй — инвариант цикла, определяющий предусловие выполнения тела. И третий оператор выполняется в цикле сразу после тела. Фактически он является завершением тела — его последним оператором.

Проще всего проиллюстрировать этот вид цикла на примере обнуления первых 20 элементов некоторого массива My_Array.

 

int i;

for (i = 0; i < 20; My_Array[i++] = 0);

 

В данном примере собственно определено пустое тело. Все его полезные действия (обнуление очередного элемента массива и увеличение индекса — параметра цикла) уложились в третий элемент заголовка. Более сложный и более «классический» пример использования цикла for приведён ниже.

Пусть мы имеем некоторый 8-ми битовый код в переменной

unsigned char Input_Byte

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

 

unsigned char Reversed_Byte;

unsigned char i;

 

Reversed_Byte = 0;

 

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

{

Reversed_Byte <<= 1; /* Shift output byte left. */

if (Input_Byte & 1) /* If input byte has 1 in the first*/

Reversed_Byte |= 1; /* pos. put 1 into the output byte.*/

Input_Byte >>=1; /* Shift input byte right for the */

} /* next bit */

 

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

 

Reversed_Byte |= Input_Byte & 1;

 

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

С помощью цикла for можно записать и решение задачи по проверке наличия одинаковых символов в строке.

 

int i, Yes;

char Ch;

for (i = 0, Ch = Str_In[i]; Ch!= '\0' && Yes == 0;)

{

Yes = (Ch == Str_In[++i]);

Ch = Str_In[i];

}

 

За счет эквивалентности значений некоторых типов (символьных, целых и логических) можно найти более короткую запись самого цикла:

 

for (i = 0; Ch = Str_In[i] &&! Yes = (Ch == Str_In[i+1]);++i);

 

В этой записи используется то свойство, что условие инварианта цикла вычисляется до тех пор, пока не будет установлено его истинность или ложность. Так, если Ch = Str_In[i] приводит к нулевому результату (текущему символу присвоен признак конца строки), то цикл будет прекращён и вторая часть условия вычисляться не будет. Если же был переслан из строки не нулевой символ, то будет вычисляться вторая часть условия Yes = (Ch == Str_In[i+1]). И если она истинна (символы равны), то отрицание этого приведёт к выходу из цикла.

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

 




Поделиться с друзьями:


Дата добавления: 2014-12-26; Просмотров: 466; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.047 сек.