Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

Программирование в Visual С++ 2005 6 страница



Операция извлечения» "указывает" в направлении, куда передаются данные — в
данном случае, из cin в каждую из двух переменных по очереди. Любые ведущие про-
белы пропускаются, и первое целое значение, введенное с клавиатуры, поступает в
переменную numl. Так происходит потому, что оператор ввода выполняется слева на-
право. Любые пробелы, следующие за numl, игнорируются, и второе введенное целое
значение читается в num2. Между следующими друг за другом значениями должны
быть какие-нибудь пробельные символы, чтобы их можно было разделить. Операция
потокового ввода завершается, когда вы нажимаете клавишу <Enter>, и выполнение
программы продолжается со следующего оператора. Конечно, могут возникать ошиб-
ки, если вы введете некорректные данные, но я предполагаю, что вы всегда все дела-
ете правильно!

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

 


последняя строка читает целое значение в numl, затем значение с плавающей точкой
в factor и, наконец, еще одно целое в num2.

Вывод в командную строку

Вы уже видели в рассмотренных выше примерах вывод в командную строку, но я
все равно хочу вернуться к этой теме. Вывод информации на дисплей осуществляют-
ся способом, дополняющим ввод. Как вы уже видели, поток вывода называется cout,
и для передачи данных в него используется операция вставки «. Эта операция также
"указывает" в направлении движения данных. Вы уже применяли ее для вывода тек-
стовой строки, заключенной в кавычки. Я могу продемонстрировать процесс вывода
значения переменной на примере простой программы.



Описание полученных результатов

Первый оператор в теле main () объявляет и инициализирует две целочисленных
переменных — numl и num2. За ним следуют два оператора вывода, первый из кото-
рых перемещает позицию экранного курсора на новую строку. Поскольку операторы
вывода выполняются слева направо, второй оператор отображает значение перемен-
ной numl, за которым следует значение num2.

Когда вы скомпилируете и запустите приведенный выше код, то получите на экра-
не следующий вывод:

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



Форматирование вывода

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

Просто подставьте вместо него оператор:

 

Конечно, если у вас несколько строк вывода, и вы хотите выровнять колонки, то
вам понадобятся какие-то дополнительные возможности, поскольку вы не знаете,
сколько знаков будет в каждом значении. С этой ситуацией можно справиться, ис-
пользуя то, что называется манипуляторами. Манипулятор модифицирует способ
управления выводом данных в поток (или вводом из потока).


90 Глава 2

 

Манипуляторы определены в заголовочном файле <iomanip>, поэтому вам пона-
добится для него добавить директиву . Манипулятором, который вам не-
обходим, будет setw (n). Он выводит значение, следующее за ним, выравнивая его в
поле пробелов шириной n, то есть setw (6) представит следующее за ним значение
в поле шириной 6 пробелов. Посмотрим на это в действии.

Чтобы получить вывод более похожий на тот, что вам нужен, вы можете изменить
программу следующим образом:

Описание полученных результатов

Среди изменений, внесенных в последнем примере — добавление директивы
♦include для заголовка <iomanip>, добавление объявления using для имени setw из
пространства имен std и вставка манипулятора setw () в выходной поток перед вы-
водом значений каждой переменной, так что их значения выводятся в поля шириной
в шесть символов. В результате вы получите симпатичный четкий вывод, в котором
два значения разделены:

1234 5678

Обратите внимание, что манипулятор setw () работает только с единственным
выходным значением, которое следует непосредственно за его вставкой в поток. Вы
должны вставлять манипуляторы непосредственно перед каждым значением, которое
хотите выровнять в пределах поля определенной ширины. Если вы вставите только
один setw (), он воздействует лишь на первое значение, отправленное в выходной
поток вслед за ним. Любые последующие значения будут выведены в обычной мане-
ре. Можете убедиться в этом, исключив второй setw (6) и его операцию вставки из
последнего примера.

Управляющие последовательности

Когда вы пишете символьную строку, заключенную в двойные кавычки, то мо-
жете включить в нее специальные символы, называемые управляющими последо-
вательностями (escape sequences). Они так называются потому, что позволяют по-
местить в строку символы, которые не могут быть представлены иным образом, за


Данные, переменные и вычисления 91

 

счет того, что они избегают (escaping) обычного процесса интерпретации символов.
Управляющая последовательность начинается с символа обратного слеша \, который
заставляет компилятор интерпретировать следующий за ним символ особым обра-
зом. Например, символ табуляции записывается, как \t, так что t понимается компи-
лятором как табуляция в строке, а не буква 't'. Взгляните на следующие два оператора
вывода:

Они выведут на экран следующие строки:

 

 


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

Фактически, вместо использования endl вы можете применять управляющую по-
следовательность символа новой строки \п в каждой строке, поэтому предыдущие
операторы можно переписать так

 

:


В табл. 2.3 даны некоторые управляющие последовательности, которые могут вам
пригодиться.

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

Вы также можете применять символы, специфицированные управляющими после-
довательностями, в инициализации переменных типа char, например:

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


92 Глава 2


Использование управляющих
последовательностей

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

 

Если вы скомпилируете и запустите эту программу, то увидите следующий вывод:

Описание полученных результатов

Первая строка в main () определяет переменную newline и инициализирует ее
символом новой строки, представленным в виде управляющей последовательности.
Затем вы можете применять newline вместо endl из стандартной библиотеки.

После отправки newline на cout выводится строка, которая применяет управля-
ющие последовательности для представления символов двойной (\ ") и одиночной
(\ *) кавычек. Вы не обязаны использовать управляющую последовательность для оди-
ночной кавычки, потому что строка ограничена двойными кавычками, и компилятор
воспринимает одиночную кавычку внутри нее так, как она есть, а не в качестве разде-
лителя. Однако внутри этой строки для представления двойной кавычки применять
управляющую последовательность необходимо. Строка начинается с управляющей
последовательности — символа новой строки, за которым идет управляющая последо-
вательность символа табуляции, поэтому выходная строка сдвигается на расстояние
табуляции вправо. Строка также заканчивается двумя экземплярами управляющих
последовательностей, выдающих звуковой сигнал, поэтому вы можете услышать два
подряд звуковых сигнала из динамика вашего компьютера.

 

Вычисления в С++

Здесь вы действительно начнете делать что-то с введенными данными. Теперь вы
знаете, как организовать простой ввод и вывод; теперь обратимся к тому, что посре-
дине — той части программы С++, которая занята обработкой данных. Все аспекты
С++, связанные с вычислениями, достаточно интуитивно понятны, так что изучение
этой темы пойдет у вас, как по маслу.


Данные, переменные и вычисления 93

 

Операторы присваивания

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

Оператор присваивания позволяет вычислить значение выражения, стоящего
справа от знака равенства — в данном случае сумму parti, part2 и part3 — и сохра-
нить результат в переменной, указанной слева от знака равенства — в данном случае,
переменной whole. В показанном операторе whole — просто сумма частей, и ничего
более.

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

Это эквивалентно присваиванию значения 2 переменной b с последующим при-
сваиванием значения b переменной а. В результате обе переменных получают значе-
ние 2.

Понятия lvalue и rvalue

lvalue (left value — левое значение) — это нечто такое, что ссылается на адрес памя-
ти и называется так потому, что любое выражение, дающее в результате lvalue, может
быть поставлено слева от знака равенства в операторе присваивания. Большинство
переменных являются lvalue, потому что они специфицируют место в памяти.
Однако, как вы вскоре убедитесь, существуют переменные, которые не являются lval-
ue, и не могут появляться слева в операторах присваивания, потому что их значения
определены как константные.

Переменные а и Ь, которые вы видели в предыдущем разделе, являются lvalue, в
то время как результат вычисления выражения а+b не может быть таковым, посколь-
ку для этого результата не определено место в памяти, где он должен быть сохранен.
Результат выражения, не являющегося lvalue, называют rvalue (right value — правое
значение).

Термин lvalue еще не раз появится в этой книге— иногда там, где вы менее всего будете его
ожидать, поэтому запомните его определение.

 

Арифметические операции

Базовые арифметические операции, которые предоставлены в ваше распоряже-
ние — сложение, вычитание, умножение и деление — обозначаются символами +, -, *
и / соответственно. В основном они работают так, как и можно было ожидать, за ис-
ключением деления, в поведении которого, как вы увидите, существуют некоторые
отклонения, когда оно применяется к целым или константам. Вы можете писать опе-
раторы вроде следующего:

Здесь будет вычислено произведение hours и rate, затем из полученного ре-
зультата вычтено deductions. Операции умножения и деления выполняются перед
операциями сложения и вычитания, чего и следовало ожидать. Позднее в этой гла-


94 Глава 2

 

ве я расскажу подробнее о порядке выполнения различных операций в выражениях.
Общий результат вычисления выражения hours * rate — deductions помещается в
переменную netPay.

Знак минус, использованный в последнем операторе, работает с двумя операнда-
ми — он вычитает значение правого операнда из значения левого операнда. Он на-
зывается бинарной операцией, потому что тут вовлечены два значения. Знак минус
также может быть использован с одним операндом — при этом он меняет его знак на
противоположный. В этом случае его называют унарной операцией. Вы можете напи-
сать следующий код:

 

 


Здесь а будет присвоено значение +5, поскольку унарный минус изменил знак опе-
ранда b.

Обратите внимание, что присваивание не эквивалентно равенству, как принято в
алгебре. Оно специфицирует действие, которое должно быть выполнено, а не кон-
статацию факта. Выражение справа от оператора присваивания вычисляется, и ре-
зультат сохраняется в lvalue — обычно переменной, которая стоит слева.

Взгляните на приведенный ниже оператор:


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



Это значит "прибавить единицу к текущему значению number и затем сохранить
результат обратно в number". Если рассматривать это как алгебраическое выражени-е, оно не имеет смысла.


Данные, переменные и вычисления 95


 


 
 


Если только вы не более тренированы в печати на клавиатуре, чем я, то весьма
вероятно, что при первой попытке компиляции будут обнаружены некоторые опечат-
ки. Когда вы исправите их, программа должна компилироваться и работать успешно.
Возможно, вы получите пару предупреждающих сообщений от компилятора. Не бес-
покойтесь о них — компилятор просто дает вам возможность убедиться в том, что вы
понимаете то, что делаете. Причины сообщений об ошибках я объясню чуть позже.

Описание полученных результатов

Одну вещь хочу подчеркнуть с самого начала — я не несу ответственности за ваш
расход обоев, если при расчете вы воспользуетесь этой программой! Как вы увидите,
ошибки в расчете необходимого количества рулонов, которое выдаст эта программы,
происходят по причине того, как работает С++, и недостаток рулонов для оклейки
реальной комнаты может достичь более 50%!

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

Стоит отметить пару важных моментов, связанных с композицией программы. Во-
первых, операторы в теле main () выровнены так, чтобы их легче было прочесть, и,
во-вторых, различные группы операторов разделены пустыми строками, чтобы выде-
лить функциональные группы. Смещение вправо (indenting) операторов — это фунда-
ментальная техника организации программного кода С++. Вы увидите, что это приме-
няется повсеместно для обеспечения визуального выделения различных логических
блоков программы.

Модификатор const

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

 

 


Оба они начинаются с нового ключевого слова — const. Это модификатор типа,
указывающий, что переменная не только имеет тип double, но также является кон-
стантной. Поскольку вы однозначно сообщаете компилятору, что эти две перемен-
ные — константы, он может проверить любой оператор, который попытается из-
менить значения этих переменных, и если обнаружит такое, выдаст сообщение об
ошибке. Переменная, объявленная как const, не является lvalue, а потому не может
помещаться в левой части оператора присваивания.

Вы можете убедиться в этом, добавив в текст программы где-нибудь после объявле-
ния rollwidth оператор вроде такого:

rollWidth = 0;


96 Глава 2

 

После этого программа перестанет компилироваться, а будет выдана ошибка (ошибка С2166: lvalue специфицирует константный объект).

 

 

Иногда бывает очень удобно определять константы, используемые в программе,
снабжая модификатором const типы переменных, в частности, когда вы используе-
те некоторые константы в программе несколько раз. Во-первых, это гораздо лучше,
чем разбрасывать по всей программе литералы, назначение которых не очевидно.
Например, значение 42 в программе может означать все что угодно, но если вы ис-
пользуете константную переменную по имени myAge, имеющую значение 42, то ее
назначение сразу становится совершенно очевидным. Кроме того, если вам понадо-
бится изменить значение применяемой константной переменной, то вам придется
сделать это один-единственный раз, в одном исходном файле, дабы гарантировать,
что это изменение автоматически появится везде, где упомянутая переменная исполь-
зуется. Эту технику вы будете использовать очень часто.

Константные выражения

Константная переменная rolllength также инициализируется арифметическим
выражением (12. 0*33.0). Возможность использования константных выражений для
инициализации переменных избавляет вас от необходимости вычислять их вручную
при написании программы. К тому же такие выражения могут оказаться более ин-
формативными, потому что, например, 33 фута по 12 дюймов каждый более ясно
указывает на смысл величины, чем если просто написать 396. Обычно компилятор
точно вычисляет константные выражения, в то время как если вы станете делать это
вручную, то в зависимости от сложности выражения и ваших способностей к вычис-
лениям, появляется вероятность того, что оно будет вычислено неверно.

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

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

Ввод программы

После объявления некоторых целочисленных переменных следующие четыре опе-
ратора программы обрабатывают ввод с клавиатуры:

 

 


Здесь выводится текст в cout, приглашающий пользователя ввести необходимую
информацию с клавиатуры, используя с in, который представляет собой стандартный
входной поток. Сначала вы получаете значение height, а затем последовательно чи-
таете length и width. В реальной программе вам понадобилось бы проверить введен-


Данные, переменные и вычисления 97

 

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

Вычисление результата

В рассматриваемой программе присутствует четыре оператора, участвующих в вы-
числении количества стандартных рулонов обоев, необходимых для оклейки комнаты:

 


Первый оператор вычисляет количество полос обоев длиной, равной высоте ком-
наты, которые получаются при разрезке одного стандартного рулона, разделив длину
рулона на высоту комнаты. То есть, если комната имеет высоту 8 футов, то вы делите
96 на 396, что должно дать результат с плавающей точкой, равный 4,125. Но здесь име-
ется одна тонкость. Переменная, куда вы помещаете результат — stripsperroll —
была объявлена как int, поэтому она может хранить только целые значения. Как
следствие, попытка сохранить любое значение с плавающей точкой как целое приво-
дит к округлению к ближайшему меньшему целому — в данном случае, к 4 — и это зна-
чение сохраняется. В общем, это тот результат, который вам нужен, поскольку хотя
они и могут подойти для оклейки стены под окном или над дверью, дробные части
полос обоев лучше проигнорировать при расчете потребности в рулонах.

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

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

Но поскольку такие присваивания неизбежны, вы можете специфицировать при-
ведение явно, чтобы продемонстрировать компилятору, что здесь нет ничего случай-
ного, и это именно то, что вы намеревались сделать. Делается это посредством явно-
го приведения значения в правой части присваивания к типу int, то есть оператор
становится таким:

 


Добавка со скобками вокруг выражения в правой части явно

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


98 Глава 2

 

Обратите внимание на то, как вычисляется периметр комнаты в следующем опе-
раторе. Чтобы умножить сумму length и width на два, выражение сложения заклю-
чается в скобки. Это гарантирует, что сложение будет выполнено первым, а результат
будет умножен на 2.0, чтобы получить правильное значение периметра. С помощью
скобок вы можете гарантировать, что вычисление будет выполнено именно в том по-
рядке, в каком нужно, потому что выражения в скобках всегда выполняются первыми.
Если есть несколько вложенных друг в друга выражений со скобками, то эти выраже-
ния вычисляются последовательно — от внутренних скобок к внешним.

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

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

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

 

Отображение результата

Результат вычисления отображается с помощью следующего оператора:

 


Это один оператор вывода, разнесенный на три строки кода. Сначала оно вы-
водит символ новой строки, затем текстовую строку "Для оклейки вашей комнаты
понадобится ". После этого следует значение переменной nrolls, за которым — еще
одна текстовая строка " рулонов обоев. ". Как видите, операторы вывода на С++ пи-
сать очень легко.

Программа завершается следующим оператором:

Здесь 0 — это возвращаемое значение, которое в данном случае передается опера-
ционной системе. Подробнее о возвращаемых значениях вы узнаете в главе 5.

Вычисление остатка

Вы видели в последнем примере, что деление одного целого значения на другое
дает целое с игнорирированием остатка, поэтому если 11 разделить на 4, то в резуль-
тате получится 2. Поскольку остаток от деления может представлять значительный
интерес, например, когда вы делите печенье между детьми, С++ предусматривает для
этого специальную операцию — %. То есть, проблему деления печений можно решить,
написав следующие операторы:


Данные, переменные и вычисления 99

 

Переменная residue получит значение 4 — число, оставшееся после деления 19 на 5.
Чтобы вычислить, сколько печенья получит каждый ребенок, вы просто используете
деление:


Дата добавления: 2015-11-04; просмотров: 24 | Нарушение авторских прав







mybiblioteka.su - 2015-2024 год. (0.029 сек.)







<== предыдущая лекция | следующая лекция ==>