Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Высокоуровневые методы программирования. Учебно-методический комплекс.pdf
Скачиваний:
0
Добавлен:
12.08.2026
Размер:
1 Мб
Скачать

Итеративная обработка представляет собой способность программы повторять один или несколько операторов. Оператор for позволяет программам повторять один или несколько операторов заданное число раз. Используя оператор while, программы повторяют операторы до тех пор, пока указанное условие истинно. Наконец, с помощью оператора do while программы выполняют операторы, по крайней мере один раз, повторяя их, если заданное условие истинно.

Оператор C++ for позволяет программам повторять один или более операторов заданное число раз.

Оператор for состоит из четырех частей: инициализации, проверяемого условия, операторов, которые повторяются, и приращения.

Оператор for не обязывает увеличивать управляющую переменную цикла именно на 1 или использовать именно приращение.

Цикл C++ while позволяет программам повторять операторы, пока указанное условие истинно.

Программы часто используют цикл while для чтения содержимого файла, пока не встретится конец файла.

Оператор C++ do while позволяет программам выполнять один или несколько операторов, по крайней мере один раз, и воз можно, повторять их на основании заданного условия.

Программы часто используют операторы do while для работы с меню

Если проверяемые условия в циклах, while или do while становятся ложью, программа продолжает свое выполнение с первого оператора, следующего за циклом.

Лекция 7 Входной поток с именем cin и выходной поток cout. Оператор извлечения (>>) и оператор вставки (<<).

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

Можно использовать входной поток cin для присваивания определенным переменным символов и чисел, введенных с клавиатуры.

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

38

При применении cin для чтения и присваивания переменной значения, введенного с клавиатуры, можно использовать содержимое переменной так, как если бы программа использовала оператор присваивания для сохранения значения в переменной.

Когда программа использует cin для выполнения ввода с клавиатуры, остерегайтесь ошибок переполнения и ошибок, возникающих при вводе пользователем значения неверного типа.

Если программы используют выходной поток cout, они помещают данные в поток с помощью оператора вставки (<<). Подобным образом, если программы применяют cin для чтения ввода с клавиатуры, они будут использовать оператор извлечения (>>).

Точно так же как выходной поток cout позволяет программам записать вывод на экран, входной поток cin позволяет программам читать ввод с клавиатуры. Когда программы используют cin для чтения ввода с клавиатуры, они должны указать переменную, в которую cin поместит данные. Следующая программа firstcin.cpp использует cin для чтения числа, введенного с клавиатуры. Программа присваивает введенное число переменной с именем number, а затем выводит значение переменной, используя выходной поток cout:

#include <iostream.h> void main(void)

{

int number; II Число, читаемое с клавиатуры

cout << "Введите ваше любимое число и нажмите Enter: "; cin >> number;

cout << "Ваше любимое число равно " << number << endl;

}

Следующая программа twonbrs.cpp запрашивает два числа. Программа присваивает числа переменным first и second. Затем программа выводит числа, используя cout:

#include <iostream.h> void main(void)

{

int first, second; // Числа, введенные с клавиатуры cout << "Введите два числа и нажмите Enter: "; cin >> first >> second;

cout << "Были введены числа " << first << " и " << second <<

endl;

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

39

}

Обратите внимание на использование с cin двух операторов извлечения:

cin >> first >> second;

В этом случае cin присвоит первое введенное значение переменной first, a второе переменной second. Если для программы требуется третье значение, можно использовать третий оператор извлечения, как показано ниже:

cin >> first >> second >> third;

Если применяется cin для чтения чисел с клавиатуры, cin используется левый пустой символ (пробел, табуляцию, возврат каретки), чтобы определить, где начинается одно значение, а где второе.

Чтение ввода с клавиатуры с помощью cin

Для чтения ввода с клавиатуры программы могут использовать входной поток cin. При использовании cin должны указать переменную, в которую cin помещает данные. Затем используется оператор извлечения (>>) для направления данных, как показано ниже:

cin >> some_variable;

Оператор извлечения называется так, потому что он извлекает (удаляет) данные из входного потока, присваивая значение указанной переменной.

Лекция 8 Функции. Выполнение функции.

При создании программ следует спроектировать каждую функцию для выполнения определенной задачи. Если обнаружится, что функция выполняет несколько задач, следует разделить ее на две или более функций. Каждая создаваемая в программах функция должна иметь уникальное имя.

Как в случае с именами переменных, имена функций, выборы, должны соответствовать операции, выполняемой функцией. Например в табл. 8, представлены назначении каждой функции.

Таблица 8. Примеры смысловых имен функций.

Имя функции

Назначение функции

 

 

Print_test_scores

Печатать тестовые очки класса

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

40

Продолжение таблицы

Accounts_payable

Get_user_name

Print_document

Calculate_income_tax

Обработать счета компании

Запрос имени пользователя

Напечатать указанный документ

Определить подоходный налог пользователя

Функция C++ по структуре подобна программе main. Другими словами, имя функции предваряется ее типом, а за ним следует список параметров, описание которых появляется в скобках. Группировка операторов функций внутри левой и правой фигурных скобок, показано ниже:

тип_возврата имя_функции (список_параметров)

{

объявления_переменных; операторы;

}

Например, структура этой функции соответствует следующей программе main:

void main (void) // тип имя (список_параметров)

{

int count; //объявления_переменных;

for (count = 0; count < 10; count++) cout << count << ' '; //Оператор

}

Следующие операторы определяют функцию с именем show_message, которая выводит сообщение на экран, используя cout.

void show_message (void)

{

cout << "Привет, учусь программировать на C++" << endl;

}

Cлово void, предшествующее имени функции, указывает функции не возвращать значение. Подобно этому, слово void, содержащееся внутри круглых скобок, указывает (компилятору C++ и программистам, читающим код), что функция не использует параметры (информацию, которую программа передает функции). Следующая программа SHOW_ MSG.CPP использует функцию show_message для вывода сообщения на экран:

#include <iostream.h>

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

41

void show_message (void)

{

cout << "Привет, учусь программировать на C++" << endl;

}

void main (void)

{

cout << "Перед вызовом функции" << endl; show_message (); cout << "Вернулись из функции" << endl;

}

Выполнение программы всегда начинается внутри main. Внутри main следующий оператор (вызов функции) вызывает функцию show_message:

show_message ();

Круглые скобки после имени функции сообщают компилятору C++, что программа использует функцию. Внутри этих скобок программа может передавать в функции информацию (параметры).

Лекция 9 Классы. Элементы класса static, private, public. Cтатические функции-элементы (методы).

До настоящего момента каждый создаваемый объект имел свой собственный набор элементов данных. В зависимости от назначения приложения могут быть ситуации, когда объекты одного и того же класса должны совместно использовать один или несколько элементов данных. Например, предположим, программа платежей, которая отслеживает рабочее время для 1000 служащих. Для определения налоговой ставки программа должна знать условия, в которых работает каждый служащий. Пусть для этого используется переменная класса state_of_work. Однако, если все служащие работают в одинаковых условиях, программа могла бы совместно использовать этот элемент данных для всех объектов типа employee. Таким образом, программа уменьшает необходимое количество памяти, выбрасывая 999 копий одинаковой информации. Для совместного использования элемента класса необходимо объявить этот элемент как static (статический). C++ позволяет иметь объекты одного и того же типа, которые совместно используют один или несколько элементов класса. Если программа присваивает значение совместно используемому элементу, то все объекты этого класса сразу же получают доступ к этому новому значению. Для создания совместно используемого элемента данных класса должны предварять имя элемента класса ключевым словом static.

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

42

После того как программа объявила элемент класса как static, она должна объявить глобальную переменную (вне определения класса), которая соответствует этому совместно используемому элементу класса. Программы могут использовать ключевое слово static, чтобы сделать метод класса вызываемым в то время, как программа, возможно, еще не объявила каких-либо объектов данного класса.

Совместное использование элемента данных Обычно, когда создаются объекты определенного класса, каждый

объект получает свой собственный набор элементов данных. Однако возможны такие ситуации, при которых объектам одного и того же класса необходимо совместно использовать один или несколько элементов данных (статические элементы данных). В таких случаях объявляется элементы данных как общие или частные, а затем предваряется тип ключевым словом static, как показано ниже:

private:

static int shared_value;

После объявления класса объявляется элемент как глобальная переменная вне класса, как показано ниже:

int class_name::shared_value;

Следующая программа share_it.cpp определяет класс book_series, совместно использующий элемент page_count, который является одинаковым для всех объектов (книг) класса (серии). Если программа изменяет значение этого элемента, изменение сразу же проявляется во всех объектах класса:

#include <iostream.h> #include <string.h> class book_series

{

public:

book_series(char *, char *, float); void show_book(void);

void set_pages(int) ; private:

static int page_count; char title[64];

char author[ 64 ]; float price;

};

int book_series::page__count;

void book_series::set_pages(int pages)

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

43

{

page_count = pages;

}

book_series::book_series(char *title, char *author, float price)

{

strcpy(book_series::title, title); strcpy(book_series::author, author); book_series::price = price;

}

void book_series:: show_book (void)

{

cout << "Заголовок: " << title << endl; cout << "Автор: " << author << endl; cout << "Цена: " << price << endl;

cout << "Страницы: " << page_count << endl;

}

void main(void)

{

book_series programming( "Учимся программировать на C++", "Jamsa", 22.95); book_series word( "Учимся работать с Word для Windows", "Wyatt", 19.95); word.set_pages(256);

programming.show_book (); word.show_book() ;

cout << endl << "Изменение page_count " << endl; programming.set_pages(512); programming.show_book();

word.show_book();

}

Класс объявляет page_count как static int. Сразу же за определением класса программа объявляет элемент page_count как глобальную переменную. Когда программа изменяет элемент page_count, изменение сразу же проявляется во всех объектах класса book_series.

Использование элементов с атрибутами public static, если объекты не существуют при объявлении элемента класса как static этот элемент совместно используется всеми объектами данного класса. Однако возможны ситуации, когда программа еще не создала объект, но ей необходимо использовать элемент. Для использования элемента программа должна объявить его как public и static. Например, следующая программа usе_mbr.cpp использует элемент page_count из класса book_series, даже если объекты этого класса не существуют:

#include <iostream.h> #include <string.h>

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

44

class book_series

{

public:

static int page_count; private:

char title [64]; char author[64]; float price;

};

int book_series::page_count; void main(void)

{

book_series::page_count = 256;

cout << "Текущее значение page_count равно " << book_series::page_count << endl;

}

В данном случае, поскольку класс определяет элемент класса page_count как public, программа может обратиться к этому элементу класса, даже если объекты класса book_series не существуют.

Использование статических функций-элементов Предыдущая программа иллюстрировала использование

статических элементов данных. Подобным образом C++ позволяет определить статические функции-элементы (методы). Если создается статический метод, программа может вызывать такой метод, даже если объекты не были созданы. Например, если класс содержит метод, который может быть использован для данных вне класса, можно сделать этот метод статическим. Ниже приведен класс menu, который использует esc-последовательность драйвера ANSI для очистки экрана дисплея. Если в системе установлен драйвер ansi.sys, можно использовать метод clear_screen для очистки экрана. Поскольку этот метод объявлен как статический, программа может использовать его, даже если объекты типа menu не существуют. Следующая программа clr_scr.cpp использует метод clear_screen для очистки экрана дисплея:

#include <iostream.h> class menu

{

public:

static void clear_screen(void);

// Здесь должны быть другие методы private:

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

45

int number_of_menu_options; };

void menu::clear_screen(void)

{

cout << '\033' << "[2J";

}

void main(void)

{

menu::clear_screen();

}

Так как программа объявляет элемент clear_screen как статический, она может использовать эту функцию для очистки экрана, даже если объекты типа menu не существуют. Функция clear_screen использует esc-последовательность ANSI Esc[2J для очистки экрана.

Использование в программах методов класса По мере создания методов класса возможны ситуации, когда

функция, созданная для использования классом, может быть полезна для операций программы, которые не включают объекты класса. Например, в классе menu была определена функция clear_screen, которую можно, использовать в программе. Если класс содержит метод, который будет использоваться вне объекта класса, ставиться перед его прототипом ключевое слово static и объявляется этот метод как public:

public:

static void clear_screen(void);

Внутри программы для вызова такой функции используйте оператор глобального разрешения, как показано ниже:

menu::clear_screen();

Если предварять элемент данных класса ключевым словом static, все объекты данного класса могут совместно использовать этот элемент. Когда элемент данных является общим, программы могут обращаться к его значению, даже если объекты этого класса не существуют. Подобно этому, если программы предваряют общий метод класса ключевым словом static, они могут использовать эту функцию для операций, которые не включают объекты класса.

Лекция 10 Массивы. Символьные строки, символьные константы.

Символьные строки хранят такую информацию, как имена файлов, названия книг, имена служащих и другие символьные

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

46

сочетания. Большинство программ на C++ широко используют символьные строки. В C++ символьные строки хранятся в массиве типа char, который заканчивается символом NULL (или ASCII 0).

Чтобы объявить символьную строку, должны объявить массив типа char,

Чтобы присвоить символы символьной строке, программы просто присваивают символы элементам массива символьных строк.

Программы C++ используют символ NULL (ASCII 0), чтобы отметить последний символ строки.

C++ позволяет программам инициализировать символьные строки при их объявлении.

Программы могут передавать символьные строки в функцию, как и любой массив.

Большинство библиотек этапа выполнения C++ обеспечивают набор функций, которые управляют символьными строками.

Программы на C++ хранят символьные строки как массив типа char. Большинство программ широко используют символьные строки.

Объявление символьных строк в программах Для объявления символьной строки внутри программы просто

объявится массив типа char с количеством элементов, достаточным для хранения требуемых символов. Например, следующее объявление создает переменную символьной строки с именем filename, способную хранить 64 символа (не забывайте, что символ NULL является одним из этих 64 символов):

char filename[64];

Как видно из рис. 10.1, это объявление создает массив с элементами, индексируемыми от filename[0] до filename[63].

Рис. 10.1. C++ трактует символьную строку как массив типа char.

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

47

Главное различие между символьными строками и другими типами массивов заключается в том, как C++ указывает последний элемент массива, программы на C++ представляют конец символьной строки с помощью символа NULL, который в C++ изображается как специальный символ '\0'. Когда присваивается символы символьной строке, должны поместить символ NULL ('\0') после последнего символа в строке. Например, следующая программа alphabet. cpp присваивает буквы от А до Я переменной alphabet, используя цикл for. Затем программа добавляет символ NULL в эту переменную и выводит ее с помощью cout.

#include <iostream.h> void main(void)

{

char alphabet [34]; // 33 буквы плюс NULL char letter; int index;

for (letter = 'A', index = 0; letter <= 'Я'; letter++, index++) alphabet[index] = letter; alphabet[index] = NULL;

cout << "Буквы " << alphabet;

}

Программа присваивает строке символ NULL, чтобы указать последний символ строки:

alphabet[index] = NULL;

Когда выходной поток cout выводит символьную строку, он по одному выводит символы строки, пока не встретит символ NULL. Символ NULL указывает программе последний символ в строке.

Цикл инициализирует и увеличивает две переменные (letter и index). Когда цикл for инициализирует или увеличивает несколько переменных, разделяйте операции запятой (запятая тоже является оператором C++):

for (letter = 'A', index = 0; letter <= 'Я'; letter++, index++)

C++ автоматически добавляет NULL к строковым константам При создании символьной строковой константы компилятор C++

автоматически добавляет символ NULL, как показано на рис. 10.2.

Рис. 10.2. Автоматическое добавление символа NULL

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

48

Компилятор C++ автоматически добавляет символ NULL к строковым константам. Когда программы выводят символьные строковые константы с помощью выходного потока cout, cout использует символ NULL (который компилятор добавляет к строке) для определения последнего символа вывода.

Следующая программа loopnull.cpp слегка изменяет предыдущую программу, используя цикл for для вывода содержимого строки:

#include <iostream.h> void main(void)

{

char alphabet[34]; //33 символа плюс NULL char letter; int index;

for (letter = 'A', index = 0; letter <= 'Я'; letter++,index++) alphabet[index] = letter; alphabet[index] = NULL;

for (index = 0; alphabet[index] 1= NULL; index++) cout << alphabet[index]; cout << endl;

}

Цикл for по одному исследует символы строки. Если символ не NULL (не последний символ строки), цикл выводит символ, увеличивает индекс, и процесс продолжается.

Как 'А' отличается от "А" При рассмотрении программ на C++ можно встретить символы, заключенные в одинарные кавычки (например, 'А') и символы, заключенные двойные кавычки ("А"). Символ внутри одинарных кавычек представляет собой символьную константу. Компилятор C++ выделяет только один байт памяти для хранения символьной константы. Однако символ в двойных кавычках представляет собой строковую константу — указанный символ и символ NULL (добавляемый компилятором). Компилятор будет выделять два байта для символьной строки. Рисунок 10.3 иллюстрирует, как компилятор C++ хранит символьную константу 'А' и строковую константу "А".

Рис. 10.3. Инициализация символьной строки

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

49

Для инициализации символьной строки при объявлении указывается требуемая строка внутри двойных кавычек, как показано ниже:

char title[64] = "Учимся программировать на языке C++";

Если количество символов, присваиваемое строке, меньше размера массива, большинство компиляторов C++ будут присваивать символы NULL остающимся элементам строкового массива. Как и в случае с массивами других типов, если не указывается размер массива, который инициализируете при объявлении, компилятор C++ распределит достаточно памяти для размещения указанных букв и символа NULL:

char title[] = "Учимся программировать на языке C++"; Следующая программа init_str.cpp инициализирует символьную

строку при объявлении:

#include <iostream.h> void main(void)

{

char title[64] = "Учимся программировать на языке C++"; char lesson[64] = "Символьные строки";

cout << "Книга: " << title << endl; cout << "Урок: " << lesson << endl;

}

Передача строк в функции Передача символьной строки в функцию подобна передаче

любого массива в качестве параметра. Внутри функции нужно просто указать тип массива (char) и левую и правую скобки массива. Например, следующая программа show_str.cpp использует функцию show_string для вывода символьной строки на экран:

#include <iostream.h>

void show_string(char string[])

{

cout << string << endl;

}

void main(void)

{

show_string("Привет, C++!"); show_string("Учусь программировать на C++");

}

Функция show_string трактует параметр символьной строки как массив:

void show_string(char string[])

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

50

Так как символ NULL указывает конец строки, функция не требует параметр, который задает количество элементов в массиве. Вместо этого функция может определить последний элемент, просто найдя в массиве символ NULL.

Следующая программа str_len.cpp создает функцию с именем string_length, которая ищет символ NULL в строке для определения количества символов, содержащихся в строке. Далее функция использует оператор return для возврата длины строки вызвавшей функции. Программа передает несколько различных символьных строк в функцию, отображая длину каждой из них на экране:

#include <iostream.h>

int string_length(char string[])

{

int i;

for (i = 0; string[] != '\0'; i++); // Ничего не делать, но перейти к

//следующему символу return(i); Длина строки

}

void main(void)

{

char title[] = "Учимся программировать на языке C++"; char lesson[] = "Символьные строки";

cout << "Строка " << title << " содержит " << string_length(title) << " символов"

<< endl;

cout << "Строка " << lesson << " содержит " << string_length(lesson) << "

символов" << endl;

}

Многие функции просматривают символьные строки символ за символом в поиске NULL. Следующий цикл for иллюстрирует, как программа может искать NULL в строке:

for (index = 0; string[index] != NULL; index++)

Поскольку символ NULL равен 0, многие программы упрощают циклы, которые ищут NULL, как показано ниже:

for (index = 0; string[index]; index++);

В данном случае пока символ, содержащийся в string[index] не NULL (0 или ложь), цикл продолжается.

Использование строковых функций библиотеки этапа выполнения

Рассматривая библиотеку этапа выполнения, можно обнаружить, что она содержат много разных функций, манипулирующих строками. Например, функция strupr преобразует символьную строку в строку верхнего регистра. Подобно этому, функция strlen

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

51

возвращает количество символов в строке. Большинство библиотек этапа выполнения обеспечивают даже функции, которые позволяют просматривать строки в поисках определенного символа. Например, следующая программа strupr.cpp иллюстрирует использование функций strupr и strlwr библиотеки этапа выполнения:

#include <iostream.h>

#include <string.h> // Содержит прототипы // функций strupr и strlwr

void main(void)

{

char title[] = "Учимся программировать на языке C++"; char lesson[] = "Символьные строки";

cout << "Верхний регистр: " << strupr(title) << endl; cout << "Нижний регистр: " << strlwr(lesson) << endl;

}

Лекция 11 Файловый поток. Вывод в файловый поток. Чтение из входного файлового потока. Определение конца файла.

По мере усложнения программ они будут сохранять и получать информацию, используя файлы. Используя выходной файловый поток, можно писать информацию в файл с помощью оператора вставки (<<).

Используя входной файловый поток, можно читать хранимую в файле информацию с помощью оператора извлечения (>>).

Для открытия и закрытия файла используется методы файловых классов.

Для чтения и записи файловых данных можно использовать операторы вставки и извлечения, а также некоторые методы файловых классов.

Cout представляет собой объект типа ostream (выходной поток). Используя класс ostream, программы могут выполнять вывод в cout с использованием оператора вставки или различных методов класса, например cout.put. Заголовочный файл iostream.h определяет выходной поток cout. Аналогично, заголовочный файл fstream.h определяет класс выходного файлового потока с именем ofstream. Используя объекты класса ofstream, программы могут выполнять вывод в файл.

ofstream file_object("FILENAME.EXT");

Если указана имя файла при объявлении объекта типа ofstream, C++ создаст новый файл на диске, используя указанное имя, или

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

52

перезапишет файл с таким же именем, если он уже существует на диске Следующая программа out_file.cpp создает объект типа ofstream и затем использует оператор вставки для вывода нескольких строк текста в файл bookinfo.dat:

#include <fstream.h> void main(void)

{

ofstream book_file("BOOKINFO.DAT");

book_file << "Учимся программировать на языке C++, " << "Вторая редакция" << endl;

book_file << "Jamsa Press" << endl; book_file << "22.95" << endl;

}

В данном случае программа открывает файл bookinfo.dat и затем записывает три строки в файл, используя оператор вставки.

Чтение из входного файлового потока Программы могут выполнить операции ввода из файла,

используя объекты типа ifstream. Опять же, просто создается объект, передавая ему в качестве параметра требуемое имя файла:

ifstream input_file("filename.ext");

Следующая программа file_in.cpp открывает файл bookinfo.dat, который созданы с помощью предыдущей программы, и читает, а затем отображает первые три элемента файла:

#include <iostream.h> #include <fstream.h> void main(void)

{

ifstream input_file("BOOKINFO.DAT") ; char one[64], two[64], three[64]; input_file >> one;

input_file >> two; input_file >> three; cout << one << endl; cout << two << endl; cout << three << endl;

}

Если откомпилировать и запустить эту программу, то, она отобразит первые три строки файла. Однако, подобно cin, входные файловые потоки используют пустые символы, чтобы определить, где заканчивается одно значение и начинается другое.

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

53

В результате при запуске предыдущей программы на дисплее появится следующий вывод:

С:\> FILE_IN <ENTER>

учимся

программировать на С++

Чтение целой строки файлового ввода

Объекты типа ifstream могут использовать getline для чтения строки файлового ввода. Следующая программа fileline.cpp использует функцию getline для чтения всех трех строк файла bookinfo.dat:

#include <iostream.h> #include <fstream.h> void main(void)

{

ifstream input_file("bookinfo.dat"); char one[64], two[64], three [64] ; input_file.getline(one, sizeof(one)) ; input_file.get line(two, sizeof(two)); input_file.getline(three, sizeof(three)) ; cout << one << endl;

cout << two << endl; cout << three << endl;

}

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

Определение конца файла Обычной файловой операцией в программах является чтение

содержимого файла, пока не встретится конец файла. Чтобы определить конец файла, программы могут использовать функцию еоf потокового объекта. Эта функция возвращает значение 0, если конец файла еще не встретился, и 1, если встретился конец файла. Используя цикл while, программы могут непрерывно читать содержимое файла, пока не найдут конец файла, как показано ниже:

while (! input_file.eof())

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

54

{

// Операторы

}

В данном случае программа будет продолжать выполнять цикл, пока функция eof возвращает ложь (0). Следующая программа test_eof.cpp использует функцию eof для чтения содержимого файла bookinfo.dat, пока не достигнет конца файла:

#include <iostream.h> #include <fstream.h> void main (void)

{

ifstream input_file("BOOKINFO.DAT"); char line[64];

while (! input_file.eof())

{

input_file.getline(line, sizeof(line)); cout << line << endl;

}

}

Аналогично, следующая программа word_eof.cpp читает содержимое файла по одному слову за один раз, пока не встретится конец файла:

#include <iostream.h> #include <fstream.h> void main(void)

{

ifstream input_file("BOOKINFO.DAT"); char word[64] ;

while (! input_file.eof())

{

input_file >> word; cout << word << endl;

}

}

И наконец, следующая программа char_eof.cpp читает содержимое файла по одному символу за один раз, используя функцию get, пока не встретит конец файла:

#include <iostream.h> #include <fstream.h> void main(void)

{

ifstream input_file("BOOKINFO.DAT");

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

55

char letter;

while (! input_file.eof())

{

letter = input_file.get(); cout << letter;

}

}

Проверка ошибок при выполнении файловых операций Программы, представленные до настоящего момента,

предполагали, что во время файловых операций В/В не происходят ошибки. К сожалению, это сбывается не всегда. Например, если открывается файл для ввода, программы должны проверить, что файл существует. Аналогично, если программа пишет данные в файл, необходимо убедиться, что операция прошла успешно (к примеру, отсутствие места на диске, скорее всего, помешает записи данных). Чтобы помочь программам следить за ошибками, можно использовать функцию fail файлового объекта. Если в процессе файловой операции ошибок не было, функция возвратит ложь (0). Однако, если встретилась ошибка, функция fail возвратит истину. Например, если программа открывает файл, ей следует использовать функцию fail, чтобы определить, произошла ли ошибка, как это показано ниже:

ifstream input_file("FILENAME.DAT"); if (input_file.fail())

{

cerr << "Ошибка открытия FILENAME.EXT" << endl; exit(1);

}

Таким образом, программы должны убедиться, что операции чтения и записи прошли успешно. Следующая программа test_all.cpp использует функцию fail для проверки различных ошибочных ситуаций:

#include <iostream.h> #include <fstream.h> void main(void)

{

char line[256] ;

ifstream input_file("BOOKINFO.DAT") ;

if (input_file.fail()) cerr << "Ошибка открытия bookinfo.dat" << endl; else

{

while ((! input_file.eof()) && (! input_file.fail()))

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

56

{

input_file.getline(line, sizeof(line)) ;

if (! input_file.fail()) cout << line << endl;

}

}

}

Закрытие файла, если он больше не нужен При завершении программы операционная система закроет

открытые ею файлы. Однако, как правило, если программе файл больше не нужен, она должна его закрыть. Для закрытия файла программа должна использовать функцию close, как показано ниже:

input_file.close ();

Когда закрывается файл, все данные, которые программа писала в этот файл, сбрасываются на диск, и обновляется запись каталога для этого файла.

Управление открытием файла

Впримерах представленных программ файловые операции ввода

ивывода выполнялись с начала файла. Однако, когда записывается данные в выходной файл, вероятно, захотится, чтобы программа добавляла информацию в конец существующего файла. Для открытия файла в режиме добавления должны при его открытии указать второй параметр, как показано ниже:

ifstream output_file("filename.ext", ios::app);

Вданном случае параметр ios::app указывает режим открытия файла. По мере усложнения программ они будут использовать сочетание значений для режима открытия файла, которые перечислены в табл. 11.1.

Таблица 11.1. Значения режимов открытия.

Режим открытия

ios::app

Назначение

Открывает файл в режиме добавления, располагая файловый указатель в конце файла.

ios::ate

Располагает файловый указатель в конце файла.

 

 

ios::in

Указывает открыть файл для ввода.

 

 

ios::nocreate

Если указанный файл не существует, не создавать файл и

 

возвратить ошибку.

ios::noreplace

Если файл существует, операция открытия должна быть

 

прервана и должна возвратить ошибку.

ios::out

Указывает открыть файл для вывода.

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

57

Продолжение таблицы

ios::trunc Сбрасывает (перезаписывает) содержим, з существующего файла.

Следующая операция открытия файла открывает файл для вывода, используя режим ios::noreplace, чтобы предотвратить перезапись существующего файла:

ifstream output_file("FIlename.EXT", ios::out ios::noreplace);

Выполнение операций чтения и записи Все представленные программы, выполняли файловые операции

над символьными строками. По мере усложнения программ, возможно, понадобится читать и писать массивы и структуры. Для этого программы могут использовать функции read и write. При использовании функций read и write должны указатся буфер данных, в который данные будут читаться или из которого они будут записываться, а также длину буфера в байтах, как показано ниже:

input_file.read(buffer, sizeof(buffer)) ; output_file.write(buffer, sizeof(buffer));

Например, следующая программа stru_out.cpp использует функцию write для вывода содержимого структуры в файл teacher.dat:

#include <iostream.h> #include <fstream.h> void main(void)

{

struct teacher

{

char name[64]; int age;

float mark;

} student = { "Ali Khan", 33, 25000.0 }; ofstream teact_file("teacher.DAT") ;

emp_file.write((char *) & student, sizeof(teacher));

}

Функция write обычно получает указатель на символьную строку. Символы (char *) представляют собой оператор приведения типов, который информирует компилятор, что передается указатель на другой тип. Подобным образом следующая программа stru_in.cpp использует метод read для чтения из файла информации о служащем:

#include <iostream.h> #include <fstream.h> void main(void)

{

struct teacher

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

58

{

char name [6 4] ; int age;

float mark;

} student = { "Ali Khan", 33, 25000.0 }; ifstream teach_file("teacher.DAT");

emp_file.read((char *) & student, sizeof(teacher)); cout << student.name << endl;

cout << student.age << endl; cout << student. mark << endl;

}

Заголовочный файл fstream.h определяет классы ifstream и ofstream, с помощью которых программа может выполнять операции файлового ввода и вывода.

Для открытия файла на ввод или вывод нужно объявить объект типа ifstream или ofstream, передавая конструктору этого объекта имя требуемого файла.

После того как программа открыла файл для ввода или вывода, она может читать или писать данные, используя операторы извлечения (>>) и вставки (<<).

Программы могут выполнять ввод или вывод символов в файл или из файла, используя функции get и put.

Программы могут читать из файла целую строку, используя функцию getline.

Большинство программ читают содержимое файла, пока не встретится конец файла. Программы могут определить конец файла с помощью функции eof.

Когда программы выполняют файловые операции, они должны проверять состояние всех операций, чтобы убедиться, что операции выполнены успешно. Для проверки ошибок программы могут использовать функцию fail.

Если программам необходимо вводить или выводить такие данные, как структуры или массивы, они могут использовать методы read и write.

Если программа завершила работу с файлом, его следует закрыть с помощью функции close.

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

59

Лекция 12 Изменения параметров в функции. Стеки. Передача параметров по адресу.

Для изменения параметров в функции фактически требуется больше шагов, чем можно предположить.

Если функция не использует указатели или ссылки, она не может изменить значение параметра.

Для изменения значения параметра функция должна знать адрес параметра в памяти.

Оператор адреса C++ (&) позволяет программе определить адрес переменной в памяти.

Когда программа узнает адрес памяти, она сможет использовать операцию разыменования C++ (*) для определения значения, хранимого по данному адресу.

Если программе нужно изменить значение параметров функции, программа передает в функцию адрес параметра.

Изменение значения параметра функции представляет собой обычную операцию.

Почему функции обычно не могут изменить значения параметров Следующая программа nochange.cpp передает два параметра с именами big и small в функцию display_values. Функция display_values, в свою очередь, присваивает обоим параметрам число 1001 и затем выводит значение каждого параметра. Когда функция завершается, программа возобновляется и выводит значения этих же

параметров:

#include <iostream.h>

void display_values(int a, int b) { a = 1001;

b = 1001;

cout << "Значения в функции display_values равны " << а << " и " << b << endl;

}

void main(void)

{

int big = 2002, small = 0;

cout << "Значения до функции " << big << " и" << small << endl; display_values(big, small);

cout << "Значения после функции " << big << " и " << small << endl;

}

После запуска на экране появится следующий вывод:

С:\> NOCHANGE <ENTER>

Значения до функции 2002 и 0

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

60

Значения в функции display_values равны 1001 и 1001 Значения после функции 2002 и 0

Значения параметров в функции display_values были изменены (1001). Однако после завершения функции значения переменных big и small в main остались прежними. Чтобы понять, почему изменение параметров не повлияло на переменные big и small в main, вам необходимо понять, как C++ передает параметры в функции.

Когда программы передают параметр в функцию, то по умолчанию С++ делает копию значения параметра и помещает эту копию во временный участок памяти, называемый стеком. Затем функция использует копию значения для выполнения своих операций. Когда функция завершается, C++ сбрасывает содержимое стека и все изменения, сделанные функцией в копиях значений параметра.

Переменная представляет собой имя, присваиваемое программой ячейке памяти, которая хранит значение определенного типа. Предположим, например, что переменные big и small находятся в ячейках памяти 10 и 12. Если передаются переменные в функцию display_values, C++ поместит копии значений этих переменных в стек. На рис. 12.1 показано, что далее функция display_values будет использовать копии значений переменных.

Рис. 12.1. C++ размещает копии значений параметров во временном участке памяти, называемом стеком.

Функция display_values может обращаться к содержимому стека, в котором находятся копии значений 2002 и 0. Так как функция display_values ничего не знает о ячейках памяти big и small (адреса 10 и 12), функция не может изменить реальные значения переменных.

Почему функции C++ обычно не могут изменить значения параметров?

Когда передается параметры в функцию, C++ размещает копии значений параметров во временном участке памяти, называемом

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

61

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

Изменение значения параметра Для изменения значения параметра функция должна знать адрес

памяти параметра. Чтобы сообщить функции адрес параметра, программы должны использовать оператор адреса C++ (&). Следующий вызов функции иллюстритует как программа будет использовать оператор адреса для передачи адресов переменных big и small в функцию change_values:

change_values (&big, &small); Передача параметров по адресу Внутри функции должны сообщить C++ , что программа будет

передавать параметры с помощью адреса. Для этого объявляется переменные-указатели, предваряя имя каждой переменной звездочкой, как показано ниже:

void сhange_values (int. *big, int. *small) ---> Указатель на тип

int

Переменная-указатель представляет собой переменную, которая содержит адрес памяти. Внутри функции должны сообщить C++ , что функция работает с адресом параметра. Для этого предваряется имя параметра звездочкой, как показано ниже:

*big = 1001; *small = 1001;

Следующая программа chgparam.cpp использует оператор адреса для передачи адресов параметров big и small в функцию change_values. Функция, в свою очередь, использует указатели участков памяти параметров. Следовательно, изменения параметров, сделанные функцией, остаются и после завершения функции:

#include <iostream.h>

void change_values (int *a, int *b)

{

*a = 1001; *b = 1001;

cout << "Значения в функции display_values" << " равны " << *а << " и " << *b << endl;

}

void main(void)

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

62

{

int big = 2002, small = 0;

cout << "Значения перед функцией " << big << " и " << small << endl; change_values(&big, &small);

cout << "Значения после функции " << big << " и " << small << endl;

}

Когда откомпилируется и запустится программа, на экране появится следующий вывод:

C:\> CHGPARAM <ENTER>

Значения перед функцией 2002 и 0

Значения в функции display_values равны 1001 и 1001 Значения после функции 1001 и 1001

Значения, которые функция change_values присваивает параметрам, остаются и после завершения функции. Чтобы понять, почему изменения, которые функция выполнила над переменными, остались после ее завершения, необходимо вспомнить, что функция имеет доступ к ячейке памяти каждой переменной. Если передается параметры по адресу, C++ помещает адрес каждой переменной в стек, как показано на рис. 12.2.

Рис. 12.2 Передача параметров по адресу.

Используя указатели (адреса памяти) внутри функции, change_values может обратиться к памяти по адресу каждого параметра, изменяя значения параметров, что и требуется.

Изменение значений параметров в функциях Для изменения значения параметра в функции, функция должна

знать адрес параметра в памяти. Следовательно, программа должна передать адрес параметра с помощью оператора адреса C++ :

some_function(&some_variable);

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

63

Внутри функции должны сообщить C++ , что функция будет работать с адресом памяти (указателем). Для этого при объявлении предваряется имя параметра звездочкой:

void some_function(int *some_variable);

Далее внутри функции должны употреблять звездочку перед именем переменной:

*some_variable = 1001; cout << *some_variable;

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

Второй пример Если программа передает указатели на параметры, параметры

могут быгь любого типа, например int, float или char. Функция, которая использует указатели, объявляет переменные соответствующего типа, предваряя имя каждой переменной звездочкой, подтверждающей, что такая переменная является указателем. Следующая программа swapvals.cpp передает адреса двух параметров типа float в функцию swap_values. Функция в свою очередь использует указатели на каждый параметр, чтобы обменять значения параметров:

#include <iostream.h>

void swap_values(float *a, float *b)

{

float temp; temp = *a; *a = *b; *b = temp;

}

void main(void)

{

float big = 10000.0; float small = 0.00001;

swap_values(&big, &small);

cout << "Big содержит " << big << endl; cout << "Small содержит " << small << endl;

}

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

64

Как видно, программа передает параметры в функцию swap_values по адресу. Внутри функции программа использует указатели на ячейки памяти параметров. Видно, функция объявляет а и b как указатели на значения типа float:

void swap_values(float *a, float *b)

Однако функция объявляет переменную temp просто как float, а не как указатель на float. float temp;

Рассмотрим следующий оператор: temp = *а;

Этот оператор побуждает C++ присвоить переменной temp значение указываемое переменной а (т. е. значение переменной big, равное 10000.0). Поскольку temp имеет тип float, присваивание корректно. Переменная-указатель представляет собой переменную, которая хранит адрес. Следующий оператор объявляет temp как указатель на ячейку памяти, содержащую значение типа float.

float *temp;

В данном случае temp может хранить адрес значения с плавающей точкой но не само значение.

Если удалить оператор разыменования (*), стоящий перед переменной а внутри присваивания, то оператор будет пытаться присвоить значение, хранимое в а (которое является адресом), переменной temp. Поскольку temp может содержать значение с плавающей точкой, но не адрес значения с плавающей точкой, возникнет ошибка.

Лучшим способом понять, как компилятор C++ трактует указатели, является исследование ассемблерного вывода компилятора. Большинство компиляторов C++ обеспечивают ключ командной строки, который можно использовать, чтобы указать компилятору выводить ассемблерный листинг. Читая ассемблерный листинг, можно лучше понять, как компилятор использует стек, когда передает параметры в функцию.

Когда программа передает параметр в функцию, C++ помещает копию значения параметра во временный участок памяти, называемый стеком. Любые изменения, которые функция осуществляет над параметром, влияют только на эту копию, расположенную в стеке.

Для изменения значения параметра функция должна знать адрес соответствующей переменной.

Ф КазНПУ 703-12-11. Учебно-методический комплекс дисциплины для обучающегося. Издание третье.

65

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]