СДЕЛАЙТЕ СВОИ УРОКИ ЕЩЁ ЭФФЕКТИВНЕЕ, А ЖИЗНЬ СВОБОДНЕЕ
Благодаря готовым учебным материалам для работы в классе и дистанционно
Скидки до 50 % на комплекты
только до
Готовые ключевые этапы урока всегда будут у вас под рукой
Организационный момент
Проверка знаний
Объяснение материала
Закрепление изученного
Итоги урока
Опорный конспект для студентов 1-2 курсов при изучении языка программирования С++
Язык программирования С++.
Литература:
Лафоре Р. Объектно-ориентированное программирование в С++ – СПб.:Питер, 2003.
Павловская Т.А. C/C++ Программирование на языке высокого уровня. – СПб.:Питер, 2003.
Подбельский В.В. Язык С++: Учебное пособие.– М.: Финансы и статистика, 2000.
Страуструп Б. Язык программирования С++.– СПб.:Бином, 2002.
История и эволюция C++
С++ — компилируемый строго типизированный язык программирования общего назначения. Поддерживает разные парадигмы программирования: процедурную, обобщённую, функциональную; наибольшее внимание уделено поддержке объектно-ориентированного программирования.
Язык С. 1972 г. Денис Ритчи (Bell), цель – системное программирование (UNIX)
Язык С++. 1983 г. Бьерн Страуструп (Bell), цель – реализация методологии ООП
Язык Java. 1994 г. Патрик Наутон, Билл Джой, Джеймс Гослинг (Sun), цель – переносимость и надежность
Язык C#. 2000 г. Андерс Хейлсберг и др. (Microsoft), цель – удобство и надежность
Perl, PHP. цель – простота использования
Этапы создания программы
Алфавит языка С++
Прописные и строчные латинские буквы (различаются в именах), знак подчеркивания
Цифры (0…9)
Специальные знаки “ { } , | [ ] ( ) + - * / % \ ; ‘ : ? ! & ~ ^ . #
Разделители (пробел, табуляция, перевод строки)
Лексемы С++
Имена ( не рекомендуется начинать с _)
Ключевые слова
Знаки операций (одно и двухсимвольные)
Константы
Разделители
Комментарии
однострочные // комментарий
многострочные /* длинные */
Типы данных С++
Базовые типы
|
| C/C++ | Pascal (Delphi) |
| Целые | char | shortint |
|
| int (short int) | integer |
|
| unsigned char | byte |
|
| unsigned int (short) | word |
|
| long int | longint |
|
| unsigned long int | cardinal |
| Веществ. | float | single |
|
| double | double |
|
| long double | extended |
Специальные типы
bool – логический (true/false) – в С++
В С целое значение =0 – ложь, не равно 0 - истина
void–пустой. Используется для обозначения функций без значений и нетипизированных указателей
Константы
Целые:
десятичные 123, 0, 98
восьмеричные 01, 015
шестнадцатиричные 0xA1, 0X00FF
Вещественные 5.8, .2e-3
Символьные ‘A’, ‘xy’, ‘\n’, ‘\123’, ‘\\’
Строковые “привет”, “1 \n 2”
Структура программы
#include iostream.h
main()
{
cout n”;
return 0;
}
Строка #include является директивой препроцессора, т.е. сообщением препроцессору С++. Строки, начинающиеся с #, обрабатываются препроцессором перед компиляцией программы. Данная строка дает указание препроцессору включить в программу содержание головного файла потока ввода/вывода iostream.h. Этот файл должен быть включен для всех программ, которые выводят данные на экран или вводят данные с клавиатуры, используя принятый в С++ стиль, основанный на понятии потока ввода-вывода.
Строка main() является частью каждой программы на С++. Круглые скобки после main показывают, что main — это программный блок, называемый функцией. Программа на С++ содержит одну или более функций, одна из которых должна быть main. Обычно программа на С++ начинается выполнением функции main, даже если main — не первая функция программы.
Левая фигурная скобка { должна начинать тело каждой функции. Соответствующая правая фигурная скобка } должна заканчивать каждую функцию.
Строка cout n"; является командой компьютеру напечатать на экране строку символов, заключенную в кавычки. Полная строка, включающая cout, операцию n" и точку с запятой (;), называется оператором. Каждый оператор должен закапчиваться точкой с запятой (известной также как признак конца оператора).
Все вводы и выводы в С++ выполняются над потоками символов. Таким образом, когда выполняется предыдущий оператор, он посылает поток символов Добро пожаловать в С++! объекту стандартный поток вывода cout, который обычно «связан» с экраном.
Операция называется операцией поместить в поток. При выполнении этой программы значение справа от оператора, правый операнд, помещается в поток вывода. Символы правого операнда обычно выводятся в точности так, как они выглядят между двойными кавычками. Заметим, однако, что символы \n не выводятся на экране.
Обратный слэш (\) называется знаком перехода или escape-символом (эскейп). Он свидетельствует о том, что должен выводиться «специальный» символ. Когда обратный слэш встречается в цепочке символов, следующий символ комбинируется с обратным слэшем и формирует управляющую последовательность (escape последовательность). Управляющая последовательность \n означает новую строку. Она вызывает перемещение курсора (т.е. индикатора текущей позиции на экране) к началу следующей строки на экране.
Управляющая последовательность
| \n | Новая строка. Позиционирование курсора к началу следующей строки. |
| \t | Символ горизонтальной табуляции. Перемещение курсора к следующей позиции табуляции. |
| \r | Возврат каретки. Позиционирование курсора к началу текущей строки, запрет перехода к следующей строке. |
| \a | Сигнал тревоги. Звук системного звонка. |
Строка return 0 показывает, что программа успешно окончена. Включается в конце каждой функции main. Ключевое слово С++ return — один из нескольких способов выхода из функции. Когда оператор return используется в конце main, как в этой программе, значение 0 свидетельствует о том, что программа завершена успешно.
Пример программы
#include iostream.h
int main()
{ int a, b; //описание переменных
cin a b; //ввод
cout сумма” вывод
return 0; //возврат
}
В C++ ввод/вывод выполняется с использованием операторов, а не функций ввода/вывода.
Оператор вывода — это , а оператор ввода — .
Рассмотрим следующую инструкцию C++:
cout
Эта инструкция осуществляет вывод строки в заранее определенный поток cout, который автоматически связывается с терминалом, когда программа C++ начинает выполняться. С помощью оператора вывода
cout
В общем случае, для вывода на экран терминала используется следующая обычная форма оператора
сout
Здесь выражение может быть любым действительным выражением C++, включая другие выражения вывода. Для считывания значения с клавиатуры, используйте оператор ввода . Например, в этом фрагменте целая величина вводится в num:
int num;
cin num;
В общем случае для ввода значения с клавиатуры, используйте следующую форму оператора :
cin переменная;
Расширенное толкование символов является примером перегрузки операторов. Для правильного использования операторов ввода/вывода в C++ вы должны включить в программу заголовочный файл iostream.h. Он является одним из стандартных заголовочных файлов C++ и поставляется с компилятором.
Большинство программ выполняет арифметические вычисления. На рисунке 1 звездочка (*) обозначает умножение, а знак процента (%) —- это операция вычисления остатка. Арифметические операции на рисунке 1 являются бинарными операциями.
Рис. 1. Арифметические операции.
Целочисленное деление дает целый результат; например, выражение 7/4 равно 1, а выражение 17/5 равно 3. Заметим, что любая десятичная часть при целочисленном делении просто отбрасывается (т.е. усекается) — округление не производится.
В С++ имеется операция вычисления остатка %, которая дает в качестве результата остаток от целочисленного деления. Выражение х % у дает остаток от деления х на у. Таким образом, 7 % 4 равно 3, 17 % 5 равно 2.
Попытка использования операции вычисления остатка % с нецелочисленными операндами является синтаксической ошибкой.
Арифметические выражения на С++ должны быть записаны в одну строку, чтобы программу можно было ввести в компьютер. Таким образом, такое выражение как «а разделить на b» должно быть записано в виде а / b так, чтобы все константы, переменные и операции размещались в одной строке.
Круглые скобки используются в С++ в основном точно так же, как и в алгебраических выражениях. Например, чтобы перемножить величины а и b+с, надо написать
а * (b + c)
С++ применяет операции в арифметических выражениях в порядке старшинства, определенного правилами старшинства операций, которые, вообще говоря, совпадают с теми, которые используются в алгебре:
1. Операции в выражениях, заключенных внутри круглых скобок, выполняются в первую очередь. Таким образом, круглые скобки можно использовать для формирования любой желательной для программиста последовательности вычислений. Скобки имеют высший уровень приоритета. В случае вложенных, или встроенных круглых скобок операции внутри самой внутренней пары круглых скобок выполняются первыми.
2. Следующими выполняются операции умножения, деления и вычисления остатка. Если выражение содержит несколько операций умножения, деления и вычисления остатка, то операции выполняются слева направо. Говорят, что операции умножения, деления и вычисления остатка имеют одинаковый уровень приоритета.
3. Операции сложения и вычитания выполняются последними. Если выражение содержит несколько операций сложения и вычитания, то операции выполняются слева направо. Операции сложения и вычитания тоже имеют одинаковый уровень приоритета.
Правила старшинства операции дают возможность выполнять операции в правильной последовательности.
Последовательность выполнения операций.
Рассмотрим несколько выражений в свете правил, определяющих последовательность выполнения операций. Каждый пример представляется алгебраическим выражением и его эквивалентом на С++.
Ниже приводится пример среднего арифметического значения пяти членов:
Алгебра: m=
С++: m = (а + b + с + d + e) /5;
Круглые скобки необходимы, так как деление имеет более высокий уровень приоритета, чем сложение. Полная величина (a + b + c + d + e) делится на 5.
Если ошибочно проигнорировать круглые скобки, получим a+b+c+d+e/5, что эквивалентно a+b+c+d+
Следующий пример — уравнение прямой линии: Алгебра: у = mx + b C++: y= m*x+b
Никаких круглых скобок не требуется. Умножение выполняется первым, потому что оно имеет более высокий приоритет, чем сложение.
Следующий пример содержит операции вычисления остатка (%), умножения, деления, сложения и вычитания:
Операции отношений
Если операции ==. !=, = и = и и =
Смешивание операции проверки на равенство == с операцией присваивания =. Операция проверки на равенстве должна читаться как «равно», а операция присваивания должна читаться как «присваивает».
Математические функции.
Операции присваивания.
В С++ имеется несколько операций присваивания, позволяющих сокращать запись присваиваемых выражений. Например, оператор с = с + 3; может быть сокращен применением составной операции сложения += : с += 3;
Операция += прибавляет значение выражения, записанного справа от операции, к величине переменной, указанной слева, и сохраняет результат в этой переменной. Любой оператор вида
переменная = переменная операция выражение;
где операция — одна из бинарных операций +, *, / или % (или иные операции), может быть записан в виде
переменная операция = выражение;
Таким образом, присваивание с += 3 добавляет 3 к с.
Арифметические операции присваивания.
Компилятор может компилировать немного быстрее, если использовать «сокращенные» операции присваивания (составные присваивания). Некоторые компиляторы генерируют код, который выполняется быстрее при использовании «сокращенных» операций присваивания. Значительное повышение эффективности получается, если такие небольшие улучшения находятся внутри цикла и могут повторяться много раз.
Операции инкремента и декремента.
В С++ имеется унарная операция инкремента ++ (увеличение на 1) и унарная операция декремента -- (уменьшение на 1). Если переменная с должна быть увеличена на 1, лучше применить оператор ++, чем выражения с=с+1 или с+=1. Если операция инкремента или декремента помещена перед переменной, говорят о префиксной форме записи инкремента или декремента. Если операция инкремента или декремента записана после переменной, то говорят о постфиксной форме записи. При префиксной форме переменная сначала увеличивается или уменьшается на единицу, а затем это ее новое значение используется в том выражении, в котором она встретилась. При постфиксной форме в выражении используется текущее значение переменной, и только после этого се значение увеличивается или уменьшается на единицу.
Операции инкремента и декремента.
Пример программы, которая демонстрирует различие между префиксной и постфиксной формами операции инкремента ++. Постфиксная форма записи операции инкремента вызывает увеличение переменной с после того, как она использована в операторе вывода. При префиксной форме переменная с изменяется до того, как будет использована в операторе вывода.
Программа выводит на экран значения с до и после применения операции ++. Операция -- действует аналогично.
// Префиксная и постфиксная формы операции инкремента
#include
main ()
{
int с;
с=5;
cout endl;
cout c++endl; // Постфиксная форма инкремента
cout с
c=5;
cout с
cout
cout
return 0; // успешное окончание
}
На экране:
5
5
6
5
6
6
Логические операции.
С++ предоставляет логические операции, которые могут использоваться для формирования сложных условий путем комбинирования простых условий. Логическими операциями являются && (логическое И), || (логическое ИЛИ) и ! (логическое НЕ, называемое также логическое отрицание).
Обычно операторы программы выполняются друг за другом в той последовательности, в которой они написаны. Это называется последовательным выполнением. Однако, различные операторы С ++ позволяют программисту указать, что следующим должен выполняться не очередной оператор в тексте программы, а какой-то другой. Это называется передачей управления.
Все программы могут быть написаны с использованием всего трех управляющих структур:
структура следования;
структура выбора;
структура повторения.
Структура следования встроена в C++. Пока не указано иное, компьютер выполняет операторы C++ один за другим в той последовательности, в которой они записаны.
С++ обеспечивает три типа структур выбора альтернатив:
Структура if (ЕСЛИ)
Структура if/else (ЕСЛИ-ИНАЧЕ)
Структура switch (ВЫБОР)
Структура выбора if выполняет некоторое действие (обработку), если проверяемое условие истинно, или пропускает его, если условие ложно. Структура выбора if/else выполняет одно действие, если условие истинно, и выполняет другое действие, если оно ложно. Структура выбора switch выполняет одно из множества действий в зависимости от значения проверяемого выражения.
Структура if (ЕСЛИ) называется структурой с единственным выбором, поскольку она выбирает или игнорирует единственное действие.
Синтаксис оператора if:
if (условие) операторы;
Структура if/else (ЕСЛИ-ИНАЧЕ) называется структурой с двойным выбором, так как она осуществляет выбор между двумя различными действиями.
Синтаксис оператора if/ else:
if (условие) операторы; else операторы;
Структура switch (ВЫБОР) называется структурой с множественным выбором, так как она осуществляет выбор среди множества различных действий.
Порой алгоритм может содержать ряд альтернативных решений, причем некоторую переменную (или выражение) надо проверять отдельно для каждого постоянного целого значения, которое она может принимать; в зависимости от результатов этой проверки должны выполняться различные действия. Для принятия подобных решений в С++ имеется структура множественного выбора switch.
Структура switch состоит из ряда меток case и необязательной метки default (умолчание).
Синтаксис оператора switch:
switch (переменная)
{
case значение1: операторы; break;
case значение2: операторы; break;
case значение3: операторы; break;
…
case значение n: операторы; break;
default: операторы; break;
}
Задача. Проходной бал на экзамене — 60. Напечатать «Зачет», если оценка у студента больше или равна 60.
Решим задачу, используя структуру if с единственным выбором.
#include
main ()
{
int g;
cout endl;
cing;
if (g=60) cout Зачет”
return 0; // успешное окончание
}
Решим эту же задачу, используя структуру if/ else с двойным выбором.
#include
main ()
{
int g;
cout endl;
cing;
if (g=60)
cout Зачет”
else
cout Незачет”
return 0; // успешное окончание
}
Решим эту же задачу, используя структуру switch с множественным выбором.
#include
main ()
{
int g;
cout endl;
cing;
switch (g)
{
case 60:
cout Зачет”
default:
cout Незачет”
return 0; // успешное окончание
}
Решим задачу, с использованием логических операций и структуры if/ else.
З
адача. Дано a,b.Вычислить у, если:
ab, если ab0
у=
1, иначе.
#include
main ()
{
int a, b, y;
cout endl;
cinа;
cout b”endl;
cinb;
if (a0)
{
y=a*b;
cout y=”yendl;
}
else
{
y=1;
cout Значение y=”
}
return 0; // успешное окончание
}
Операторы break и continue.
Операторы break и continue изменяют поток управления. Когда оператор break выполняется в структуре switch, происходит немедленный выход из структуры. Программа продолжает выполнение с первого оператора после структуры. Обычное назначение оператора break — досрочно прерывать цикл или пропустить оставшуюся часть структуры switch.
Оператор continue в структурах вызывает пропуск оставшейся части тела структуры и начинается выполнение следующей итерации цикла.
Задача. Найти площадь треугольника со сторонами a,b,c.
#include
#include
main ()
{int a, b, c;
float p, s;
cout endl;
cinа;
cout b”endl;
cinb;
cout c”endl;
cinc;
if (a0&&b0&&c0&&(a+b=c)&&(b+c)=a&&(a+c)=b)
{ p=(a+b+c)/2;
s=sqrt(p*(p-a)*(p-b)*(p-c));
cout Значение y=”
else
{
cout endl;
}
return 0; // успешное окончание
}
Задача. Найти площадь круга.
#include
#include
main ()
{
float p=3.14, r, s;
cout R”endl;
cinr;
if (r0)
{
s=p*pow(r,2);
cout Площадь круга S=”
}
else
{
cout endl;
}
return 0; // успешное окончание
}
Задача. Найти объем куба.
#include
#include
main ()
{
float a, v;
cout Введите сторону куба a”
cina;
if (a0)
{
v=pow(a,3);
cout Объем куба V=”
}
else
{
cout endl;
}
return 0; // успешное окончание
}
Задача. По введенному числу определить месяц.
#include
#include
main ()
{
clrscr();
int m;
cout Введите число”
cinm;
switch (m){
case 1: case 2: case 12: coutЗима”; break;
case 3: case 4: case 5: coutВесна”; break;
case 6: case 7: case 8: coutЛето”; break;
case 9: case 10: case 11: coutОсень”; break;
default: cout
}
getch();
return 0;}
Циклические структуры.
Структура повторения позволяет программисту определить действие, которое должно повторяться, пока некоторое условие остается истинным. С++ обеспечивает три типа структур повторения:
while (ПОКА),
do/while (ДО)
for (СЧЕТЧИК)
Cтруктура while.
Оператор (или операторы), записанные в теле структуры повторения while (ПОКА) составляют тело while, которое может быть отдельным или составным оператором.
Синтаксис оператора while.
переменная цикла=начальное значение;
while (условие)
{
операторы;
переменная цикла++;
}
В теле структуры while не предусматривается действие, которое приведет к тому, что со временем условие while станет ложным. Выполнение подобной структуры повторения никогда не прервется - такая ошибка называется «зацикливание».
Язык С++ чувствителен к регистру. Все зарезервированные ключевые слова С++, такие, как while, if и else, содержат только символы нижнего регистра.
Пример 1.
#include
main ()
{
int counter = 1; // задание начального значения
while (counter
{
cout counter endl; // вывод значения
counter++; // увеличение
}
return 0; // успешное окончание
}
Структура do/ while.
Структура повторения do/while похожа на структуру while. В структуре while условие продолжения циклов проверяется в начале цикла, до того, как выполняется тело цикла. В структуре do/while проверка условия продолжения циклов производится после того, как тело цикла выполнено, следовательно, тело цикла будет выполнено по крайней мере один раз.
К
огда do/while завершается, выполнение программы продолжается с оператора, следующего за предложением while. В структуре do/while нет необходимости использовать фигурные скобки, если тело состоит только из одного оператора. Но фигурные скобки обычно все же ставят, чтобы избежать путаницы между структурами while и do/while.
Синтаксис оператора do/ while.
переменная цикла=начальное значение;
do
{
операторы;
переменная цикла ++;
while (условие);
}
Пример 2.
#include
main ()
{
int counter = 1; // задание начального значения
do
{
cout counter
}
while (counter++
return 0; // успешное окончание
}
С
труктура for.
Синтаксис оператора for.
for (переменная цикла=начальное значение; условие; шаг)
{
операторы;
}
Пример: Изменение управляющей переменной от 1 до 100 с шагом 1.
for (int i = 1; i
Пример: Изменение управляющей переменной от 100 до 1 с шагом -1 (с уменьшением на 1).
for (int i = 100; i = 1; i--)
Пример: Изменение управляющей переменной от 7 до 77 с шагом 7.
for (int i = 7; i
Пример: Изменение управляющей переменной от 20 до 2 с шагом -2.
for (int i = 20; i = 2; i -= 2)
Пример: Изменение управляющей переменной в следующей последовательности: 2, 5, 8, 11, 14.
for (int j = 2; j
Пример: Изменение управляющей переменной в следующей последовательности: 99, 88, 77, 66, 55, 44, 33, 22, 11, 0.
for (int j = 99; j = 0; j -= 11)
Пример: Использование оператора setw.
for (int counter=1; counter
{
cout setw(3) counter;
}
Оператор setw(3) определяет, что следующая величина будет напечатана с шириной (размером) поля 3, т.е. ее значение будет содержать по крайней мере 3 символьных позиции.. Если длина выходной величины менее 3 символов, она по умолчанию будет выровнена в поле по правому символу. Если длина выходной величины более 3, размер поля будет увеличен, чтобы вместить полную величину. Можно использовать обращение setiosflags(ios::left) для того, чтобы задать выравнивание по левому символу.
Пример:
cout « setiosflags(ios::fixed | ios::showpoint)
В приведенном операторе вывода данный формат указывает, что переменная amount должна печататься как значение с фиксированной точкой и с обязательной печатью этой точки (задается выражением setiosflags(ios::fixed|ios::showpoint)) с правым выравниванием в поле размером в 21 символ (задается выражением setw(21)) и с двумя цифрами после десятичной точки (задается выражением setprecision(2)).
Задача. Рассчитать сумму целых чисел от 1 до 10? Решить с помощью for.
#include
main ()
{
int i;
float a, s=0;
for (i=1;i
{ cout Введите число”
cina;
s+=a;}
cout Сумма S=”
return 0;
}
Задача. Возвести число x в степень y? Решить с помощь. while.
#include
main ()
{
int x, у, i, power;
i = 1; power = 1;
coutВведите число”
cinx;
coutendl;
cin y;
while (i
{power *= x;
++i;}
cout Возведение в “степень”числа”
return 0;
}
Генерация случайных чисел.
Элемент случайности может быть введен в компьютерные приложения с помощью функции rand из стандартной библиотеки С.
Рассмотрим следующий оператор:
i = rand() ;
Функция rand генерирует целое число в диапазоне между 0 и RAND_MAX (символическая константа, определенная в заголовочном файле ). Значение RAND_MAX должно быть по меньшей мере равно 32767 — максимальное положительное значение двухбайтового (т.е. 16-битового) целого числа. Если rand действительно вырабатывает случайные целые число, то при каждом вызове rand результирующее число имеет равную вероятность оказаться любым целым, лежащим между 0 и RAND_MAX.
Диапазон значений, которые вырабатываются непосредственно функцией rand, отличается от диапазонов, которые требуются в специальных приложениях.
Например, программа, моделирующая бросание монеты, требует только двух значений: 0 для «орла» и 1 для «решки». Программе, моделирующей метание кости с шестью гранями, должны бы потребоваться случайные целые числа в диапазоне от 1 до 6. Программа, которая случайным образом определяет тип следующего космического корабля (из четырех возможных), пересекающего горизонт в видеоигре, должна требовать случайные целые числа в диапазоне от 1 до 4.
Для того, чтобы выработать целые числа в диапазоне от 0 до 5, используем операцию вычисления остатка % в сочетании с rand: rand() % 6.
Это называется масштабированием. Число 6 называется масштабирующим коэффициентом. Затем мы сдвигаем диапазон чисел, добавляя 1 к полученному результату.
Пример: Сдвинутые, масштабируемые целые числа, полученные по закону 1+ rand () % 6.
#include
#include
#include
main()
{
for (int i=1; i
{
cout
if (i % 5 == 0) cout
}
return 0;
}
Функция rand на самом деле генерирует псевдослучайные числа. Повторный вызов rand производит последовательность чисел, которые кажутся случайными. Но та же самая последовательность повторяется при каждом повторении программы. Когда программа тщательно отлажена, она может быть использована для получения разных последовательностей случайных чисел при каждом выполнении.
Это называется рандомизацией и реализуется в законченном виде с помощью стандартной библиотечной функции srand. Функция srand получает целый аргумент unsigned и при каждом выполнении программы задает начальное число, которое функция rand использует для генерации последовательности квазислучайных чисел. Прототип функции srand находится в заголовочном файле .
Значение, генерируемое функцией rand, всегда находится в диапазоне:
0
Ширина диапазона определяется числом, используемым для масштабирования rand с помощью операции вычисления остатка, а начало диапазона равно числу, которое прибавляется к rand %. Мы можем записать этот результат в общем виде:
n = а + rand() % b;
где а — величина сдвига (которая равна первому числу в требуемом диапазоне последовательных целых чисел), a b — масштабирующий коэффициент (который равен ширине требуемого диапазона целых чисел).
Одномерные массивы.
Нумерованный список, элементы которого однотипны по структуре, способу использования называют массивом. Массивы бываю одномерными и многомерными.
Одномерный массив (вектор)- это упорядоченная структура данных. Элемент массива определяется своей позицией. В простейшем случае – это отсчет смещения от начала массива. Число индексов, требующихся для определения элемента, называется размерностью или, как принято говорить в математике, рангом массива.
П
ример: 0 1 2 3 4 5 индекс массива
| -2 | -1 | 0 | 1 | 2 | 3 | э |
Массив a состоит шести элементов -2, -1, 0, 1, 2, 3. Размерность равна 6.
Массивы в языке С++ описываются следующим образом:
тип_элементов имя [размер];
Размер массива задается константным выражением. Индексы элементов – целые числа, начиная с нуля, т.е индексация массивов начинается с нуля.
Например, int a[100];
определяет массив a c элементами a[0], a[1], …, a[99].
Одномерный массив в С++ можно ввести тремя способами:
с помощью инициализации;
ручной ввод (с клавиатуры);
с помощью генератора случайных чисел.
Инициализация массива.
При описании массива можно указать начальные значения элементов через запятую в фигурных скобках. При инициализации размер массива можно не указывать. Например,
int p[] = {0,1,2,3,4,5};
К элементам массива можно обратиться, указав имя и в квадратных скобках индекс. Контроль выхода за пределы массива не производится.
Ручной ввод массива.
При вводе массива используется оператор for.
for (i=0; i
cina[i];
Ввод массива с помощью функции rand().
for (i=0; i
a[i]=rand();
Одномерный массив в С++ можно вывести двумя способами:
Вывод массива на экран в строку:
for (i=0; i
cout
или
for (i=0; i
couta[i]t“;
Вывод массива на экран в столбец:
for (i=0; i
cout
или
for (i=0; i
couta[i]n“;
Задача: Найти максимальный (минимальный) элемент массива a[n], где n – ввести самостоятельно.
Для решения данной задачи, необходимо вначале присвоить максимальное (минимальное значение) первому элементу массива. Затем в цикле проверять условие на максимум (минимум). Если максимальное (минимальное) значение меньше (больше) начального, того сделать переприсвоение.
Решаем задачу используя ручной ввод.
#include //подключение библиотек
#include
#include
#include
main ()
{
clrscr(); // очистка экрана
int i,n; // описание переменных
float a[100], max; // описание перменных
coutn=”; cinn; // ввод переменной
cout
for (i=0; in; i++) cina [i]; // ввод переменной массива
coutn”;
for (i=0; in; i++) couta [i]
coutendl; // переход на новую строку
max=a[0]; // первоначальное присвоение
for (i=0; in; i++)
if (maxa[i]) // проверка условия
max=a[i]; // переприсвоение
cout max=”maxendl; //вывод max
getch(); // задержка экрана
return 0; // завершение программы
}
Решаем эту же задачу, используя генератор случайных чисел.
#include
#include
#include
#include
main ()
{
clrscr();
int i,n;
float a[100], max;
coutn;
for (i=0; i
coutПолученный массив \n”;
for (i=0; i
cout
max=a[0];
for (i=0; i
if (max
max=a[i];
cout ax=”ax
getch();
return 0;
}
Самостоятельно найти минимальный элемент массива, используя ручной ввод и генератор случайных чисел.
Сортировка массивов
Сортировка данных (т.е. размещение данных в определенном порядке, таком как возрастание или уменьшение) является одним из наиболее важных применений компьютеров.
Рассмотрим сортировку массива а из 10 элементов в возрастающем порядке, которая называется пузырьковая сортировка или сортировка погружением, потому что наименьшее значение постепенно «всплывает», продвигаясь к вершине (началу) массива, подобно пузырьку воздуха в воде, тогда как наибольшее значение погружается на дно (конец) массива. Этот прием требует нескольких проходов по массиву. При каждом проходе сравнивается пара следующих друг за другом элементов. Если пара расположена в возрастающем порядке или элементы одинаковы, то мы оставляем значения как есть. Если же пара расположена в убывающем порядке, значения меняются местам в массиве.
Сначала сравниваем а[0] и а[1], затем а[1] и а[2], потом а[2] и а[3] и т.д. до тех пор, пока проход не закончится сравнением а[8] и а[9]. Хотя элементов 10, производится только девять сравнений. При выбранном способе последовательных сравнений большое значение может перемещаться в массиве вниз на много позиций за один проход, но малое значение может быть передвинуто вверх только на одну позицию. При первом проходе наибольшее значение гарантированно опустится на место нижнего элемента массива а[9]. При втором проходе второе наибольшее значение гарантированно опустится на место а[8]. При девятом проходе девятое наибольшее значение опустится на место а[1]. Это оставляет наименьшему значению место а[0], так что для сортировки массива из 10 элементов нужно только девять проходов.
Сортировка выполняется с помощью вложенного цикла for. Если необходима перестановка, она выполняется тремя присваиваниями
r = а[i] ; a[i] = a[i + 1]; a[i + 1] = r;
где дополнительная переменная r временно хранит одно из двух переставляемых значений. Перестановку нельзя выполнить двумя присваиваниями
a[i] = a[i + 1]; a[i + 1] = a[i];
Если, например, a[i] равно 7, a a[i + 1] равно 5, то после первого присваивания оба значения будут 5, а значение 7 будет потеряно. Следовательно, необходима дополнительная переменная r.
Главное достоинство пузырьковой сортировки заключается в простоте ее программирования. Однако, пузырьковая сортировка выполняется медленно. Это становится очевидным при сортировке больших массивов.
Задача. Сортировка значения массива в возрастающем порядке
#include
#include
main()
{
const int n = 10;
int i, a[n] = {2, 6, 4, 8, 10, 12, 89, 68, 45, 37};
cout endl;
for (i=0; i
cout
for (j=1; j
for (i=0; i
if (a[i]a[i+1])
{
r=a[i];
a[i]=a[i+1];
a[i+1]=r;
}
coutendlendl;
for (i=0; i
cout
coutendl;
return 0;
}
Многомерные массивы.
Массивы в С++ могут иметь много индексов. Обычным представлением многомерных массивов являются таблицы значений, содержащие информацию в строках и столбцах. Чтобы определить отдельный табличный элемент, нужно указать два индекса: первый (по соглашению) указывает номер строки, а второй (по соглашению) указывает номер столбца. Таблицы или массивы, которые требуют двух индексов для указания отдельного элемента, называются двумерными массивами. Многомерный массив может иметь более двух индексов. Компиляторы С++ поддерживают по меньшей мере 12-мерные массивы.
Массивы с m строками и n столбцами называют массивами m на n.
Каждый элемент в массиве а определяется именем элемента в форме a[i][j];
a — это имя массива, a i и j — индексы, которые однозначно определяют каждый элемент в а.
Многомерный массив в С++ можно ввести тремя способами:
с помощью инициализации;
ручной ввод (с клавиатуры);
с помощью генератора случайных чисел.
Инициализация массива.
При описании массива можно указать начальные значения элементов через запятую в фигурных скобках. Например,
int a [3][2] = { {1,1}, {0,2}, {1,0}};
К элементам массива можно обратиться, указав имя и в квадратных скобках индекс. Контроль выхода за пределы массива не производится.
Ручной ввод массива.
При вводе массива используются 2 оператора for.
for (i=0; i
for (j=0; j
cina[i][j];
Ввод массива с помощью функции rand().
for (i=0; i
for (j=0; j
a[i][j]=rand();
Многомерный массив в С++ можно вывести тремя способами:
Вывод массива на экран в строку:
for (i=0; i
for (j=0; j
couta[i][j]
Вывод массива на экран в столбец:
for (i=0; i
for (j=0; j
cout
Вывод массива на экран в виде матрицы:
for (i=0; i
{
for (j=0; j
cout
cout
}
Задача. Найти сумму (произведение) элементов в каждой строке. Самостоятельно найти max(min) в каждой строке.
#include
#include
#include
#include
main ()
{clrscr(); //
int i,j,n;float a[100][100],s[100];
coutn;
for (i=0; i
for (j=0; j
a[i][j]=rand()%7+4; // формирование массива случайными числами из диапазона [4;10].
cout
for (i=0; i
for (j=0; j
cout
coutn";
s[i]=0;} // подготовка суммы массива s
for (i=0; i
for (j=0; j
s[i]+=a[i][j]; // суммирование по строкам
for (i=0;i
cout
getch(); // задержка экрана
return 0;}
Задача. Найти максимальный элемент в каждом столбце. Самостоятельно найти сумму (произведение) в каждом столбце.
#include
#include
#include
#include
main ()
{clrscr();
int i,j,n; float a[100][100],p[100],max[100];
coutn;
for (i=0; i
for (j=0; j
a[i][j]=rand();
cout
for (i=0; i
for (j=0; j
cout
max[i]=a[0][0];
}
for (j=0; j
for (i=0; i
{
if (max[j]
max[j]=a[i][j];
}
for(i=0;i
cout
getch();
return 0;}
Модули в С++ называются функциями и классами. Обычно программы на С++ пишутся путем объединения новых функций, которые пишет сам программист, с функциями, уже имеющимися в стандартной библиотеке С, и путем объединения новых классов, которые пишет сам программист, с классами, уже имеющимися в различных библиотеках классов.
Стандартная библиотека С обеспечивает широкий набор функций для выполнения типовых математических расчетов, операций со строками, с символами, ввода-вывода, проверки ошибок и многих других полезных операций. Это облегчает работу программиста, поскольку эти функции обладают многими из необходимых программисту свойств.
Функции стандартной библиотеки С являются частью среды программирования С++. Программист может написать функции, чтобы определить какие-то специфические задачи, которые можно использовать в разных местах программы. Эти функции иногда называют функциями, определенными пользователем.
Операторы, реализующие данную функцию, пишутся только один раз и скрыты от других функций. Функция активизируется (т. е. начинает выполнять запроектированную для нее задачу) путем вызова функции. В вызове функции указывается ее имя и дается информация (в виде аргументов), необходимая вызываемой функции для ее работы.
Это аналогично иерархической форме управления. Начальник (вызывающая функция или вызывающий оператор) просит подчиненного (вызываемую функцию) выполнить задание и возвратить (т.е. сообщить) результаты после того, как задание выполнено. Функция-начальник не знает, как функция-подчиненный выполняет порученное ей задание. Подчиненный может вызвать другие подчиненные функции, причем начальник не будет осведомлен об этом. На рисунке функция main, иерархически связанная с несколькими рабочими функциями.
Заметим, что worker1 действует как функция начальника по отношению к worker4 и worker5. Взаимоотношения между функциями могут отличаться от показанных на этом рисунке иерархических отношений.
Функции.
Функции позволяют пользователю использовать модульное программирование (составлять программу из модулей). Все переменные объявляются в описаниях функций локальными переменными — они известны только для функции, в которой они описаны. Большинство функций имеют список параметров, который обеспечивает значения для связующей информации между функциями. Параметры тоже являются локальными переменными.
В программах, содержащих много функций, main должна быть построена как группа вызовов функций, которые и выполняют основную часть работы.
Существует несколько причин для построения программ на основе функций. Подход «разделяй и властвуй» делает разработку программ более управляемой. Другая причина — повторное использование программных кодов, т.е. использование существующих функций как стандартных блоков для создания новых программ.
Повторное использование — основной фактор развития объектно-ориентированного программирования. При продуманном присвоении имен функций и хорошем их описании программа может быть создана быстрее из стандартизированных функций, соответствующих определенным задачам.
Третья причина — желание избежать в программе повторения каких-то фрагментов. Код, оформленный в виде функции, может быть выполнен в разных местах программы простым вызовом этой функции.
Каждая функция должна выполнять одну хорошо определенную задачу и имя функции должно наглядно отражать данную задачу. Это способствует успешному повторному использованию программного обеспечения.
Размещайте пустую строку между описаниями функций, чтобы отделить функции и облегчить чтение программы.
Определения функций.
Каждая программа, которую мы рассматривали, содержала функцию, называемую main, которая вызывает стандартные библиотечные функции для выполнения соответствующих им задач. Теперь мы рассмотрим, как программисты пишут свои собственные необходимые им функции.
Формат описания функции имеет вид:
тип-возвращаемого-значения имя-функции (список-параметров)
{
объявления и операторы
}
Рассмотрим программу, которая использует функцию square для вычисления квадратов целых чисел от 1 до 10.
Функция square активизируется или вызывается в main вызовом square(х). Функция создает копию значения х в параметре у. Затем square вычисляет у*у. Результат передается в ту точку main, из которой была вызвана square, и затем этот результат выводится на экран. Благодаря структуре повторения for этот процесс повторяется десять раз.
Описание square показывает, что эта функция ожидает передачи в нее целого параметра у. Ключевое слово int, предшествующее имени функции, указывает, что square возвращает целый результат. Оператор return в square передает результат вычислений обратно в вызывающую функцию.
Задача. Функция square, определяемая программистом.
#include
int square(int); //прототип функции
main()
{
for (int i=1; i
cout
cout
return 0;
}
int square(int y) // описание функции
{
return y*y;
}
Строка int square(int); является прототипом функции. Тип данных int в круглых скобках указывает компилятору, что функция square ожидает в операторе вызова целое значение аргумента. Тип данных int слева от имени функции square указывает компилятору, что square возвращает оператору вызова целый результат. Компилятор обращается к прототипу функции для проверки того, что вызовы функции square содержат правильный возвращаемый тип, правильное количество аргументов, правильный тип аргументов и правильный порядок перечисления аргументов.
Имя-функции — это любой правильно написанный идентификатор.
Тип-возвращаемого-значения — это тип данных результата, возвращаемого из функции оператору ее вызова. Тип возвращаемого значения void указывает, что функция не возвращает никакого значения. Компилятор предполагает тип int для неопределенного типа возвращаемого значения.
Пропуск типа возвращаемого значения в описании функции вызывает синтаксическую ошибку, если прототип функции определяет возвращаемый тип иначе, чем int.
Если забыть вернуть значение из функции, в которой предполагается возвращение результата, это может привести к неожиданным ошибкам. Описание языка С++ указывает, что результат такой оплошности не определенен. В этом случае обычно компиляторы С++ выдают предупреждающее сообщение.
Возвращение какого-то значения из функции, для которой тип возвращаемого значения объявлен как void, вызывает синтаксическую ошибку.
Несмотря на то, что пропущенный тип возвращаемого значения по умолчанию int, всегда задавайте тип возвращаемого значения явным образом. Исключением является функция main, для которой тип возвращаемого значения обычно не указывается.
Список-параметров — это список разделенных запятыми объявлений тех параметров, которые получает функция при ее вызове. Если функция не получает никаких значений, список-параметров задается как void. Тип должен быть указан явно для каждого параметра в списке параметров.
Объявление параметров функции, имеющих одинаковый тип, в виде float х, у вместо float х, float у. Объявление параметра float х, у вызовет ошибку компиляции, так как типы надо указывать для каждого параметра в списке.
Точка с запятой после правой круглой скобки, закрывающей список параметров в описании функции, является синтаксической ошибкой.
Повторное определение параметра функции как локальной переменной этой функции является синтаксической ошибкой.
Не используйте одинаковые имена для аргументов, передаваемых в функцию, и соответствующих параметров в описании функции, хотя это и не является ошибкой. Использование разных имен помогает избежать двусмысленности.
Объявления и операторы внутри фигурных скобок образуют тело функции. Тело функции рассматривается как блок. Блок — это просто составной оператор, который включает объявления. Переменные могут быть объявлены в любом блоке, а блоки могут быть вложенными. При любых обстоятельствах функция не может быть описана внутри другой функции.
Описание функции внутри другой функции является синтаксической ошибкой. Выбор осмысленных имен функций и осмысленных имен параметров делает программу более легко читаемой и помогает избежать излишних комментариев.
Обычно функция должна быть не длиннее одной страницы. Еще лучше, если она будет не длиннее половины страницы. Безотносительно к длине функции она должна хорошо определять только одну задачу. Небольшие функции способствуют повторному использованию программных кодов.
Программа должна быть написана как совокупность небольших функций. Это облегчает написание, отладку, сопровождение и модификацию программы.
Функция, требующая большого количества параметров, возможно, выполняет слишком много задач. Попробуйте разделить такую функцию на небольшие функции, которые выполняют отдельные задачи. Заголовок функции по возможности не должен занимать более одной строки.
Прототип функции, заголовок функции и вызовы функции должны быть согласованы между собой по количеству, типу и порядку следования аргументов и параметров и по типу возвращаемых результатов.
Существует три способа возврата управления к точке, из которой была вызвана функция. Если функция не должна возвращать результат, управление возвращается или просто при достижении правой фигурной скобки, завершающей функцию, или при выполнении оператора return;
Если функция должна возвращать результат, то оператор return выражение; возвращает значение выражения в обращение к функции.
Следующий пример использует определенную программистом функцию maximum для определения и возвращения наибольшего из трех целых чисел. Вводятся три целых числа. Затем эти целые числа передаются функции maximum, которая определяет наибольшее из чисел. Это значение возвращается функции main с помощью оператора return в maximum и печатается.
Задача. Определение максимального из трех целых чисел
#include
int maximum(int, int, int); // прототип функции
main ()
{
int a, b, c;
cout
cinаbс;
cout
return 0;
}
int maximum(int x, int y, int z) // определение функции maximum
{int max=x;
if (ymax)
max=y;
if (zmax)
max=z;
return max;
}
Прототипы функций.
Прототип функции является одной из наиболее важных особенностей С++. Прототип функции указывает компилятору тип данных, возвращаемых функцией, количество параметров, которое ожидает функция, тип параметров и ожидаемый порядок их следования. Компилятор использует прототип функции для проверки правильности вызовов функции. В С++ требуются прототипы функций. Используйте директиву препроцессора #include, чтобы получить прототипы стандартных библиотечных функций из заголовочных файлов соответствующих библиотек. Используйте также #include для заголовочных файлов, содержащих прототипы функций, используемых вами или членами вашей группы.
Прототип функции maximum имеет вид
int maximum(int, int, int);
Этот прототип указывает, что maximum имеет три аргумента типа int и возвращает результат типа int. Заметим, что прототип функции такой же, как заголовок описания функции maximum, за исключением того, что в него не включены имена параметров (х, у и z).
Имена параметров могут быть включены в прототипы функции с целью документирования. Компилятор эти имена игнорирует.
Отсутствие точки с запятой в конце прототипа функции является синтаксической ошибкой.
Вызов функции, который не соответствует прототипу функции, ведет к синтаксической ошибке. Синтаксическая ошибка возникает также в случае отсутствия согласования между прототипом и описанием функции. Например, если бы в программе на максимум из трех чисел прототип функции был бы написан так:
void maximum(int, int, int); компилятор сообщил бы об ошибке, потому что возвращаемый тип void в прототипе функции отличался бы от возвращаемого типа int в заголовке функции.
Другой важной особенностью прототипов функций является приведение типов аргументов, т.е. задание аргументам подходящего типа. Например, математическая библиотечная функция sqrt может быть вызвана с аргументом целого типа, даже если функция прототип в math.h определяет аргумент типа double, и при этом функция будет работать правильно. Оператор
cout С++. Правила приведения определяют, как типы могут быть преобразованы в другие типы без потерь. В приведенном выше примере sqrt тип int автоматически преобразуется в double без изменения его значений. Однако double преобразуется в int с отбрасыванием дробной части значения double. Преобразование больших целых типов в малые целые типы (например, long в short) может также привести к изменению значений.
Правила приведения типов применяются к выражениям, содержащим значения двух или более типов данных; такие выражения относятся к выражениям смешанного типа. Тип каждого значения в выражении смешанного типа приводится к «наивысшему» типу, имеющемуся в выражении (на самом деле создается и используется временная копия выражения — истинные значения остаются неизменными).
Преобразование значений к низшему типу может привести к неверным значениям. Поэтому значения могут преобразовываться к низшему типу только путем явного присваивания значения переменной низшего типа, либо с помощью операции приведения к типу. Значения аргументов функции преобразуются к типам параметров в прототипе функции так, как если бы они были непосредственно присвоены переменным этих типов. Если наша функция square, которая использует параметр целого типа, вызывается с аргументом с плавающей точкой, аргумент преобразуется к типу int (низшему типу) и squre обычно возвращает неверное значение. Например, square(4.5) возвратит 16 вместо 20.25.
Преобразование от высшего типа в иерархии типов к низшему может изменить значение данных. Отсутствие прототипа функции, когда функция не определена перед ее первым вызовом, приводит к синтаксической ошибке. Прототип функции, размещенный вне описания какой-то другой функции, относится ко всем вызовам данной функции, появляющимся после этого прототипа в данном файле. Прототип функции, размещенный внутри описания некоторой функции, относится только к вызовам внутри этой функции.
Рассмотрим применение функций на примере поиска в массиве.
Поиск в массивах: линейный поиск и двоичный поиск
Часто программисту приходится работать с большими объемами данных, хранящимися в виде массивов. Может оказаться необходимым определить, содержит ли массив значение, которое соответствует определенному ключевому значению. Процесс нахождения какого-то элемента массива называют поиском. Рассмотрим два способа поиска — простой линейный поиск и более эффективный двоичный поиск — дихотомию.
Линейный поиск сравнивает каждый элемент массива с ключом поиска. Поскольку массив не упорядочен, вполне вероятно, что отыскиваемое значение окажется первым же элементом массива. Но в среднем, однако, программа должна сравнить с ключей поиска половину элементов массива.
Задача. Линейный поиск в массиве.
#include
int linearSearch(int [], int, int);
main ()
{const int n=100;
int a[n], k, element;
for (int i=0; in; i++) //создание некоторых данных
a[i] =2*i;
coutendl;
cink;
l=linearSearch(a, k, n);
if (l!=-1)
cout
else
cout
return 0;}
int linearSearch(int array[], int key, int m)
{
for (int j=0; j
if (array[j] == key)
return n;
return -1;
}
Метод линейного поиска хорошо работает для небольших или для несортированных массивов. Однако, для больших массивов линейный поиск неэффективен. Если массив отсортирован, можно использовать высокоэффективный метод двоичного поиска.
Алгоритм двоичного поиска исключает половину еще непроверенных элементов массива после каждого сравнения. Алгоритм определяет местоположение среднего элемента массива и сравнивает его с ключом поиска. Если они равны, то ключ поиска найден и выдается индекс этого элемента. В противном случае задача сокращается на половину элементов массива. Если ключ поиска меньше, чем средний элемент массива, то дальнейший поиск осуществляется в первой половина массива, а если больше, то во второй половине. Если ключ поиска не совпадает со средним элементом выбранного подмассива (части исходного массива), то алгоритм повторно применяется и сокращает область поиска до четверти исходного массива. Поиск продолжается до тех пор, пока ключ поиска не станет равным среднему элементу или пока оставшийся подмассив содержит хотя бы один элемент, не равный ключу поиска (т.е. пока не найден ключ поиска).
Задача. Двоичный поиск в массиве.
#include
#include
int binarySearch(int [], int, int, int, int);
void printHeader(int);
void printRow(int [], int, int, int, int);
main ()
{
const int arraySize=15;
int a [arraySize], key, result;
for (int i = 0; i размещение
// данных в массиве
a[i] = 2 * i;
cout cin key;
printHeader(arraySize);
result = binarySearch(a, key, 0, arraySize - 1, arraySize); if (result != -1)
cout
else
cout
// Двоичный поиск
int binarySearch (int b[], int searchKey, int low, int high, int size)
{
int middle;
while (low
{
middle=low + high) / 2;
printRow(b, low, middle, high, size);
if (searchKey == b[middle]) // соответствие
return middle;
else if (searchKey
high = middle - 1; // определение нижнего конца массива
else
low = middle +1; // определение верхнего конца массива
}
return -1; // searchKey не найден
// Печать заголовка выходных данных
void printHeader(int size)
{
cout
for (int i=0; i
cout
cout
for (i=0; i
cout
cout
}
// Печать одной строки, показывающей текущую обрабатываемую часть массива
void printRow(int b[], int low, int mid, int high, int size)
{
for (int i=0; i
if (ihigh)
cout
else if (i==mid)
cout
else
cout
cout
}
Символы и строки.
Символы — это фундаментальные стандартные блоки исходных программ на С++. Каждая программа составлена из последовательностей символов, которые, если их объединение в группу имеет смысл, интерпретируются компьютером как последовательности инструкций, используемых для выполнения задачи. Программа может содержать символьные константы.
Символьная константа — это целое значение, представленное как символ в одинарных кавычках. Значение символьной константы — это целочисленное значение в наборе машинных символов.
Например, V представляет собой целое значение z, а '\n' представляет собой целое значение символа перехода на новую строку.
Строка — это последовательность символов, обрабатываемая как единый модуль. Строка может включать буквы, цифры и разнообразные специальные символы, такие как +, -, *, /, $ и другие.
Литеральные константы или строковые константы записываются в С++ в двойных кавычках следующим образом:
"John Q.Doe" (имя)
"9999 Main Street" (адрес улицы)
"Waltham, Massachusetts" (город и штат)
"(201)555-1212" (номер телефона)
Строка в С++ — это массив символов, оканчивающийся нулевым символом ('\0'). Строка доступна через указатель на первый символ в строке. Значением строки является адрес ее первого символа. Таким образом можно сказать, что в С++ строка является указателем — указателем на первый символ строки. В этом смысле строки подобны массивам, потому что массив тоже является указателем на свой первый элемент.
Строка может быть объявлена либо как массив символов, либо как переменная типа char*. Каждое из объявлений присваивает переменной строке начальное значение «синий».
char color[ ] = "синий"; char *colorPtr = "синий";
Первое объявление создает массив из 6 элементов color содержащий символы 'с', 'и', 'н', 'и', 'й' и '\0\
Второе объявление создает переменную указатель colorPtr, который указывает на строку «синий» где-то в памяти.
Объявление char colorf] = {"синий"} может быть записано
char color[ ] = {'с', 'и', 'н', 'и', 'й', '\0'};
Когда объявляется массив символов, содержащий строку, он должен быть достаточно большим, чтобы хранить строку и ее завершающий нулевой символ. Предыдущее объявление определяет размер массива автоматически, основываясь на количестве начальных значений в списке.
При хранении строки в массиве символов убедитесь, что массив достаточно велик, чтобы вместить наибольшую строку, которую потребуется хранить. В С++ допускается хранить строки любой длины. Если строка больше символьного массива, в котором она должна храниться, символы, выходящие за конец массива, будут изменять данные в разделах памяти, следующих за массивом.
Строку можно присвоить массиву, используя операцию cin — взять из потока. Например, строку можно присвоить символьному массиву word[20] следующим оператором:
cinword;
Вводимая пользователем строка хранится в word. Предыдущий оператор считывает символы до тех пор, пока не встретится пробел, символ табуляции, символ новой строки или указатель конца файла. Cтрока не должна быть длиннее 19 символов, чтобы оставить место для завершающего нулевого символа. Манипулятор потока setw, с которым мы познакомились, можно использовать для гарантии того, что строка, считанная в word, не превысит размер массива. Например, оператор
cinsetw(20)word;
указывает, что cin должен считать максимум 19 символов в массив word и оставить 20-й символ в массиве для хранения завершающего нулевого символа. Манипулятор потока setw применяется только к следующему вводимому значению символа.
В некоторых случаях желательно вводить в массив полную строку текста. С этой целью С++ снабжен функцией cin.getline. Функция cin.getline требует три аргумента — массив символов, в котором должна храниться строка текста, длина и символ-ограничитель. Например, фрагмент программы
char sentence[80];
cin.getline(sentence, 80, '\n');
объявляет массив sentence из 80 символов, затем считывает строку текста с клавиатуры в этот массив. Функция прекращает считывание символов в случаях, если встречается символ-ограничитель '\n', если вводится указатель конца файла или если количество считанных символов оказывается на один меньше, чем указано во втором аргументе (последний символ в массиве резервируется для завершающего нулевого символа). Если встречается символ-ограничитель, он считывается и отбрасывается. Третий аргумент cin.getline имеет '\n' в качестве значения по умолчанию, так что предыдущий вызов функции мог бы быть написан в следующем виде:
cin.getline(sentence, 80);
Функции работы со строками из библиотеки обработки строк
Библиотека обработки строк обеспечивает много полезных функций для работы со строковыми данными, сравнения строк, поиска в строках символов и других подстрок, разметки строк (разделения строк на логические куски) и определения длины строк. Рассмотрим некоторые типовые функции работы со строками из библиотеки обработки строк (из стандартной библиотеки С). Сведения об этих функциях сведены в таблице. Некоторые функции в таблице имеют параметры с типом данных size_t. Этот тип определяется в заголовочном файле stddef.h (из стандартной библиотеки С) как беззнаковый целый тип, такой, как unsigned int или unsigned long.
Функция strcpy копирует свой второй аргумент — строку в свой первый аргумент — массив символов, который должен быть достаточно большим, чтобы хранить строку и ее завершающий нулевой символ, который также копируется. Функция strncpy эквивалентна strcpy за исключением того, что strncpy указывает количество символов, которое должно быть скопировано из строки в массив.
Функция strncpy не обязательно должна копировать завершающий нулевой символ своего второго аргумента; завершающий нулевой символ записывается только в том случае, если количество символов, которое должно быть скопировано, по крайней мере на один больше, чем длина строки.
Например, если второй аргумент — "test", завершающий нулевой символ записывается только в случае, если третий аргумент strncpy по меньшей мере равен 5 (четыре символа в "test" плюс один завершающий нулевой символ). Если третий аргумент больше пяти, завершающий нулевой символ добавляется к массиву до тех пор, пока не будет записано общее количество символов, указанное третьим аргументом.
| Прототип функции | Описание функции |
| char *strcpy(char *s1, const char *s2) | |
| | Копирует строку s2 в массив символов s1. Возвращает значение s1. |
| char *strncpy(char*sl, const char *s2, size_t n) | |
| | Копирует не более n сиволов из строки s2 в массив символов s1. Возвращает значение s1. |
| char *strcat(char *s1, const char *s2) | |
| | Добавляет строку s2 к строке s1. Первый символ строки s2 записывается поверх завершающего нулевого символа строки s1. Возвращает значение s1. |
| char *strncat(char*s1, const char *s2, size t n) | |
| | Добавляет не более n символов строки s2 в строку s1. Первый символ из s2 записывается поверх завершающего нулевого символа в s1. Возвращает значение s1. |
| int strcmp(const char *s1, const char *s2) | |
| | Сравнивает строки s1 и s2. Функция возвращает значение 0, меньшее, чем 0 или большее, чем 0, если s1 соответственно равна, меньше или больше, чем s2. |
| int strcmp(const char *s1, const char *s2, size_t n) | |
| | Сравнивает до n символов строки s1 со стокой s2. Функция возвращает значение 0, меньшее, чем 0 или большее, чем 0, если s1 соответственно равна, меньше или больше, чем s2. |
| char *strtok(char *s1, const char *s2) | |
| | Последовательность вызовов strtok разбивает строку s1 на «лексемы» - логические куски, такие, как слова в строке текста -разделенные символами, содержащимися в строке s2. Первый вызов содержит в качестве первого аргумента s1, а последующие вызовы для продолжения обработки той же строки, содержат в качестве первого аргумента NULL. При каждом вызове возвращается указатель на текущую лексему. Если при вызове функции лексем больше нет, возвращается NULL. |
| size t strlen(const char *s) | |
| | Определяет длину строки s. Возвращает количество символов, предшествующих завершающему нулевому символу. |
Задача. Использование strcpy и strncpy
# include
#include
main()
{
char x[ ]="Поздравляю Вас с днем рождения";
char у[35], z [15];
cout
strncpy(z, х, 14);
z[14]='\0' ;
cout
return 0;
}
Задача. Использование strcat и strncat.
# include
# include
main()
{
char s1 [25]="Счастливого";
char s2[ ] ="Нового Года";
char s3 [40]=" ";
cout
cout
cout
cout
return 0;
}
Базовая графика в среде Borland С++ 3.1
В настоящее время во всех современных компьютерах применяется графический режим вывода информации, а операционная система Windows не знает символьного режима. В языке программирования C++ с реализацией под операционную систему DOS графические функции хранятся в библиотеке graphics.lib, а прототипы (объявления) этих функций находятся в файле graphics.h.
Инициализация графического режима
Самым первым вопросом работы с графикой является проверка работоспособности графического режима в вашей среде программирования. Следующий пример написан именно с данной целью. Скомпилируйте его.
Листинг 1. Демонстрация работы графического режима
// proba1.cpp
#include
#include
#include
#include
int main(void)
{/* 1. Автоматическое определение наибольшего графического режима: gdriver = DETECT */
int gdriver = DETECT, gmode, errorcode;
/* Инициализация графического режима */
initgraph(&gdriver, &gmode, "");
/* Результат инициализации */
errorcode = graphresult();
if (errorcode != grOk) /* Если ошибка */
{printf("Ошибка инициализации: %s\n", grapherrormsg(errorcode));
printf("Нажмите любую клавишу");
getch(); exit(1); /* Завершить программу */
}
/* 2. Рисование линии из правого верхнего угла в левый нижний */
line(0, 0, getmaxx(), getmaxy());
/* 3. Закрытие графического режима */
getch(); closegraph();
return 0;
}
Если вы не внесли опечаток в текст программы, тогда файл proba1.exe начнет работать. По диагонали экрана должна рисоваться на черном фоне белая линия из правого верхнего угла в левый нижний угол.
Типовые ошибки инициализации
Возможны три причины, по которым программа proba1.exe с графикой будет работать не так, как мы предположили.
Первая — отсутствие в рабочей папке с исполняемым файлом proba1.exe файла драйвера egavga.bgi. Результатом работы программы будет сообщение:
Ошибка инициализации: Device driver file not found
Нажми любую клавишу (Press any key to halt)
Это как-то даже неуместно называть проблемой. Из папки BGI среды программирования файл egavga.bgi переписывается в вашу рабочую папку и все.
Другой вариант. Файл egavga.bgi «лежит» в папке рядом с файлом proba1.exe, но линия не рисуется. Если программа proba1.exe начинает вытворять неизвестно что (или выдает другую ошибку или по экрану начинает «бегать» курсор), тогда смело сотрите старый драйвер egavga.bgi и поищите у знакомых или на дисках новую версию. «Ломаные» драйверы встречаются не так редко.
Третья причина — это экзотический «баг». Она встречается в основном в компьютерных сетях. По неизвестной причине файл драйвера egavga.bgi отказывается работать до тех пор, пока с этого файла не снять атрибут «только для чтения». Надеюсь, что вы не работаете с удаленного компьютера в сети, поскольку там есть еще ряд особенностей работы среды программирования, связанных c загрузкой среды с другого компьютера и атрибутами «только для чтения».
Графические примитивы
Основу мы уже заложили: знаем, как переключиться в графический режим, где применить функции и как правильно завершить работу графической части. Теперь займемся непосредственно разбором примеров с рисованием графических функций. Самые простые функции называются графическими примитивами. Условно примитивы можно разделить на группы: примитивы рисования контуров и площадные фигуры. К примитивам контуров относятся: линии (line), прямоугольники (rectangle), дуги (arc), окружности (circle), эллипсы (ellipse), многоугольники (drawpoly) и прочие не закрашиваемые внутри фигуры. Площадными, закрашиваемыми внутри фигурами являются прямоугольники (bar, bar3d), круговые и эллиптические секторы (pieslice, sector). Если у вас фигура замкнута, но не залита, например, многоугольник (drawpoly), то его всегда можно закрасить внутри с помощью функций закраски (floodfill, setfillstyle). Для выбора цвета рисования применяется функция задания текущего (по умолчанию) цвета графических примитивов (setcolor). Для определения цвета точки по ее координатам на экране существует функция getpixel, а для вывода точки заданным цветом на экран — setpixel. Вот и весь смысл работы с выводом графических примитивов. Данная логика интуитивно понятна обычному школьнику. Подробное описание и параметры графических функций можно найти в любом справочнике по C++. Если у вас под рукой нет справочника, тогда наберите в редакторе среды программирования интересующее вас имя функции, наведите на него курсор и нажмите комбинацию клавиш Ctrl+F1. На экране появится описание функции и внизу подсказки ссылка на пример программы с выбранной графической функцией. Например, если вы введете имя функции rectangle и нажмете нужные клавиши, появится подсказка по функции рисования прямоугольника с характерным примером применения. Но кое-что вы можете увидеть и в примере из листинга 2.2, в котором воедино собраны некоторые распространенные функции для работы с примитивами.
Листинг 2. Демонстрация работы графических функций
// rectangl.cpp
#include
#include
#include
#include
void main(void)
{int gdriver = DETECT, gmode, errorcode;
int xr=50,yr=20,left, top, right, bottom;
int stangle=0, endangle=360, xradius=40, yradius=25;
int radius=25;
int stangle_arc = 90, endangle_arc = 225;
int xb=0, yb=200, midx, midy;
// 1 Инициализация графического режима
initgraph(&gdriver, &gmode, ""); errorcode = graphresult();
if (errorcode != grOk) {
printf("Ошибка: %s\n", grapherrormsg(errorcode));
printf("Нажмите любую клавишу"); getch(); exit(1); }
// 2 Рисование
setcolor(WHITE);
outtextxy(xr,yr+100,
"rectangle ellipse circle arc");
left = xr +0; top = yr +0;
right = xr+100; bottom = yr+50;
rectangle(left,top,right,bottom);
ellipse(xr+150, yr+25, stangle, endangle, xradius, yradius);
circle(xr+250, yr+25, radius);
arc(xr+350, yr+25, stangle_arc, endangle_arc, radius);
midx = xb; midy = yb;
outtextxy(xb+100, yb+60, "bar + setfillstyle");
outtextxy(xb+100, yb+200, "sector + setfillstyle");
for (int i=SOLID_FILL; i
{ setfillstyle(i, YELLOW);
bar(midx+i*50, midy, midx+40+i*50,midy+40);
sector(midx+i*50+35, midy+150, stangle_arc, endangle_arc, xradius, yradius);
}
// 3 Закрытие графического режима
getch(); closegraph(); }
В этой простой программе обратите внимание на перечисление типов закраски площадных фигур в цикле for (int i=SOLID_FILL; i
Таблица 1. Типы стандартных заливок замкнутых областей
| I=0 | ENUM_FILL | Заливка цветом фона |
| I=1 | SOLID_FILL | Заливка текущим цветом (установленным setcolor()) |
| I=2 | LINE_FILL | Горизонтальная штриховка |
| I=3 | LTSLASH_FILL | Штриховка тонкими линиями под углом 45° влево |
| I=4 | SLASH_FILL | Штриховка толстыми линиями под углом 45° влево |
| I=5 | BKSLASH_FILL | Штриховка толстыми линиями под углом 45° вправо |
| I=6 | LTBKSLASH_FILL | Штриховка линиями под углом 45° вправо |
| I=7 | HATCH_FILL | Штриховка в клетку |
| I=8 | XHATCH_FILL | Штриховка в клетку под углом 45° |
| I=9 | INTERLEAVE_FILL | Частая штриховка в клетку под 45° |
| I=10 | WIDEDOT_FILL | Заполнение редкими точками |
| I=11 | CLOSEDOT_FILL | Заполнение частыми точками |
| I=12 | USER_FILL | По шаблону программиста |
На рис. 1 показана экранная копия работы программы rectang1.cpp, иллюстрирующая перечисленные способы заполнения внутренних областей.
Рисунок .1. Демонстрация работы графических функций.
51