Отправляет email-рассылки с помощью сервиса Sendsay

C и C++ для начинающих

  Все выпуски  

C и C++ для начинающих


Служба Рассылок Subscribe.Ru проекта Citycat.Ru

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

Сразу хочу извиниться за прошлый раз: я не рассказал вам о функции вычисления квадратного корня, необходимой в домашнем задании. Это функция
 double sqrt (double x);
объявленная в файле <math.h>

Еще одно техническое замечание: в связи с некоторыми обстоятельствами (а конкретно - надвигающейся сессией) переодичность выпусков рассылки временно (ориентировочно до середины июня) будет понижена до одного раза в неделю.

Небольшое предисловие: в С, как и во многих других языках, существует конструкция так называемого составного выражения. Он позволяет трактовать несколько выражений как одно. В С составное выражение заключается в фигурные скобки:
 {
  выражение_1;
  выражение_2;
    ......
  выражение_n;
 }
Обратите внимание, что составное выражение в С не возвращает значения.

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

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

Пример:
 #include <math.h>

 double SafeSqrt (double x)
 {
  if (x >= 0)
   return sqrt (x);
  else
  {
   printf ("Ошибка: корень из отрицательного числа не существует\n");
   return 0;
  }
 }
Что делает эта функция? Как можно видеть, она проверяет, можно ли из данного числа извлечь корень, и если можно, то извлекает его. В противном случае она печатает на экране сообщение об ошибке. Теперь вы можете вызывать эту функцию и не волноваться по поводу возможного аварийного завершения работы программы.

Следует иметь в виду, что вся конструкция if-else является простым выражением, но не возвращает никакого значения, поэтому не может стоять в условии другой конструкции if.
 if (a > 5)
  if (a == 10)
   printf ("a\n");
 else
  printf ("b\n");
Внимание, вопрос: когда напечатается символ "b"? Глядя на текст, можно подумать, что это произойдет в том случае, если a < 5. Тем не менее по правилам языка C слово else относится к ближайшему для него слову if, так что "b" будет напечатано, если а больше 5, но не равно 10. (Помните, что C не обращает внимания на фроматирование текста. Вы можете даже переписать весь текст программы в одну строчку). Для того, чтобы достичь желаемого эффекта, необходимо написать этот участок так:
 if (a > 5)
 {
  if (a == 10)
   printf ("a\n");
 }
 else
  printf ("b\n");
Еще одно замечание. В С в качестве условия может стоять любое выражение. Иногда это может привести к труднонаходимым ошибкам. Пример:
 int a;

 a = 5;
 if (a = 2)
  printf ("а равно 2\n");
 else
  printf ("a не равно 2\n");
Вопреки ожиданиям, программа все время будет печатать, что а равно 2. В чем дело? Внимательно присмотритесь к условию: мы просто написали a = 2 вместо a == 2, то есть в условии стоит оператор присваивания, а он, как я писал ранее, возвращает присвоенное значение (то есть 2). Это значение интерпретируется компилятором как True, т.к. 2 не равно нулю, и выполняется соответствующая ветвь. С другой стороны, это дает языку дополнительную гибкость:
 char ch;

 if ((ch = getch ()) == 27)
  printf ("Вы нажали Escape\n");
(здесь используется функция чтения одного символа со стандартного устройства ввода (то есть клавиатуры)
 char getch (void);
объявленная в файле <conio.h>). В данном случае с клавиатуры читается один символ, заносится в переменную ch и проверяется на соответствие коду клавиши Esc (27) - и все это одним выражением.

Теперь чуть более сложная задача. Необходимо написать функцию, которая принимает целое число от 1 до 5 и печатает его в виде строки (т.е. "один", "два", и т.д.) Конечно, это можно сделать так:
 #include <stdio.h>

 void myfunc (int a)
 {
  if (a == 1)
   printf ("Один\n");
  else
   if (a == 2)
    printf ("Два\n");
   else
    if (a == 3)
     printf ("Три\n");
    else
     if (a == 4)
      printf ("Четыре\n");
     else
      if (a == 5)
       printf ("Пять\n");
      else
       printf ("Неизвестное число\n");
 }
Язык С представляет более удобную форму выполнения необходимой нам задачи. Это управляющая конструкция выбора:
 #include <stdio.h>

 void myfunc (int a)
 {
  switch (a)
  {
   case 1:
    printf ("Один\n");
    break;
   case 2:
    printf ("Два\n");
    break;
   case 3:
    printf ("Три\n");
    break;
   case 4:
    printf ("Четыре\n");
    break;
   case 5:
    printf ("Пять\n");
    break;
   default:
    printf ("Неизвестное число\n");
    break;
  }
 }
Как работает эта конструкция? Как вы можете догадаться, она ищет строку "case значение_переменной_а" и исполняет участок кода от нее до конца блока switch или до зарезервированного слова break. Если соответствий не найдено, исполняется блок default.

Зачем нужно слово break? Оно придает больше гибкости конструкции. Рассмотрим такой участок кода:
 switch (a)
 {
  case 1:
   b = 5;
  case 2:
   printf ("a = 1 или a = 2\n");
   break;
  case 3:
   printf ("a = 3\n");
 }
Как он будет себя вести? Если a = 1, то переменная b получит значение 5, а затем будет выведена строка "a = 1 или a = 2". Если же a = 2, то будет выведена так же строка. Таким образом, одно действие включает в себя другое, при этом в коде нет повторяющихся участков.

Частным случаем может служить тот вариант, когда в ответ на несколько значений переменной предусмотрена одинаковая реакция. В таким случае достаточно поставить несколько слов case подряд:
 switch (a)
 {
  case 1:
  case 2:
   printf ("a = 1 или a = 2\n");
   break;
  case 3:
  case 4:
   printf ("a = 3 или a = 4\n");
   break;
 }
Еще одно замечание: в качестве меток case могут выступать только целочисленные константы. Поэтому если вам необходимо сравнивать значение с переменной или с дробной величиной - вам придется пользоваться конструкцией if. В языке С есть еще один очень мощный способ ветвления - это оператор ?:. Он оформляется так:
 условие ? выражение_1 : выражение_2
В общем этот оператор действует так же, как и if - выполняет выражение_1, если условие истинно, и выражение_2 в противном случае. Тем не менее он сильно отличается от if: это оператор, то есть он возвращает значение (это значение, возвращенное выполненной веткой) и не может содержать в качестве частей составные выражения. Пример:
 int max1 (int a, int b)
 {
  if (a > b)
   return a;
  else
   return b;
 }

 int max2 (int a, int b)
 {
  return (a > b) ? a : b;
 }
Сравните эти две идентичные по работе функции. Какая из них вам больше понравилась?

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

Домашнее задание:
  1. Теперь модифицируйте вашу программу решения квадратного уравнения (или напишите ее) так, чтобы она решала любые кавдратные уравнения (в том числе вырожденные).
  2. Написать функцию, которая определяет существование и тип треугольника с тремя заданными сторонами (длины сторон передаются в функцию как параметры). Возвращать 0, если треугольник не существует, 1 - если треугольник существует и он остроугольный, 2 - в остальных случаях.
Напоминание: для того, чтобы вести рассылку макстмально эффективно, мне нужна обратная связь. На сегодняшний момент на рассылку подписаны уже 14 человек, и я до сих пор не получил ни одного письма. То есть вопросов ни у кого из вас нет. А, насколько мне известно, вопросов не бывает в двух случаях: когда все понятно или когда ничего не понятно. Так какой из вариантов имеет место быть? Также могу порекомендовать присылать решения домашних заданий. Если сильно боитесь за свой ящик - присылайте с QuickMail'а. Помните: для меня очень важно ваше мнение!

За сим все. До встречи!

Ведущий рассылки, av

http://subscribe.ru/
E-mail: ask@subscribe.ru

В избранное