При записи в файл появляются лишние строчки
Задача: сделать простейшую безразмерную базу данных. База данных должна содержать все типы данных Си, включая enum и union. Нужно реализовать считывание базы данных из файла, вставки и удаления элемента, вывод базы данных и поиск
Программа является базой данных клиентов. Реализована на Си через двусвязный список. Проблема в том, что при записи в файл первые строчки заполняются либо случайными символами из таблицы ASCII, либо пробелами(зависит от того, где компилировать; пробовал в repl.it, xcode и VSC gcc)
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
enum Month {
January=1,
Febrary=2,
March=3,
April=4,
May=5,
June=6,
July=7,
August=8,
September=9,
October=10,
November=11,
December=12
};
struct date{
int Year;
int Day;
enum Month month;
};
union category{
char symb;
short int digit;
};
struct client{
char name[256];
struct date born;
double discont;
char gender;
char city[256];
unsigned int id;
union category Category;
struct client * prev;
struct client * next;
};
void rec_enter(struct client * new_client)//Ввод данных с терминала
{
printf("Введите имя клиента: \n");
scanf("%s", new_client->name);
printf("Введите идентификатор клиента: \n");
scanf("%d", &new_client->id);
printf("Введите дату рождения ДД ММ ГГ\n: ");
scanf("%d %d %d", &new_client->born.Day, &new_client->born.month, &new_client->born.Year);
/*printf("Введите день рождения\n: ");
scanf("%d", &new_client->born.Day);
printf("Введите месяц рождения: \n");
scanf("%d", &new_client->born.month);
printf("Введите год рождения: \n");
scanf("%d", &new_client->born.Year);*/
printf("Введите размер дисконта: \n");
scanf("%lf", &new_client->discont);
printf("Введите пол: \n");
while ( getchar() != '\n' );
scanf("%c", &new_client->gender);
while ( getchar() != '\n' );
printf("Введите город: \n");
scanf("%s", new_client->city);
printf("Введите категорию клиента: \n");
while ( getchar() != '\n' );
scanf("%c", &new_client->Category.symb);
while ( getchar() != '\n' );
}
struct client * new_rec() //Ввод данных
{
struct client * new_client = (struct client *) malloc(sizeof(struct client));
new_client->next = NULL;
rec_enter(new_client);
return new_client;
}
void add(struct client * head){
struct client * new_client = new_rec();
new_client->next=NULL;
struct client* uk=head;
for(;uk->next!=NULL;uk=uk->next);
printf("Конец добавления нового элемента\n\n");
new_client->prev=uk;
uk->next=new_client;
}
void print(struct client* new_client) // Вывод данных о клиенте в терминал
{
printf("Имя клиента: %s\n",new_client->name);
printf("Идентификатор клиента: %d\n", new_client->id);
printf("Дата рождения: %d %d %d\n", new_client->born.Day, new_client->born.month, new_client->born.Year);
/*printf("День рождения: %d\n", new_client->born.Day);
printf("Месяц рождения: %d\n", new_client->born.month);
printf("Год рождения: %d\n", new_client->born.Year);*/
printf("Размер дисконта: %lf\n", new_client->discont);
printf("Пол: %c\n", new_client->gender);
printf("Город: %s\n",new_client->city);
printf("Категория клиента: %c\n", new_client->Category.symb);
printf("\n");
}
void Remove(struct client* uk) //Удаление клинта из базы данных
{
if(uk==NULL) return; //Если указатель на клиента равен NULL, то выходим из функции
uk->prev->next=uk->next; // С предыдущего элемента перебросить связь на следующий
if(uk->next!=NULL) uk->next->prev=uk->prev; //Со следующего элемента перебросить связь на предыдущий
free(uk);
}
void insert(struct client* uk) //Вставка клиента в базу данных
{
struct client* new_client = new_rec();
new_client->prev=uk; // ссылка на предыдущий элемент для нового элемента
new_client->next=uk->next; // ссылка на следующей элемент для нового элемента
if(uk->next!=NULL) uk->next->prev=new_client; // ссылка на предыдущий элемент для следующего элемента
uk->next=new_client; // Указатель на новый элемент для элемента, после которого вставляем новый элемент
}
struct client* find(struct client* head, int id) //Поиск клиента по идентификатору
{
struct client* uk=head;
for(;uk!=NULL;uk=uk->next)
if(uk->id==id)
break;
return uk;
}
int main(void) {
setlocale(LC_ALL, "Russian");
struct client * head = (struct client*) malloc(sizeof(struct client));//Выделение памяти для первого мнимого элемента
head->next=NULL;
struct client * CurrentRec=NULL; // Указатель на текущий элемент
int m, Out=0;
while(!Out)
{
printf("\nВыберите действие:\n");
printf("1. Чтение базы данных из файла\n");
printf("2. Добавить клиента\n");
printf("3. Редактировать данные клиента\n");
printf("4. Удалить клиента\n");
printf("5. Поиск по базе данных\n");
printf("6. Вывод базы данных\n");
printf("7. Запись базы данных в файл\n");
printf("8. Выход\n");
printf("-> ");
scanf("%d",&m);
switch(m)
{
case 1: // Чтение базы данных из файла
{
FILE *FIn;
FIn = fopen("base.txt", "r");
// Очистить старую базу
for(struct client* uk=head->next;uk!=NULL;)
{
struct client* tmp=uk;
uk=uk->next;
free(tmp);
}
head->next=NULL;
while(!feof(FIn))
{
char str[10];
struct client * new_client = (struct client *) malloc(sizeof(struct client));//Выделение памяти для нового элемента
fscanf(FIn, "%s", new_client->name);// Чтение имени
fscanf(FIn, "%d", &new_client->id);// Чтение идентификатора
fscanf(FIn, "%d", &new_client->born.Day);
int x;
// fscanf(FIn, "%d", &x);
// new_client->born.month=x;
fscanf(FIn, "%d", &new_client->born.month);
fscanf(FIn, "%d", &new_client->born.Year);
fscanf(FIn, "%lf", &new_client->discont);
fscanf(FIn, "%s", str);
new_client->gender=str[0];
fscanf(FIn, "%s", new_client->city);
fscanf(FIn, "%s", str);
new_client->Category.symb=str[0];
new_client->next=NULL;
struct client* uk=head;
for(;uk->next!=NULL;uk=uk->next);
new_client->prev=uk;
uk->next=new_client;
}
fclose(FIn);
}
break;
case 2: // Добавить клиента
add(head);
printf("Конец ввода даных \n");
print(head->next);
break;
case 3: // Редактирование данных клиента
if(CurrentRec==NULL)
{
printf("Не выбрана текущая запись \n\n");
break;
}
rec_enter(CurrentRec);
break;
case 4: // Удалить клиента
{
printf("Введите идентификатор клиента, которого хотите удалить: ");
int id;
scanf("%d", &id);
struct client* uk=find(head, id);
if(uk==NULL){
printf("Идентификатор не найден в базе данных\n");
break;
}
Remove(uk);
printf("Запись удалена из базы данных\n\n");
break;
}
case 5: // Поиск по базе данных
{
printf("Введите идентификатор клиента: ");
int id;
scanf("%d", &id);
struct client* uk=find(head, id);
if(uk==NULL){
printf("Идентификатор не найден в базе данных\n");
break;
}
print(uk);
CurrentRec=uk;// Запомнить адрес найденной записи
break;
}
case 6: // Вывод базы данных
{
struct client* uk=head->next;
for(;uk!=NULL;uk=uk->next)
{
print(uk);
printf("-------------------\n");
}
break;
}
case 7: // Запись базы данных в файл
{
FILE *FOut;
FOut = fopen("base.txt", "w");
for(struct client* uk=head;uk!=NULL;uk=uk->next)
{
fprintf(FOut, "%s\n", uk->name);
fprintf(FOut, "%d\n", uk->id);
fprintf(FOut, "%d\n",uk->born.Day);
fprintf(FOut, "%d\n", uk->born.month);
fprintf(FOut, "%d\n", uk->born.Year);
fprintf(FOut, "%lf\n",uk->discont);
fprintf(FOut, "%c\n", uk->gender);
fprintf(FOut, "%s\n", uk->city);
fprintf(FOut, "%c\n", uk->Category.symb);
}
fclose(FOut);
}
break;
case 8: // Выход
printf("Выход из программы...\n");
Out=1;
break;
default:
printf("Неверный ввод комманды!\n");
break;
}
}
return 0;
}
Тест (на месте пропусков пустые строчки):
Ввод | Ожидание | Файл |
---|---|---|
Denis | Denis | |
1000 | 1000 | 0 |
12 | 12 | 0 |
5 | 5 | 0 |
1975 | 1975 | 0 |
17.0 | 17.0 | 0.000000 |
M | M | |
SPB | SPB | |
A | A | |
Lena | Lena | Denis |
1001 | 1001 | 1000 |
30 | 30 | 12 |
1 | 1 | 5 |
2000 | 2000 | 1975 |
15.0 | 15.0 | 17.000000 |
F | F | M |
MSC | MSC | SPB |
B | B | A |
Timofey | Timofey | Lena |
1002 | 1002 | 1001 |
1 | 1 | 30 |
8 | 8 | 1 |
1990 | 1990 | 2000 |
8.0 | 8.0 | 15.000000 |
M | M | F |
Tula | Tula | MSC |
C | C | B |
Timofey | ||
1002 | ||
1 | ||
8 | ||
1990 | ||
8.000000 | ||
M | ||
Tula | ||
C |
Как видно, из-за пустых и состоящих из нулей строчек, все клиенты "съехали" на одну позицию. Следовательно, чтение базы данных из файла и вывод базы данных в терминале тоже работают некорректно.
Из-за чего это может быть и как возможно исправить?