Лекция 2
-
История создания языка С и С++
Язык С (читается "Си") создан в начале 70х годов Кеном Томпсон и Дэннис Ритчи из Bell Labs. Сначала они создали часть компилятора С, затем использовали ее для компиляции остальной части компилятора С и, наконец, применили полученный в результате компилятор для компиляции операционной системы UNIX. Операционная система UNIX первоначально распространялась в исходных кодах на С среди университетов и лабораторий, а получатель мог откомпилировать исходный код на С в машинный код с помощью подходящего компилятора С.
Распространение исходного кода сделало операционную систему UNIX уникальной; программист мог изменить операционную систему, а исходный код мог быть перенесен с одной аппаратной платформы на другую. С был третьим языком, который разработали Томсон и Ритчи в процессе создания UNIX; первыми двумя были, разумеется, А и В.
Что касается грамматики и синтаксиса, то С является структурным языком программирования (основные принципы структурного программирования?). В то время как многие современные программисты мыслят в категориях классов и объектов, программисты на С думают в категориях процедур и функций. В С можно определить собственные абстрактные типы данных, используя ключевое слово struct. Аналогично можно описывать собственные целые типы (перечисления) и давать другие названия существующим типам данных при помощи ключевого слова typedef. В этом смысле С является структурным языком с зародышами объектно-ориентированного программирования.
Широкое распространение языка C на различных типах компьютеров (иногда называемых аппаратными платформами) привело, к сожалению, ко многим вариациям языка. Они были похожи, но несовместимы друг с другом. Это было серьезной проблемой для разработчиков программ, нуждавшихся в написании совместимых программ, которые можно было бы выполнять на нескольких платформах. Стало ясно, что необходима стандартная версия C. В 1983г. ANSI (Американский Национальный Комитет Стандартов) сформировал технический комитет для создания стандарта языка C. В 1989 стандарт был утвержден. ANSI скооперировался с ISO (Международной Организацией Стандартов), чтобы стандартизовать C в международном масштабе; совместный стандарт был опубликован в 1990 году. Этот стандарт совершенствуется до сих пор и поддерживается большинством фирм разработчиков компиляторов.
Бьерн Страуструп, работающий в той же компании Bell Labs решил дополнить язык C возможностями, имеющимися в языке Симула. Страуструп добавил к Си возможность работы с классами и объектами. В результате практические задачи моделирования оказались доступными для решения как с точки зрения времени разработки (благодаря использованию Симула-подобных классов), так и с точки зрения времени вычислений (благодаря быстродействию C). В первую очередь в C были добавлены классы (с инкапсуляцией), наследование классов, строгая проверка типов. Ранние версии языка, первоначально именовавшегося «C with classes» («Си с классами»), стали доступны с 1980 года.
Позже язык стал называться C++. Сегодня это один из наиболее популярных языков программирования в мире.
Хотя язык программирования С++ справедливо называют продолжением С и любая работоспособная программа на языке С будет поддерживаться компилятором С++, при переходе от С к С++ был сделан весьма существенный скачок. Язык С++ выигрывал от своего родства с языком С в течение многих лет, поскольку многие программисты обнаружили, что для того, чтобы в полной мере воспользоваться преимуществами языка С++, им нужно отказаться от некоторых своих прежних знаний и приобрести новые, а именно: изучить новый способ концептуальности и решения проблем программирования. Перед тем как начинать осваивать С++, Страуструп и большинство других программистов, использующих С++ считают изучение языка С необязательным.
2. Структура программы на языке С++
Программа на языке С++ в простейшем виде имеет следующий вид:
директивы препроцессора
void main()
{
операторы функции
}
main – это имя главной функции программы. Помимо нее программа может содержать произвольное количество других функций (об этом речь пойдет позже). В С++ нет понятия процедуры, поэтому подразумевается, что функция должна обязательно вернуть какое-либо значение. Тип этого значения указывается перед именем функции. Если же функция ничего не возвращает, то указывается тип void, что означает пустое значение. В ближайшее время мы будем работать с функциями только такого типа.
Тело функции заключается в фигурные скобки. Каждый оператор заканчивается точкой с запятой.
Директивы препроцессора представляют собой инструкции, записанные в тексте программы на СИ, и выполняемые до трансляции программы. Директивы препроцессора позволяют изменить текст программы, например, вставить текст из другого файла, запретить трансляцию части текста, присвоить часто используемой константе имя и т.п. Все директивы препроцессора начинаются со знака #. После директив препроцессора точка с запятой не ставятся.
Чаще всего используется директива #include, которая позволяет включать в текст программы указанный файл. Если файл является стандартной библиотекой и находится в папке компилятора, он заключается в угловые скобки. Если файл находится в текущем каталоге проекта, он указывается в кавычках. Для файла, находящегося в другом каталоге необходимо в кавычках указать полный путь.
#include
#include "func.c"
Основной стандартной библиотекой языка Си является библиотека stdio.h. Она содержит основные функции для организации ввода-вывода, для работы с файлами, а также ряд некоторых стандартных констант. В языке С++ для организации ввода-вывода используется библиотека iostream. Однако в С++ можно использовать также функции из стандартных библиотек языка Си.
3. Идентификаторы, ключевые слова, комментарии
Имена, или идентификаторы, служат для того чтобы обращаться к программным объектам и различать их, то есть идентифицировать. В идентификаторе могут использоваться буквы, цифры и символ подчеркивания. Прописные и строчные буквы в языке Си различаются. Например, sysop, SySoP и SYSOP — три разных имени.
Первым символом идентификатора может быть буква или знак подчеркивания, но не цифра. Длина идентификатора не ограничена. Пробелы внутри имен не допускаются.
Имена даются элементам программы, к которым требуется обращаться: переменным, типам, константам и т. д. При выборе идентификатора необходимо следить, чтобы он не совпадал с ключевыми словами.
Ключевые слова — это зарезервированные идентификаторы, которые имеют специальное значение для компилятора. Их можно использовать только в том смысле, в котором они определены. Список ключевых слов – стр.19 учебника [1].
Комментарии предназначены для записи пояснений к программе и формирования документации. Компилятор комментарии игнорирует. Внутри комментария можно использовать любые символы. В C++ есть два вида комментариев: однострочные и многострочные.
Однострочный комментарий начинается с двух символов прямой косой черты (//) и заканчивается символом перехода на новую строку, многострочный заключается между символами-скобками /* и */ и может занимать часть строки, целую строку или несколько строк.
4. Скалярные типы данных. Константы.
Основная цель любой программы состоит в обработке данных. Данные различного типа хранятся и обрабатываются по-разному. В любом алгоритмическом языке каждая константа, переменная, результат вычисления выражения или функции должны иметь определенный тип.
Тип данных определяет:
· внутреннее представление данных в памяти компьютера;
· множество значений, которые могут принимать величины этого типа;
· операции и функции, которые можно применять к величинам этого типа.
Все типы языка C++ можно разделить на основные и составные. В языке C++ определено шесть основных типов данных для представления целых, вещественных, символьных и логических величин. На основе этих типов программист может вводить описание составных типов. К ним относятся массивы, перечисления, функции, структуры, ссылки, указатели, объединения и классы.
Основные (стандартные) типы данных часто называют арифметическими, поскольку их можно использовать в арифметических операциях. Для описания основных типов определены следующие ключевые слова:
int (целый);
char (символьный);
wchar_t (расширенный символьный);
bool (логический):
float (вещественный);
double (вещественный с двойной точностью).
Первые четыре типа называют целочисленными (целыми), последние два - типами с плавающей точкой
Существует четыре спецификатора типа, уточняющих внутреннее представление и диапазон значений стандартных типов:
· short (короткий);
· long (длинный);
· signed (знаковый);
· unsigned (беззнаковый).
Целый тип (int). Размер типа int не определяется стандартом, а зависит от компьютера и компилятора. Для 16-разрядного процессора под величины этого типа отводится 2 байта, для 32-разрядного - 4 байта, для 64-разрядного 4 или 8 байт.
Спецификатор short перед именем типа указывает компилятору, что под число требуется отвести 2 байта независимо от разрядности процессора. Спецификатор long означает, что целая величина будет занимать 4 байта.
Внутреннее представление величины целого типа - целое число в двоичном коде. При использовании спецификатора signed старший бит числа интерпретируется как знаковый (0 - положительное число, 1 - отрицательное). Спецификатор unsigned позволяет представлять только положительные числа, поскольку старший разряд рассматривается как часть кода числа. Таким образом, диапазон значений типа int зависит от спецификаторов. По умолчанию все целочисленные типы считаются знаковыми, то есть спецификатор signed можно опускать.
Типы short int, long int, signed int и unsigned int можно сокращать до short, long, signed и unsigned соответственно.
Символьный тип (char). Под величину символьного типа отводится обычно 1 байт. Его можно использовать как для хранения символов кодировочной таблицы ACSII, так и для хранения целых чисел в диапазоне от -128 до 127. При использовании спецификатора unsigned значения могут находиться в пределах от 0 до 255.
Расширенный символьный тип (wchar_t). Тип wchar_t предназначен для работы с набором символов, для кодировки которых недостаточно 1 байта, например, Unicode. Размер этого типа зависит от реализации; как правило, он равен 2 байтам.
Логический тип (bool). Величины логического типа могут принимать только значения true и false, являющиеся зарезервированными словами. Внутренняя форма представления значения false - 0 (нуль). Любое другое значение интерпретируется как true. При преобразовании к целому типу true имеет значение 1.
Типы с плавающей точкой (float, double и long double).Стандарт C++ определяет три типа данных для хранения вещественных значений: float, double и long double.
Величины типа float занимают 4 байта, из которых один двоичный разряд отводится под знак мантиссы, 8 разрядов под порядок и 23 под мантиссу.
Для величин типа double, занимающих 8 байт, под порядок и мантиссу отводится 11 и 52 разряда соответственно.
Спецификатор long перед именем типа double указывает, что под величину отводится 10 байтов.
Для получения точной информации и том, сколько памяти занимает тот или иной тип, необходимо пользоваться операцией sizeof, результатом которой является размер типа в байтах.
Тип void. Кроме перечисленных, к основным типам языка относится тип void, но множество значений этого типа пусто. Он используется для определения функций, которые не возвращают значения, для указания пустого списка аргументов функции, как базовый тип для указателей и в операции приведения типов.
Константами называют неизменяемые величины. Различаются целые, вещественные, символьные и строковые константы.
Вещественные константы имеют по умолчанию тип double.
Символьные константы, состоящие из одного символа, занимают в памяти один байт и имеют стандартный тип char.
Символ обратной косой черты (\) используется для представления:
- кодов, не имеющих графического изображения (например, \n — перевод курсора в начало следующей строки);
- символов апострофа, обратной косой черты, вопроса и кавычки;
- любого символа с помощью его 16-ричного или 8-ричного кода, например, \073, \0xF5.
Последовательности символов, начинающиеся с обратной косой черты, называют управляющими, или escape-последовательностями. Управляющая последовательность интерпретируется как одиночный символ. Подробнее об этом – стр.21 учебника [1].
Строковые константы, отделенные в программе только пробельными символами, при компиляции объединяются в одну. Длинную строковую константу можно разместить на нескольких строках, используя в качестве знака переноса обратную косую черту, за которой следует перевод строки. Например, строка
"Пермский \
университет"
полностью эквивалентна строке
"Пермский университет"
В конец каждого строкового литерала компилятором добавляется нулевой символ, представляемый управляющей последовательностью \0.
Константам, встречающимся в программе, приписывается тот или иной тип в соответствии с их видом. Если этот тип по каким-либо причинам не устраивает программиста, он может явно указать требуемый тип с помощью суффиксов L, l (long) и U, u (unsigned). Например, константа 32L будет иметь тип long и занимать 4 байта. Можно использовать суффиксы L и U одновременно, например, Ox22UL или 05Lu.
При описании типа переменной можно сразу же присвоить начальное значение.
Пример
int a,b=4,c;
5. Операции ввода-вывода. Форматный вывод
В С++ нет встроенных в язык средств ввода-вывода. Для этих целей используется библиотека ввода-вывода iostream, которая включается в текст программы с помощью директивы препроцессора #include.
#include
Библиотека iostream.h определяет три стандартных потока:
- cin стандартный входной поток
- cout стандартный выходной поток
Для их использования в Microsoft Visual Studio обязательно необходимо прописать строку:
using namespace std;
Для выполнения операций ввода-вывода переопределены две операции поразрядного сдвига:
>> получить из входного потока
<< поместить в выходной поток.
Ввод значения переменной:
cin >> идентификатор;
Возможно многократное назначение потоков:
cin >> переменная1 >> переменная2 >>...>> переменная n;
При наборе данных на клавиатуре значения для такого оператора должны быть разделены символами пробела или нажатием клавиши .
Например:
int n;
char j;
cin >> n >> j;
Вывод информации:
cout << значение;
Возможно многократное назначение потоков:
cout <<значение1 <<значение2 << ... << значение n;
Например:
int n;
char j;
cin >> n >> j;
cout << "Значение n равно" << n << "j=" << j;
Пример. Программа ввода-вывода значения переменной в C++
#include
#include "windows.h"
using namespace std;
void main()
{
setlocale (LC_ALL, "Russian")
int i;
cout << "Введите целое число\n";
cin >> i;
cout << "Вы ввели число " << i << ", спасибо!";
}
Несколько пояснений к программе.
В C++ есть такое понятие как пространство имен.
Пространство имен - это группа имен, в которой имена не совпадают. Один и тот же идентификатор может быть независимо определён в нескольких пространствах. Таким образом, значение, связанное с идентификатором, определённым в одном пространстве имён, может иметь (или не иметь) такое же значение, как и такой же идентификатор, определённый в другом пространстве.
Например, Андрей работает в компании X, а его как работника равен 123. Олег работает в компании Y, а его ID также равен 123. Единственное (с точки зрения некой системы учёта), благодаря чему Андрей и Олег могут быть различимы при совпадающих ID, это их принадлежность к разным компаниям. Различие компаний в этом случае представляет собой систему различных пространств имён (одна компания — одно пространство).
В больших базах данных могут существовать сотни и тысячи идентификаторов. Пространства имён (или схожие структуры) реализуют механизм для сокрытия локальных идентификаторов. Их смысл заключается в группировке логически связанных идентификаторов в соответствующих пространствах имён, таким образом, делая систему модульной. Ограничение видимости переменных может также производиться путём задания класса её памяти.
Имена в различных пространствах имен не конфликтуют между собой, даже если они совпадают. Пространства имен вводятся для снижения вероятности конфликта имен и полезны в случае использования имен из нескольких различных библиотек.
Каждая переменная, класс и т.п. принадлежат какому-то пространству имен. По умолчанию используется пространство имен с пустым именем, однако все стандартные функции (в том числе функции ввода-вывода) расположены в пространстве имен std. Чтобы явно указать, а каком пространству имен принадлежит та или иная функция, необходимо указывать название пространства имен перед ее вызовом, то есть
std::cout << "Введите целое число\n";
std::cin >> i;
std::cout << "Вы ввели число " << i << ", спасибо!";
Чтобы не указывать одно и то же имя пространства имен несколько раз, можно однократно использовать инструкцию
using namespace имя_пространства имен;
Эта инструкция заставляет компилятор признавать все члены одного пространства имен без дополнительного определения имени этого пространства. Если в программе есть переменные, классы и функции, принадлежащие разным пространствам имен, то используются специальные объявления. Речь о них пойдет позже.
Функции позволяют использовать русский шрифт при выводе сообщений.. Для их использования необходимо подключить библиотеку windows.h.
Система ввода/вывода С++ включает способ изменения параметров форматирования потока. Для этого используются специальные функции, называемые манипуляторами, которые могут включаться в выражения ввода/вывода.
Для использования манипуляторов с параметрами в программу необходимо включить заголовочный файл iomanip.
Основные стандартные манипуляторы:
endl Вывод символа новой строки (переход в новую строку)
setprecision(int p) Устанавливает число цифр после запятой при выводе
setw(int w) Устанавливает ширину поля равной w
fixed Вывод числа в форме с фиксированной точкой
scientific Вывод числа в экспоненциальной форме
Пример:
#include
#include
using namespace std;
void main()
{
cout << setprecision (2) << 1000.243 << endl;
cout << setw (20) << "Hello there.";
}
Программа выводит следующие данные:
1000.24
Hello there.
Подробнее про манипуляторы и флаги ввода-вывода можно прочитать здесь - http://kvodo.ru/urok-10-formatirovannyiy-vvod-vyivod-v-c.html
6. Основные операции языка С++
Прежде чем рассмотреть основные операции языка С++, введем понятие операнда.
Операнд - это переменное или постоянное значение, которым оперирует процессор в процессе реализации программных вычислений. Это могут быть константы, переменные, функции, выражения и другие объекты языка программирования, над которым производится операция.
Операция - это символ, представляющий собой некоторую операцию, производимую с данными.
В языке Си существуют несколько видов операций: арифметические операции, операции сравнения, битовые и логические операции. Примерами операндов могут служить, например, два слагаемых, над которыми производится операция суммирования, или операция смены знака числа. В зависимости от количества операндов, операции в языке С++ делятся на унарные, бинарные и тернарную. Обратите внимание, что операции перечислены в порядке их приоритета.
Унарные операции
1) Операции увеличения и уменьшения значения на 1 (++ и --). Эти операции, называемые также инкрементом и декрементом, имеют две формы записи - префиксную, когда операция записывается перед операндом, и постфиксную. В префиксной форме сначала изменяется операнд, а затем его значение становится результирующим значением выражения, а в постфиксной форме значением выражения является исходное значение операнда, после чего он изменяется.
int x = 3; у = 3, z;
z=++x;
cout<z=y++;
cout<cout<
cout<}
Результат работы программы:
Значение префиксного выражения: 4
Значение постфиксного выражения: 3
Значение х после приращения: 4
Значение у после приращения: 4
2) Операция определения размера sizeof предназначена для вычисления размера объекта или типа в байтах, и имеет две формы:
sizeof (выражение)
sizeof (тип)
Например:
int x,y;
x=2; y=3;
cout<
cout<3) Операции отрицания (-, ! и ~). Арифметическое отрицание (унарный минус -) изменяет знак операнда целого или вещественного типа на противоположный. Логическое отрицание (!) дает в результате значение 0, если операнд есть истина (не нуль), и значение 1, если операнд равен нулю. Поразрядное отрицание (~), часто называемое побитовым, инвертирует каждый разряд в двоичном представлении целочисленного операнда.
Бинарные операции
1) Деление (/) и остаток от деления (%). Операция деления применима к операндам арифметического типа. Если оба операнда целочисленные, результат операции округляется до целого числа, в противном случае тип результата определяется правилами преобразования. Когда переменные и константы различных типов смешиваются в выражениях, то происходит преобразование к одному типу. Компилятор преобразует все операнды «вверх», к типу операнда, занимающего больший объем памяти.
Операция остатка от деления применяется только к целочисленным операндам. Знак результата зависит от реализации.
Пример
#include
void main(){
int x = 11, y = 4;
float z = 4;
cout<
cout<
}
Результат работы программы:
Результаты деления: 2 2.750000
Остаток: 3
Чтобы привести результат вычислений к нужному типу при целочисленном делении, кроме использования форматного вывода можно использовать операции приведения float(x) или double(x).
Пример
#include
using namespace std;
void main(){
int x = 11, у = 4;
float z = 4, r1, r2;
r1=float(x)/y;
r2=float(x)/z;
cout << "Результаты деления: " << r1 ,<< r2 << endl;
}
Обратите внимание, что при их применении к целым числам (например float(4)) результат останется целым!!
2) Операции сдвига (<<и >>) применяются к целочисленным операндам. Они сдвигают двоичное представление первого операнда влево или вправо на количество двоичных разрядов, заданное вторым операндом. При сдвиге влево (<<) освободившиеся разряды обнуляются. При сдвиге вправо (>>) освободившиеся биты заполняются нулями, если первый операнд беззнакового типа, и знаковым разрядом в противном случае. Операции сдвига не учитывают переполнение и потерю значимости.
3) Операции отношения (<, <=, >, >=, ==, !=) сравнивают первый операнд со вторым. Операнды могут быть арифметического типа или указателями. Результатом операции является значение true или false. Операции сравнения на равенство и неравенство имеют меньший приоритет, чем остальные операции сравнения.
Обратите внимание на разницу между операцией проверки на равенство (==) и операцией присваивания (=), результатом которой является значение, присвоенное левому операнду.
4) Поразрядные операции (&, |, ^) применяются только к целочисленным операндам и работают с их двоичными представлениями. При выполнении операций операнды сопоставляются побитово (первый бит первого операнда с первым битом второго, второй бит первого операнда со вторым битом второго, и т д.).
При поразрядной конъюнкции, или поразрядном И (операция обозначается &) бит результата равен 1 только тогда, когда соответствующие биты обоих операндов равны 1.
При поразрядной дизъюнкции, или поразрядном ИЛИ (операция обозначается |) бит результата равен 1 тогда, когда соответствующий бит хотя бы одного из операндов равен 1.
При поразрядном исключающем ИЛИ (операция обозначается ^) бит результата равен 1 только тогда, когда соответствующий бит только одного из операндов равен 1.
5) Логические операции (&& и ||). Операнды логических операций И (&&) и ИЛИ (||) могут иметь арифметический тип, при этом операнды в каждой операции могут быть различных типов. Преобразования типов не производятся, каждый операнд оценивается с точки зрения его эквивалентности нулю (операнд, равный нулю, рассматривается как false, не равный нулю - как true).
6) Операции присваивания (=, +=, -=, *= и т. д.). Операции присваивания могут использоваться в программе как законченные операторы. В Си допустима следующая запись оператора присваивания: a=b=c=2.
Примеры:
b-=2; //b=b-2
c*=b; //c=c*b;
7) Формат операции простого присваивания (=):
операнд_1 = операнд_2
Тернарная операция
Условная операция (?:). Эта операция тернарная, то есть имеет три операнда. Ее формат:
операнд_1 ? операнд_2 : операнд_3
Если результат вычисления операнда 1 равен true, то результатом условной операции будет значение второго операнда, иначе - третьего операнда. Вычисляется всегда либо второй операнд, либо третий. Их тип может различаться. Условная операция является сокращенной формой условного оператора if.
#include
void main()
{
int a = 11, b = 4, max;
max = (b > a)? b : a;
cout<
}
Результат работы программы:
Наибольшее число: 11
Достарыңызбен бөлісу: |