Должен состоять только из латинских букв (A-Z a-z) , цифр (0-9) и символа '_'. Длина никнейма не должна быть менее 3 и больше 15 символов. Ваша страница будет доступна по адресу: http://free-lancing.ru/profile/логин
E-mail
Скрыть e-mail
Используется для сервисных уведомлений, не публикуется на страницах портала. Пожалуйста, используйте существующий адрес электронной почты, к которому Вы имеете доступ, так как для активации аккаунта Вы должны будете пройти по ссылке, которая будет послана на этот адрес.
Программирование → Структуры с меняющимися размерами данных
Размещена: 21.05.2009 11:38
Автор: Виталий Рычков (WinMain)
В разных форумах по программированию на C++ регулярно задаются вопросы: как записать структуру с текстовыми полями в бинарный файл, а затем прочитать её оттуда? Типичной ошибкой для начинающих программистов является попытка записать напрямую в файл структуру, содержащую указатели на текстовые строки. В итоге в файл записываются лишь значения указателей, но не сами строки. Возьмём в качестве примера небольшую структуру, в которой используются классы CString для текстовых данных:
typedef struct _CUSTOM_DATA
{
CString strName; // Имя
CString strFamily; // Фамилия
CString strAddress; // Адрес
CString strCompany; // Компания
CString strMailBox; // Почта
} CUSTOM_DATA, *LPCUSTOM_DATA;
В таком виде структура удобна для обмена данными внутри приложения, например: ввод информации через графический интерфейс, запись в таблицу СУБД, вывод в отчётный документ или экспорт в текстовый файл, и т.д. Но для записи в бинарный файл такая структура неприемлема, поскольку класс CString содержит лишь указатель на символьный массив, а сам текст находится вне класса. Тогда каким же образом текстовые данные можно записать из данной структуры в бинарный файл, а затем прочитать их из файла обратно в структуру? Для этого используются так называемые структуры с меняющимся размером данных, у которых фиксированный размер имеет лишь начало структуры (заголовок), а за ним располагаются сами данные в определённой последовательности. Выглядит структура так:
typedef struct _CUSTOM_DATA_PERSIST
{
DWORD dwDataSize;
WORD wOffsetName;
WORD wOffsetFamily;
WORD wOffsetAddress;
WORD wOffsetCompany;
WORD wOffsetMailBox;
TCHAR tcStrData[1];
} CUSTOM_DATA_PERSIST, *LPCUSTOM_DATA_PERSIST;
Суть в том, что для инициализации такой структуры нужно сначала определить размер всех данных, которые будут записываться в файл. Т.е. необходимо узнать длину каждой строки вместе с нулевым символом на конце, сложить их вместе, прибавить к этому значению размер заголовка структуры, а затем выделить в памяти массив соответствующего размера, в котором разместятся эти данные. Текстовые строки в массиве располагаются последовательно одна за другой, разделённые нулевыми символами, а в заголовке структуры для каждой строки указываются смещения от начала первой строки. Ещё необходимо в заголовке структуры указать размер всего массива данных, чтобы потом при чтении данных из файла, можно было заранее выделить для них массив нужного размера. В таком виде эта структура записывается в файл. При чтении структуры из файла, чтобы получить указатель на нужную строку, надо прибавить к значению указателя на первую строку величину смещения для нужной строки. Как же тогда пользоваться такой структурой для обмена данными в приложении, если процесс её инициализации и обращения к ней выглядит таким сложным и трудоёмким? А не нужно её для этого использовать. Такие структуры следует применять лишь для хранения данных в файле, для передачи данных по сети или для локального обмена данными между приложениями. А для передачи данных внутри приложения следует пользоваться более простым и удобным вариантом первой структуры. Т.е. фактически для одних и тех же данных нужно определить два типа структур. При записи данных в файл и при чтении их из файла необходимо реализовать процедуру передачи данных из одной структуры в другую. Вот как это выглядит в коде на C++:
#include "stdafx.h"
#include
typedef struct _CUSTOM_DATA
{
CString strName; // Имя
CString strFamily; // Фамилия
CString strAddress; // Адрес
CString strCompany; // Компания
CString strMailBox; // Почта
} CUSTOM_DATA, *LPCUSTOM_DATA;
typedef struct _CUSTOM_DATA_PERSIST
{
DWORD dwDataSize;
WORD wOffsetName;
WORD wOffsetFamily;
WORD wOffsetAddress;
WORD wOffsetCompany;
WORD wOffsetMailBox;
TCHAR tcStrData[1];
} CUSTOM_DATA_PERSIST, *LPCUSTOM_DATA_PERSIST;
int SaveDataToFile(LPCUSTOM_DATA data, LPCTSTR szFile)
Представленный пример выполнен в среде Visual C++ 2005. Для его повторения нужно с помощью «визарда» создать проект приложения Win32 Console, включив опцию поддержки ATL.