You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:45:54