0.2. Первая программа - StriderAJR/StudentCpp GitHub Wiki
Первые шаги хромого
Такая программа состоит из одного-единственного файла main.cpp
со следующим содержимым:
#include <iostream>
void main()
{
std::cout << "Hello, World!" << std::endl;
system("pause");
}
Это самая простая программа, которая выводит на консоль сообщение Hello, World!
. Разберем ее пошагово.
Возможности всех языков программирования на данный момент очень и очень обширны. Уместить все возможности в один-единственный файл не то чтобы не возможно, но такой файл будет гигантским. Поэтому в языках программирования существует механизм "многомодульности", который позволяет создавать отдельные "модули", в которых хранятся какие-то "возможности" или так называемый "функционал". Т.е. подключение какого-то специального модуля (их еще называют библиотеками) позволит вашей программе делать какие-то действия, которые запрограммировали другие программисты до вас или же подключить ваши собственные модули.
Любой компилятор С++ поставляется с уже имеющимся набором стандартных библиотек.
#include <iostream>
Директива #include
- это команда предпроцессора, которая подключает сторонний модуль в ваш файл с кодом. Как это делается? Очень просто. Предпроцессор, который по сути начинает работу еще до компилятора, обрабатывает только текст программы. Если выражаться очень упрощенным языком, то предпроцессор - это текстовый обработчик, который умеет копировать текст из файла в файл, делать замену одного куска текста на другой и т.п.
Команда #include
открывает запрашиваемый файл подключаемого модуля, полностью копирует его содержимое и вставляет вместо строчки, где эта команда вызывается. Так и происходит подключение библиотек в С++.
Библиотека iostream
- одна из стандартных библиотек и позволяет осуществлять операции с вводом информации в программу и ее выводом из программы, например, на консоль. iostream
так и расшифровывается - input output stream
. Что такое stream
(англ. поток) будет рассказано позже.
Дальше в нашей программе Hello, World
идет тело функции main:
void main()
{
// какие-то команды
}
Функция - это некоторый набор команд (действий), которым дано какое-то имя и который можно вызывать (запускать) из другого места в программе неограниченное кол-во раз.
У каждой функции есть список параметров - список значений, которые заведомо функции неизвестны, но с которыми она должна работать. У функции может и не быть никаких параметров, тогда список параметров остается пустым. В нашем примере список параметров как раз-таки пуст, поэтому внутри круглых скобок ничего нет - void main()
.
Также функция может возвращать некое значение, которое является результатом работы функции. Тип данных значения, которое возвращается функцией в качестве результата записывается перед именем самой функции.
Возврат значения осуществляется с помощью команду return
. После вызова этой команды работа функции завершается.
Общий шаблон записи функции можно определить как:
тип_возвращаемого_значения имя_функции(список_параметров_через_запятую)
{ // начало блока кода
// какие-то действия, которые должны выполняться
return значение; // возвращаем значение-результат работы функции
} // конец блока кода
Например, функция сложения двух чисел. Такая функция принимает 2 числа типа int
в качестве параметров и будет возвращать сумму этих чисел как результат.
int add(int a, int b)
{
return a+b;
}
int add(int a, int b)
int
- тип данных возвращаемого значения функцииadd
- имя функции (может быть любым на выбор программиста)int a
- первый параметр -переменная типа данных int с именем a (имя может быть любым)int b
- второй параметр -переменная типа данных int с именем b (имя может быть любым)
Функция может и не возвращать никакого значения, т.е. она просто выполняет какие-то действия, но значения-результата у нее нет. В этом случае тип данных возвращаемого значения записывается как void
- отсутствие типа данных.
Так, например, и работает функция main
в нашем случае:
void main()
{
// какие-то команды
}
NB! Некоторые компиляторы С++ (например, gpp
) не принимают функцию main
без возвращаемого значения. В этом случае main
обычно записывают так:
int main()
{
// какие-то команды
return 0;
}
При запуске исполняемого файла (для Windows это *.exe
файл) весь исходный код загружается в оперативную память. Там хранятся и переменные, и исходные коды программа, другие данные, которые касаются непосредственно этой программы. В языках программирования для простоты работы программиста принято, чтобы начало выполнения алгоритма программы находилось в любом месте (модуле) программы и помечалось специальным имененем, так называемой функцией main
.
Т.к. main
обычная функция, хоть и должна иметь строго заданное имя, но тип возвращаемого значения и список параметров может быть разным в зависимости от потребностей программы. Например:
void main()
{
return;
// Т.к. в данном случае main не должна возвращать никакого значения,
// то return записывается без какого-либо значения
// return можно было и вовсе не писать в данном случае
}
void main()
{
}
Иногда программа запускается без интерфейса пользователя (например, различные утилиты, либо работающие программы в "скрытом" режиме), и тогда нужно знать завершилась ли программа успехом или ошибкой. Для этого функция main
может возвращать значение с кодом завершения программы, каким-то сообщением или просто значением-результатом работы.
int main()
{
return 0;
}
int main()
{
return -5;
}
char main()
{
return 'Q';
}
char* main()
{
return "Done";
}
Параметры у функции main
нужны для передачи параметров в программу при ее запуске. Пример - утилита ping
в Windows. Если вызвать командную строку Windows и вызвать команду
ping ya.ru
то начнется обмен пакетами с доменом ya.ru
, а если ввести команду
ping /?
то на экран выведется справка по данной утилите.
Т.е. как видно, вызывая одну и ту же утилиту ping
с разными параметрами, мы получаем разный результат. Для этого и существует передача параметров в функцию main
.
void main(int num, char c)
{
}
Обычно в функции main
в качестве параметров передают кол-во параметров и массив строк, которые и являются самими параметрами:
void main(int argc, char* argv[])
{
}
Дальше в программе идет вывод сообщения Hello, World!
на экран консоли:
std::cout << "Hello, World!" << std::endl;
В языке Си ввод и вывод на консоль осуществлялись с помощью функций scanf
и printf
соответственно. В языке С++ тоже есть эти функции, но они считаются устаревшими и остались в С++ только для обратной совместимости с программами написанными на чистом языке Си. В С++ же по стандарту лучше использовать переменные-потоки.
cout
(console output) - это выходной поток вывода на консольcin
(console input) - это входной поток чтения с консоли
Оба этих потока хранятся в библиотеке iostream
. Именно ради была подключена эта библиотека в начале программы. Однако в данной программе обращение к потоку идет с помощью записи std::cout
.
На самом деле внутри библиотеки iostream
есть так называемое "пространство имен" (namespace
), которое выступает в роли контейнера (если проще, коробки), внутри которого уже хранятся какие-то функции и переменные. Пространства имен нужны для обеспечения безопасности различных модулей, чтобы не было ситуаций, что разные библиотеки содержат функции или переменные с одинаковыми именами из-за чего возникнет неоднозначность, и компилятор будет выдавать ошибки. (Представьте, что в аудитории находится несколько человек по имени "Иван" и вновь пришедший в аудиторию человек позовет кого-то "Иван!" - этому человеку придется долго выяснить, какой же Иван на самом деле ему нужен) Любую неоднозначность программа трактует как ошибку. Чтобы избежать таких ситуаций и был создан механизм пространств имен.
std
- это и есть имя пространства имен, которое находится внутри библиотеки iostream. Оператор::
- это оператор уточнения видимости.
Таким образом запись
std::cout
расшифровывается программой как "внутри std лежит переменная cout, вот она-то мне и нужна".
Если не уточнять видимость (т.е. не указывать полный путь до местонахождения переменной cout
), то программа не найдет переменную и выдаст ошибку, что идентификатор не найден. Сама по себе программа не будет ничего искать внутри пространства имен, потому что С++ язык воспитанный и по чужим коробкам без разрешения не лазает. С помощью оператора уточнения видимости мы "разрешаем" программе залезть в пространство имен std
и там поискать нужную переменную.
Возвращаясь к команде вызова на консоль:
std::cout << "Hello, World!" << std::endl;
Оператор
<<
- это оператор побитого сдвига влево. В своем изначальном виде этот оператор производит сдвиг числа влево на заданное кол-во разрядов.
int a = 5 << 2;
После такого переменная a будет равна 20 (число 0000 0101 сдвинули влево на 2 разряда и получили 0001 0100).
Но в языках программирования существует такое понятие как перегрузка - явление, когда операторы или функции в нестандартной ситуации были запрограммированы вести себя по-другому.
Для оператора побитого сдвига стандартным является работа с числами, но специально для работы с потоками этот оператор запрограммировали, что в поток, записанный слева от оператора, записывать значение записанное справа от оператора.
std::cout << "Hello, World!";
Здесь в поток cout записывается строка Hello, World!
, поток же затем в свою очередь выведет эту строку на экран.
Для потоков также допустимо записывать несколько операторов <<
подряд, тогда значения справа будут записаны в поток последовательно, одно за другим.
std::cout << "Hello, World!" << std::endl;
В поток cout
сначала запишется строка Hello, World!
, а затем константа endl
, которая также хранится внутри пространства имен std
.
endl
(end line) - это константа, которая хранит символ\n
, символ переноса строки.
В С++ вообще есть много текстовых служебных символов. Все они записываются с символом \
перед ними. Например:
\n
- перенос строки\t
- горизонтальная табуляция\v
- вертикальная табуляция\a
- звуковой сигнал типа "писк" и т.д.