1. НачинаемВ этой главе представлены основные элементы языка: встроенные типы данных, определения именованных объектов, выражений и операторов, определение и использование именованных функций. Мы посмотрим на минимальную законченную С++ программу, вкратце коснемся процесса компиляции этой программы, узнаем, что такое препроцессор, и бросим самый первый взгляд на поддержку ввода и вывода. Мы увидим также ряд простых, но законченных С++ программ. 1.1. Решение задачиПрограммы обычно пишутся для того, чтобы решить какую-то конкретную задачу.
Например, книжный магазин ведет запись проданных книг. Регистрируется название
книги и издательство, причем запись идет в том порядке, в каком книги продаются.
Каждые две недели владелец магазина вручную подсчитывает количество проданных
книг с одинаковым названием и количество проданных книг от каждого издателя.
Этот список сортируется по издателям и используется для составления последующего
заказа книг. Нас попросили написать программу для автоматизации этой деятельности. 1.2. Программа на языке C++В С++ действие называется выражением, а выражение, заканчивающееся точкой с запятой, - инструкцией. Инструкция - это атомарная часть С++ программы, которой в программе на С++ соответствует предложение естественного языка. Вот примеры инструкций С++: int book_count = 0; book_count = books_on_shelf + books_on_order; cout << "значение переменной book_count: " << book_count; Первая из приведенных инструкций является инструкцией объявления. book_count
можно назвать идентификатором, символической переменной (или просто
переменной) или объектом. Переменной соответствует область в памяти
компьютера, соотнесенная с определенным именем (в данном случае book_count),
в которой хранится значение типа (в нашем случае целого). 0 - это константа.
Переменная book_count инициализирована значением 0. значение переменной book_count: 11273 если значение book_count равно 11273 в данной точке выполнения программы. int main() { readIn(); sort(); compact(); print(); return 0; } Исполнение программы начинается с выполнения первой инструкции функции main(),
в нашем случае - вызовом функции readIn(). Затем одна за другой исполняются
все дальнейшие инструкции, и, выполнив последнюю инструкцию функции main(),
программа заканчивает работу. return 0; Инструкция return обеспечивает механизм завершения работы функции. Если оператор
return сопровождается некоторым значением (в данном примере 0), это значение
становится возвращаемым значением функции. В нашем примере возвращаемое
значение 0 говорит об успешном выполнении функции main(). (Стандарт С++ предусматривает,
что функция main() возвращает 0 по умолчанию, если оператор return не использован
явно.) void readIn() { cout << "readIn()\n"; } void sort() { cout << "sort()\n"; } void compact() { cout << "compact()\n"; } void print() { cout << "print ()\n"; } Тип void используется, чтобы обозначить функцию, которая не возвращает никакого
значения. Наши заглушки не производят никаких полезных действий, они только
выводят на терминал сообщения о том, что были вызваны. Впоследствии мы заменим
их на реальные функции, выполняющие нужную нам работу. #include <iostream> using namespace std; void readIn() { cout << "readIn()\n"; } void sort() { cout << "sort()\n"; } void compact() { cout << "compact()\n"; } void print() { cout << "print ()\n"; } int main() { readIn(); sort(); compact(); print(); return 0; Здесь iostream - стандартный заголовочный файл библиотеки ввода/вывода (обратите
внимание: у него нет расширения). Эта библиотека содержит информацию о потоке
cout, используемом в нашей программе. #include является директивой препроцессора,
заставляющей включить в нашу программу текст из заголовочного файла iostream.
(Директивы препроцессора рассматриваются в разделе 1.3.) #include <iostream> следует инструкция using namespace std; Эта инструкция называется директивой using. Имена, используемые в стандартной
библиотеке С++ (такие, как cout), объявлены в пространстве имен std и невидимы
в нашей программе до тех пор, пока мы явно не сделаем их видимыми, для чего
и применяется данная директива. (Подробнее о пространстве имен говорится в разделах
2.7 и 8.5.) $ CC prog1.C Здесь $ представляет собой приглашение командной строки. CC - команда вызова
компилятора С++, принятая в большинстве UNIX-систем. Команды вызова компилятора
могут быть разными в разных системах. int main( { // ошибка - пропущена ')' readIn(): // ошибка - недопустимый символ ':' sort(); compact(); print(); return 0 // ошибка - пропущен символ ';' } ошибки типизации. С каждой переменной и константой в С++ сопоставлен некоторый
тип. Например, число 10 - целого типа. Строка "hello", заключенная
в двойные кавычки, имеет символьный тип. Если функция ожидает получить в качестве
параметра целое значение, а получает символьную строку, компилятор рассматривает
это как ошибку типизации. readIn() sort() compact() print() В С++ набор основных типов данных - это целый и вещественный числовые типы, символьный тип и логический, или булевский. Каждый тип обозначается своим ключевым словом. Любой объект программы ассоциируется с некоторым типом. Например: int age = 10; double price = 19.99; char delimiter = ' '; bool found = false; Здесь определены четыре объекта: age, price, delimiter, found, имеющие соответственно
типы целый, вещественный с двойной точностью, символьный и логический. Каждый
объект инициализирован константой - целым числом 10, вещественным числом 19.99,
символом пробела и логическим значением false. age = 33.333; то значением переменной age станет целое число 33. (Стандартные преобразования
типов, а также общие проблемы преобразования типов рассматриваются в разделе
4.14.) // заголовочный файл с определением типа string #include <string> string current_chapter = "Начинаем"; // заголовочный файл с определением типа vector #include <vector> vector<string> chapter_titles(20); Здесь current_chapter - объект типа string, инициализированный константой "Начинаем". Переменная chapter_titles - вектор из 20 элементов строкового типа. Несколько необычный синтаксис выражения vector<string> сообщает компилятору о необходимости создать вектор, содержащий объекты типа string. Для того чтобы определить вектор из 20 целых значений, необходимо написать: vector<int> ivec(20); Никакой язык, никакие стандартные библиотеки не способны обеспечить нас всеми
типами данных, которые могут потребоваться. Взамен современные языки программирования
предоставляют механизм создания новых типов данных. В С++ для этого служит механизм
классов. Все расширенные типы данных из стандартной библиотеки С++, такие как
строка, комплексное число, вектор, список, являются классами, написанными на
С++. Классами являются и объекты из библиотеки ввода/вывода. 1.2.1. Порядок выполнения инструкцийПо умолчанию инструкции программы выполняются одна за другой, последовательно. В программе int main() { readIn(); sort(); compact(); print(); return 0; } первой будет выполнена инструкция readIn(), за ней sort(), compact() и наконец
print(). // readIn() возвращает количество прочитанных записей // возвращаемое значение имеет тип int int readIn() { ... } // ... int main() { int count = readIn(); // если количество записей больше 1, // то вызвать sort() и compact() if ( count > 1 ) { sort(); compact(); } if ( count == 0 ) cout << "Продаж не было\n"; else print(); return 0; } Первая инструкция if обеспечивает условное выполнение блока программы: функции
sort() и compact() вызываются только в том случае, если count больше 1. Согласно
второй инструкции if на терминал выводится сообщение "Продаж не было",
если условие истинно, т.е. значение count равно 0. Если же это условие ложно,
производится вызов функции print(). (Детальное описание инструкции if приводится
в разделе 5.3.) int main() { int iterations = 0; bool continue_loop = true; while ( continue_loop != false ) { iterations++; cout << "Цикл был выполнен " << iterations << "раз\n"; if ( iterations == 5 ) continue_loop = false; } return 0; } В этом надуманном примере цикл while выполняется пять раз, до тех пор пока переменная iterations не получит значение 5 и переменная continue_loop не станет равной false. Инструкция iterations++; увеличивает значение переменной iterations на единицу. (Инструкции цикла детально рассматриваются в главе 5.) 1.3. Директивы препроцессораЗаголовочные файлы включаются в текст программы с помощью директивы препроцессора
#include. Директивы препроцессора начинаются со знака "диез" (#),
который должен быть самым первым символом строки. Программа, которая обрабатывает
эти директивы, называется препроцессором (в современных компиляторах
препроцессор обычно является частью самого компилятора). #include <some_file.h> #include "my_file.h" Если имя файла заключено в угловые скобки (<>), считается, что нам нужен
некий стандартный заголовочный файл, и компилятор ищет этот файл в предопределенных
местах. (Способ определения этих мест сильно различается для разных платформ
и реализаций.) Двойные кавычки означают, что заголовочный файл - пользовательский,
и его поиск начинается с того каталога, где находится исходный текст программы. #ifndef BOOKSTORE_H #define BOOKSTORE_H /* содержимое файла bookstore.h */ #endif Условная директива #ifndef проверяет, не было ли значение BOOKSTORE_H определено
ранее. (BOOKSTORE_H - это константа препроцессора; такие константы принято писать
заглавными буквами.) Препроцессор обрабатывает следующие строки вплоть до директивы
#endif. В противном случае он пропускает строки от #ifndef до # endif. #define BOOKSTORE_H определяет константу препроцессора BOOKSTORE_H. Поместив эту директиву непосредственно
после директивы #ifndef, мы можем гарантировать, что содержательная часть заголовочного
файла bookstore.h будет включена в исходный текст только один раз, сколько бы
раз ни включался в текст сам этот файл. int main() { #ifdef DEBUG cout << "Начало выполнения main()\n"; #endif string word; vector<string> text; while ( cin >> word ) { #ifdef DEBUG cout << "Прочитано слово: " << word << "\n"; #endif text.push_back(word); } // ... } Если константа DEBUG не определена, результирующий текст программы будет выглядеть так: int main() { string word; vector<string> text; while ( cin >> word ) { text.push_back(word); } // ... } В противном случае мы получим: int main() { cout << "Начало выполнения main()\n"; string word; vector<string> text; while ( cin >> word ) { cout << "Прочитано слово: " << word << "\n"; text.push_back(word); } // ... } Константа препроцессора может быть определена в командной строке при вызове компилятора с помощью опции -D (в различных реализациях эта опция может называться по-разному). Для UNIX-систем вызов компилятора с определением препроцессорной константы DEBUG выглядит следующим образом: $ CC -DDEBUG main.C Есть константы, которые автоматически определяются компилятором. Например, мы можем узнать, компилируем ли мы С++ или С программу. Для С++ программы автоматически определяется константа __cplusplus (два подчеркивания). Для стандартного С определяется __STDC__. Естественно, обе константы не могут быть определены одновременно. Пример: #idfef __cplusplus // компиляция С++ программы extern "C"; // extern "C" объясняется в главе 7 #endif int main(int,int); Другими полезными предопределенными константами (в данном случае лучше сказать переменными) препроцессора являются __LINE__ и __FILE__. Переменная __LINE__ содержит номер текущей компилируемой строки, а __FILE__ - имя компилируемого файла. Вот пример их использования: if ( element_count == 0 ) cerr << "Ошибка. Файл: " << __FILE__ << " Строка: " << __LINE__ << "element_count не может быть 0"; Две константы __DATE__ и __TIME__ содержат дату и время компиляции. #include <assert.h> assert.h - это заголовочный файл стандартной библиотеки С. Программа на C++
может ссылаться на заголовочный файл как по его имени, принятому в C, так и
по имени, принятому в C++. В стандартной библиотеке С++ этот файл носит имя
cassert. Имя заголовочного файла в библиотеке С++ отличается от имени соответствующего
файла для С отсутствием расширения .h и подставленной спереди буквой c (выше
уже упоминалось, что в заголовочных файлах для C++ расширения не употребляются,
поскольку они могут зависеть от реализации). #include <cassert> включает в текст программы содержимое файла cassert. Но поскольку все имена, используемые в стандартной библиотеке С++, определены в пространстве std, имя assert() будет невидимо до тех пор, пока мы явно не сделаем его видимым с помощью следующей using-директивы: using namespace std; Если же мы включаем в программу заголовочный файл для библиотеки С #include <assert.h> то надобность в using-директиве отпадает: имя assert() будет видно и так .
(Пространства имен используются разработчиками библиотек для предотвращения
засорения глобального пространства имен. В разделе 8.5 эта тема рассматривается
более подробно.) 1.4. Немного о комментарияхКомментарии помогают человеку читать текст программы; писать их грамотно считается
правилом хорошего тона. Комментарии могут характеризовать используемый алгоритм,
пояснять назначение тех или иных переменных, разъяснять непонятные места. При
компиляции комментарии выкидываются из текста программы поэтому размер получающегося
исполняемого модуля не увеличивается. /* * Это первое знакомство с определением класса в C++. * Классы используются как в объектном, так и в * объектно-ориентированном программировании. Реализация * класса Screen представлена в главе 13. */ class Screen { /* Это называется телом класса */ public: void home(); /* переместить курсор в позицию 0,0 */ void refresh ();/* перерисовать экран */ private: /* Классы поддерживают "сокрытие информации" */ /* Сокрытие информации ограничивает доступ из */ /* программы к внутреннему представлению класса */ /* (его данным). Для этого используется метка */ /* "private:" */ int height, width; } Слишком большое число комментариев, перемежающихся с кодом программы, может
ухудшить читаемость текста. Например, объявления переменных width и height в
данном тексте окружены комментариями и почти не заметны. Рекомендуется писать
развернутое объяснение перед блоком текста. Как и любая программная документация,
комментарии должны обновляться в процессе модификации кода. Увы, нередко случается,
что они относятся к устаревшей версии. /* комментарии /* */ не могут быть вложенными. * Строку "не вкладываются" компилятор рассматривает, * как часть программы. Это же относится к данной и следующей строкам */ int main() { Один из способов решить проблему вложенных комментариев – поставить пробел
между звездочкой и косой чертой: /* * Первое знакомство с определением класса в C++. * Классы используются как в объектном, так и в * объектно-ориентированном программировании. Реализация * класса Screen представлена в главе 13. */ class Screen { Обычно в программе употребляют сразу оба типа комментариев. Строчные комментарии удобны для кратких пояснений – в одну или полстроки, а комментарии, ограниченные /* и */, лучше подходят для развернутых многострочных пояснений. 1.5. Первый взгляд на ввод/выводЧастью стандартной библиотеки С++ является библиотека iostream, которая реализована
как иерархия классов и обеспечивает базовые возможности ввода/вывода. #include <iostream> Чтобы значение поступило в стандартный вывод или в стандартный вывод для ошибок используется оператор <<: int v1, v2; // ... cout << "сумма v1 и v2 = "; cout << v1 + v2; cout << "\n"; Последовательность "\n" представляет собой символ перехода на новую строку. Вместо "\n" мы можем использовать предопределенный манипулятор endl. cout << endl; Манипулятор endl не просто выводит данные (символ перехода на новую строку), но и производит сброс буфера вывода. (Предопределенные манипуляторы рассматриваются в главе 20.) Операторы вывода можно сцеплять. Так, три строки в предыдущем примере заменяются одной: cout << "сумма v1 и v2 = " << v1 + v2 << "\n"; Для чтения значения из стандартного ввода применяется оператор ввода (>>): string file_name; // ... cout << "Введите имя файла: "; cin >> file_name; Операторы ввода, как и операторы вывода, можно сцеплять: string ifile, ofile; // ... cout << "Введите имя входного и выходного файлов: "; cin >> ifile >> ofile; Каким образом ввести заранее неизвестное число значений? Мы вернемся к этому вопросу в конце раздела 2.2, а пока скажем, что последовательность инструкций string word; while ( cin >> word ) // ... считывает по одному слову из стандартного ввода до тех пор, пока не считаны все слова. Выражение ( cin >> word ) возвращает false, когда достигнут конец файла. (Подробнее об этом – в главе 20.) Вот пример простой законченной программы, считывающей по одному слову из cin и выводящей их в cout: #include <iostream> #include <string> int main () { Вот первое предложение из произведения Джеймса Джойса “Пробуждение Финнегана”: riverrun, past Eve and Adam's Если запустить приведенную выше программу и набрать с клавиатуры данное предложение, мы увидим на экране терминала следующее: Прочитано слово: riverrun, Прочитано слово: past Прочитано слово: Eve, Прочитано слово: and Прочитано слово: Adam's Все слова прочитаны! (В главе 6 мы рассмотрим вопрос о том, как убрать знаки препинания из вводимых слов.) 1.5.1. Файловый ввод/выводБиблиотека iostream поддерживает и файловый ввод/вывод. Все операции, применимые в стандартному вводу и выводу, могут быть также применены к файлам. Чтобы использовать файл для ввода или вывода, мы должны включить еще один заголовочный файл: #include <fstream> Перед тем как открыть файл для вывода, необходимо объявить объект типа ofstream: ofstream outfile("name-of-file"); Проверить, удалось ли нам открыть файл, можно следующим образом: if ( ! outfile ) // false, если файл не открыт cerr << "Ошибка открытия файла.\n" Так же открывается файл и для ввода, только он имеет тип ifstream: ifstream infile("name-of-file"); if ( ! infile ) // false, если файл не открыт cerr << "Ошибка открытия файла.\n" Ниже приводится текст простой программы, которая читает файл с именем in_file и выводит все прочитанные из этого файла слова, разделяя их пробелом, в другой файл, названный out_file. #include <iostream> #include <fstream> #include <string> int main() {
Содержание |
2011-04-08 16:59:41 Оксана Параллельно с прочтением книги, я пытаюсь прорабатывать предложенный код примеров через компилятор VS 6.0. Хотелось бы знать, какую версию компилятора использовал автор, т.к. не все примеры работают у меня. 2011-04-08 20:12:22 Александр Этой работе больше 10 лет. Так что корректируйте под свой компилятор. 2011-04-25 16:46:39 Денис По тексту: В UNIX для этого выполняется следующая команда: $ CC prog1.C Здесь $ представляет собой приглашение командной строки. CC - команда вызова компилятора С++, принятая в большинстве UNIX-систем. Команды вызова компилятора могут быть разными в разных системах. 2011-07-18 00:55:48 Александр Да у меня также работают не все примеры. Так как я недавно начал изучать C++, то хотелось бы узнать как проверить версию компилятора и где найти инструкцию по работе с этой версией. Различия между версиями. 2011-08-06 14:48:35 Андрей приложите рисунок или видео !!! 2011-08-14 17:23:53 Василий А где компилятор? 2011-08-17 20:39:31 Илья Отличная статья!Нашлось подобие книжки!Кстати у меня всё работает-компилятор Dev-C++! 2011-08-30 22:30:46 Никита Достаточно хорошая и подробная статья, огромный сенк! 2011-09-28 18:36:04 Дмитриц В последней программе две ошибки. Строки, в которых используется cerr не закрыты, не стоит ";". 2011-10-18 03:34:20 ииисус почему после инклудов нет using namespace std; ? qt, например, ругается при определении string 2011-10-19 15:37:14 Дмитрий у меня visual C++ express edition, не работает cout пишет не обьявленный идентификатор, iostream был подключен 2011-11-08 10:36:18 Николай Дмитрий, после подключения include объявите стандартное пространство имён: using namespace std; 2012-01-11 22:25:59 Артур Чётко но пока поучу еще php 2012-02-15 08:54:21 Павел К сожалению, у меня почему-то не работает пример простой законченной программы из пункта 1.5. При пошаговой отладке выяснилось, что программа зацикливается в цикле while. После полного прочтения строки она заново предлагает ввести строку, а не выводит сообщение, что все слова прочитаны. Использую Visual C++ 2008 Express edition 2012-02-29 10:31:39 Владимир Хорошая статья Народ,у кого все получается и все примеры работают выложите пжлста проги которыми сами пользуетесь 2012-03-11 18:28:36 Стёпа Всё ништяк, хороший учебник ! мне понравился всё работает (если чтото-когдато не понимаешь погугли) 2012-05-29 23:09:10 Иван Как написать программу для поиска телефонных номеров на странице интернет версии газеты Aviso и других?У меня есть Exel файл с номерами,которые нужно исключить(выделить). 2012-06-17 14:05:38 RUSLAN Какие книги предлогаете для начинающих? Иногда у меня не хватает логики для решении задач. Чтобы понимать и логику развивать в этой программирвание что надо делать? 2012-07-10 16:33:42 влад я нихера не понял...и потскажите с++ надо скачивать иль он уже есть и если есть то как его найти и запустить 2012-07-19 01:19:03 Мишуил Влад, это не для тебя. Не заморачивайся этой тупой фигнёй - иди лучше дом2 посмотри. Оставить комментарий: |