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

使用fwrite存储char值后加载返回错误数据的问题求助

问题描述

计算器程序使用fwrite存储运算结果,用整数类型时运行正常,但改用char类型后加载得到异常数据。例如存储结果50,加载后显示:

2


2

已通过自定义debug函数验证运算结果已正确存入save变量,问题出在存储或加载代码中。此前使用char data_out[]预定义形式时可正常存储char数据,需排查问题原因并修复。

相关代码
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <cbm.h>

int integer1;
int integer2;
int integer3;
int option;
char save;
char c;
FILE *fp;

void startup() {
    textcolor (COLOR_WHITE);
    bordercolor (COLOR_BLACK);
    bgcolor (COLOR_BLACK);
    clrscr ();
}

void get2nums() {
    printf("FIRST NUMBER?\n");
    scanf("%d", &integer1);
    printf("SECOND NUMBER?\n");
    scanf("%d", &integer2);
}

void addition() {
    get2nums();
    save = integer1 + integer2;
    printf("%d", save);
    printf("\n");
}

void subtraction() {
    get2nums();
    save = integer1 - integer2;
    printf("%d", save);
    printf("\n");
}

void multiplication() {
    get2nums();
    save = integer1 * integer2;
    printf("%d", save);
    printf("\n");
}

void division() {
    get2nums();
    if(integer2 == 0)
        printf("Div by 0 undefined\n");
    else
        save = integer1 / integer2;
        printf("%d with %d remainder", integer1 / integer2, integer1 % integer2);
        printf("\n");
}

static void savedata(void) {
    char data_out = save;

    _filetype = 's';
    if ((fp = fopen ("CALCDATA", "w")) == 0) {
        printf("ERROR COULD NOT OPEN FILE\r\n");
        printf("CHECK DISK DRIVE\n"); 
        exit(1);
    }
    fwrite (&data_out, sizeof(data_out), 1, fp);
    fclose (fp);
}

static void loaddata(void) {
    _filetype = 's';
    if ((fp = fopen ("CALCDATA", "r")) == 0) {
        printf("ERROR COULD NOT OPEN FILE\r\n");
        printf("CHECK DISK DRIVE\n");
        exit(1);
    }
    while (1) {
        c = fgetc (fp);
        if (feof (fp)) {
            break;
        }
        printf("\n");
        printf ("%c\n", c);
    }
    fclose (fp);
}

void debug() {
    printf("%d", save);
}

int main() {
    startup();
    for( ;; ) {
        printf("\n");
        printf("ADVANCED CALCULATOR VERSION 0.9\n");
        printf("CALCULATOR OPTIONS ARE:\n");
        printf("1. ADDITION\n");
        printf("2. SUBTRACTION\n");
        printf("3. MULTIPLICATION\n");
        printf("4. DIVISION\n");
        printf("5. SAVE PREVIOUS\n");
        printf("6. LOAD SAVE\n");
        printf("7. QUIT\n");
        printf("PLEASE SELECT YOUR OPTION.\n");

        scanf("%d", &option);

        if(option == 1)
            addition();
        else if(option == 2)
            subtraction();
        else if(option == 3)
            multiplication();
        else if(option == 4)
            division();
        else if(option == 5)
            savedata();
        else if(option == 6)
            loaddata();
        else if(option == 7)
            exit(1);
        else
            printf("INVALID RESPONSE\n");
    }
    return 0;
}
问题排查与修复方案

核心问题分析

  1. 二进制存储与字符解析不匹配:
    你用fwrite直接写入char类型的二进制值(比如数值50),但读取时用fgetc后以%c格式输出,这会把二进制值当作ASCII字符解析——ASCII码50对应的字符就是2,这就是加载后显示2的原因。额外的换行则是读取循环中多余的printf("\n")导致的格式混乱。

  2. 读取逻辑错误:
    loaddata中的循环用fgetc读取二进制数据,且fgetc返回的EOF是int类型,存入char变量会被截断,可能导致循环逻辑异常;同时单次存储仅一个字符,完全不需要循环读取。

  3. 文件模式问题:
    存储二进制数据时,未使用二进制模式打开文件(wb/rb),部分系统会自动转换换行符,导致二进制数据被篡改。

  4. char类型范围限制:
    若运算结果超出char的取值范围(通常是-128~127,有符号情况下),会发生溢出,导致存储的二进制值异常。

具体修复方案

方案1:二进制存储+二进制读取(保持char类型存储)

修改存储和加载函数,统一使用二进制模式与fread/fwrite:

static void savedata(void) {
    char data_out = save;

    _filetype = 's';
    // 用二进制模式写文件
    if ((fp = fopen ("CALCDATA", "wb")) == 0) {
        printf("ERROR COULD NOT OPEN FILE\r\n");
        printf("CHECK DISK DRIVE\n"); 
        exit(1);
    }
    fwrite (&data_out, sizeof(data_out), 1, fp);
    fclose (fp);
}

static void loaddata(void) {
    _filetype = 's';
    // 用二进制模式读文件
    if ((fp = fopen ("CALCDATA", "rb")) == 0) {
        printf("ERROR COULD NOT OPEN FILE\r\n");
        printf("CHECK DISK DRIVE\n");
        exit(1);
    }
    char data_in;
    // 单次读取一个char即可,无需循环
    size_t read_len = fread(&data_in, sizeof(data_in), 1, fp);
    if (read_len == 1) {
        // 以数值格式输出,而非字符格式
        printf("\n%d\n", data_in);
    }
    fclose (fp);
}

方案2:文本模式存储(还原之前可用的字符串存储逻辑)

将数值转为字符串后存储,读取时直接输出字符串:

#include <string.h> // 需要引入string.h头文件

static void savedata(void) {
    char data_out[10];
    // 将数值转为字符串
    sprintf(data_out, "%d", save);

    _filetype = 's';
    if ((fp = fopen ("CALCDATA", "w")) == 0) {
        printf("ERROR COULD NOT OPEN FILE\r\n");
        printf("CHECK DISK DRIVE\n"); 
        exit(1);
    }
    // 写入字符串内容
    fwrite(data_out, strlen(data_out), 1, fp);
    fclose (fp);
}

// loaddata函数可保留原逻辑,或简化为单次读取
static void loaddata(void) {
    _filetype = 's';
    if ((fp = fopen ("CALCDATA", "r")) == 0) {
        printf("ERROR COULD NOT OPEN FILE\r\n");
        printf("CHECK DISK DRIVE\n");
        exit(1);
    }
    char data_in[10];
    fgets(data_in, sizeof(data_in), fp);
    printf("\n%s\n", data_in);
    fclose (fp);
}

额外优化建议

  • 若运算结果可能超出char范围,将save变量改为int类型,避免溢出;
  • 除法函数的代码存在缩进错误,else后的printf未被包含在分支内,需添加大括号修正:
    else {
        save = integer1 / integer2;
        printf("%d with %d remainder", integer1 / integer2, integer1 % integer2);
        printf("\n");
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 23:25:18