Привет всем, я новичок в C. Мне пришлось создать «библиотеку», где я могу хранить некоторые книги и вносить в них некоторые изменения (добавить книгу, удалить книгу или изменить ее), используя массив структур, то я должен сохранить его в файл.
Проблема в том, что должна быть возможность удалить книгу и перезаписать изменения в файле, открытом в режиме "r + b", с помощью функции fwrite ().
Сначала я читаю из файла массив массивов и подсчитываю количество книг в нем, используя fread (), затем, удаляя книгу, прокручиваю структуры вниз и присваиваю пустую структуру последней структуре.
Ex.
После удаления «Book2» и прокрутки вниз структур:
После назначения пустой структуры последней прочитанной:
- Книга1
- book3
- Random_Stuff
Затем я сохраняю только первые две структуры в файл, и когда я читаю файл, я получаю:
Если я перезаписываю файл тремя структурами, я получаю:
- Книга1
- book3
- Random_Stuff
И это разумно, но как я могу перезаписать весь файл только в этом случае первыми двумя структурами, использующими fwrite ()?
Это моя структура
typedef struct book {
char title[MAXTIT];
char autor[MAXAUT];
float price;
} info;
Это функция удаления книги:
void remove_book(info bibl[], int * num) {
// Empty structure to assign to the last structure after the removal
info empty;
char title[256];
puts("Enter the title of the book you want to remove:");
read(title, 256);
// Scrolling down the structures to cover the removed one
for (int i = 0 ; i < *num ; i++)
if (strcmp(title, bibl[i].title) == 0) {
for (int index = i ; index < *num ; index++)
bibl[index] = bibl[index + 1];
bibl[*num] = empty;
(*num)--;
break;
}
for (int index = 0 ; index < *num ; index++)
printf("%s, autor: %s, price: %.2f €\n", bibl[index].title, bibl[index].autor, bibl[index].price);
}
Это полный код (на всякий случай):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAXTIT 40 // Maximum lenght of the title
#define MAXAUT 40 // Maximum lenght of the name of the autor
#define MAXBOOK 10 // Maximum number of books
typedef struct book {
char title[MAXTIT];
char autor[MAXAUT];
float price;
} info;
int size = sizeof(info);
int counter = 0;
int counterp;
FILE * fp;
char file_name[64];
int menu(void);
void add_book(info [], int *);
void remove_book(info [], int *);
void modify_book(info [], int);
void input(info [], int *, int *);
char *read(char *, int);
int main(void) {
info bibl[MAXBOOK];
int index, choice;
puts("Please, enter the file to be read:");
read(file_name, 64);
// If returns a NULL pointer puts an error message and ends the program
if (!(fp = fopen(file_name, "r+b"))) {
fprintf(stderr, "An error occurred while trying to open \"%s\".", file_name);
exit(1);
}
// Read the content of the file
input(bibl, &counter, &counterp);
// If the file is empty lets the user add a book
if (counterp == 0) {
add_book(bibl, &counter);
fwrite(&bibl[counterp], size, counter - counterp, fp);
// If the user added a book shows the content of the file
if (counter > 0) {
puts("Updated file content:");
for (index = 0 ; index < counter ; index++)
printf("%d) %s, autor: %s, price: %.2f €\n", index + 1, bibl[index].title, bibl[index].autor, bibl[index].price);
putchar('\n');
}
}
// If there is something in the file lets the user choose between some options (add, remove, modify a book or simply quit)
if (counter > 0) {
// Menu returns a value for the switch function
choice = menu();
// Repeats the choice until the "Quit" option has been chosen
while (choice) {
switch(choice) {
// First case, reads from the file, adds the book and writes everything in the file
case 1 : input(bibl, &counter, &counterp);
add_book(bibl, &counter);
fwrite(&bibl[counterp], size, counter - counterp, fp);
break;
// Second case, reads from the file, (should) removes the book and overwrites everything in the file
case 2 : input(bibl, &counter, &counterp);
remove_book(bibl, &counter);
rewind(fp); // Rewind to overwrite the new values in the file
fwrite(&bibl[0], size, counterp, fp);
break;
// Third case, reads from the file, modifies the book and overwrites everything in the file
case 3 : input(bibl, &counter, &counterp);
modify_book(bibl, counter);
rewind(fp); // Same as before
fwrite(&bibl[0], size, counter, fp);
break;
// Forth case, quits the menu
case 4 : break;
// Should never activate but I put it in case I'd like to modify something in the menu ecc...
default : fputs("You entered wrong data!", stderr);
break;
}
// If a change has been made shows the new content
if (choice >= 1 && choice <= 3) {
puts("Updated file content:");
for (index = 0 ; index < counter ; index++)
printf("%d) %s, autor: %s, price: %.2f €\n", index + 1, bibl[index].title, bibl[index].autor, bibl[index].price);
putchar('\n');
}
// Exit the loop in case of "Quit" option
if (choice == 4)
break;
choice = menu();
}
} else
puts("No books? What a pity!");
// If fclose() != NULL, an error occurred
if (fclose(fp))
fprintf(stderr, "An error occurred while trying to close \"%s\".", file_name);
puts("Ending process...");
return 0;
}
// Function that shows the options of the menu
int menu(void) {
int num;
puts("Choose between:\n1) Add a book\n2) Remove book\n3) Modify a book\n4) Quit");
while (scanf("%d", &num) != 1 || num < 1 || num > 4)
puts("Choice between:\n1) Add a book\n2) Remove book\n3) Modify a book\n4) Quit");
while (getchar() != '\n');
return num;
}
// Function used to add a book to the file (works fine)
void add_book(info bibl[], int * num) {
int index;
bool flag = false;
puts("Please, enter a new title ([enter] at the start of the line ends the process):");
while (*num < MAXBOOK && read(bibl[*num].title, MAXTIT) && bibl[*num].title[0] != '\0') {
puts("Now enter the autor.");
read(bibl[*num].autor, MAXAUT);
for (index = 0 ; index < *num ; index++)
if (strcmp(bibl[index].title, bibl[*num].title) == 0 && strcmp(bibl[index].autor, bibl[*num].autor) == 0) {
puts("This book is already in your library.");
puts("Please, enter a new title ([enter] at the start of the line ends the process):");
flag = true;
break;
}
if (flag)
continue;
puts("And finally enter the price.");
scanf("%f", &bibl[(*num)++].price);
while (getchar() != '\n');
if (*num < MAXBOOK)
puts("\nPlease, enter a new title ([enter] at the start of the line ends the process):");
}
}
// Function that should work and do what it's meant to do but it doesn't for I don't know what reason
void remove_book(info bibl[], int * num) {
// Empty structure to assign to the last structure after the removal
info empty;
char title[256];
puts("Enter the title of the book you want to remove:");
read(title, 256);
// Scrolling down the structures to cover the removed one
for (int i = 0 ; i < *num ; i++)
if (strcmp(title, bibl[i].title) == 0) {
for (int index = i ; index < *num ; index++)
bibl[index] = bibl[index + 1];
bibl[*num] = empty;
(*num)--;
break;
}
for (int index = 0 ; index < *num ; index++)
printf("%s, autor: %s, price: %.2f €\n", bibl[index].title, bibl[index].autor, bibl[index].price);
}
// Function used to change a book's informations
void modify_book(info bibl[], int num) {
char title[256];
int choice;
puts("Enter the title of the book you want to modify:");
read(title, 256);
puts("Choose what you want to modify:\n1) Title\n2) Autor\n3) Price\n4) Everything");
while(scanf("%d", &choice) != 1 || choice < 1 || choice > 4)
puts("Choose what you want to modify:\n1) Title\n2) Autor\n3) Price\n4) Everything");
while (getchar() != '\n');
for (int i = 0 ; i < num ; i++) {
if (strcmp(title, bibl[i].title) == 0) {
switch (choice) {
case 1 : puts("Please, enter the new title of the book:");
read(bibl[i].title, MAXTIT);
break;
case 2 : puts("Enter the new autor of the book:");
read(bibl[i].autor, MAXAUT);
break;
case 3 : puts("Enter the new price:");
scanf("%f", &bibl[i].price);
while (getchar() != '\n');
break;
case 4 : puts("Please, enter the title of the book:");
read(bibl[i].title, MAXTIT);
puts("Now enter the autor of the book:");
read(bibl[i].autor, MAXAUT);
puts("And finally its cost:");
scanf("%f", &bibl[i].price);
while (getchar() != '\n');
break;
default : break;
}
break;
}
}
for (int index = 0 ; index < num ; index++)
printf("%s, autor: %s, price: %.2f €\n", bibl[index].title, bibl[index].autor, bibl[index].price);
}
// Function that reads from the file in which we are saving the structures
void input(info bibl[], int * counter, int * counterp) {
*counter = 0;
rewind(fp);
while (*counter < MAXBOOK && fread(&bibl[*counter], size, 1, fp) == 1) {
if (*counter == 0)
printf("Actual content of the file \"%s\":\n", file_name);
printf("%d) %s by %s: %.2f €\n", *counter + 1, bibl[*counter].title, bibl[*counter].autor, bibl[*counter].price);
(*counter)++;
}
if (*counter > 0 && *counter < MAXBOOK)
putchar('\n');
*counterp = *counter;
if (*counter == MAXBOOK) {
fprintf(stderr, "The file \"%s\" is full.", file_name);
exit(1);
}
}
// Better alternative for gets()
char *read(char * str, int len) {
char * res, * here;
if (res = fgets(str, len, stdin))
if (here = strchr(str, '\n'))
*here = '\0';
else
while (getchar() != '\n');
return res;
}