如何在C语言中标记二进制文件的最后一个结构体为DELETED
标记二进制文件最后一个cliente结构体为"deleted"的实现方案
需要将二进制文件file.dat中最后一个写入的cliente结构体标记为"deleted"。现有代码已实现客户信息写入、文件内容打印、按客户名计算总金额功能,已知可使用fseek()函数,但不清楚具体实现方式。
原代码
#include <stdio.h> #include <string.h> struct s_cliente { int codice; char nome[10]; char merce[10]; float prezzo; }; typedef struct s_cliente cliente; cliente inserisciCliente(cliente c1); void inserisciOrdine(); void stampaFile(); float calcolaPrezzo(char nome[10]); void eliminaLast(); int main() { char nome[10]; float prezzotot = 0; int opz = 0; do { printf("\nInserisci un'opzione: \n1)Inserisci un cliente\n2)Stampa i clienti all'interno del file\n3)Ricerca un cliente e calcola l'importo dovuto\n"); scanf("%d", &opz); switch (opz) { case 1: inserisciOrdine(); break; case 2: stampaFile(); break; case 3: getchar(); scanf("%s", nome); prezzotot = calcolaPrezzo(nome); if (prezzotot != 0) { printf("\nImporto dovuto dal cliente %s: %.2f euro", nome, prezzotot); } else { printf("\nCliente non trovato"); } break; default: printf("\nOpzione non valida"); break; } } while (opz != 5); return 0; } cliente inserisciCliente(cliente c1) { printf("\nInserisci il codice: "); scanf("%d", &c1.codice); getchar(); printf("Inserisci il nome: "); scanf("%s", c1.nome); getchar(); printf("Inserisci la merce: "); scanf("%s", c1.merce); printf("Inserisci prezzo: "); scanf("%f", &c1.prezzo); return c1; } void inserisciOrdine() { FILE *foutput = fopen("file.dat", "ab"); cliente c1; c1 = inserisciCliente(c1); fwrite(&c1, sizeof(c1), 1, foutput); fclose(foutput); } void stampaFile() { FILE *file_lettura = fopen("file.dat", "rb"); if (file_lettura != NULL) { cliente c1; while (fread(&c1, sizeof(cliente), 1, file_lettura) == 1) { printf("Codice: %d, Nome: %s, Merce: %s, Prezzo: %.2f\n", c1.codice, c1.nome, c1.merce, c1.prezzo); } fclose(file_lettura); } else { printf("Errore nell'apertura del file per la lettura.\n"); } } float calcolaPrezzo(char nome[10]) { float prezzotot = 0; FILE *file_lettura = fopen("file.dat", "rb"); cliente c1; if (file_lettura != NULL) { while (fread(&c1, sizeof(cliente), 1, file_lettura) == 1) { if (strcmp(nome, c1.nome) == 0) { prezzotot += c1.prezzo; } } fclose(file_lettura); } else { printf("\nErrore nella lettura"); } return prezzotot; }
修改后的完整实现
1. 结构体添加删除标记
在struct s_cliente中新增字段存储删除状态:
struct s_cliente { int codice; char nome[10]; char merce[10]; float prezzo; char deleted[8]; // 标记状态:默认"active",删除后设为"deleted" };
2. 实现eliminaLast()核心函数
通过fseek定位最后一条记录并修改标记:
void eliminaLast() { FILE *file = fopen("file.dat", "rb+"); if (file == NULL) { printf("\nErrore nell'apertura del file per la modifica."); return; } // 定位到最后一个结构体的起始位置 fseek(file, -sizeof(cliente), SEEK_END); cliente c1; // 读取最后一条记录并修改标记 if (fread(&c1, sizeof(cliente), 1, file) == 1) { strncpy(c1.deleted, "deleted", 7); c1.deleted[7] = '\0'; // 确保字符串结束符 // 回退到该记录的起始位置,写回修改后的数据 fseek(file, -sizeof(cliente), SEEK_CUR); fwrite(&c1, sizeof(cliente), 1, file); printf("\nUltimo cliente marcato come cancellato."); } else { printf("\nIl file è vuoto o non contiene clienti."); } fclose(file); }
3. 更新写入函数,默认标记为未删除
新添加的客户默认设置为活跃状态:
void inserisciOrdine() { FILE *foutput = fopen("file.dat", "ab"); cliente c1; c1 = inserisciCliente(c1); // 默认设置为未删除状态 strncpy(c1.deleted, "active", 6); c1.deleted[7] = '\0'; fwrite(&c1, sizeof(c1), 1, foutput); fclose(foutput); }
4. 更新主菜单与循环逻辑
添加标记最后一个客户的选项,同时修正退出逻辑:
int main() { char nome[10]; float prezzotot = 0; int opz = 0; do { printf("\nInserisci un'opzione: \n" "1)Inserisci un cliente\n" "2)Stampa i clienti all'interno del file\n" "3)Ricerca un cliente e calcola l'importo dovuto\n" "4)Marca l'ultimo cliente come cancellato\n" "5)Esci\n"); scanf("%d", &opz); switch (opz) { case 1: inserisciOrdine(); break; case 2: stampaFile(); break; case 3: getchar(); scanf("%s", nome); prezzotot = calcolaPrezzo(nome); if (prezzotot != 0) { printf("\nImporto dovuto dal cliente %s: %.2f euro", nome, prezzotot); } else { printf("\nCliente non trovato"); } break; case 4: eliminaLast(); break; case 5: printf("\nUscita dal programma."); break; default: printf("\nOpzione non valida"); break; } } while (opz != 5); return 0; }
5. 更新打印与计算函数,过滤已删除条目
修改stampaFile():
void stampaFile() { FILE *file_lettura = fopen("file.dat", "rb"); if (file_lettura != NULL) { cliente c1; while (fread(&c1, sizeof(cliente), 1, file_lettura) == 1) { // 仅打印未删除的客户 if (strcmp(c1.deleted, "deleted") != 0) { printf("Codice: %d, Nome: %s, Merce: %s, Prezzo: %.2f\n", c1.codice, c1.nome, c1.merce, c1.prezzo); } } fclose(file_lettura); } else { printf("Errore nell'apertura del file per la lettura.\n"); } }
修改calcolaPrezzo():
float calcolaPrezzo(char nome[10]) { float prezzotot = 0; FILE *file_lettura = fopen("file.dat", "rb"); cliente c1; if (file_lettura != NULL) { while (fread(&c1, sizeof(cliente), 1, file_lettura) == 1) { // 忽略已删除的客户记录 if (strcmp(c1.deleted, "deleted") != 0 && strcmp(nome, c1.nome) == 0) { prezzotot += c1.prezzo; } } fclose(file_lettura); } else { printf("\nErrore nella lettura"); } return prezzotot; }
关键逻辑说明
fseek(file, -sizeof(cliente), SEEK_END):直接定位到文件末尾前一个结构体的起始位置,精准指向最后一条记录。- 修改标记后需用
fseek回退指针:因为读取记录后文件指针会自动移动到下一条位置,需回退一个结构体大小才能覆盖原记录。 - 所有新记录默认标记为
active,打印和计算操作自动过滤deleted标记的记录,保证数据逻辑一致性。
内容的提问来源于stack exchange,提问作者Lorelius Hogglefart
相关产品推荐
相关产品推荐

