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

  • Функции fread() и fwrite()

  • Функция fseek() и выполнение ввода-вывода с произвольным доступом

  • Функции fprintf() и fscanf()

  • Приложение Б: Использование устаревшего С++-компилятора

  • Приложение В: *.NET-расширения для C++

  • Ключевые слова .NET-среды

  • _ _event

  • Шилдт c++_базовый_курс издание 3. Герберт Шилдт С базовый курс


    Скачать 9.37 Mb.
    НазваниеГерберт Шилдт С базовый курс
    АнкорШилдт c++_базовый_курс издание 3.pdf
    Дата13.02.2017
    Размер9.37 Mb.
    Формат файлаpdf
    Имя файлаШилдт c++_базовый_курс издание 3.pdf
    ТипКнига
    #2637
    страница31 из 33
    1   ...   25   26   27   28   29   30   31   32   33
    Функции ferror() и rewind()
    Функция ferror() используется для определения факта возникновения ошибки при выполнении операции с файлом. Ее прототип имеет такой вид.
    int ferror(FILE *fp);
    Здесь параметр fp — действительный файловый указатель. Функция ferror() возвращает значение true, если при выполнении последней файловой операции произошла ошибка; в противном случае — значение false. Поскольку возникновение ошибки возможно при выполнении любой операции с файлом, функцию ferror() необходимо вызывать сразу после каждой функции обработки файлов; в противном случае информацию об ошибке можно попросту потерять.
    Функция rewind() перемещает индикатор позиции файла в начало файла, заданного в качестве аргумента. Ее прототип выглядит так.
    void rewind(FILE *fp);
    Здесь параметр fp — действительный файловый указатель.
    Функции fread() и fwrite()
    В файловой системе языка С предусмотрено две функции, fread() и fwrite(), которые позволяют считывать и записывать блоки данных. Эти функции подобны С++-функциям
    read() и write(). Их прототипы имеют следующий вид.
    size_t fread(void *buffer, size_t num_bytes, size_t count, FILE
    *fp);
    size_t fwrite(const void *buffer, size_t num_bytes, size_t count, FILE *fp);
    При вызове функции fread() параметр buffer представляет собой указатель на область памяти, которая предназначена для приема данных, считываемых из файла. Функция
    считывает count объектов длиной num_bytes из потока, адресуемого файловым указателем
    fp. Функция fread() возвращает количество считанных объектов, которое может оказаться меньше заданного значения count, если при выполнении этой операции возникла ошибка или был достигнут конец файла.
    При вызове функции fwrite() параметр buffer представляет собой указатель на информацию, которая подлежит записи в файл. Эта функция записывает count объектов длиной num_bytes в поток, адресуемый файловым указателем fp. Функция fwrite()
    возвращает количество записанных объектов, которое будет равно значению count, если при выполнении этой операции не было ошибки.
    Если при вызове функций fread() и fwrite() файл был открыт для выполнения двоичной операции, то они могут считывать или записывать данные любого типа. Например,
    следующая программа записывает в дисковый файл значение типа float.
    /* Запись в дисковый файл значения с плавающей точкой.
    */
    #include
    int main()
    {
    FILE *fp;
    float f = 12.23F;
    if((fp=fopen("test", "wb"))==NULL) {
    printf("He удается открыть файл.\n");
    return 1;
    }
    fwrite(&f, sizeof(float), 1, fp);
    fclose(fp);
    return 0;
    }
    Как показано в этой программе, роль буфера может выполнять (и при том довольно часто) одна переменная.
    С помощью функций fread() и fwrite() часто выполняется считывание и запись
    содержимого массивов или структур. Например, следующая программа, используя одну только функцию fwrite(), записывает содержимое массива значений с плавающей точкой
    balance в файл с именем balance. Затем с помощью одной лишь функции fread() программа считывает элементы этого массива и отображает их на экране.
    #include
    int main()
    {
    register int i;
    FILE *fp;
    float balance[100];
    /* Открываем файл для записи. */
    if((fp=fopen("balance", "w"))==NULL) {
    printf("He удается открыть файл.\n");
    return 1;
    }
    for(i=0; i<100; i++) balance[i] = (float) i;
    /* Одним "махом" сохраняем весь массив balance. */
    fwrite(balance, sizeof balance, 1, fp);
    fclose(fp);
    /* Обнуляем массив. */
    for(i=0; i<100; i++) balance[i] = 0.0;

    /* Открываем файл для чтения. */
    if((fp=fopen("balance", "r"))==NULL) {
    printf("He удается открыть файл.\n");
    return 1;
    }
    /* Одним "махом" считываем весь массив balance. */
    fread(balance, sizeof balance, 1, fp);
    /* Отображаем содержимое массива. */
    for(i=0; i<100; i++) printf("%f ", balance[i]);
    fclose(fp);
    return 0;
    }
    Использовать функции fread() и fwrite() для считывания и записи блоков данных более эффективно, чем многократно вызывать функции fgetc() и fputc().
    Функция fseek() и выполнение ввода-вывода с произвольным доступом
    С-система ввода-вывода позволяет выполнять операции считывания и записи данных с произвольным доступом. Для этого служит функция fseek(), которая устанавливает нужным образом индикатор позиции файла. Ее прототип таков.
    int fseek(FILE *fp, long numbytes, int origin);
    Здесь параметр fp — файловый указатель, возвращаемый функцией fopen(), параметр
    numbytes — количество байтов относительно исходного положения, заданного параметром
    origin. Параметр origin может принимать одно из следующих макроимен (определенных в заголовке stdio.h).

    Следовательно, чтобы переместить индикатор позиции в файле на numbytes байтов относительно его начала, в качестве параметра origin необходимо использовать значение
    SEEK_SET. Для перемещения относительно текущей позиции используйте значение
    SEEK_CUR, а для смещения с конца файла — значение SEEK_END.
    Нулевое значение результата функции свидетельствует об успешном выполнении функции fseek(), а ненулевое— о возникновении сбоя. Как правило, функцию fseek() не рекомендуется использовать для файлов, открытых в текстовом режиме, поскольку преобразование символов может привести к ошибочным перемещениям индикатора позиции в файле. Поэтому лучше использовать эту функцию для файлов, открытых в двоичном режиме. Например, если вам нужно считать 234-й байт в файле test, выполните следующий код.
    int func1()
    {
    FILE *fp;
    if((fp=fopen("test", "rb")) == NULL) {
    printf("He удается открыть файл.\n");
    exit (1);
    }
    fseek(fp, 234L, SEEK_SET);
    return getc(fp); /* Считывание одного символа, расположенного на 234-й позиции. */
    }
    Функции fprintf() и fscanf()
    Помимо рассмотренных выше основных функций ввода-вывода, С-система ввода-вывода включает функции fprintf() и fscanf(). Поведение этих функций аналогично поведению
    функций printf() и scanf(), за исключением того, что они работают с файлами. Именно поэтому эти функции обычно используются в С-программах. Прототипы функций fprintf() и
    fscanf() выглядят так.
    int fprintf(FILE * fp, const char *fmt_string, ...);
    int fscanf(FILE * fp, const char *fmt_string, ...);
    Здесь параметр fp — файловый указатель, возвращаемый функцией fopen(). Функции
    fprintf() и fscanf() работают подобно функциям printf() и scanf() соответственно, за исключением того, что их действие направлено на файл, определенный параметром fp.
    Удаление файлов
    Функция remove() удаляет заданный файл. Ее прототип выглядит так.
    int remove(const char *filename);
    Она возвращает нуль при успешном удалении файла и ненулевое значение в противном случае.
    Приложение Б: Использование устаревшего С++-компилятора
    Программы, приведенные в этой книге, полностью соответствуют стандарту ANSI/ISO
    для C++ и могут быть скомпилированы практически любым современным С++- компилятором, включая Visual C++ (Microsoft) и C++ Builder (Borland). Следовательно, при использовании современного компилятора у вас не должно быть проблем с компиляцией программ из этой книги. (В этом случае вам вообще не понадобится информация,
    представленная в этом приложении.)
    Но если вы используете компилятор, созданный несколько лет назад, то при попытке скомпилировать наши примеры он может выдать целый список ошибок, не распознав ряд новых С++-средств. И в этом случае не стоит волноваться. Для того чтобы эти программы заработали со старыми компиляторами, нужно внести в них небольшие изменения. Чаще всего старые и новые С++-программы отличаются использованием двух средств: заголовков и пространств имен. Вот об этом и пойдет речь в этом приложении.
    Как упоминалось в главе 2, инструкция #include включает в программу заданный заголовок. Для более ранних версий C++ под заголовками понимались файлы с расширением .h. Например, в старой С++-программе для включения заголовка iostream была бы использована следующая инструкция.
    #include
    В этом случае в программу был бы включен заголовочный файл iostream.h. Таким образом, включая в старую С++-программу заголовок, необходимо задавать имя файла с расширением .h.
    В новых С++-программах в соответствии со стандартом ANSI/ISO для C++ используются заголовки другого типа. Современные заголовки определяют не имена файлов, а стандартные идентификаторы, которые могут совпадать с таковыми, но не всегда.

    Современные С++-заголовки представляют собой абстракцию, которая попросту гарантирует включение в программу требуемой информации.
    Поскольку современные заголовки необязательно являются именами файлов, они не должны иметь расширение .h. Они определяют имя заголовка, заключенного в угловые скобки. Вот, например, как выглядят два современных заголовка, подлерживаемых стандартом C++.


    Чтобы преобразовать эти "новые" заголовки в "старые" заголовочные файлы,
    достаточно добавить расширение .h.
    Включая современный заголовок в программу, необходимо помнить, что его содержимое относится к пространству имен std. Как упоминалось выше, пространство имен — это просто декларативная область. Ее назначение — локализовать имена идентификаторов во избежание коллизий с именами. Старые версии C++ помещают имена библиотечных функций в глобальное пространство имен, а не в пространство имен std, используемое современными компиляторами. Таким образом, работая со старым компилятором, не нужно использовать эту инструкцию:
    using namespace std;
    В действительности большинство старых компиляторов вообще не воспримут инструкцию using namespace.
    Два простых изменения
    Если ваш компилятор не поддерживает пространства имен и новые заголовки, он выдаст одно или несколько сообщений об ошибках при попытке скомпилировать первые несколько строк программ, приведенных в этой книге. В этом случае в эти программы необходимо внести только два простых изменения: использовать заголовок старого типа и удалить
    namespace-инструкцию. Например, замените эти инструкции
    #include
    using namespace std;
    такой.
    #include
    Это изменение преобразует "новую" программу в "старую". Поскольку при использовании "старого" заголовка в глобальное пространство имен считывается все содержимое заголовочного файла, необходимость в использовании namespaee-инструкции отпадает. После внесения этих изменений, программу можно скомпилировать с помощью старого компилятора.
    Иногда приходится вносить и другие изменения. C++ наследует ряд заголовков из языка
    С. Язык С не поддерживает современный стиль использования С++-заголовков, используя
    вместо них заголовочные .h-файлы. Для разрешения обратной совместимости стандарт C++
    по-прежнему поддерживает заголовочные С-файлы. Однако стандарт C++ также определяет современные заголовки, которые можно использовать вместо заголовочных С-файлов. В С
    ++-версиях стандартных С-заголовков к имени С-файла просто добавляется префикс 'c' и опускается расширение .h. Например, С++-заголовком для файла math.h служит заголовок
    , а для файла string.h— заголовок . Несмотря на то что в С++-программу разрешено включать заголовочный С-файл, против такого подхода у разработчиков стандарта есть существенные возражения (другими словами, это не рекомендовано).
    Поэтому в настоящей книге используются современные С++-заголовки во всех инструкциях
    #include. Если ваш компилятор не поддерживает С++-заголовки для С-заголовков, просто замените "старые" заголовочные файлы.
    Приложение В: *.NET-расширения для C++
    Разработанная компанией Microsoft интегрированная оболочка .NET Framework
    определяет среду, которая предназначена для поддержки разработки и выполнения сильно распределенных приложений, основанных на использовании компонентных объектов. Она позволяет "мирно сосуществовать" различным языкам программирования и обеспечивает безопасность, переносимость программ и общую модель программирования для платформы
    Windows. Несмотря на относительную новизну оболочки .NET Framework, по всей вероятности, в ближайшем будущем в этой среде будут работать многие С++-программисты.
    Интегрированная оболочка .NET Framework предоставляет управляемую среду, которая следит за выполнением программы. Программа, предназначенная для помещения в оболочку .NET Framework, не компилируется с целью получения объектного кода. Вместо этого она переводится на промежуточный язык MSIL (Microsoft Intermediate Language), а затем выполняется под управлением универсального средства CLR (Common Language
    Runtime). Управляемое выполнение— это механизм, который поддерживает ключевые преимущества, предлагаемые оболочкой .NET Framework.
    Чтобы воспользоваться преимуществами управляемого выполнения, необходимо применять для С++-программ специальный набор нестандартных ключевых слов и директив препроцессора, которые были определены разработчиками компании Microsoft. Важно понимать, что этот дополнительный набор не включен в стандарт C++ (ANSI/ISO Standard
    C++). Поэтому код, в котором используются эти ключевые слова, нельзя переносить в другие среды выполнения.
    Описание оболочки .NET Framework и методов С++-программирования, необходимых для ее использования, выходит за рамки этой книги. Однако здесь приводится краткий обзор .NET-расширения языка C++ ради тех программистов, которые работают в .NET-среде.
    Ключевые слова .NET-среды
    Для поддержки .NET-среды управляемого выполнения С++-программ Microsoft вводит в язык C++ следующие ключевые слова.

    Краткое описание каждого из этих ключевых слов приведено в следующих разделах.
    _ _abstract
    Ключевое слово _ _abstract используется в сочетании со словом _ _gc при определении абстрактного управляемого класса. Объект _ _abstract-класса создать нельзя. Для класса,
    определенного с использованием ключевого слова _ _abstract, необязательно включение в него чисто виртуальной функции.
    _ _box
    Ключевое слов _ _box заключает в специальную оболочку значение внутри объекта.
    Такая "упаковка" позволяет использовать тип этого значения в коде, который требует, чтобы данный объект был выведен из класса System::Object, базового класса для всех .NET- объектов.
    _ _delegate
    Ключевое слово _ _delegate определяет объект-делегат, который инкапсулирует указатель на функцию внутри управляемого класса (т.е. класса, модифицированного ключевым словом _ _gc).
    _ _event
    Ключевое слово _ _event определяет функцию, которая представляет некоторое событие.
    Для такой функции задается только прототип.
    _ _finally
    Ключевое слово _ _finally — это дополнение к стандартному С++-механизму обработки исключительных ситуаций. Оно используется для определения блока кода, который должен выполняться после выхода из блоков try/catch. При этом не имеет значения, какие условия приводят к завершению try/catch-блока. Блок _ _finally должен быть выполнен в любом случае.
    _ _gc
    Ключевое слово _ _gc определяет управляемый класс. Обозначение "gc" представляет собой сокращение от словосочетания "garbage collection" (т.е. "сборка мусора") и означает,
    что объекты этого класса автоматически подвергаются процессу утилизации памяти,
    освобождаемой во время работы программы, когда они больше не нужны. В объекте отпадает необходимость в случае, когда на него не существует ни одной ссылки. Объекты _
    _gc-класса должны создаваться с помощью оператора new. Массивы, указатели и интерфейсы также можно определять с использованием ключевого слова _ _gc.

    _ _identifier
    Ключевое слово _ _identifier позволяет любому другому ключевому слову языка C++
    использоваться в качестве идентификатора. Эта возможность не предназначена для широкого применения и введена для решения специальных задач.
    _ _interface
    Ключевое слово _ _interface определяет класс, который должен действовать как интерфейс. В любом интерфейсе ни одна из функций не должна включать тело, т.е. все функции интерфейса являются неявно заданными чисто виртуальными функциями. Таким образом, интерфейс представляет собой абстрактный класс, в котором не реализована ни одна из его функций.
    _ _nogc
    Ключевое слово _ _nogc определяет неуправляемый класс. Поскольку такой
    (неуправляемый) тип класса создается по умолчанию, ключевое слово _ _nogc используется редко.
    _ _pin
    Ключевое слово _ _pin используется для определения указателя, который фиксирует местоположение в памяти объекта, на который он указывает. Таким образом,
    "закрепленный" объект не будет перемещаться в памяти в процессе сборки мусора. Как следствие, сборщик мусора не в состоянии сделать недействительным указатель,
    модифицированный с помощью ключевого слова _ _pin.
    _ _property
    Ключевое слово _ _property определяет свойство, являющееся функцией-членом, которая позволяет установить или получить значение некоторой переменной (члена данных класса).
    Свойства предоставляют удобное средство управления доступом к закрытым (private) или защищенным (protected) данным.
    _ _sealed
    Ключевое слово _ _sealed предохраняет модифицируемый им класс от наследования другими классами. Это ключевое слово можно также использовать для информирования о том, что виртуальная функция не может быть переопределена.
    1   ...   25   26   27   28   29   30   31   32   33


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