使用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; }
问题排查与修复方案
核心问题分析
二进制存储与字符解析不匹配:
你用fwrite直接写入char类型的二进制值(比如数值50),但读取时用fgetc后以%c格式输出,这会把二进制值当作ASCII字符解析——ASCII码50对应的字符就是2,这就是加载后显示2的原因。额外的换行则是读取循环中多余的printf("\n")导致的格式混乱。读取逻辑错误:
loaddata中的循环用fgetc读取二进制数据,且fgetc返回的EOF是int类型,存入char变量会被截断,可能导致循环逻辑异常;同时单次存储仅一个字符,完全不需要循环读取。文件模式问题:
存储二进制数据时,未使用二进制模式打开文件(wb/rb),部分系统会自动转换换行符,导致二进制数据被篡改。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
相关产品推荐
相关产品推荐

