C语言中含char*的结构体数组读写二进制文件后指针设置求助
解决带指针的结构体数组二进制读写异常问题
嘿,我一眼就看出你问题的症结了——你写入二进制文件的时候,完全漏掉了每个point结构体里的namelength字段!
你当前的写入逻辑只把所有name的字符数据写到了文件里,但没有保存每个point对应的namelength值。这就导致读取程序里的POINTS[i].namelength都是malloc后未初始化的垃圾值,你的指针移动逻辑完全基于错误的长度,自然会出现“第一个非空name打印所有内容”的问题——因为那个垃圾长度可能远大于实际的单个name长度,把后面的所有name都包含进去了。
下面是修正后的完整读写流程和代码:
一、正确的写入流程
我们需要把结构体的关键元数据(总点数N、每个point的namelength)和name内容一起写入文件,步骤如下:
- 用
wb模式打开二进制文件 - 先写入总点数
N,让读取程序知道要分配多少个point结构体 - 逐个写入每个
point的namelength字段 - 最后写入所有name的字符内容
修正后的写入代码:
// 打开二进制输出文件 if ((fin = fopen(name, "wb")) == NULL){ printf("the output binary data file cannot be open\n"); exit(0); } // 写入总点数N if (fwrite(&N, sizeof(N), 1, fin) != 1) { printf("Failed to write total points count to file\n"); exit(0); } // 逐个写入每个point的namelength for (int i = 0; i < N; i++) { if (fwrite(&POINTS[i].namelength, sizeof(unsigned char), 1, fin) != 1) { printf("Failed to write namelength for point %d\n", i); exit(0); } } // 写入所有name的字符内容(保留你原来的逻辑) for (int i=0; i < N; i++){ if (POINTS[i].namelength){ if( fwrite(POINTS[i].name, sizeof(char), POINTS[i].namelength, fin) != POINTS[i].namelength){ printf("when writing names to the output binary data file\n"); exit(0); } } } fclose(fin); // 别忘了关闭文件,确保数据写入磁盘
二、正确的读取流程
读取时要严格对应写入的顺序,并且注意用rb模式打开文件(Windows下文本模式会破坏二进制数据):
- 用
rb模式打开二进制文件 - 读取总点数
N - 分配
point数组内存 - 逐个读取每个
point的namelength,同时计算总字符数namestot - 分配所有name的内存
- 读取所有name内容,再根据正确的
namelength设置name指针
修正后的读取代码:
// 打开二进制输入文件,必须用rb模式! if ((fin = fopen (argv[1], "rb")) == NULL){ printf("the data file does not exist or cannot be opened\n"); exit(0); } // 读取总点数N if (fread(&N, sizeof(N), 1, fin) != 1) { printf("Failed to read total points count from file\n"); exit(0); } // 分配point数组内存 if((POINTS = (point *) malloc (N * sizeof(point))) == NULL){ printf("when allocating memory for the points vector\n"); exit(0); } // 读取每个namelength并计算总字符数namestot size_t namestot = 0; for (int i = 0; i < N; i++) { if (fread(&POINTS[i].namelength, sizeof(unsigned char), 1, fin) != 1) { printf("Failed to read namelength for point %d\n", i); exit(0); } namestot += POINTS[i].namelength; } // 分配所有name的内存 char *allnames = NULL; if((allnames = (char *) malloc (namestot * sizeof(char))) == NULL){ printf("when allocating memory for the names vector"); exit(0); } // 读取所有name内容 if (fread(allnames, sizeof(char), namestot, fin) != namestot){ printf("when reading names from the binary data file\n"); exit(0); } // 设置name指针,用临时指针避免破坏allnames的起始地址 char *current_ptr = allnames; for (int i = 0; i < N; i++){ if(POINTS[i].namelength > 0){ POINTS[i].name = current_ptr; current_ptr += POINTS[i].namelength; // 如果你需要用printf("%s")打印,这里可以手动加'\0'(注意要提前多分配内存) // *current_ptr = '\0'; // current_ptr++; } else { POINTS[i].name = NULL; // 空name设置为NULL,避免野指针 } } fclose(fin); // 关闭文件 // 后续使用完记得释放内存,避免泄漏 // free(POINTS); // free(allnames);
三、额外注意事项
- 二进制模式必须用对:写入用
wb,读取用rb,Windows系统中文本模式会自动转换换行符,导致二进制数据错位。 - 字符串结尾问题:如果原结构体的
name是C风格字符串(带'\0'),写入时要把'\0'也计入namelength并写入;如果没有'\0',打印时要指定长度,比如printf("%.*s", POINTS[i].namelength, POINTS[i].name),避免越界访问。 - 内存释放:程序结束前记得释放
POINTS和allnames的内存,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Arduino
相关产品推荐
相关产品推荐

