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

使用指针编辑文件中结构体数据的问题求助

结构体数据文件读写与编辑的问题修复

问题现象

  1. 编辑指定学生数据时,新数据总是追加到文件末尾,无法覆盖目标结构体位置
  2. 文件中存在多个结构体数据,但fread仅能读取前2条

原始代码

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

struct studentdata{
int student_number;
char student_name[40];
int student_id;
char student_address[60];
int phone_number;
};

void main(){
FILE *p;
struct studentdata insert;
int edit_student;
int location;
struct studentdata change;
struct studentdata *edit;
edit = &change;

p = fopen("students.txt","a");

printf("Insert student\n\n ");
    printf("Student Number: ");
    scanf("%d", &insert.student_number);
    printf("Student Name: ");
    scanf("%s", &insert.student_name);
    printf("Student ID: ");
    scanf("%d", &insert.student_id);
    printf("Address: ");
    scanf("%s", &insert.student_address);
    printf("Phone Number: ");
    scanf("%d", &insert.phone_number);
    printf("\tData saved sucessfully.\n");

        fwrite(&insert, sizeof(struct studentdata), 1, p);
        fclose(p);


        p = fopen("students.txt","r+");

        while(fread(&change,sizeof(struct studentdata),1,p)){
        printf("Student Number: %d\n", change.student_number);
        printf("Student Name: %s\n", change.student_name);
        printf("Student ID: %d\n", change.student_id);
        printf("Address: %s\n", change.student_address);
        printf("Phone Number: %d\n", change.phone_number);
        if (feof(p))
                break;
        }

        printf("Please input the student number you want to edit:");
        scanf("%d",&edit_student);
        fseek(p, 0, SEEK_SET);
        system("cls");


        while(fread(&change,sizeof(struct studentdata),1,p)){

        if ( change.student_number == (edit_student) ){

                    location = ftell(p);

                setbuf(stdin, NULL);
                    printf("Current student name: %s\n", change.student_name);
                    printf("\New student name: ");
                    scanf("%s", &edit->student_name);
                    printf("Current Student ID: %d\n", change.student_id);
                    printf("\tNew Student ID: ");
                    scanf("%d", &edit->student_id);
                    printf(" Current Address: %s\n", change.student_address);
                    printf("\tAddress / CP: ");
                    scanf("%s", &edit->student_address);
                    printf("Current Phone Number: %d\n", change.phone_number);
                    printf("\tPhone Number: ");
                    scanf("%d", &edit->phone_number);

                        location = ftell(p);

                    fwrite(&edit,sizeof(struct studentdata),1,p);
                    fclose(p);
                    break;
        }
            if (feof(p))
                break;
        }
}

问题原因分析

1. 编辑时无法覆盖目标数据的原因

  • 调用fread找到目标结构体后,ftell(p)返回的是读取完该结构体后的位置,而非结构体起始位置,直接写入会写到下一个结构体的位置
  • 写入时错误传递了&edit(指针的地址),而不是edit(指针指向的结构体数据),导致写入的是指针值而非结构体内容
  • 没有在写入前将文件指针移动到目标结构体的起始位置

2. fread只能读取2条数据的原因

  • 第一次读取循环中,while(fread(...))本身会在读取到文件末尾时终止,但额外添加了if(feof(p)) break;,干扰了正常读取流程,导致提前终止
  • 文件打开使用文本模式,可能因换行符转换破坏结构体的二进制布局,导致读取异常

修复后的代码

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

struct studentdata{
    int student_number;
    char student_name[40];
    int student_id;
    char student_address[60];
    int phone_number;
};

int main(){
    FILE *p;
    struct studentdata insert;
    int edit_student;
    long location; // 用long存储ftell返回值,避免溢出
    struct studentdata change;
    struct studentdata *edit = &change;

    // 二进制追加模式写入,避免文本模式的换行转换问题
    p = fopen("students.txt","ab");
    if(p == NULL){
        perror("Failed to open file for writing");
        return 1;
    }
    printf("Insert student\n\n");
    printf("Student Number: ");
    scanf("%d", &insert.student_number);
    printf("Student Name: ");
    scanf("%s", insert.student_name); // 数组名本身是地址,无需&
    printf("Student ID: ");
    scanf("%d", &insert.student_id);
    printf("Address: ");
    scanf("%s", insert.student_address);
    printf("Phone Number: ");
    scanf("%d", &insert.phone_number);
    printf("\tData saved successfully.\n");

    fwrite(&insert, sizeof(struct studentdata), 1, p);
    fclose(p);

    // 二进制读写模式打开,保证结构体读写一致
    p = fopen("students.txt","rb+");
    if(p == NULL){
        perror("Failed to open file for reading");
        return 1;
    }
    printf("\nAll student data:\n");
    // 移除多余feof判断,fread返回值直接控制循环
    while(fread(&change, sizeof(struct studentdata), 1, p)){
        printf("Student Number: %d\n", change.student_number);
        printf("Student Name: %s\n", change.student_name);
        printf("Student ID: %d\n", change.student_id);
        printf("Address: %s\n", change.student_address);
        printf("Phone Number: %d\n\n", change.phone_number);
    }
    // 重置文件指针到开头
    fseek(p, 0, SEEK_SET);

    // 编辑指定学生
    printf("Please input the student number you want to edit: ");
    scanf("%d", &edit_student);
    system("cls");

    int found = 0;
    while(fread(&change, sizeof(struct studentdata), 1, p)){
        if(change.student_number == edit_student){
            found = 1;
            // 计算结构体起始位置:读取后的位置减去结构体大小
            location = ftell(p) - sizeof(struct studentdata);
            // 定位到结构体起始位置
            fseek(p, location, SEEK_SET);

            printf("Current student name: %s\n", change.student_name);
            printf("New student name: ");
            scanf("%s", edit->student_name);
            printf("Current Student ID: %d\n", change.student_id);
            printf("New Student ID: ");
            scanf("%d", &edit->student_id);
            printf("Current Address: %s\n", change.student_address);
            printf("New Address: ");
            scanf("%s", edit->student_address);
            printf("Current Phone Number: %d\n", change.phone_number);
            printf("New Phone Number: ");
            scanf("%d", &edit->phone_number);

            // 写入修改后的结构体,传递正确的结构体地址
            fwrite(edit, sizeof(struct studentdata), 1, p);
            printf("\tData updated successfully.\n");
            break;
        }
    }
    if(!found){
        printf("Student number %d not found.\n", edit_student);
    }
    fclose(p);
    return 0;
}

关键修复点

  • 将文件打开模式改为二进制模式(rb+/ab),避免文本模式下的换行符转换破坏结构体的二进制布局
  • 修正ftell的位置计算:读取完结构体后,文件指针在结构体末尾,需减去结构体大小得到起始位置,再用fseek定位写入
  • 写入时传递edit(结构体指针)而非&edit(指针的地址),确保写入的是结构体数据
  • 移除循环内多余的feof判断,while(fread(...))本身会在读取失败或到末尾时终止循环
  • 数组名本身就是地址,scanf读取字符串时无需加&(如insert.student_name而非&insert.student_name)
  • 标准main函数返回int类型,替换void main
  • 添加文件打开失败的错误判断,增强程序健壮性

内容的提问来源于stack exchange,提问作者JackJones90

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 22:10:30