Консультация № 183994
09.09.2011, 10:06
65.00 руб.
0 3 1
Здравствуйте! У меня возникли сложности с таким вопросом:
Для хранения данных о планшетных сканерах описать структуру вида
struct scan_info{
char model[25]; // наименование модели
int price: // цена
double x_s1ze: // горизонтальный размер области сканирования
double y__s1ze: // вертикальный размер области сканирования
1nt optr: // оптическое разрешение
int grey: // число градаций серого
}:
Написать функцию, которая записывает данные о сканере из приведенной структуры
в требуемую позицию в бинарном файле. Структура файла: в первых двух
байтах размещается значение типа int, определяющее количество сделанных в
файл записей; далее без пропусков размещаются записи о сканерах. Запись может
осуществляться в любую позицию, причем если между вводимой записью и
последней (или началом файла) имеются пропуски, они заполняются нулями.
Написать функцию, которая «уплотняет» описанный выше бинарный файл путем
удаления из него записей, содержащих все пули.
Привести пример программы, создающей файл с данными о сканерах (данные
вводятся с клавиатуры) из не менее шести записей и осуществляющий его уплотнение.
Все необходимые данные для функций должны передаваться им в качестве параметров.
Использование глобальных переменных в функциях не допускается.
(желательно использовать потоковые классы)

Обсуждение

давно
Мастер-Эксперт
425
4118
12.09.2011, 16:32
общий
в первых двух байтах размещается значение типа int

Это принципиально - 2 байта? Ведь int в 32-ух разрядных ОС равен 4 байтам. Или Вы принципиально занимаетесь только 16-ти разрядными программами?
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
13.09.2011, 09:28
общий
Адресаты:
Задание аналогично консультации №176579 (для консольных приложений). Можно сделать на основе его добавив недостающие пункты задания.
Неизвестный
13.09.2011, 15:19
общий
это ответ
Здравствуйте, Посетитель - 380644!
Код в приложении. Записи будем просто считывать в массив (для реально большого количества записей этот метод может оказаться недопустимым из-за объёма памяти). Поскольку ничего по этому поводу не сказано, скомпилировано в Visual Studio 2005.
Во-первых, о количестве записей. В VS тип int имеет размерность 4 байта, поскольку у Вас в задаче требуется использовать два первых байта, то для размерности используется тип short, который имеет размерность 2 байта в этой среде.
Во-вторых, о работе с файлами. Поскольку в задаче предполагается ввод записи в произвольную позицию, то последовательный доступ к файлу при записи нам не помощник. Необходимо всё время вручную следить за позицией в файле при помощи функции fseek (файл, на_сколько_сдвинуть, откуда_начинать). Размер одной пустой позиции в файле равен размеру одной записи, только всё её содержимое - нули. Создаётся нулевая запись при помощи функции memset (куда, чем_заполнить, сколько_байт), которая заполняет память по заданному адресу заданным значением (в данном случае - 0). Сравнение записи с нулём производится с помощью фунции memcmp (адрес1, адрес2, число_байт), которая возвращает 0 в случае, если переменные заполнены одинаковыми данными.
Остальное должно быть ясно из комментариев.
Удачи!

Приложение:
#include <conio.h>
#include <stdlib.h>
#include <memory.h>

struct scan_info {
char model[25]; // наименование модели
int price; // цена
double x_size; // горизонтальный размер области сканирования
double y__size; // вертикальный размер области сканирования
int optr; // оптическое разрешение
int grey; // число градаций серого
};

const int min_records = 6; //минимальное число записей для ввода (нулевые учитываются)

void PrintArray (scan_info* si, int count) //вывод записей на экран из массива
{
for (int i=0; i<count; i++)
printf ("\n%i. %s price: %i grey: %i", i+1, si[i].model, si[i].price, si[i].grey);
}

void PrintFromFile (char* fname) //вывод записей на экран из файла
{
FILE* f = fopen (fname, "rb"); //открываем файл
if (!f) { //ошибка, если не открылся
printf ("Error");
return;
}
short count; //читаем количество записей
int k = fread (&count, sizeof(short), 1, f);
if (k!=1) { //ошибка, если считалось неверное количество данных
printf ("Error");
return;
}
scan_info* si = new scan_info[count]; //выделяем место под массив
k = fread (si, sizeof(scan_info), count, f); //считываем массив
if (k!=count) {
printf ("Error");
return;
}
for (int i=0; i<count; i++) //выводим на экран
printf ("\n%i. %s price: %i grey: %i", i+1, si[i].model, si[i].price, si[i].grey);
fclose (f);
}


void OptimizeFile (char* fname) //сжатие записей из файла
{
FILE* f = fopen (fname, "r+b"); //открываем файл
if (!f) { //ошибка, если не открылся
printf ("Error");
return;
}
short count; //читаем количество записей
int k = fread (&count, sizeof(short), 1, f);
if (k!=1) { //ошибка, если считалось неверное количество данных
printf ("Error");
return;
}
scan_info* si = new scan_info[count]; //выделяем место под массив
k = fread (si, sizeof(scan_info), count, f); //считываем массив
if (k!=count) {
printf ("Error");
return;
}

PrintArray (si, count); //выводим на экран для контроля
fseek (f, sizeof(short), SEEK_SET); //переходим в начало файла, пропуская число записей

short newcount = 0; //число реальных записей
scan_info nul; //нулевая запись для сравнения
memset (&nul, 0, sizeof(nul)); //заполняем нулями

for (int i=0; i<count; i++) { //просмотриваем массив
if (memcmp (&nul, &si[i], sizeof(scan_info))!=0) { //Если запись не идентична нулевой
k = fwrite (&si[i], sizeof(scan_info), 1, f); //пишем запись в файл
if (k!=1) {
printf ("Error");
return;
}
newcount++; //наращиваем реальное количество
}
}

fseek (f, 0, SEEK_SET); //переходим в начало файла
k = fwrite (&newcount, sizeof(short), 1, f); //пишем реальное количество записей
if (k!=1) {
printf ("Error");
return;
}

fclose (f); //закрываем файл

printf ("\nFile after optimization: \n"); //выводим получившееся для контроля
PrintFromFile (fname);
}

void CreateFile (char* fname) //создание файла
{
short n = 0; //количество записей
int pos;
scan_info si, nul;
memset (&nul, 0, sizeof(nul)); //нулевая запись для пропусков заполняется нулями
FILE* f = fopen (fname, "wb");
if (!f) {
printf ("Error");
return;
}
int k = fwrite (&n, sizeof(short), 1, f); //пока пишем 0 в файл
if (k!=1) {
printf ("Error");
return;
}
char c = 'y'; //признак выхода из цикла
while (c=='y') { //вводим записи
printf ("\nInput new record.\nInput model:\n");
scanf ("%s", &si.model);
printf ("\nInput price:\n");
scanf ("%d", &si.price);
printf ("\nInput horizontal size:\n");
scanf ("%f", &si.x_size);
printf ("\nInput vertical size:\n");
scanf ("%f", &si.y__size);
printf ("\nInput optical resolution:\n");
scanf ("%d", &si.optr);
printf ("\nInput shade of grey:\n");
scanf ("%d", &si.grey);
printf ("\nInput position to save (-1 for write to the end):\n");
scanf ("%d", &pos); //дополнительно спрашиваем позицию для сохранения

n++; //наращиваем количество
if (pos<0) pos = n; //если ввели отрицательную позицию, пишем в конец файла
if (pos>n) { //если позиция дальше текущей
fseek (f, (n-1)*sizeof(si)+sizeof(short), SEEK_SET); //переставляем указатель в файле на текущее место
while (pos>n) { //пишем столько нулевых записей, сколько позиций надо пропустить
fwrite (&nul, sizeof(nul), 1, f);
n++;
}
} else if (pos<n) { //если позиция раньше текущей
n--; //не считаем эту запись - она займёт имеющееся место
fseek (f, (pos-1)*sizeof(si)+sizeof(short), SEEK_SET); //ставим указатель на нужное место
} else //пишем на текущую позицию, ставим на неё указатель
fseek (f, (n-1)*sizeof(si)+sizeof(short), SEEK_SET);


k = fwrite (&si, sizeof(si), 1, f); //пишем запись в файл
if (k!=1) {
printf ("Error");
return;
}
if (n>=min_records) { //если 6 записей уже введено, то предлагаем прервать ввод
printf ("\nPress \'y\', if you want to continue, or any other key, if you don\'t\n");
c = getch(); //если будет введён не у, то выйдем из цикла
}
}

fseek (f, 0, SEEK_SET); //идём в начало файла
k = fwrite (&n, sizeof(short), 1, f); //пишем реальное количество записей
if (k!=1) {
printf ("Error");
return;
}
fclose (f); //закрываем файл
}

int _tmain(int argc, _TCHAR* argv[])
{ //пример
CreateFile ("c:\\scans"); //создаём файл
OptimizeFile ("c:\\scans"); //сортируем по цене
getch(); //ожидаем пользователя
return 0;
}
5
Форма ответа