БлогNot. Структура со строками string и файловые чтение/запись массива таких структур

Помощь дата->рейтинг Поиск Почта RSS канал Статистика nickolay.info Домой

Структура со строками string и файловые чтение/запись массива таких структур

В отличие от этого примера, используем в структурном типе данных более удобные в обращении и современные строки string и файловые потоки вместо классических си-строк char * и файлов из <cstdio>. Лекции по всем этим темам можно найти в оглавлении.

В итоге должна получиться программка, которая покажет непосредственное задание значений полям структурной переменной и ввод значений полей с консоли, а также запись файла структур и последующее его контрольное чтение. Проверяться она будет в консоли Visual Studio 2015, проект создан как вот здесь.

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

#define _CRT_SECURE_NO_WARNINGS /*для работы sprintf*/
#include <iostream> /*ввод-вывод с консоли*/
#include <string> /*работа со string*/
#include <fstream> /*работа с файлом через поточные методы*/
#include <iomanip> /*setw*/
#include <cstdlib> /*exit*/
#include <windows.h> /*system*/
#include <clocale> /*setlocale*/
using namespace std; /*чтобы не писать std::cin или std::string*/

Опишем структурный тип данных, включающий в себя идентификатор (номер) записи, две строки для хранения имени и даты рождения, а также вещественное поле money для хранения, например, зарплаты:

struct note {
 int id; string name,date; double money;
};

Мы не указываем какие-либо ограничения на длину строки в надежде, что система назначит её автоматически.

Так как программа может завершиться тремя способами - нормально, при ошибке записи файла и при ошибке его чтения, напишем функцию error с аргументом n (номер ошибки), которая будет за это отвечать. Ошибка номер ноль, как принято в C++, будет означать нормальное завершение. Вообще такую "общую точку выхода" зачастую полезно делать в процедурно-ориентированном коде:

void error(int n) {
 string msg[] = { "OK. Normal shutdown", "Can't open file to write!", "Can't open file to read!" };
 cout << endl << msg[n];
 system("pause>nul"); exit(n);
}

Функция для ввода данных с консоли input получает аргументами адрес структуры a, куда нужно заносить данные (это может быть, в том числе, и адрес элемента массива структур) и идентификатор записи i, остальные поля записи она запрашивает у пользователя.

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

Также обратите внимание, что мы не должны "резать" поля структуры кодом вроде

if (a.name.size()>23) a.name.resize(23);

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

Со всеми этими оговорками, простейшая функция ввода записи получилась такой:

void input(note &a, int i) {
 int d,m,y; char c; 
 a.id = i;
 cout << endl << "Name="; getline (cin,a.name); 
 cout << endl << "Date dd.mm.yyyy=";  cin >> d >> c >> m >> c >> y;
 if (d<1 || d>31 || m<1 || m>12 || y<1) { d=m=1; y=1970; }
 char buf[12]; sprintf (buf,"%02d.%02d.%04d",d,m,y); a.date = buf;
 cout << endl << "Money="; cin >> a.money; 
 if (a.money<0 || a.money>1e9) a.money=0;
}

Функция output, соответственно, выводит в консоль поля записи a, переданной аргументом:

void output(note a) {
 cout.precision (2);
 cout << endl << setw(3) << a.id << setw(24) << a.name << setw(12) << a.date << setw(10) << fixed << a.money;
}

При корректных данных должны получиться столбцы одинаковой ширины.

Главной программе осталось русифицировать консоль и создать массив записей, для простоты предусмотрим там всего 2 элемента:

int main() {
 setlocale(LC_ALL,".1251"); SetConsoleCP(1251); SetConsoleOutputCP(1251);
 const int n = 2;
 note notes[n];

Первый элемент с id, равным нулю, зададим программно, а второй введём с консоли:

 notes[0] = { 0, "Ivanov V.P.", "12.11.2000", 40000 };
 input (notes[1],1);

Откроем файл notes.dat для записи и поместим туда данные, заодно печатая их в консоль:

 ofstream ofile("notes.dat", ios::binary); if (!ofile) error (1);
 for (int i = 0; i < n; i++) {
  output(notes[i]);
  ofile.write((char*)&notes[i], sizeof(note));
 }
 ofile.close();

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

 ifstream ifile("notes.dat", ios::binary); if (!ifile) error(2);
 note note; cout << endl << "Reading from file";
 while (ifile.read((char*)&note, sizeof(note))) output(note);
 ifile.close();
 error(0);
}

Вы понимаете, что наш файл - двоичный, и открывать его текстовым редактором бессмысленно.

Вот лог работы нашей программы:

Name=Петров Вася

Date dd.mm.yyyy=22.03.2000

Money=35000

  0             Ivanov V.P.  12.11.2000  40000.00
  1             Петров Вася  22.03.2000  35000.00
Reading from file
  0             Ivanov V.P.  12.11.2000  40000.00
  1             Петров Вася  22.03.2000  35000.00
OK. Normal shutdown

теги: программирование форматы c++ учебное

01.12.2018, 12:35; рейтинг: 49

  свежие записипоиск по блогукомментариистатистикао "вирусах" в архивах .zip

Наверх Яндекс.Метрика
© PerS
вход