straustrup2 (852740), страница 28
Текст из файла (страница 28)
Всеоперации отношений:==!=<><=>=дают в результате целое 1, если отношение выполняется, и 0 в противном случае. Обычно определяютконстанты TRUE как 1 и FALSE как 0.В операторе if, если выражение имеет ненулевое значение, выполняется первый оператор, а иначевыполняется второй (если он указан).
Таким образом, в качестве условия допускается любоевыражение типа целое или указатель. Пусть a целое, тогдаif (a)// ...эквивалентноif (a != 0) ...Логические операции&&||!обычно используются в условиях. В операциях && и || второй операнд не вычисляется, если результатопределяется значением первого операнда. Например, в выраженииif (p && l<p->count)// ...сначала проверяется значение p, и только если оно не равно нулю, то проверяется отношение l<p>count.Некоторые простые операторы if удобно заменять выражениями условия. Например, вместооператораif (a <= b)max = b;elsemax = a;лучше использовать выражениеmax = (a<=b) ? b : a;Условие в выражении условия не обязательно окружать скобками, но если их использовать, товыражение становится понятнее.Простой переключатель (switch) можно записать с помощью серии операторов if. Например,switch (val) {case 1:f();break;case 2:g();break;default:h();break;}можно эквивалентно задать так:if (val == 1)f();else if (val == 2)g();elseh();Смысл обеих конструкций совпадает, но все же первая предпочтительнее, поскольку в ней нагляднеепоказана суть операции: проверка на совпадение значения val со значением из множества констант.91Бьерн Страуструп.Язык программирования С++Поэтому в нетривиальных случаях запись, использующая переключатель, понятнее.Нужно позаботиться о каком-то завершении оператора, указанного в варианте переключателя, еслитолько вы не хотите, чтобы стали выполняться операторы из следующего варианта.
Например,переключательswitch (val)case 1:cout <<case 2:cout <<default:cout <<}{// возможна ошибка"case 1\n";"case 2\n";"default: case not found\n";при val==1 напечатает к большому удивлению непосвященных:case 1case 2default: case not foundИмеет смысл отметить в комментариях те редкие случаи, когда стандартный переход на следующийвариант оставлен намеренно. Тогда этот переход во всех остальных случаях можно смело считатьошибкой. Для завершения оператора в варианте чаще всего используется break, но иногдаиспользуются return и даже goto.
Приведем пример:switch (val) {// возможна ошибкаcase 0:cout << "case 0\n";case1:case 1:cout << "case 1\n";return;case 2:cout << "case 2\n";goto case1;default:cout << "default: case not found\n";return;}Здесь при значении val равном 2 мы получим:case 2case 1Отметим, что метку варианта нельзя использовать в операторе goto:goto case 2;// синтаксическая ошибка3.3.2 Оператор gotoПрезираемый оператор goto все-таки есть в С++:goto идентификатор;идентификатор: операторВообще говоря, он мало используется в языках высокого уровня, но может быть очень полезен, еслитекст на С++ создается не человеком, а автоматически, т.е. с помощью программы. Например,операторы goto используются при создании анализатора по заданной грамматике языка с помощьюпрограммных средств.
Кроме того, операторы goto могут пригодиться в тех случаях, когда на первыйплан выходит скорость работы программы. Один из них - когда в реальном времени происходят какието вычисления во внутреннем цикле программы.92Бьерн Страуструп.Язык программирования С++Есть немногие ситуации и в обычных программах, когда применение goto оправдано. Одна из них выход из вложенного цикла или переключателя. Дело в том, что оператор break во вложенных циклахили переключателях позволяет перейти только на один уровень выше.
Приведем пример:void f(){int i;int j;for ( i = 0; i < n; i++)for (j = 0; j<m; j++)if (nm[i][j] == a) goto found;// здесь a не найдено// ...found:// nm[i][j] == a}Есть еще оператор continue, который позволяет перейти на конец цикла. Что это значит, объяснено в$$3.1.5.3.4 Комментарии и расположение текстаПрограмму гораздо легче читать, и она становится намного понятнее, если разумно использоватькомментарии и систематически выделять текст программы пробелами. Есть несколько способоврасположения текста программы, но нет причин считать, что один из них - наилучший. Хотя у каждогосвой вкус.
То же можно сказать и о комментариях.Однако можно заполнить программу такими комментариями, что читать и понимать ее будет толькотруднее. Транслятор не в силах понять комментарий, поэтому он не может убедиться в том, чтокомментарий:[1] осмысленный,[2] действительно описывает программу,[3] не устарел.Во многих программах попадаются непостижимые, двусмысленные и просто неверные комментарии.Лучше вообще обходиться без них, чем давать такие комментарии.Если некий факт можно прямо выразить в языке, то так и следует делать, и не надо считать, чтодостаточно упомянуть его в комментарии.
Последнее замечание относится к комментариям, подобнымприведенным ниже://////////////переменную "v" необходимо инициализировать.переменная "v" может использоваться только в функции "f()".до вызова любой функции из этого файланеобходимо вызвать функцию "init()".в конце своей программы вызовите функцию "cleanup()".не используйте функцию "weird()".функция "f()" имеет два параметра.При правильном программировании на С++ такие комментарии обычно оказываются излишними. Чтобыименно эти комментарии стали ненужными, можно воспользоваться правилами связывания ($$4.2) иобластей видимости, а также правилами инициализации и уничтожения объектов класса ($$5.5).Если некоторое утверждение выражается самой программой, не нужно повторять его в комментарии.Например:a = b + c;count++;// a принимает значение b+c// увеличим счетчик countТакие комментарии хуже, чем избыточные.
Они раздувают объем текста, затуманивают программу имогут быть даже ложными. В то же время комментарии именно такого рода используют для примеров в93Бьерн Страуструп.Язык программирования С++учебниках по языкам программирования, подобных этой книге. Это одна из многих причин, по которойучебная программа отличается от настоящей.Можно рекомендовать такой стиль введения комментариев в программу:[1]начинать с комментария каждый файл программы: указать в общих чертах, что в нейопределяется, дать ссылки на справочные руководства, общие идеи по сопровождениюпрограммы и т.д.;[2]снабжать комментарием каждое определение класса или шаблона типа;[3]комментировать каждую нетривиальную функцию, указав: ее назначение, используемыйалгоритм (если только он неочевиден) и, возможно, предположения об окружении, в которомработает функция;[4]комментировать определение каждой глобальной переменной;[5]давать некоторое число комментариев в тех местах, где алгоритм неочевиден илинепереносим;[6]больше практически ничего.Приведем пример:///*tbl.c: Реализация таблицы имен.Использован метод Гауссасм.
Ральстон "Начальный курс по ..." стр. 411.*/// в swap() предполагается, что стек AT&T начинается с 3B20./************************************Авторские права (c) 1991 AT&T, IncВсе права сохранены**************************************/Правильно подобранные и хорошо составленные комментарии играют в программе важную роль.Написать хорошие комментарии не менее трудно, чем саму программу, и это - искусство, в которомстоит совершенствоваться.Заметим, что если в функции используются только комментарии вида //, то любую ее часть можносделать комментарием с помощью /* */, и наоборот.3.5 Упражнения1.(*1) Следующий цикл for перепишите с помощью оператора while:for (i=0; i<max_length; i++)if (input_line[i] == '?') quest_count++;Запишите цикл, используя в качестве его управляющей переменной указатель так, чтобы условиеимело вид *p=='?'.2.(*1) Укажите порядок вычисления следующих выражений, задав полную скобочную структуру:a = b + c * d <<a & 077 != 3a == b || a == cc = x != 00 <= i < 7f(1,2) + 3a = - 1 + + b -a = b == c ++a = b = c = 0a[4][2] *= * b ?a-b, c=d2 & 8&& c < 5- 5c : * d * 294Бьерн Страуструп.Язык программирования С++3.(*2) Укажите 5 различных конструкций на С++, значение которых неопределено.4.(*2) Приведите 10 разных примеров непереносимых конструкций на С++.5.(*1) Что произойдет при делении на нуль в вашей программе на С++? Что будет в случаепереполнения или потери значимости?6.(*1) Укажите порядок вычисления следующих выражений, задав их полную скобочную структуру:*p++*--p++a-(int*)p->m*p.m*a[i]7.(*2) Напишите такие функции: strlen() - подсчет длины строки, strcpy() - копирование строк и strcmp()- сравнение строк.
Какими должны быть типы параметров и результатов функций? Сравните их состандартными версиями, имеющимися в <string.h> и в вашем руководстве.8.(*1) Выясните, как ваш транслятор отреагирует на такие ошибки:void f(int a, int b){if (a = 3) // ...if (a&077 == 0) // ...a := b+1;}Посмотрите, какова будет реакция на более простые ошибки.9.(*2) Напишите функцию cat(), которая получает два параметра-строки и возвращает строку,являющуюся их конкатенацией. Для результирующей строки используйте память, отведенную спомощью new. Напишите функцию rev() для перевертывания строки, переданной ей в качествепараметра.