C语言文件指针跨函数传递异常:读取hw4.data数据乱码求助
问题分析与修复
我尝试从hw4.data文件读取数据并查找指定姓名,用户通过命令行参数输入待查找姓名。程序其他功能正常,但无法在SCAN与LOAD函数间正确传递文件指针,且读取文件输出乱码。作业要求在main函数中定义文件,并在这两个函数间传递,相关代码及hw4.data格式如下:
原代码
#include <stdio.h> #include <stdlib.h> struct _data { char name[20]; long number; }; int SCAN(FILE *(*stream)) { // 遍历文件统计条目数量 int size = 0; char s_temp[100]; long l_temp; while (1) { fscanf(*stream, "%s %ld", s_temp, &l_temp); if (feof(*stream)) break; size++; } return size; } struct _data* LOAD(FILE *stream, int size) { // 遍历文件将条目加载到数据数组 struct _data* d = malloc(size * sizeof(struct _data)); int i; for (i = 0; i < size; i++) { fscanf(stream, "%s %ld", d[i].name, &d[i].number); } return d; } void SEARCH(struct _data *BlackBox, char* name, int size) { // 遍历数组查找指定姓名 int i; int found = 0; for (i = 0; i < size; i++) { printf("%s %s\n", BlackBox[i].name, name); if (strcmp(BlackBox[i].name, name) == 0) { printf("*******************************************\nThe name was found at the %d entry.\n*******************************************\n", i); found = 1; break; } } if (found == 0) { printf("*******************************************\nThe name was NOT found.\n*******************************************\n"); } } void FREE(struct _data* BlackBox, int size) { // 释放动态数组 free(BlackBox); } int main(int argv, char* argc[]) { if (argv == 2) { printf("The argument supplied is %s\n", argc[1]); FILE* file = fopen("./hw4.data", "r"); int size = SCAN(&file); struct _data* data = LOAD(&file, size); SEARCH(data, argc[1], size); fclose(file); return 0; } else { printf("*******************************************\n* You must include a name to search for.*\n*******************************************\n"); return 0; } }
hw4.data格式
ron 7774013 jon 7774014 tom 7774015 won 7774016
错误点与修复方案
1. 文件指针位置未重置
SCAN遍历文件后,指针已移到文件末尾(EOF),LOAD继续读取会直接读到EOF,导致读取失败出现乱码。解决:SCAN结束后用rewind重置指针到文件开头。
2. feof使用逻辑错误
原代码先执行fscanf再检查feof,当读到EOF时feof才置位,但此时已执行size++,会多统计1条数据。正确做法是检查fscanf返回值,成功读取2个字段才计数。
3. 文件指针传递冗余
SCAN无需二级指针,直接传递FILE*即可,文件指针本身是指向FILE结构体的指针,传递指针值足够操作文件。
4. main函数参数顺序错误
main标准参数是int argc, char* argv[],原代码写反argv和argc,导致命令行参数读取错误。
5. 缺失<string.h>头文件
SEARCH使用strcmp需要包含<string.h>,否则可能出现编译错误或未定义行为。
6. 未调用FREE释放内存
原代码未调用FREE释放动态数组,造成内存泄漏。
修正后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> // 新增strcmp所需头文件 struct _data { char name[20]; long number; }; int SCAN(FILE *stream) { // 改为传递FILE*,无需二级指针 int size = 0; char s_temp[100]; long l_temp; // 检查fscanf返回值,成功读取2个字段才计数 while (fscanf(stream, "%s %ld", s_temp, &l_temp) == 2) { size++; } // 重置文件指针到开头,供LOAD函数使用 rewind(stream); return size; } struct _data* LOAD(FILE *stream, int size) { struct _data* d = malloc(size * sizeof(struct _data)); if (d == NULL) { // 新增内存分配失败检查 perror("malloc failed"); exit(EXIT_FAILURE); } int i; for (i = 0; i < size; i++) { // 读取失败时处理 if (fscanf(stream, "%s %ld", d[i].name, &d[i].number) != 2) { perror("fscanf failed"); free(d); // 已分配的内存要释放 exit(EXIT_FAILURE); } } return d; } void SEARCH(struct _data *BlackBox, char* name, int size) { int i; int found = 0; for (i = 0; i < size; i++) { if (strcmp(BlackBox[i].name, name) == 0) { printf("*******************************************\nThe name was found at the %d entry.\n*******************************************\n", i); found = 1; break; } } if (!found) { printf("*******************************************\nThe name was NOT found.\n*******************************************\n"); } } void FREE(struct _data* BlackBox) { // size参数无意义,移除 free(BlackBox); } int main(int argc, char* argv[]) { // 修正参数顺序 if (argc == 2) { printf("The argument supplied is %s\n", argv[1]); FILE* file = fopen("./hw4.data", "r"); if (file == NULL) { // 新增文件打开失败检查 perror("fopen failed"); return EXIT_FAILURE; } int size = SCAN(file); struct _data* data = LOAD(file, size); SEARCH(data, argv[1], size); FREE(data); // 调用释放内存 fclose(file); return EXIT_SUCCESS; } else { printf("*******************************************\n* You must include a name to search for.*\n*******************************************\n"); return EXIT_FAILURE; } }
内容的提问来源于stack exchange,提问作者FunkyMunky
相关产品推荐
相关产品推荐

