Else
Else
puts("Файл сохранен!"); //Удачная запись файла
free(array);//Освобождение выделенной динамической памяти
return 0; //Выход
}
/* ------------ Функция загрузки файла --------------------
Параметры: name - имя файла
arr - указатель на массив (по ссылке)
num - число элементов в массиве (по ссылке)
Возвращаемое значение: 0 - успешное завершение
1 - ошибка открытия файла
2 - ошибка выделения памяти
-------------------------------------------------------- */
int LoadFile(const char *name, int **arr, int *num)
{
FILE *file = fopen(name,"rb");//Открытие файла для чтения
if (!file) return 1; //Если открыть не удалось, то выход
//Установка файлового указателя в конец файла
fseek(file,0,SEEK_END);
//Определение числа элементов в файле
int n = ftell(file)/sizeof (int );
//Установка файлового указателя в начало файла
fseek(file,0,SEEK_SET);
//Выделение динамической памяти
int *ptr = (int *)calloc(n,sizeof (int ));
//Если память не выделилась, то закрываем файл и выход
if (!ptr) { fclose(file); return 2;}
//Считываем файл в динамически созданный массив
fread(ptr,sizeof (int ),n,file);
fclose(file); //Закрываем файл
//Записываем значения размера массива и указателя на
//массив в парамеры, переданные по ссылке
*num = n; *arr = ptr;
return 0; //Выход
}
/* --------------- Функция записи файла ------------------
Параметры: name - имя файла,
arr - указатель на массив,
num - количество элементов
Возвращаемое значение: 0 - успешное завершение
1 - ошибка записи в файл
------------------------------------------------------- */
int SaveFile(const char *name, int *arr, int num)
{
//Открытие файла для записи
FILE *file = fopen(name,"wb");
//Если файл открыть не удалось, то выход
if (!file) return 1;
fwrite(arr,sizeof (int ),num,file); //Запись данных в файл
fclose(file); //Зыкрываем файл
return 0; //Выход
}
/* -------- Функции сравнения двух элементов --------------
Параметры: два элемента следующие по порядку
Возвращаемое значение: 1 - необходима перестановка
0 - перестановка не нужна
-------------------------------------------------------- */
int CmpInc(int a,int b) //По возрастанию
{
if (a>b) return 1;
return 0;
}
int CmpDec(int a,int b) //По убыванию
{
if (a<b) return 1;
return 0;
}
/* --------------- Функция сортировки ---------------------
Параметры: arr - указатель на массив элементов,
num - число элементов в массиве,
cmp - указатель на функцию сравнения.
Реализован алгоритм сортировки пузырьком с оптимизацией
-------------------------------------------------------- */
void Sort(int *arr,int num, int (*cmp)(int ,int ))
{
int last = num;
while (last>0){
int pos = 0;
for (int i=0;i<last-1;i++)
if (cmp(arr[i],arr[i+1])){
int tmp=arr[i]; arr[i]=arr[i+1]; arr[i+1]=tmp;
pos = i+1;
}
last = pos;
}
}
Задача 8.2: Дан бинарный файл, содержащий вещественные числа (тип double ). Переписать файл, упорядочив хранящиеся в нем значения. Имя файла и направление сортировки передаются в параметрах командной строки. Направление сортировки передается в формате: dir:inc (по возрастанию) или dir:dec (по убыванию). Алгоритм сортировки реализовать так, чтобы минимизировать объем данных из файла в оперативной памяти.
Программа для задачи
#include < stdio.h> //Библиотека функций ввода и вывода
#include < string.h> //Библиотека функций обработки строк
#include < stdlib.h> //Библиотека стандартных функций
/* -------------- Главная функция main ----------------- */
int main(int argc, char *argv[])
{ //Если параметров меньше трех, то выход из программы
if (argc < 3) { puts("Мало параметров!"); return 0;}
char name[50] = ""; //Имя исходного файла
int dir = -1; //Направление сортировки
//Цикл обработки параметров командной строки
for (int i=1;i<argc;i++){
//Преобразование символов строки к нижнему регистру
_strlwr(argv[i]);
//Если это параметр направления сортировки по
//возрастанию, то переменной dir присваиваем - ноль
if (strcmp(argv[i],"dir:inc")==0) dir = 0;
//Если это параметр направления сортировки по
//убыванию, то переменной dir присваиваем - единица
else if (strcmp(argv[i],"dir:dec")==0) dir = 1;
//В противном случае: это имя файла, которое
//копируем в переменную name
else strcpy(name,argv[i]);
}
//Если имя файла не найдено в параметрах, то вывод
//сообщения и выход из программы
if (strcmp(name,"")==0)
{ puts("Имя файла не указано!"); return 0;}
//Если направление сортировки не найдено, то вывод
//сообщения и выход из программы
if (dir == -1)
{ puts("Направление сортировки не указано!"); return 0;}
//Открытие файла для чтения и записи
FILE *file = fopen(name,"rb+");
//Если файл открыть не удалось, то вывод сообщения и
//выход из программы
if (!file) { puts("Невозможно открыть файл!"); return 0;}
//Файловый указатель устанавливаем в конец файла
fseek(file,0,SEEK_END);
//Определяем количество элементов в файле
int size = ftell(file)/sizeof (double );
/* ------------------------------------------------------
Реализован алгоритм поиска максимального или минимального
элемента (в зависимости от направления сортировки)
------------------------------------------------------ */
//Цикл: пока есть не упорядоченные элементы в файле
while (size>0){
//Устанавливаем файловый указатель на начало файла
fseek(file,0,SEEK_SET);
//Индекс ind и значение value найденного максимума
int ind = 0; //(минимума) в файле
double value = 0.0;
//Считываем первое значение в файле
fread(&value,sizeof (double ),1,file);
//Цикл по всем не упорядоченным элементам в файле
for (int i=1;i<size;i++){
double cur; //Объявляем локальную переменную
//и считываем в нее следующее значение из файла
fread(&cur,sizeof (double ),1,file);
//Если сортировка по возрастанию и найден новый
if (((dir==0)&&(cur>value))|| //максимум
//Если сортировка по убыванию и найден новый
((dir==1)&&(cur<value))){ //минимум
//Сохраняем значение в переменной value и
value = cur; ind = i;//позицию в переменной ind
}
}
//Если найденный максимум (или минимум) находится не
//в конце файла, то осуществляем его перестановку с
if (ind != size-1){ //последним рассматриваемым элементом
double tmp; //Локальная переменная
//Установка файлового указателя на последний элемент
fseek(file,(size-1)*sizeof (double ),SEEK_SET);
//Считываем значение последнего элемента в tmp
fread(&tmp,sizeof (double ),1,file);
//Установка файлового указателя на последний элемент
fseek(file,(size-1)*sizeof (double ),SEEK_SET);
//Записываем значение максимума (или минимума)
fwrite(&value,sizeof (double ),1,file);
//Установка файлового указателя на позицию максимума
fseek(file,ind*sizeof (double ),SEEK_SET); //(минимума)
//Записываем значение из tmp на позицию максимума
fwrite(&tmp,sizeof (double ),1,file); //(минимума)
}
size--; //Уменьшаем число рассматриваемых элементов
}
fclose(file); //Закрываем файл
return 0; //Выход
}
Задача 8.3: В текстовом файле содержатся записи с информацией о студентах: фамилия, имя, отчество (строки, максимум 15 символов), номер зачетной книжки (целое шестизначное число), средний балл (целое число от 1 до 10). Каждая запись содержится в отдельной строке, поля разделяются одним или несколькими пробелами. Упорядочить файл по значению одного из полей. Имя файла, поле и направление сортировки указываются в параметрах командной строки. Поле сортировки: SURNAME (фамилия), NAME (имя), PATRONYMIC (отчество), NUMBER (номер зачетной книжки), RATE (средний балл). Направления сортировки: INC - по возрастанию, DEC - по убыванию.
Программа для задачи
#include < stdio.h> //Библиотека функций ввода и вывода
#include < string.h> //Библиотека функций обработки строк
#include < stdlib.h> //Библиотека стандартных функций
typedef struct{ //Объявление структуры
char fio[3][16]; //Поля: фамилия, имя, отчество
int number,rate; //Поля: номер книжки и средний балл
} STUDENT;
//Функция загрузки списка из файла
int LoadList(const char *,STUDENT **,int *);
//Функция записи списка в файл
int SaveList(const char *,STUDENT *,int );
//Функция сортировки
void Sort(STUDENT*,int ,int ,int );
/* ------------- Главная функция main ------------------ */
int main(int argc, char *argv[])
{ //Если параметров менее четырех, то вывод сообщения и
if (argc < 4) { puts("Мало параметров!"); return 0;} //выход
char name[50] = ""; //Название файла
int dir = -1, field = -1; //Направление и поле сортировки
//Разбор параметров командной строки
for (int i=1;i<argc;i++){
_strlwr(argv[i]); //Преобразование к нижнему регистру
//Сравнение со всеми ключами и установка значений
if (strcmp(argv[i],"inc")==0) dir = 0;
else if (strcmp(argv[i],"dec")==0) dir = 1;
else if (strcmp(argv[i],"surname") == 0) field = 0;
else if (strcmp(argv[i],"name") == 0) field = 1;
else if (strcmp(argv[i],"patronymic") == 0)
field = 2;
else if (strcmp(argv[i],"number") == 0)
field = 3;
else if (strcmp(argv[i],"rate") == 0)
field = 4;
else strcpy(name,argv[i]);//Имя файла
}
//Если имя файла не указано - вывод сообщения и выход
if (strcmp(name,"")==0)
{ puts("Имя файла не указано!"); return 0;}
//Если направление не указано - вывод сообщения и выход
if (dir == -1)
{ puts("Направление сортировки не указано!"); return 0;}
//Если поле не указано - вывод сообщения и выход
if (field == -1)
{ puts("Поле сортировки не указано!"); return 0;}
STUDENT *list = NULL ; //Указатель на список
int num = 0; //Число элементов в списке
//Вызов функции чтения списка из файла
switch (LoadList(name,&list,&num)){
//Если файл не существует или его имя указано неверно
case 1: { puts("Can\'t open file!"); return 0;}
//Если недостаточно динамической памяти для обработки
case 2: { puts("Few memory!"); return 0;}
}
Sort(list,num,field,dir); //Сортировка списка
//Вызов функции записи списка в файл и вывод сообщения
if (SaveList(name,list,num))
puts("Список записать не удалось!");
puts("Список был записан в файл!");
free(list); //Освобождение памяти
return 0; //Выход
}
/* --------- Функция добавления записи в список ----------
Параметры: list - указатель на список (по ссылке)
num - количество записей в списке (по ссылке)
value - значение, добавляемое к списку.
Возвраащемое значение: 1 - успешное завершение
0 - нехватка памяти
------------------------------------------------------- */
int Add(STUDENT **list,int *num, STUDENT value)
{
STUDENT *tmp = //Перевыделение памяти под список
(STUDENT*)realloc(*list,(*num+1)*sizeof (STUDENT));
if (!tmp) return 0; //Если не удалось выделить - выход
tmp[*num] = value; //Записываем новый элемент в список
(*num)++; //Увеличиываем число элементов
*list = tmp; //Сохраняем новое значение указателя
return 1; //Выход
}
/* --------- Функция загрузки списка из файла ------------
Параметры: name - имя файла,
list - указатель на список (по ссылке),
num - число записей в списке (по ссылке)
Возвращаемое значение: 0 - успешное завершение,
1 - файл не найден
2 - не хватает динамической памяти
-------------------------------------------------------- */
int LoadList(const char *name, STUDENT **list, int *num)
{
FILE *file = fopen(name,"r");//Открытие файла для чтения
if (!file) return 1; //Если открыть не удалось, то выход
while (!feof(file)){ //Цикл: пока не конец файла
STUDENT val; //Локальная переменная
int res = 1;
//Считываем строку и заносим в список
if (fscanf(file,"%s %s %s %d %d", //Формат
&val.fio[0],&val.fio[1],&val.fio[2],//ФИО
&val.number, //Номер книжки
&val.rate //Средний балл
)==5) res = Add(list,num,val);
//Если добавить запись в список не удалось, то
if (!res) { fclose(file); return 2;} //выход
}
fclose(file); //Закрытие файла
return 0; //Выход
}
/* --------- Функция записи списка в файл ---------------
Параметры: name - имя файла
list - указатель на список
num - количество записей в списке
Возвращаемое значение: 0 - успешное завершение
1 - ошибка создания файла
------------------------------------------------------ */
int SaveList(const char *name, STUDENT *list, int num)
{
FILE *file = fopen(name,"w"); //Открытие файла для записи
if (!file) return 1; //Если открыть не удалось, то выход
for (int i=0;i<num;i++) //Цикл: запись списка в файл
fprintf(file,"%-15s %-15s %-15s %6d %2d\n",
list[i].fio[0],list[i].fio[1],list[i].fio[2],
list[i].number,list[i].rate);
fclose(file); //Закрытие файла
return 0; //Выход
}
/* ---------- Функция сравнения двух элементов -----------
Параметры: st1, st2 - два элемента для сравнения
field - номер поля, по которому сравниваются
dir - направление сравнения
Вовзращаемое значение: > 0 - больше,
< 0 - меньше,
= 0 - равно
----------------------------------------------------- */
int Cmp(STUDENT st1,STUDENT st2, int field, int dir)
{
if (!dir){ //Если сравнение по возрастанию
//Возвращаем значение в соответствии с номером поля
switch(field){
case 0: return strcmp(st1.fio[0],st2.fio[0]);
case 1: return strcmp(st1.fio[1],st2.fio[1]);
case 2: return strcmp(st1.fio[2],st2.fio[2]);
case 3: return st1.number - st2.number;
case 4: return st1.rate - st2.rate;
}
}else{ //Если сравнение по убыванию
//Возвращаем значение в соответствии с номером поля
switch (field){
case 0: return strcmp(st2.fio[0],st1.fio[0]);
case 1: return strcmp(st2.fio[1],st1.fio[1]);
case 2: return strcmp(st2.fio[2],st1.fio[2]);
case 3: return st2.number - st1.number;
case 4: return st2.rate - st1.rate;
}
}
return 0; //Выход
}
/* ---------- Функция сортировки (внутренняя) ------------
Алгоритм сортировки: быстрый алгоритм Хоара
Параметры: list - указатель на список
iLo, iHi - нижний и верхний индексы
field - номер поля, по которому сравниваются
dir - направление сравнения
-------------------------------------------------------- */
void QuickSort(STUDENT *list, int iLo, int iHi,
int field, int dir)
{
int Lo = iLo, Hi = iHi;
STUDENT mid = list[(Lo+Hi)/2];
do{
while (Cmp(list[Lo],mid,field,dir)<0) Lo++;
while (Cmp(list[Hi],mid,field,dir)>0) Hi--;
if (Lo <= Hi){
STUDENT tmp = list[Lo];
list[Lo] = list[Hi];
list[Hi] = tmp;
Lo++; Hi--;
}
}while (Lo <= Hi);
if (Hi > iLo) QuickSort(list,iLo,Hi,field,dir);
if (Lo < iHi) QuickSort(list,Lo,iHi,field,dir);
}
/* ---------- Функция сортировки (интерфейсная) -----------
Алгоритм сортировки: быстрый алгоритм Хоара
Параметры: list - указатель на список
num - размер списка
field - номер поля, по которому сравниваются
dir - направление сравнения
-------------------------------------------------------- */
void Sort(STUDENT *list,int num, int field, int dir)
{
QuickSort(list,0,num-1,field,dir);
}
Задача 8.4: Дан бинарный файл, содержащий записи об абонентах оператора мобильной связи: фамилия, имя и отчество абонента (строки по 15 символов), номер телефона (целое положительное семизначное число), дата подключения (дд.мм.гггг). Программа должна по запросу пользователя найти всех абонентов подключившихся за определенный период (вводится как две даты). Все найденные записи выводятся на экран, а затем, по требованию пользователя, сохраняются в файл (имя файла вводит пользователь). Записи выводятся в хронологическом порядке. Имя исходного файла передается в параметрах командной строки.
Программа для задачи
#include < stdio.h> //Библиотека функций ввода и вывода
#include < string.h> //Библиотека функций обработки строк
#include < stdlib.h> //Библиотека стандартных функций
typedef struct{ //Описание структуры для хранения даты
unsigned dd:5,mm:4,yy:14;//с использованием битовых полей
} DATE;
typedef struct{ //Описание структуры для хранения
char fio[3][16]; //информации об абоненте
int number;
DATE date;
} ABONENT;
//Функция загрузки списка из файла
int LoadList(const char *,ABONENT **,int *);
void Sort(ABONENT*,int ); //Функция сортировки
void Search(ABONENT *,int ,DATE,DATE);//Функция поиска
int InputDate(DATE *); //Функция ввода даты
int CmpDate(DATE,DATE); //Функция сранения дат
/* ---------- Главная функция программы main ----------- */
int main(int argc, char *argv[])
{
//Если имя исходного файла не указано, то выход
if (argc < 2) { puts("Не указано имя файла!"); return 0;}
ABONENT *list = NULL; //Указатель на список записей
int num = 0; //Количество записей в списке
//Вызов функции загрузки списка и анализ ее результата
switch (LoadList(argv[1],&list,&num)){
case 1: { puts("Невозможно открыть файл!"); return 0;}
case 2: { puts("Недостаточно памяти!"); return 0;}
}
Sort(list,num); //Сортировка списка по дате
DATE date_from, date_to; //Переменные для хранения дат
do{ //Ввод дат с которой и по какую осуществлять поиск
do //Ввод даты с которой осуществляется поиск
printf("Начальная дата: ");//с проверкой корректного
while (InputDate(&date_from)); //ввода
do //Ввод даты по которую осуществляется поиск
printf("Конечная дата: ");//с проверкой корректного
while (InputDate(&date_to)); //ввода
//Если даты введены в хронологическом порядке, то выход
if (CmpDate(date_from,date_to) <= 0) break ; //из цикла
puts("Даты введены некорректно!");//Сообщение об ошибке
}while (1);
Search(list,num,date_from,date_to); //Поиск в списке
free(list); //Удаление списка
return 0; //Выход
}
/* ------------ Функция загрузки списка -------------------
Параметры: name - имя файла,
list - указатель на список (по ссылке),
num - количество записей в списке (по ссылке)
Возвращаемое значение: 0 - успешное завершение,
1 - некорректное имя файла
2 - нехватка динамической памяти
-------------------------------------------------------- */
int LoadList(const char *name, ABONENT **list, int *num)
{
FILE *file = fopen(name,"rb"); //Открытие файла
if (!file) return 1; //Если открыть не удалось, то выход
fseek(file,0,SEEK_END); //Переход в конец файла
//Определение количества записей в файле
int cnt = ftell(file)/sizeof (ABONENT);
fseek(file,0,SEEK_SET); //Переход в начало файла
//Выделение динамической памяти под список
ABONENT *tmp = (ABONENT *)calloc(cnt,sizeof (ABONENT));
//Если память не выделилась, то выход
if (!tmp) { fclose(file); return 2;}
fread(tmp,sizeof (ABONENT),cnt,file); //Считывание даных
fclose(file); //Закрытие файла
*list = tmp; *num = cnt; //Установка переменных по ссылке
return 0; //Выход
}
/* --------- Функция поиска одной записи в списке ---------
Параметры: list - указатель на список,
num - количество записей в списке,
start - номер записи, с которой начинать поиск,
date_from - левая граница временного промежутка,
date_to - правая граница временного промежутка
Возвращаемое значение: -1 - запись не найдена,
≥0 - номер записи в списке.
Реализован алгоритм линейного поиска.
-------------------------------------------------------- */
int Find(ABONENT *list, int num, int start,
DATE date_from, DATE date_to)
{
for (int i=start;i<num;i++)
if ((CmpDate(list[i].date,date_from)>=0)&&
(CmpDate(list[i].date,date_to)<=0)) return i;
return -1;
}
/* --------- Функция поиска всех записей в списке ---------
Параметры: list - указатель на список,
num - количество записей в списке,
start - номер записи, с которой начинать поиск,
date_from - левая граница временного промежутка,
date_to - правая граница временного промежутка
-------------------------------------------------------- */
void Search(ABONENT *list, int num, DATE date_from,
DATE date_to)
{
char fname[50] = ""; //Имя файла для отчета
for (int i=0;i<2;i++){ //Цикл на две итерации
FILE *file = stdout; //Установка на стандартный вывод
//Если это вторая итерация, то вывод в файл
if (i == 1) file=fopen(fname,"w");
//Если открыть файл не удалось, то выход
if (!file) { puts("Невозможно создать файл!"); return ;}
int ind = -1; //Индекс найденной записи
//Поиск записей в цикле, выход - если запись не найдена
while ((ind=Find(list,num,ind+1,date_from,date_to))!=-1)
//Вывод найденной записи
fprintf(file,"%-15s %-15s %-15s %7u %2u.%2u.%4u\n",
list[ind].fio[0], list[ind].fio[1],
list[ind].fio[2], list[ind].number,
list[ind].date.dd, list[ind].date.mm,
list[ind].date.yy
);
char ch = 'n'; //Символ для диалога с пользователем
while (i==0){ //Если это первая итерация
//Вопрос пользователю
printf("Сохранить файл? (y/n): ");
//Очистка буфера ввода и ввод символа
fflush(stdin); scanf("%c",&ch);
//Если ответ положительный
if ((ch == 'y')||(ch == 'Y')){
printf("Имя файла: ");//Приглашение к вводу
scanf("%s",fname); //и ввод имени файла
break ; //Выход из вложенного цикла
}
//Если ответ отрицательный, то выход
if ((ch == 'n')||(ch == 'N')) return ;
}
}
}
/* ---- Функция ввода даты и проверки ее корректности -----
Параметр: date - структура дата, в которую осуществляется
ввод (по ссылке)
Возвращаемое значение: 0 - дата введена корректно
1 - дата введена не корректно
-------------------------------------------------------- */
int InputDate(DATE *date)
{
unsigned day,mon,year; //Локальные переменные
//Ввод значения в формате дд.мм.гггг.
//Если ввод некорректный, то выход со значением 1
if (scanf("%u.%u.%u",&day,&mon,&year) != 3) return 1;
//Проверка корректности введенных значений
if ((day<1)||(day>31)||(mon<1)||(mon>12)||(year<1))
return 1;
//Проверка корректности ввода числа для месяцев, в
//которых 30 дней и для февраля с учетом високосного года
switch (mon){
case 4: case 6: case 9: case 11:
if (day>30) return 1; else break ;
case 2: if (( (year%4)&&(day>28))||
(!(year%4)&&(day>29))) return 1;
}
//Запись значений в структуру
date->dd = day; date->mm = mon; date->yy = year;
return 0; //Выход
}
/* ------------- Функция сравнения двух дат ---------------
Параметр: dt1 - первая дата,
dt2 - вторая дата
Возвращаемое значение: 0 - даты равны,
1 - первая дата «больше»,
-1 - вторая дата «больше»
-------------------------------------------------------- */
int CmpDate(DATE dt1, DATE dt2)
{
if (dt1.yy > dt2.yy) return 1;
else if (dt1.yy < dt2.yy) return -1;
if (dt1.mm > dt2.mm) return 1;
else if (dt1.mm < dt2.mm) return -1;
if (dt1.dd > dt2.dd) return 1;
else if (dt1.dd < dt2.dd) return -1;
return 0;
}
/* ------- Функция сортировки списка (внутренняя) ---------
Параметр: list - указатель на список,
iLo - нижний индекс,
iHi - верхний индекс.
Реализует алгоритм Хоара
-------------------------------------------------------- */
void QuickSort(ABONENT *list, int iLo, int iHi)
{
int Lo = iLo, Hi = iHi;
ABONENT mid = list[(Lo+Hi)/2];
do{
while (CmpDate(list[Lo].date,mid.date)<0) Lo++;
while (CmpDate(list[Hi].date,mid.date)>0) Hi--;
if (Lo <= Hi){
ABONENT tmp = list[Lo];
list[Lo] = list[Hi];
list[Hi] = tmp;
Lo++; Hi--;
}
}while (Lo <= Hi);
if (Hi > iLo) QuickSort(list,iLo,Hi);
if (Lo < iHi) QuickSort(list,Lo,iHi);
}
/* -------- Функция сортировки списка (внешняя) -----------
Параметр: list - указатель на список,
num - количество элементов в списке
-------------------------------------------------------- */
void Sort(ABONENT *list,int num)
{
QuickSort(list,0,num-1);
}
Задача 8.5: Дан бинарный файл, содержащий записи об абонентах оператора мобильной связи: фамилия, имя и отчество абонента (строки по 15 символов), номер телефона (целое положительное семизначное число), дата подключения (дд.мм.гггг). Программа должна по запросу пользователя (водит номер телефона) найти абонента с этим номером и вывести его ФИО и дату подключения. Программа должна работать в интерактивном режиме: после вывода найденной информации переходить к новому запросу. Выход из программы - ввод слова exit. При реализации программы использовать библиотечные функции сортировки и поиска. Имя исходного файла передается в параметрах командной строки.
Программа для задачи
#include < stdio.h> //Библиотека функций ввода и вывода
#include < string.h> //Библиотека функций обработки строк
#include < stdlib.h> //Библиотека стандартных функций
typedef struct{ //Описание структуры для хранения даты
unsigned dd:5,mm:4,yy:14;//с использованием битовых полей
} DATE;
typedef struct{ //Описание структуры для хранения
char fio[3][16]; //информации об абоненте
int number;
DATE date;
} ABONENT;
//Функция загрузки списка из бинарного файла
int LoadList(const char *,ABONENT **,int *);
//Функция сравнения двух записей
int Cmp(const void *,const void *);
/* -------- Главная функция программы main ------------- */
int main(int argc, char *argv[])
{
//Если имя исходного файла не указано, то выход
if (argc < 2) { puts("Имя файла не указано!"); return 0;}
ABONENT *list = NULL ; //Указатель на список записей
int num = 0; //Количесвто записей в списке
//Вызов функции загрузки списка и разбор ее значения
switch (LoadList(argv[1],&list,&num)){
case 1: { puts("Невозможно открыть файл!"); return 0;}
case 2: { puts("Недостаточно памяти!"); return 0;}
}
qsort(list,num,sizeof (ABONENT),Cmp);//Сортировка списка
while (1){ //Цикл интерактивного режима работы
char str[100]; //Буфер ввода
printf(">:"); //Приглашение к вводу
gets(str); //Ввод строки
//Если введено слово «exit», то выход из цикла
if (strncmp(str,"exit",4) == 0) break ;
ABONENT key = {{ "","",""} ,0,{ 0,0,0}} ;//Ключ для поиска
//Преобразование запрашиваемого номера из
key.number = atoi(str); //введенной строки
//Проверка корректности ввода телефонного номера
if ((key.number < 1000000)||(key.number > 9999999)){
puts("Телефонный номер введен неправильно!");
continue ; //Переход к следующей итерации
}
//Поиск записи в списке по введенному номеру
ABONENT *ptr =
(ABONENT *)bsearch(&key,list,num,sizeof (ABONENT),Cmp);
//Если запись не найдена, то выводим сообщение
if (!ptr) puts("Не найдено!");
//Иначе: выводим на экран найденную запись
else printf("%-15s %-15s %-15s %7u %2u.%2u.%4u\n",
ptr->fio[0], ptr->fio[1], ptr->fio[2],
ptr->number,
ptr->date.dd, ptr->date.mm, ptr->date.yy);
}
free(list); //Удаление списка
return 0; //Выход
}
/* ------------ Функция загрузки списка -------------------
Описание и комментарии в предыдущем примере
-------------------------------------------------------- */
int LoadList(const char *name, ABONENT **list,int *num)
{
FILE *file = fopen(name,"rb");
if (!file) return 1;
fseek(file,0,SEEK_END);
int cnt = ftell(file)/sizeof (ABONENT);
fseek(file,0,SEEK_SET);
ABONENT *tmp = (ABONENT *)calloc(cnt,sizeof (ABONENT));
if (!tmp) { fclose(file); return 2;}
fread(tmp,sizeof (ABONENT),cnt,file);
fclose(file);
*list = tmp; *num = cnt;
return 0;
}
/* ----------- Функция сравнения двух записей -------------
Параметр: el1 - указатель на первую запись,
el2 - указатель на вторую запись
Возвращаемое значение:
0 - телефонные номера равны,
1 - телефонный номер перой записи «больше»,
-1 - телефонный номер второй записи «больше»,
-------------------------------------------------------- */
int Cmp(const void *el1, const void *el2)
{
ABONENT *ptr1 = (ABONENT *)el1, *ptr2 = (ABONENT *)el2;
if (ptr1->number > ptr2->number) return 1;
else if (ptr1->number < ptr2->number) return -1;
return 0;
}
«ПОЛИГРАФИЧЕСКИЙ ДИЗАЙН»