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

C语言质数查找程序异常:fread读取长度大于fwrite写入长度

解决二进制文件写入/读取时文件大小非8倍数的异常问题

问题描述

我编写了一个质数查找程序,每完成100次迭代后,将新找到的质数以long long类型(8字节)写入文件。但多次运行程序后出现异常:读取到的文件长度不是8的倍数(比如出现3073字节的情况),触发了自定义的文件校验错误。运行环境为Windows 10,初始无目标文件,尝试过修改fopen模式为"ab+",最终问题由@user3121023解决。

完整代码

主文件(main.c)

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

long long *loadPrimeNums(char *fileName);
void putPrimeNumsInList(long long *primeNums);
void addIntNode(void);
void initialize(void);
void DestroyIntNodes(void);
void writeInFile(void);
void run(void);

int main () 
{
    initialize();
    putPrimeNumsInList(loadPrimeNums("primeNums"));
    run();
    
    writeInFile();
    DestroyIntNodes();
    _fcloseall();
    return 0;   
}

实现文件(prime.c)

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

struct longLongNode
{
    long long value;
    struct longLongNode *next;
};

long long *loadPrimeNums(char *fileName);
void putPrimeNumsInList(long long *primeNums);
void addLongLongNode(void);
void initialize(void);
void DestroyIntNodes(void);
void writeInFile(void);
void run(void);

FILE *primeNums_fp;
long long currentOffset;
struct longLongNode *head, *tail, *lastOldPrimeNum;

void run()
{
    struct longLongNode *current;
    current = head;
    
    int isPrime = 1;
    for (int i = 0; i < 100; i++)
    {
        while (current != NULL)
        {
            if (currentOffset % current->value == 0)
            {
                isPrime = 0;
                break;
            }
            current = current->next;
        }
        if (isPrime == 0)
        {
            isPrime = 1;
        }
        else
        {
            addLongLongNode();
        }
        currentOffset++;
        current = head;
    }
}


void writeInFile()
{
    int numberOfNewPrimes = 0;
    long long *newPrimes;
    struct longLongNode *current;
    current = lastOldPrimeNum;
    
    while (current->next != NULL)
    {
        numberOfNewPrimes++;
        current = current->next;
    }
    
    if (numberOfNewPrimes > 0)
    {
        current = lastOldPrimeNum->next;
        newPrimes = (long long *)malloc(sizeof *newPrimes * numberOfNewPrimes);
        
        for (int i = 0; i < numberOfNewPrimes; i++)
        {
            newPrimes[i] = current->value;
            current = current->next;
        }
        fseek(primeNums_fp, 0L, 2);
        fwrite(newPrimes, sizeof *newPrimes, numberOfNewPrimes, primeNums_fp);
        printf("Freeing newPrimes: The array that is used to write the new prime numbers to file.\n");
        free(newPrimes);
    }
}

void initialize()
{
    head = (struct longLongNode *)malloc(sizeof *head);
    head->value = 2;
    head->next = NULL;
    lastOldPrimeNum = head;
}

void addLongLongNode()
{
    struct longLongNode *temp;
    temp = (struct longLongNode *)malloc(sizeof *temp);
    temp->value = currentOffset;
    temp->next = NULL;
    tail->next = temp;
    tail = temp;
}

long long *loadPrimeNums(char *fileName)
{
    int num;
    long long *ret;
    // 关键修改:使用"ab+"二进制模式打开文件
    primeNums_fp = fopen("primeNums", "ab+");
    fseek(primeNums_fp, 0L, 2);
    if (ftell(primeNums_fp) != 0)
    {
        if (ftell(primeNums_fp) % sizeof *ret == 0)
        {
            num = ftell(primeNums_fp) / sizeof *ret;
            ret = (long long *)malloc(sizeof *ret * (num + 1));
            rewind(primeNums_fp);
            fread(ret, sizeof *ret, num, primeNums_fp);
            ret[num] = -1;
            return ret;
        }
        else if (ftell(primeNums_fp) != -1)
        {
            printf("ERROR!!! ftell(fp): %lld", ftell(primeNums_fp));
            _fcloseall();
            exit(0);
        }
    }
    return NULL;
}

void putPrimeNumsInList(long long *primeNums)
{
    struct longLongNode *current, *temp;
    
    current = head;
    tail = head;
    
    
    if (primeNums != NULL) 
    {
        for (int i = 0; primeNums[i] != -1; i++)
        {
            temp = (struct longLongNode *)malloc(sizeof *temp);
            temp->value = primeNums[i];
            temp->next = NULL;
            current->next = temp;
            current = temp;
        }
        tail = current;
        lastOldPrimeNum = current;
    }
    currentOffset = current->value + 1;
    printf("Freeing primeNums: The array that contains the initially loaded prime numbers of the file.\n");
    free(primeNums);
}

void DestroyIntNodes()
{
    struct longLongNode *current, *next;
    current = head;
    for (int i = 1; current != NULL; i++)
    {
        next = current->next;
        printf("%d: Freeing %lld\n", i, current->value);
        free(current);
        current = next;
    }
}

问题原因

Windows系统中,fopen使用"a+"模式时默认是文本模式,文本模式会自动对换行符进行转换:写入时将\n(0x0A)替换为\r\n(0x0D0A),读取时反向转换。而程序写入的是long long类型的二进制数据,若数据中恰好包含值为0x0A的字节,就会被额外插入一个0x0D字节,导致文件大小不再是8的倍数,触发校验错误。

解决方案

将文件打开模式从"a+"改为"ab+",明确指定二进制模式打开文件。二进制模式下系统不会对文件内容做任何转换,保证long long类型数据(8字节)的写入和读取完整性,文件大小始终保持8的倍数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 06:25:10