c语言文件特定位置的信息删除

我已经有一个学生信息文本
在这里我想理由文件打开方式的“w"方式进行删除某一个学生的信息,程序运行正常,但是文本内容并没有改变,
恳请指点指点我哪里错了,我已经很努力的调试了,但仍没有成效。

struct score
{
    char id[8];
    char name[11];
    float gaoshu;
    float lisan;
    float luoji;
    float gpa_gaoshu;
    float gpa_lisan;
    float gpa_luoji;
    float gpa;
    int rank;//排名 
};
 int cancle(int n)
{
    struct score st[100];
    struct score sub[99];
    char id[8];
    int find=0;
    printf("请输入你要删除的学生学号:"); 
    scanf("%s", &id);
    FILE *fp;
    fp=fopen("学生成绩管理2.txt","r");
    if(fp==NULL)
    {
        printf("打开文件失败,请联系管理员\n");
        getch(); 
        return -1;   
    }
    int c=0;
    int index=0;//用于记录目标序号 
    while(!feof(fp))
    { 
        fscanf(fp,"%s %s %f %f %f %f %f %f %f %d\n",st[c].id,st[c].name,st[c].gaoshu,st[c].lisan,st[c].luoji,st[c].gpa_gaoshu,st[c].gpa_lisan,st[c].gpa_luoji,st[c].gpa,st[c].rank);
        if(strcmp(id,st[c].id)==0)
        {
            find = 1;
            index = c;
        } 
        c++;
    }
    fclose(fp);
    if(n==0)
    {
        printf("已经没有学生成绩信息了,请按任意键返回\n");
        getch();  
        showmenu();
        return n;
    }
    if(find==0)
    {
        printf("没有该学生成绩信息,请按任意键返回\n");
        getch();  
        showmenu();
        return n;
    }
    else 
    {
        int i;
        //删除 
        for(i=0;i<c;i++)
        {
            if(i < index)
            {
                sub[i] = st[i];
            }
            else
            {
                sub[i] = st[i+1];
            }
        }
        FILE *fp2;
        fp2=fopen("学生成绩管理3.txt","w");
    
        for(i=0;i<c-1;i++)
        {
            fprintf(fp2,"%s %s %f %f %f %f %f %f %f %d\n",sub[i].id,sub[i].name,sub[i].gaoshu,sub[i].lisan,sub[i].luoji,sub[i].gpa_gaoshu,sub[i].gpa_lisan,sub[i].gpa_luoji,sub[i].gpa,sub[i].rank);     
        } 
        fclose(fp2);
        printf("学号为%s的学生成绩删除成功,请按任意键返回\n",id);
        getch();
        showmenu();
        return n-1;
    }     
}

我的文本格式
1001 leo 100.00 100.00 100.00 64.00 64.00 64.00 192.00 0
1002 mary 99.00 99.00 99.00 63.90 63.90 63.90 191.70 0
1003 erin 60.00 60.00 60.00 0.00 0.00 0.00 0.00 0
1004 dennle 80.00 80.00 80.00 62.00 62.00 62.00 186.00 0
1005 kin 20.00 90.00 70.00 0.00 63.00 61.00 124.00 0
1006 bore 90.00 80.00 50.00 63.00 62.00 0.00 125.00 0
1007 wake 80.00 80.00 90.00 62.00 62.00 63.00 187.00 0
1008 cid 78.00 76.00 88.00 61.80 61.60 62.80 186.20 0
1009 cold 87.00 78.00 86.00 62.70 61.80 62.60 187.10 0
1010 summy 76.00 65.00 45.00 61.60 60.50 0.00 122.10 0
1011 hot 60.00 60.00 60.00 0.00 0.00 0.00 0.00 0
1012 cool 59.00 50.00 50.00 0.00 0.00 0.00 0.00 0
1013 hand 80.00 10.00 78.00 62.00 0.00 61.80 123.80 0
1014 rool 80.00 30.00 40.00 62.00 0.00 0.00 62.00 0
1015 roof 78.00 57.00 87.00 61.80 0.00 62.70 124.50 0
1016 wave 87.00 77.00 66.00 62.70 61.70 60.60 185.00 0
1017 like 99.00 77.00 77.00 63.90 61.70 61.70 187.30 0
1018 heud 28.00 88.00 76.00 0.00 62.80 61.60 124.40 0
1019 tghde 76.00 80.00 20.00 61.60 62.00 0.00 123.60 0
1020 yehdy 77.00 77.00 66.00 61.70 61.70 60.60 184.00 0

第34行,从文件读取学生信息那个fscanf()函数那里,在每个float结构成员前面加一个&取址符后可以读取到数据;

但在实际测试时发现,读取的浮点数还有误差,测试把这些成员由float类型改为double类型就读取数据正常了。

测试如下:

参考链接:


C语言中fscanf函数读取double型浮点数的问题_Lutx的博客-CSDN博客 转载时请注明出处和作者联系方式作者联系方式:Lutx (80437#zj.com)  在C语言里面, 将一个浮点数输出到文件中, 可以使用符号%f, 如 double a = 0.0;fprintf(fp, "a = %f", a); 而如果要从文件中读取一个double类型的浮点数, 就不能用%f, 而要用%lf才可以. 如 double a;float https://blog.csdn.net/lutx/article/details/5072043


#include <stdio.h> 
#include <conio.h>
#include <string.h>
#include <stdlib.h>

struct score
{
    char id[8];
    char name[11];
     // https://blog.csdn.net/lutx/article/details/5072043
    //  下面的结构成员由float改为double,可以正常读取文件中的相应数据了。 
    double gaoshu;
    double lisan;
    double luoji;
    double gpa_gaoshu;
    double gpa_lisan;
    double gpa_luoji;
    double gpa;
    int rank;//排名 
};

void showmenu()
{
    system("cls"); 
    printf("*----------------------------------------------------*\n");
    printf("*               欢迎使用**成绩管理系统               *\n");
    printf("*----------------------------------------------------*\n"); 
    printf("*               1: 录入成绩                         *\n");
    printf("*               2: 删除成绩                         *\n");
    printf("*               3: 修改成绩                         *\n");
    printf("*               4: 成绩查询                         *\n");
    printf("*               5: 成绩计算并排名                   *\n");
    printf("*               6: 显示成绩信息                     *\n");
    printf("*               0: 保存信息并退出系统               *\n");
    printf("*----------------------------------------------------*\n");
    printf("选择操作<0-6>                                         \n");
    return;
}

 int cancle(int n)
{
    struct score st[100];
    struct score sub[99];
    char id[8];
    int find=0;
    printf("请输入你要删除的学生学号:"); 
    scanf("%s", id);
    FILE *fp;
    fp=fopen("学生成绩管理2.txt","r");
    if(fp==NULL)
    {
        printf("打开文件失败,请联系管理员\n");
        // https://blog.csdn.net/m0_65601072/article/details/124651590
        getch(); 
        return -1;   
    }
    int c=0;
    int index=0;//用于记录目标序号 
    while(!feof(fp))
    { 
            //在每个float结构成员之前加个&取址符,以便顺利获取信息到结构成员 
        fscanf(fp,"%s %s %lf %lf %lf %lf %lf %lf %lf %d\n",st[c].id,st[c].name,
        &st[c].gaoshu,&st[c].lisan,&st[c].luoji,&st[c].gpa_gaoshu,&st[c].gpa_lisan,&st[c].gpa_luoji,&st[c].gpa,&st[c].rank);
        
//        printf("读取信息为;%s %s %lf %lf %lf %lf %lf %lf %lf %d\n",st[c].id,st[c].name,
//        st[c].gaoshu,st[c].lisan,st[c].luoji,st[c].gpa_gaoshu,st[c].gpa_lisan,st[c].gpa_luoji,st[c].gpa,st[c].rank);
        
        if(strcmp(id,st[c].id)==0)
        {
            find = 1;
            index = c;
        } 
        c++;
    }
    fclose(fp);
    if(n==0)
    {
        printf("已经没有学生成绩信息了,请按任意键返回\n");
        getch();  
        showmenu();
        return n;
    }
    if(find==0)
    {
        printf("没有该学生成绩信息,请按任意键返回\n");
        getch();  
        showmenu();
        return n;
    }
    else 
    {
        int i;
        //删除 
        for(i=0;i<c;i++)
        {
            if(i < index)
            {
                sub[i] = st[i];
            }
            else
            {
                sub[i] = st[i+1];
            }
        }
        FILE *fp2;
        fp2=fopen("学生成绩管理3.txt","w");
    
        for(i=0;i<c-1;i++)
        {
            fprintf(fp2,"%s %s %.2f %.2f %.2f %.2f %.2f %.2f %.2f %d\n",sub[i].id,sub[i].name,sub[i].gaoshu,sub[i].lisan,sub[i].luoji,sub[i].gpa_gaoshu,sub[i].gpa_lisan,sub[i].gpa_luoji,sub[i].gpa,sub[i].rank);     
        } 
        fclose(fp2);
        printf("学号为%s的学生成绩删除成功,请按任意键返回\n",id);
        getch();
        showmenu();
        return n-1;
    }     
}
 


int main(void){
    
    
    cancle(20);
    
    return 0;
}


学生成绩管理2.txt (测试数据文件):

1001 leo 100.00 100.00 100.00 64.00 64.00 64.00 192.00 0
1002 mary 99.00 99.00 99.00 63.90 63.90 63.90 191.70 0
1003 erin 60.00 60.00 60.00 0.00 0.00 0.00 0.00 0
1004 dennle 80.00 80.00 80.00 62.00 62.00 62.00 186.00 0
1005 kin 20.00 90.00 70.00 0.00 63.00 61.00 124.00 0
1006 bore 90.00 80.00 50.00 63.00 62.00 0.00 125.00 0
1007 wake 80.00 80.00 90.00 62.00 62.00 63.00 187.00 0
1008 cid 78.00 76.00 88.00 61.80 61.60 62.80 186.20 0
1009 cold 87.00 78.00 86.00 62.70 61.80 62.60 187.10 0
1010 summy 76.00 65.00 45.00 61.60 60.50 0.00 122.10 0
1011 hot 60.00 60.00 60.00 0.00 0.00 0.00 0.00 0
1012 cool 59.00 50.00 50.00 0.00 0.00 0.00 0.00 0
1013 hand 80.00 10.00 78.00 62.00 0.00 61.80 123.80 0
1014 rool 80.00 30.00 40.00 62.00 0.00 0.00 62.00 0
1015 roof 78.00 57.00 87.00 61.80 0.00 62.70 124.50 0
1016 wave 87.00 77.00 66.00 62.70 61.70 60.60 185.00 0
1017 like 99.00 77.00 77.00 63.90 61.70 61.70 187.30 0
1018 heud 28.00 88.00 76.00 0.00 62.80 61.60 124.40 0
1019 tghde 76.00 80.00 20.00 61.60 62.00 0.00 123.60 0
1020 yehdy 77.00 77.00 66.00 61.70 61.70 60.60 184.00 0

img

将里面的 scanf("%s", &id);修改为 scanf("%s", id);

非常感谢刚刚那位发消息的大哥

  • 以下回答由chatgpt基于相关博客总结生成:

    我可以提供一种解决方案,具体步骤如下:

    1. 首先,我们需要打开需要修改的文件,并且以读写的方式打开。假设文件名为“student.txt”,则代码如下:
    FILE *fp = fopen("student.txt", "r+");
    if (fp == NULL) {
        printf("Failed to open file\n");
        return 0;
    }
    
    1. 接下来,我们需要找到需要删除的行号。假设我们要删除第三行,代码如下:
    int line_to_delete = 3;
    
    1. 我们需要遍历文件,找到需要删除的行,并且标记位置。具体做法是逐行读取文件,记录当前行号,当行号等于需要删除的行号时记录文件指针的位置,代码如下:
    char line[100];
    int current_line = 1;
    long int line_pos = ftell(fp); // 记录第一行的位置
    while (fgets(line, 100, fp) != NULL) {
        if (current_line == line_to_delete) {
            line_pos = ftell(fp); // 如果是目标行,记录位置
            break;
        }
        current_line++;
    }
    
    1. 找到目标行的位置后,我们需要将文件指针移动到该位置并且覆盖该行。为了覆盖这一行,我们可以将文件指针移动到下一行的位置,然后将下一行的数据向上移动一行。代码如下:
    fseek(fp, line_pos, SEEK_SET); // 将文件指针移动到目标行
    long int next_line_pos = ftell(fp);
    while (fgets(line, 100, fp) != NULL) {
        next_line_pos = ftell(fp);
        fseek(fp, next_line_pos, SEEK_SET);
    }
    fseek(fp, line_pos, SEEK_SET); // 将文件指针移动到目标行
    fwrite("\n", 1, 1, fp); // 覆盖当前行,写入空字符串
    line_pos = ftell(fp);
    fseek(fp, next_line_pos, SEEK_SET); // 将文件指针移动到下一行
    while (fgets(line, 100, fp) != NULL) {
        fwrite(line, strlen(line), 1, fp); // 将下一行数据向上移动一行
        next_line_pos = ftell(fp);
        fseek(fp, next_line_pos, SEEK_SET);
    }
    ftruncate(fileno(fp), line_pos); // 将文件截断到最后一行(覆盖目标行)
    
    1. 最后,关闭文件:
    fclose(fp);
    

    希望这个解决方案对你有所帮助。如果有任何问题,请随时联系我。