当C中有多个同名记录时如何删除记录

Posted

技术标签:

【中文标题】当C中有多个同名记录时如何删除记录【英文标题】:How to delete a record when there's more than one record of the same name in C 【发布时间】:2021-09-28 21:24:39 【问题描述】:

我正在为 s 献血系统编写代码。我目前正在为删除捐赠者记录功能而苦苦挣扎。

删除记录功能是删除一个给定名字的捐赠者的记录。如果文件中有两个或多个同名记录,则程序会要求提供手机号码。虽然可能有不止一个人同名,但每个人都有一个唯一的手机号码。

我的问题是多条记录使用同名时,删除了错误的记录。

如果只有一条具有该名称的记录,则程序会以所需的方式删除该记录。

(变量 i 全局声明为 int i)

这里是删除功能

void delete(struct blood *b,int n)

    char name[50];
    int phone;
    int found=0;
    int c=0;
    FILE *fp = fopen("bloodrecord.txt", "r");
    FILE *fp1 = fopen("temp.txt", "w");
    printf("\nEnter Name: ");
    scanf("%s", name);
    printf("---------------------------------------------\n");
    while(fread(&b[i],sizeof(struct blood),1,fp))
    
        if(strcmpi(b[i].name,name)==0) 
        
            c=c+1;
            printf("\nName: %s\n",b[i].name);
            printf("Age: %d\n", b[i].age);
            printf("Mobile no.: %d\n", b[i].phone);
            printf("Blood group: %s\n", b[i].bg );
            printf("Weight: %d\n", b[i].weight);
            printf("Sex: %s\n",b[i].sex);
            printf("Address: %s\n",b[i].add);
            printf("\n");
            if (c==1)
                  
                found=1; 
            
            else if(c>1)
                   
                printf("\nThere are more than one occurences of this name in the records\n");                    
                printf("\nPlease enter the mobile number of the donor: ");
                scanf("%d", &phone);        
                if (b[i].phone == phone)
                
                    found=1;
                                   
            
             
        else
        fwrite(&b[i],sizeof(struct blood),1,fp1);
    

    fclose(fp);
    fclose(fp1);

    if (found==1)
    
        fp1 = fopen("temp.txt", "r");
        fp = fopen("bloodrecord.txt", "w");
        
        while(fread(&b[i],sizeof(struct blood),1,fp1))
        
            fwrite(&b[i],sizeof(struct blood),1,fp);
        
        fclose(fp);
        fclose(fp1);
    
    else
    
        printf("\n\aRECORD DOES NOT EXIST.\n");
    
    printf("RECORD SUCCESSFULLY DELETED");
    
    getchar();
    getchar();   

【问题讨论】:

我认为您需要分多个步骤执行此操作:首先找到并计算“命中”的数量。然后在第二步中,根据条件查找和擦除。 scanf(" %[^\n]s", name); 与dangerous as gets 相同,因为您可以轻松读取超出缓冲区容量的数据。还知道%[]%s 是两个独立的转换说明符,您不要将它们组合在一起。始终指定最大长度 %49[^\n],即缓冲区的长度 - 1。(考虑使用涉及 fgets 的更强大的方法)。 这些是文本文件吗(.txt 扩展名暗示了这一点)?如果是这样,那么fwrite 不合适。 Aditya Ranjan,谁或什么文字建议scanf(" %[^\n]s", name); @Aditya Ranjan - 作为函数的第一个参数传递的内容。 i 的定义及其在调用时的值是什么? 【参考方案1】:

我建议为了简化程序,您在开始时要求捐赠者的姓名和捐赠者的手机号码。

然后您处理输入文件并一次性查找姓名和手机号码。

我从您的代码开始并进行了一些更改。见 cmets。

请注意,我没有测试过这段代码,也没有编译过它。它基本上应该是正确的,但是如果我犯了语法错误,可能会出现编译器错误。

我假设您在代码中正确使用了struct blood,因为您没有提供定义该结构的代码。

我假设int 足够大,可以容纳手机号码。由于int 的大小可能会有所不同并且由编译器确定,因此对于手机号码而言,它可能足够大,也可能不够大。见Range of values in C Int and Long 32 - 64 bits

我不明白的一件事是您为什么使用b[i] 语法以及变量i 定义在哪里?您可以改为在 delete() 函数中使用局部变量。

我还有 delete() 函数返回一个值,指示它是否找到匹配项。这可能有用,也可能没用。

int delete()

    struct blood b;
    char name[50] = 0;
    int phone;
    int found = 0;
    FILE *fp = fopen("bloodrecord.txt", "r");
    FILE *fp1 = fopen("temp.txt", "w");

    // Ask for the donor's mobile number along with their name
    // at the beginning to make the search easier and be able to
    // do this in a single pass.
    printf("\nEnter Name of the donor: ");
    scanf("%49s", name);     // Oka's comments about scanf().
    printf("\nPlease enter the mobile number of the donor: ");
    scanf("%d", &phone);        
    printf("---------------------------------------------\n");

    while(fread(&b, sizeof(struct blood), 1, fp))
    
        // check both donor's name and donor's mobile number.
        if(strcmpi(b.name, name) == 0 && b.phone == phone) 
        
            // print out the donor data and indicate we are deleting
            // this donor record.
            printf("Deleting donor record\n");
            printf("  Name: %s\n", b.name);
            printf("  Age: %d\n", b.age);
            printf("  Mobile no.: %d\n", b.phone);
            printf("  Blood group: %s\n", b.bg );
            printf("  Weight: %d\n", b.weight);
            printf("  Sex: %s\n", b.sex);
            printf("  Address: %s\n", b.add);
            printf("\n");
            found = 1;
             
        else 
            // we are keeping this donor record so write it to the
            // temp file.
            fwrite(&b, sizeof(struct blood), 1, fp1);
        
    

    fclose(fp);
    fclose(fp1);

    if (found == 1)
    
        // file temp.txt has deleted donors so lets updated
        // the original file, bloodrecord.txt, with the updated
        // list of donors.
        fp1 = fopen("temp.txt", "r");
        fp = fopen("bloodrecord.txt", "w");
        
        while(fread(&b, sizeof(struct blood), 1, fp1))
        
            fwrite(&b, sizeof(struct blood), 1, fp);
        
        fclose(fp);
        fclose(fp1);
        printf("RECORD SUCCESSFULLY DELETED");
    
    else
    
        printf("\n\aRECORD DOES NOT EXIST.\n");
    
    
    getchar();
    getchar();

    return found;  // indicate if we found a match or not.

【讨论】:

旁白:不要考虑fread(&b, sizeof(struct blood), 1, fp1) 和其他人,而是考虑fread(&b, sizeof b, 1, fp1)。使用sizeof(struct blood),需要查看代码以查看是否使用了正确的类型。如果b 的类型发生变化,则需要做更多的工作来更新代码。 sizeof b 修复了这两个问题。 @chux-ReinstateMonica 这是一个很好的观点。谢谢。【参考方案2】:

我重用了您的大部分代码,并添加了第二遍来处理实际删除(第一遍搜索匹配的记录)。

void delete(struct blood *b,int n)
    
        const int MOBILE_SIZE = 16;
        char name[50];
        int phone = 0;
        int found=0;
        int c=0;
        FILE *fp = fopen("bloodrecord.txt", "r");
        FILE *fp1 = fopen("temp.txt", "w");
        printf("\nEnter Name: ");
        scanf("%s", name);
        printf("---------------------------------------------\n");
        while(fread(&b[i],sizeof(struct blood),1,fp))
        
            if(strcmpi(b[i].name,name)==0) 
            
                c=c+1;
                printf("\nName: %s\n",b[i].name);
                printf("Age: %d\n", b[i].age);
                printf("Mobile no.: %d\n", b[i].phone);
                printf("Blood group: %s\n", b[i].bg );
                printf("Weight: %d\n", b[i].weight);
                printf("Sex: %s\n",b[i].sex);
                printf("Address: %s\n",b[i].add);
                printf("\n");
                found = 1;
                 
        
        /* Finished the first pass. Now, start again */
        rewind(fp)
        if (c > 1) 
            printf("There are multiple records for the name %s\n", name);
            printf("\nEnter Mobile Number: ");
            scanf("%d", &phone);
        
        while(fread(&b[i],sizeof(struct blood),1,fp))
        
            if((c == 1 && strcmpi(b[i].name,name)==0)
                        || (c > 1 && strcmpi(b[i].name,name) == 0 && b[i].mobile == mobile))
                continue; /* skip this record */
                 
            else
                fwrite(&b[i],sizeof(struct blood),1,fp1);
        
        fclose(fp);
        fclose(fp1);
    
        if (found==1)
        
            fp1 = fopen("temp.txt", "r");
            fp = fopen("bloodrecord.txt", "w");
            
            while(fread(&b[i],sizeof(struct blood),1,fp1))
            
                fwrite(&b[i],sizeof(struct blood),1,fp);
            
            fclose(fp);
            fclose(fp1);
        
        else
        
            printf("\n\aRECORD DOES NOT EXIST.\n");
        
        printf("RECORD SUCCESSFULLY DELETED");
        
        getchar();
        getchar();   
    

【讨论】:

scanf("%s", name); 教别人是一种非常糟糕的做法。见我上面的评论。您至少必须使用字段宽度说明符 scanf("%49s", name);,以确保此代码安全。即使这样它也很容易出错,必须维护两个幻数。

以上是关于当C中有多个同名记录时如何删除记录的主要内容,如果未能解决你的问题,请参考以下文章

当引用表中没有匹配的记录时,delete语句如何与REFERENCE约束冲突?

连接多个表后如何从sql查询结果中删除重复记录

当一列具有唯一值时如何删除重复记录

C#如何清除所有外键引用,以便将删除的主键记录保存到数据库中?

如何删除一个数据库中某个学生的全部记录

如何确定正在删除哪些记录?