C语言字节转DNA字符打印时末尾出现多余字节问题求助
嘿,我帮你揪出几个导致解码后出现多余字节的核心问题,咱们一个个拆解解决:
1. B2T函数返回局部数组,触发未定义行为
你在B2T里定义的res[4]是局部栈数组,函数执行完毕后,这块内存会被系统回收。返回它的指针相当于返回一个无效的内存地址,后续用这个指针读取内容时,会拿到内存里的随机垃圾数据,这就是你看到多余字节的重要原因之一。
修复方案:
让调用者提前准备好数组并传入函数,简单又安全:
// 修改B2T,让调用者传入存储结果的数组 void B2T(int num, char* res) { int sw[] = { 6,4,2,0 }; char tab[4] = { 'A', 'C', 'G', 'T' }; for (int i = 0; i < 4; i++) { res[i] = tab[(num >> sw[i]) & 3]; } res[4] = '\0'; // 必须添加字符串终止符! }
调用的时候在main的解码分支里这样写:
char ress[5]; // 4个字符 + 1个终止符 B2T(temp, ress); printf_s("%s\n", ress);
2. 字符串缺少终止符,导致printf_s越界输出
C语言里的字符串必须以'\0'结尾,printf_s("%s")会一直读取直到遇到这个终止符。你原来的res[4]只存了4个字符,没有预留终止符的位置,所以printf_s会继续读取内存中后面的随机数据,表现为多余字节。
上面的修复方案已经顺便解决了这个问题——把数组扩容到能容纳终止符,并且手动添加res[4] = '\0'。
3. feof的使用方式错误,会多读一次无效数据
feof的特性是:只有当读取操作失败后,它才会返回真。你用while(feof(I)==0)的写法,会导致最后一次读取失败后,仍然进入循环处理无效的temp值,这也可能带来异常输出。
修复方案:把读取操作直接放在循环条件里,比如解码分支改成:
case 'd': fopen_s(&I, "result.bin", "r"); // 用fscanf_s的返回值判断是否读取成功 while (fscanf_s(I, "%X", &temp) == 1) { char ress[5]; B2T(temp, ress); printf_s("%s\n", ress); } fclose(I); break;
编码分支同理,把while(feof(I)==0)改成while(fscanf_s(I, "%s", tab, 5) == 1)。
4. 编码时写入的是文本格式,不是真正的二进制字节
你现在用fprintf_s(O, "%X ", res)写入的是文本形式的十六进制字符串(比如"3F "),而不是你想要的二进制字节。如果你的需求是“编码为字节”,应该用二进制方式写入:
// 编码分支里替换fprintf_s为fwrite fwrite(&res, sizeof(unsigned char), 1, O); // 假设res是单字节值,根据实际情况调整类型
对应的解码用fread读取二进制:
unsigned char temp; while (fread(&temp, sizeof(unsigned char), 1, I) == 1) { char ress[5]; B2T(temp, ress); printf_s("%s\n", ress); }
这样才是真正的字节级编码/解码,避免文本格式带来的额外问题。
把这些问题都修复后,你应该就能得到预期的4字符序列,不会再出现多余字节了。
内容的提问来源于stack exchange,提问作者daniktl

