从自制二进制文件调用fread()时触发Segmentation Fault问题求助
问题排查与修复方案
咱们先直接点明核心问题:你写入二进制文件的是指针的内存地址,而不是字符串的实际内容,这就是读取时触发段错误的根本原因。
为什么会触发段错误?
你的struct sequence里的char *sequence和char *label是指针变量,它们存储的是字符串在内存中的起始地址。当你用fwrite(&final_entry, sizeof(struct sequence), 1, out)写入文件时,实际上只把这两个地址值(比如0x7f123456)写进了二进制文件。
而第二个程序运行时,它的进程内存空间和第一个程序完全独立——第一个程序里的内存地址在新进程里要么是无效的,要么指向的是随机垃圾数据。当你用printf访问这些指针时,自然会触发段错误。
第一个脚本的其他潜在问题
除了核心的指针存储问题,你的第一个脚本还有几个会导致未定义行为的bug:
- 未初始化的
fasta数组:char fasta[BUZZ_SIZE];没有初始化,直接用strcat拼接会从随机内存位置开始写入,大概率会破坏其他数据。 - 数组越界:
char *seqs[3];只能存3个指针,但你要处理4个序列,循环idx<4会越界写入栈内存,可能导致程序崩溃或数据错乱。char *this_seq[1];只能存1个指针,但你要存label和sequence两个值,同样会越界。
- 嵌套使用
strtok的风险:strtok依赖全局状态,嵌套调用(外层按>分割,内层按\n分割)很容易出现逻辑错误,比如后续的strtok会干扰前一个的状态。
具体修复方案
要解决问题,你需要把字符串的实际内容写入二进制文件,而不是指针。这里提供两种可行思路:
思路1:使用固定大小字符数组(简单直接)
修改结构体,把指针换成固定大小的字符数组,这样写入时会直接存储字符串内容:
#define MAX_LABEL_LEN 64 #define MAX_SEQ_LEN 256 struct sequence { char sequence[MAX_SEQ_LEN]; char label[MAX_LABEL_LEN]; };
然后在第一个脚本中,用strncpy把内容复制到结构体的数组里,记得手动添加字符串终止符:
// 替换原来的final_entry赋值逻辑 strncpy(final_entry.label, this_seq[0], MAX_LABEL_LEN - 1); final_entry.label[MAX_LABEL_LEN - 1] = '\0'; // 确保字符串结尾 strncpy(final_entry.sequence, this_seq[1], MAX_SEQ_LEN - 1); final_entry.sequence[MAX_SEQ_LEN - 1] = '\0';
这样修改后,fwrite写入的就是结构体里的实际字符串内容,第二个脚本读取后可以直接正常访问。
思路2:存储长度+内容(支持可变长度)
如果你的序列长度不固定,这个方案更灵活:写入时先存字符串的长度,再存内容;读取时先读长度,再分配内存读取内容。
写入脚本修改:
// 针对每个sequence,依次写入label长度、label内容、序列长度、序列内容 size_t label_len = strlen(final_entry.label); fwrite(&label_len, sizeof(size_t), 1, out); fwrite(final_entry.label, sizeof(char), label_len, out); size_t seq_len = strlen(final_entry.sequence); fwrite(&seq_len, sizeof(size_t), 1, out); fwrite(final_entry.sequence, sizeof(char), seq_len, out);
读取脚本修改:
struct sequence this_seq; size_t len; for (n=0;n<4;n++) { // 读取label fread(&len, sizeof(size_t), 1, fasta_bin); this_seq.label = malloc(len + 1); // 分配内存,预留终止符位置 fread(this_seq.label, sizeof(char), len, fasta_bin); this_seq.label[len] = '\0'; // 读取sequence fread(&len, sizeof(size_t), 1, fasta_bin); this_seq.sequence = malloc(len + 1); fread(this_seq.sequence, sizeof(char), len, fasta_bin); this_seq.sequence[len] = '\0'; printf(">%s\n%s\n", this_seq.label, this_seq.sequence); // 记得释放内存,避免泄漏 free(this_seq.label); free(this_seq.sequence); }
额外的第一个脚本优化建议
- 初始化
fasta数组:char fasta[BUZZ_SIZE] = {0};,避免strcat的未定义行为。 - 调整数组大小:把
char *seqs[3];改成char *seqs[4];,char *this_seq[1];改成char *this_seq[2];,避免越界。 - 不要一次性读入整个文件:如果FASTA文件很大,
BUZZ_SIZE会不够用,建议逐行处理,而不是把整个文件拼进fasta数组。
内容的提问来源于stack exchange,提问作者kamses
相关产品推荐
相关产品推荐

