Б. Страуструп - Язык программирования С++ (1119446), страница 26
Текст из файла (страница 26)
Тем более, что обычно нужнопросто вычислить одно выражение. Если это выражение задать как параметр командной строки запускакалькулятора, то можно сэкономить несколько нажатий клавиши.Как уже было сказано, выполнение программы начинается вызовом main(). При этом вызове main()получает два параметра: число параметров (обычно называемый argc) и массив строк параметров(обычно называемый argv).
Параметры - это символьные строки, поэтому argv имеет тип char*[argc+1].Имя программы (в том виде, как оно было задано в командной строке) передается в argv[0], поэтомуargc всегда не меньше единицы. Например, для командной строкиdc 150/1.1934параметры имеют значения:argcargv[0]argv[1]argv[2]2"dc""150/1.1934"0Добраться до параметров командной строки просто; проблема в том, как использовать их так, чтобы неменять саму программу. В данном случае это оказывается совсем просто, поскольку входной потокможет быть настроен на символьную строку вместо файла ($$10.5.2).
Например, можно определить cinтак, чтобы символы читались из строки, а не из стандартного входного потока:int main(int argc, char* argv[]){switch(argc) {case 1:// считывать из стандартного входного потокаbreak;case 2:// считывать из строки параметровcin = *new istream(argv[1],strlen(argv[1]));break;default:error("слишком много параметров");return 1;}// дальше прежний вариант main}При этом istrstream - это функция istream, которая считывает символы из строки, являющейся еепервым параметром. Чтобы использовать istrstream нужно включить в программу файл <strstream.h>, ане обычный <iostream.h>. В остальном же программа осталась без изменений, кроме добавленияпараметров в функцию main() и использования их в операторе switch.
Можно легко изменить функциюmain() так, чтобы она могла принимать несколько параметров из командной строки. Однако это неслишком нужно, тем более, что можно нескольких выражений передать как один параметр:dc "rate=1.1934;150/rate;19.75/rate;217/rate"Кавычки необходимы потому, что символ ';' служит в системе UNIX разделителем команд. В другихсистемах могут быть свои соглашения о параметрах командной строки.3.2 Сводка операцийПолное и подробное описание операций языка С++ дано в $$R.7. Советуем прочитать этот раздел.Здесь же приводится краткая сводка операций и несколько примеров.
Каждая операциясопровождается одним или несколькими характерными для нее именами и примером ее использования.79Бьерн Страуструп.Язык программирования С++В этих примерах class_name обозначает имя класса, member - имя члена, object - выражение, задающееобъект класса, pointer - выражение, задающее указатель, expr - просто выражение, а lvalue (адрес) выражение, обозначающее не являющийся константой объект.
Обозначение (type) задает имя типа вобщем виде (с возможным добавлением *, () и т.д.). Если оно указано без скобок, существуютограничения.Порядок применения унарных операций и операций присваивания "справа налево", а всех остальныхопераций - "слева направо". То есть, a=b=c означает a=(b=c), a+b+c означает (a+b)+c, и *p++ означает*(p++), а не (*p)++.80Бьерн Страуструп.::::.->[]()()sizeofsizeof++++--~!+&*newdeletedelete[](). *->**/%+<<>><<=>>===!=&^|&&||?:=*=/=%=+=-=<<=Язык программирования С++Операции С++Разрешение области видимостиГлобальноеВыбор членаВыбор членаИндексированиеВызов функцииСтруктурное значениеРазмер объектаРазмер типаПостфиксный инкрементПрефиксный инкрементПостфиксный декрементПрефиксный декрементДополнениеЛогическое НЕУнарный минусУнарный плюсВзятие адресаКосвенностьСоздание (размещение)Уничтожение (освобождение)Уничтожение массиваПриведение(преобразование)типаВыбор члена косвенныйВыбор члена косвенныйУмножениеДелениеОстаток от деленияСложение (плюс)Вычитание (минус)Сложение (плюс) Сдвиг влевоСдвиг вправоМеньшеМеньше или равноБольшеБольше или равноРавноНе равноПоразрядное ИПоразрядное исключающее ИЛИПоразрядное включающее ИЛИЛогическое ИЛогическое ИЛИОперация условияПростое присваиваниеПрисваивание с умножениемПрисваивание с делениемПрисваивание с взятием остатка от деленияПрисваивание со сложениемПрисваивание с вычитаниемПрисваивание со сдвигом влево81class_name :: member:: nameobject .
memberpointer -> memberpointer [ expr ]expr ( expr_list )type ( expr_list )sizeof exprsizeof ( type )lvalue ++++ lvaluelvalue --- lvalue~ expr! expr- expr+ expr& lvalue* exprnew typedelete pointerdelete[] pointer( type ) exprobject . pointer-to-memberpointer -> pointer-to-memberexpr * exprexpr / exprexpr % exprexpr + exprexpr - exprexpr << exprexpr >> exprexpr < exprexpr <= exprexpr > exprexpr >= exprexpr == exprexpr != exprexpr & exprexpr ^ exprexpr | exprexpr && exprexpr || exprexpr? expr : exprlvalue = exprlvalue *= exprlvalue /= exprlvalue %= exprlvalue += exprlvalue -= exprlvalue <<= exprБьерн Страуструп.>>=&=|=^=,Язык программирования С++Присваивание со сдвигом вправоПрисваивание с поразрядным ИПрисваивание с поразрядным включающим ИЛИПрисваивание с поразрядным исключающим ИЛИЗапятая (последовательность)lvalue >>= exprlvalue &= exprlvalue |= exprlvalue ^= exprexpr , exprВсе операции таблицы, находящиеся между двумя ближайшими друг к другу горизонтальными чертами,имеют одинаковый приоритет.
Приоритет операций уменьшается при движении "сверху вниз".Например, a+b*c означает a+(b*c), так как * имеет приоритет выше, чем +; а выражение a+b-c означает(a+b)-c, поскольку + и - имеют одинаковый приоритет, и операции + и - применяются "слева направо".82Бьерн Страуструп.Язык программирования С++3.2.1 СкобкиСинтаксис языка С++ перегружен скобками, и разнообразие их применений способно сбить с толку. Онивыделяют фактические параметры при вызове функций, имена типов, задающих функции, а такжеслужат для разрешения конфликтов между операциями с одинаковым приоритетом.
К счастью,последнее встречается не слишком часто, поскольку приоритеты и порядок применения операцийопределены так, чтобы выражения вычислялись "естественным образом" (т.е. наиболеераспространенным образом). Например, выражениеif (i<=0 || max<i)// ...означает следующее: "Если i меньше или равно нулю, или если max меньше i". То есть, оноэквивалентноif ( (i<=0) || (max<i) )// ...но не эквивалентно допустимому, хотя и бессмысленному выражениюif (i <= (0||max) < i)// ...Тем не менее, если программист не уверен в указанных правилах, следует использовать скобки, причемнекоторые предпочитают для надежности писать более длинные и менее элегантные выражения, как:if ( (i<=0) || (max<i) )// ...При усложнении подвыражений скобки используются чаще.
Не надо, однако, забывать, что сложныевыражения являются источником ошибок. Поэтому, если у вас появится ощущение, что в этомвыражении нужны скобки, лучше разбейте его на части и введите дополнительную переменную.Бывают случаи, когда приоритеты операций не приводят к "естественному" порядку вычислений.Например, в выраженииif (i&mask == 0)// ловушка! & применяется после ==не происходит маскирование i (i&mask), а затем проверка результата на 0. Поскольку у == приоритетвыше, чем у &, это выражение эквивалентно i&(mask==0). В этом случае скобки играют важную роль:if ((i&mask) == 0)// ...Имеет смысл привести еще одно выражение, которое вычисляется совсем не так, как мог бы ожидатьнеискушенный пользователь:if (0 <= a <= 99)// ...Оно допустимо, но интерпретируется как (0<=a)<=99, и результат первого сравнения равен или 0, или1, но не значению a (если, конечно, a не есть 1). Проверить, попадает ли a в диапазон 0...99, можно так:if (0<=a && a<=99)// ...Среди новичков распространена ошибка, когда в условии вместо == (равно) используют = (присвоить):if (a = 7)// ...// ошибка: присваивание константы в условииОна вполне объяснима, поскольку в большинстве языков "=" означает "равно".
Для транслятора несоставит труда сообщать об ошибках подобного рода.3.2.2 Порядок вычисленийПорядок вычисления подвыражений, входящих в выражение, не всегда определен. Например:int i = 1;v[i] = i++;Здесь выражение может вычисляться или как v[1]=1, или как v[2]=1. Если нет ограничений на порядоквычисления подвыражений, то транслятор получает возможность создавать более оптимальный код.Транслятору следовало бы предупреждать о двусмысленных выражениях, но к сожалению83Бьерн Страуструп.Язык программирования С++большинство из них не делает этого. Для операций&&||,гарантируется, что их левый операнд вычисляется раньше правого операнда. Например, в выраженииb=(a=2,a+1) b присвоится значение 3.
Пример операции || был дан в $$3.2.1, а пример операции && естьв $$3.3.1. Отметим, что операция запятая отличается по смыслу от той запятой, которая используетсядля разделения параметров при вызове функций. Пусть есть выражения:f1(v[i],i++);f2( (v[i],i++) )// два параметра// один параметрВызов функции f1 происходит с двумя параметрами: v[i] и i++, но порядок вычисления выраженийпараметров неопределен. Зависимость вычисления значений фактических параметров от порядкавычислений - далеко не лучший стиль программирования. К тому же программа становитсянепереносимой. Вызов f2 происходит с одним параметром, являющимся выражением, содержащимоперацию запятая: (v[i], i++).
Оно эквивалентно i++.Скобки могут принудительно задать порядок вычисления. Например, a*(b/c) может вычисляться как(a*b)/c (если только пользователь видит в этом какое-то различие). Заметим, что для значений сплавающей точкой результаты вычисления выражений a*(b/c) и (a*b)/ могут различаться весьмазначительно.3.2.3 Инкремент и декрементОперация ++ явно задает инкремент в отличие от неявного его задания с помощью сложения иприсваивания. По определению ++lvalue означает lvalue+=1, что, в свою очередьозначаетlvalue=lvalue+1 при условии, что содержимое lvalue не вызывает побочных эффектов. Выражение,обозначающее операнд инкремента, вычисляется только один раз. Аналогично обозначается операциядекремента (--). Операции ++ и – могут использоваться как префиксные и постфиксные операции.Значением ++x является новое (т.