首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C 語言 fread 讀取結構體數組常見錯誤:指針偏移導致輸出異常

     編輯:程式設計綜合問答

問題代碼分析

struct Student stu[30];
struct Student *p;
for (p = stu; p < stu + 30; p++) {
    fread(&p, sizeof(struct Student), 1, fp); // 錯誤 1: &p 是指針的地址,非結構體地址
}
printf("%s,%s,%.1f,%.1f,%.1f\n", p->num, p->name, p->num[0], p->num[1], p->num[2]); // 錯誤 2: p 已指向 stu[30] 越界,且格式化字符串錯誤

核心錯誤

  1. `fread(&p, ...)`:`p` 是 `Student*`,`&p` 是 `Student**` (指針的地址),寫入會破壞指針變量本身,導致後續訪問崩潰或亂碼。正確是 `fread(p, ...)` 或 `fread(&stu[i], ...)`。
  2. 循環結束後 `p` 指向 `stu+30`** (一個過去末端的位置),解引用 `p->num` 即**越界訪問** (UB)。
  3. 輸出格式錯誤:`p->num` 是 `char[10]` (學號),`p->name` 是 `char[10]` (姓名),成績在 `p->c[0..2]` (float),代碼卻用 `p->num[0..2]` 打印成績。
  4. 文本文件用二進制讀取:`cj.txt` 為文本格式 (空格/換行分隔),`fread` 按二進制原樣讀取會包含分隔符、換行符,結構體內存佈局與文本完全不匹配。應用 `fscanf` 或 `fgets`+`sscanf` 解析文本。

正確版本:文本解析 + 邊界檢查

#include 
#include 

struct Student {
    char num[10];
    char name[10];
    float c[3]; // 語文、數學、外語
};

int main() {
    FILE *fp = fopen("cj.txt", "r"); // 文本模式
    if (!fp) { perror("打開失敗"); return 1; }

    struct Student stu[30];
    int count = 0;
    
    // 逐行讀取解析,防止緩衝區溢出
    while (count < 30 && 
           fscanf(fp, "%9s %9s %f %f %f", 
                  stu[count].num, 
                  stu[count].name, 
                  &stu[count].c[0], 
                  &stu[count].c[1], 
                  &stu[count].c[2]) == 5) {
        count++;
    }
    fclose(fp);

    printf("實際讀取 %d 位學生:\n", count);
    for (int i = 0; i < count; i++) {
        // 格式:學號,姓名,語文,數學,外語 (一位小數)
        printf("%s,%s,%.1f,%.1f,%.1f\n",
               stu[i].num, stu[i].name,
               stu[i].c[0], stu[i].c[1], stu[i].c[2]);
    }
    return 0;
}

關鍵修正點總結

錯誤點修正
`fread(&p, ...)` `fscanf(fp, "%9s %9s %f %f %f", ...)` 文本解析
指針 `p` 循環後越界 用下標 `i` 遍歷輸出,或循環前保存 `struct Student *start = p`
成績字段訪問錯誤 `p->num[0]` 正確字段 `stu[i].c[0]` (float 數組)
未檢查文件打開/讀取返回值 `if (!fp) ...`、`fscanf(...) == 5` 確保 5 個字段全匹配
固定 30 次循環不匹配實際行數 `while (count < 30 && fscanf(...) == 5)` 自適應行數

補充:若文件真為二進制 (write 寫入)

// 寫入端
fwrite(&stu[i], sizeof(struct Student), 1, fp);

// 讀取端 (二進制模式 "rb")
while (count < 30 && fread(&stu[count], sizeof(struct Student), 1, fp) == 1) count++;
```
*注意:二進制跨平台存在字節序、結構體填充、浮點表示差異,生產環境推薦文本 (CSV/JSON) 或 Protocol Buffers 等序列化協議。*
							
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved