Главная страница
Навигация по странице:

  • 1.5.1. Файловый ввод/вывод

  • Язык программирования C++. Вводный курс. С для начинающих


    Скачать 5.41 Mb.
    НазваниеС для начинающих
    Дата24.08.2022
    Размер5.41 Mb.
    Формат файлаpdf
    Имя файлаЯзык программирования C++. Вводный курс.pdf
    ТипДокументы
    #652350
    страница3 из 93
    1   2   3   4   5   6   7   8   9   ...   93
    1.2.1.
    Порядок выполнения инструкций
    По умолчанию инструкции программы выполняются одна за другой, последовательно. В программе
    // заголовочный файл с определением типа string
    #include string current_chapter = "
    Начинаем";
    // заголовочный файл с определением типа vector
    #include

    С++ для начинающих
    20
    } первой будет выполнена инструкция readIn(), за ней sort(), compact() и наконец print()
    Однако представим себе ситуацию, когда количество продаж невелико: оно равно 1 или даже 0. Вряд ли стоит вызывать функции sort() и compact() для такого случая. Но вывести результат все-таки нужно, поэтому функцию print() следует вызывать в любом случае. Для этого случая мы можем использовать условную инструкцию if. Нам придется переписать функцию readIn() так, чтобы она возвращала количество прочитанных записей:
    }
    Первая инструкция if обеспечивает условное выполнение блока программы: функции sort()
    и compact() вызываются только в том случае, если count больше 1. Согласно второй инструкции if на терминал выводится сообщение “Продаж не было”, если условие истинно, т.е. значение count равно 0. Если же это условие ложно, производится вызов функции print(). (Детальное описание инструкции if приводится в разделе 5.3.)
    Другим распространенным способом непоследовательного выполнения программы является итерация, или инструкция цикла. Такая инструкция предписывает повторять int main()
    { readIn(); sort(); compact(); print(); return 0;
    // 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;

    С++ для начинающих
    21
    блок программы до тех пор, пока некоторое условие не изменится с true на false.
    Например:
    }
    В этом надуманном примере цикл while выполняется пять раз, до тех пор пока переменная iterations не получит значение 5 и переменная continue_loop не станет равной false. Инструкция iterations++; увеличивает значение переменной iterations на единицу. (Инструкции цикла детально рассматриваются в главе 5.)
    1.3.
    Директивы препроцессора
    Заголовочные файлы включаются в текст программы с помощью директивы
    препроцессора #include. Директивы препроцессора начинаются со знака “диез” (#), который должен быть самым первым символом строки. Программа, которая обрабатывает эти директивы, называется препроцессором (в современных компиляторах препроцессор обычно является частью самого компилятора).
    Директива #include включает в программу содержимое указанного файла. Имя файла может быть указано двумя способами:
    #include "my_file.h"
    Если имя файла заключено в угловые скобки (<>), считается, что нам нужен некий стандартный заголовочный файл, и компилятор ищет этот файл в предопределенных местах. (Способ определения этих мест сильно различается для разных платформ и реализаций.) Двойные кавычки означают, что заголовочный файл – пользовательский, и его поиск начинается с того каталога, где находится исходный текст программы.
    Заголовочный файл также может содержать директивы #include. Поэтому иногда трудно понять, какие же конкретно заголовочные файлы включены в данный исходный 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;
    #include

    С++ для начинающих
    22
    текст, и некоторые заголовочные файлы могут оказаться включенными несколько раз.
    Избежать этого позволяют условные директивы препроцессора. Рассмотрим пример:
    #ifndef BOOKSTORE_H
    #endif
    Условная директива #ifndef проверяет, не было ли значение BOOKSTORE_H определено ранее. (BOOKSTORE_H – это константа препроцессора; такие константы принято писать заглавными буквами.) Препроцессор обрабатывает следующие строки вплоть до директивы #endif. В противном случае он пропускает строки от #ifndef до # endif.
    Директива
    #define BOOKSTORE_H определяет константу препроцессора BOOKSTORE_H. Поместив эту директиву непосредственно после директивы #ifndef, мы можем гарантировать, что содержательная часть заголовочного файла bookstore.h будет включена в исходный текст только один раз, сколько бы раз ни включался в текст сам этот файл.
    Другим распространенным примером применения условных директив препроцессора является включение в текст программы отладочной информации. Например:
    }
    Если константа DEBUG не определена, результирующий текст программы будет выглядеть так:
    { string word;
    #define BOOKSTORE_H
    /* содержимое файла bookstore.h */ int main()
    {
    #ifdef DEBUG cout << "
    Начало выполнения main()\n";
    #endif string word; vector text; while ( cin >> word )
    {
    #ifdef DEBUG cout << "
    Прочитано слово: " << word << "\n";
    #endif text.push_back(word);
    }
    // ... int main()

    С++ для начинающих
    23
    vector text; while ( cin >> word )
    { text.push_back(word);
    }
    // ...
    }
    В противном случае мы получим:
    { cout << "
    Начало выполнения main()\n"; string word; vector text; while ( cin >> word )
    { cout << "
    Прочитано слово: " << word << "\n"; text.push_back(word);
    }
    // ...
    }
    Константа препроцессора может быть определена в командной строке при вызове компилятора с помощью опции -D (в различных реализациях эта опция может называться по-разному). Для UNIX-систем вызов компилятора с определением препроцессорной константы DEBUG выглядит следующим образом:
    $ CC -DDEBUG main.C
    Есть константы, которые автоматически определяются компилятором. Например, мы можем узнать, компилируем ли мы С++ или С программу. Для С++ программы автоматически определяется константа __cplusplus (два подчеркивания). Для стандартного С определяется __STDC__. Естественно, обе константы не могут быть определены одновременно. Пример: int main(int,int);
    Другими полезными предопределенными константами (в данном случае лучше сказать переменными) препроцессора являются __LINE__ и __FILE__. Переменная __LINE__ содержит номер текущей компилируемой строки, а __FILE__ – имя компилируемого файла. Вот пример их использования: int main()
    #idfef __cplusplus
    // компиляция С++ программы extern "C";
    // extern "C" объясняется в главе 7
    #endif

    С++ для начинающих
    24
    cerr << "
    Ошибка. Файл: " << __FILE__
    << "
    Строка: " << __LINE__
    << "element_count не может быть 0";
    Две константы __DATE__ и __TIME__ содержат дату и время компиляции.
    Стандартная библиотека С предоставляет полезный макрос assert(), который проверяет некоторое условие и в случае, если оно не выполняется, выдает диагностическое сообщение и аварийно завершает программу. Мы будем часто пользоваться этим полезным макросом в последующих примерах программ. Для его применения следует включить в программу директиву
    #include assert.h
    – это заголовочный файл стандартной библиотеки С. Программа на C++ может ссылаться на заголовочный файл как по его имени, принятому в C, так и по имени, принятому в C++. В стандартной библиотеке С++ этот файл носит имя cassert. Имя заголовочного файла в библиотеке С++ отличается от имени соответствующего файла для
    С отсутствием расширения .h и подставленной спереди буквой c (выше уже упоминалось, что в заголовочных файлах для C++ расширения не употребляются, поскольку они могут зависеть от реализации).
    Эффект от использования директивы препроцессора #include зависит от типа заголовочного файла. Инструкция
    #include включает в текст программы содержимое файла cassert. Но поскольку все имена, используемые в стандартной библиотеке С++, определены в пространстве std, имя assert()
    будет невидимо до тех пор, пока мы явно не сделаем его видимым с помощью следующей using-директивы: using namespace std;
    Если же мы включаем в программу заголовочный файл для библиотеки С
    #include то надобность в using-директиве отпадает: имя assert() будет видно и так2.
    (Пространства имен используются разработчиками библиотек для предотвращения засорения глобального пространства имен. В разделе 8.5 эта тема рассматривается более подробно.)
    1.4.
    Немного о комментариях
    Комментарии помогают человеку читать текст программы; писать их грамотно считается правилом хорошего тона. Комментарии могут характеризовать используемый алгоритм,
    2 Как было сказано ранее, не все компиляторы поддерживают пространства имен, поэтому эта разница проявляется только для последних версий компиляторов.
    if ( element_count == 0 )

    С++ для начинающих
    25
    пояснять назначение тех или иных переменных, разъяснять непонятные места. При компиляции комментарии выкидываются из текста программы поэтому размер получающегося исполняемого модуля не увеличивается.
    В С++ есть два типа комментариев. Один – такой же, как и в С, использующий символы
    /*
    для обозначения начала и */ для обозначения конца комментария. Между этими парами символов может находиться любой текст, занимающий одну или несколько строк: вся последовательность между /* и */ считается комментарием. Например:
    }
    Слишком большое число комментариев, перемежающихся с кодом программы, может ухудшить читаемость текста. Например, объявления переменных width и height в данном тексте окружены комментариями и почти не заметны. Рекомендуется писать развернутое объяснение перед блоком текста. Как и любая программная документация, комментарии должны обновляться в процессе модификации кода. Увы, нередко случается, что они относятся к устаревшей версии.
    Комментарии в стиле С не могут быть вложенными. Попробуйте откомпилировать нижеследующую программу в своей системе. Большинство компиляторов посчитают ее ошибочной:
    }
    Один из способов решить проблему вложенных комментариев – поставить пробел между звездочкой и косой чертой:
    /*
    *
    Это первое знакомство с определением класса в C++.
    *
    Классы используются как в объектном, так и в
    * объектно-ориентированном программировании. Реализация
    * класса Screen представлена в главе 13.
    */ class Screen {
    /*
    Это называется телом класса */ public: void home(); /* переместить курсор в позицию 0,0 */ void refresh ();/* перерисовать экран */ private:
    /*
    Классы поддерживают "сокрытие информации" */
    /*
    Сокрытие информации ограничивает доступ из */
    /* программы к внутреннему представлению класса */
    /* (
    его данным). Для этого используется метка */
    /* "private:" */ int height, width;
    #include
    /* комментарии /* */ не могут быть вложенными.
    *
    Строку "не вкладываются" компилятор рассматривает,
    * как часть программы. Это же относится к данной и следующей строкам
    */ int main() { cout << "
    Здравствуй, мир\n";

    С++ для начинающих
    26
    /* * /
    Последовательность символов */ считается концом комментария только в том случае, если между ними нет пробела.
    Второй тип комментариев – однострочный. Он начинается последовательностью символов // и ограничен концом строки. Часть строки вправо от двух косых черт игнорируется компилятором. Вот пример нашего класса Screen с использованием двух строчных комментариев:
    }
    Обычно в программе употребляют сразу оба типа комментариев. Строчные комментарии удобны для кратких пояснений – в одну или полстроки, а комментарии, ограниченные /* и */, лучше подходят для развернутых многострочных пояснений.
    1.5.
    Первый взгляд на ввод/вывод
    Частью стандартной библиотеки С++ является библиотека iostream, которая реализована как иерархия классов и обеспечивает базовые возможности ввода/вывода.
    Ввод с терминала, называемый стандартным вводом, “привязан” к предопределенному объекту cin. Вывод на терминал, или стандартный вывод, привязан к объекту cout.
    Третий предопределенный объект, cerr, представляет собой стандартный вывод для
    ошибок. Обычно он используется для вывода сообщений об ошибках и предупреждений.
    Для использования библиотеки ввода/вывода необходимо включить соответствующий заголовочный файл:
    #include
    Чтобы значение поступило в стандартный вывод или в стандартный вывод для ошибок используется оператор <<:
    /*
    *
    Первое знакомство с определением класса в C++.
    *
    Классы используются как в объектном, так и в
    * объектно-ориентированном программировании. Реализация
    * класса Screen представлена в главе 13.
    */ class Screen {
    //
    Это называется телом класса public: void home(); // переместить курсор в позицию 0,0 void refresh (); // перерисовать экран private:
    /*
    Классы поддерживают "сокрытие информации". */
    /*
    Сокрытие информации ограничивает доступ из */
    /* программы к внутреннему представлению класса */
    /* (
    его данным). Для этого используется метка */
    /* "private:" */ int height, width;

    С++ для начинающих
    27
    cout << "\n";
    Последовательность "\n" представляет собой символ перехода на новую строку. Вместо "\n"
    мы можем использовать предопределенный манипулятор endl. cout << endl;
    Манипулятор endl не просто выводит данные (символ перехода на новую строку), но и производит сброс буфера вывода. (Предопределенные манипуляторы рассматриваются в главе 20.)
    Операторы вывода можно сцеплять. Так, три строки в предыдущем примере заменяются одной: cout << "
    сумма v1 и v2 = " << v1 + v2 << "\n";
    Для чтения значения из стандартного ввода применяется оператор ввода (>>): cin >> file_name;
    Операторы ввода, как и операторы вывода, можно сцеплять:
    // ... cout << "
    Введите имя входного и выходного файлов: "; cin >> ifile >> ofile;
    Каким образом ввести заранее неизвестное число значений? Мы вернемся к этому вопросу в конце раздела 2.2, а пока скажем, что последовательность инструкций while ( cin >> word )
    // ... считывает по одному слову из стандартного ввода до тех пор, пока не считаны все слова.
    Выражение
    ( cin >> word ) int v1, v2;
    // ... cout << "
    сумма v1 и v2 = "; cout << v1 + v2; string file_name;
    // ... cout << "
    Введите имя файла: "; string ifile, ofile; string word;

    С++ для начинающих
    28
    возвращает false, когда достигнут конец файла. (Подробнее об этом – в главе 20.) Вот пример простой законченной программы, считывающей по одному слову из cin и выводящей их в cout:
    }
    Вот первое предложение из произведения Джеймса Джойса “Пробуждение Финнегана”: riverrun, past Eve and Adam's
    Если запустить приведенную выше программу и набрать с клавиатуры данное предложение, мы увидим на экране терминала следующее:
    Все слова прочитаны!
    (В главе 6 мы рассмотрим вопрос о том, как убрать знаки препинания из вводимых слов.)
    1.5.1.
    Файловый ввод/вывод
    Библиотека iostream поддерживает и файловый ввод/вывод. Все операции, применимые в стандартному вводу и выводу, могут быть также применены к файлам. Чтобы использовать файл для ввода или вывода, мы должны включить еще один заголовочный файл:
    #include
    Перед тем как открыть файл для вывода, необходимо объявить объект типа ofstream: ofstream outfile("name-of-file");
    Проверить, удалось ли нам открыть файл, можно следующим образом:
    #include
    #include int main ()
    { string word; while ( cin >> word ) cout << "
    Прочитано слово: " << word << "\n"; cout << "
    Все слова прочитаны!";
    Прочитано слово: riverrun,
    Прочитано слово: past
    Прочитано слово: Eve,
    Прочитано слово: and
    Прочитано слово: Adam's

    С++ для начинающих
    29
    cerr << "
    Ошибка открытия файла.\n"
    Так же открывается файл и для ввода, только он имеет тип ifstream: if ( ! infile ) // false, если файл не открыт cerr << "
    Ошибка открытия файла.\n"
    Ниже приводится текст простой программы, которая читает файл с именем in_file и выводит все прочитанные из этого файла слова, разделяя их пробелом, в другой файл, названный out_file. string word; while ( infile >> word ) outfile << word << ' '; return 0;
    }
    В главе 20 библиотека ввода/вывода будет рассмотрена подробно. А в следующих разделах мы увидим, как можно создавать новые типы данных, используя механизм классов и шаблонов. if ( ! outfile ) // false, если файл не открыт ifstream infile("name-of-file");
    #include
    #include
    #include int main()
    { ifstream infile("in_file"); ofstream outfile("out_file"); if ( ! infile ) { cerr << "
    Ошибка открытия входного файла.\n" return -1;
    } if ( ! outfile ) { cerr << "
    Ошибка открытия выходного файла.\n" return -2;
    }

    С++ для начинающих
    30
    2.
    Краткий обзор С++
    Эту главу мы начнем с рассмотрения встроенного в язык С++ типа данных “массив”.
    Массив – это набор данных одного типа, например массив целых чисел или массив строк. Мы рассмотрим недостатки, присущие встроенному массиву, и напишем для его представления свой класс Array, где попытаемся избавиться от этих недостатков. Затем мы построим целую иерархию подклассов, основываясь на нашем базовом классе Array.
    В конце концов мы сравним наш класс Array с классом vector из стандартной библиотеки С++, реализующим аналогичную функциональность. В процессе создания этих классов мы коснемся таких свойств С++, как шаблоны, пространства имен и обработка ошибок.
    2.1.
    Встроенный тип данных “массив”
    Как было показано в главе 1, С++ предоставляет встроенную поддержку для основных типов данных – целых и вещественных чисел, логических значений и символов: float fval = 3.14159;
    К числовым типам данных могут применяться встроенные арифметические и логические операции: объекты числового типа можно складывать, вычитать, умножать, делить и т.д. int ival3 = ival2 - ival; // вычитание dval = fval * ival; // умножение ival = ival3 / 2; // деление bool result = ival2 == ival3; // сравнение на равенство result = ival2 + ival != ival3; // сравнение на неравенство result = fval + ival2 < dval; // сравнение на меньше result = ival > ival2; // сравнение на больше
    В дополнение к встроенным типам стандартная библиотека С++ предоставляет поддержку для расширенного набора типов, таких, как строка и комплексное число. (Мы отложим рассмотрение класса vector из стандартной библиотеки до раздела 2.7.)
    // объявление целого объекта ival
    // ival инициализируется значением 1024 int ival = 1024;
    // объявление вещественного объекта двойной точности dval
    // dval инициализируется значением 3.14159 double dval = 3.14159;
    // объявление вещественного объекта одинарной точности fval
    // fval инициализируется значением 3.14159 int ival2 = ival1 + 4096; // сложение

    С++ для начинающих
    1   2   3   4   5   6   7   8   9   ...   93


    написать администратору сайта