CS50课程WAV音频反转代码无法通过check50检测求助
CS50 WAV反转过滤器check50不通过问题排查
我是编程新手,正在为CS50课程编写WAV音频反转过滤器代码。代码完成后,测试输入文件时主观听感是反转的,但check50功能提示文件未被正确反转。我反复检查代码未发现问题,且将输出文件再次反转后与原文件完全一致。附上代码如下:
#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include "wav.h" int check_format(WAVHEADER header); int get_block_size(WAVHEADER header); int main(int argc, char *argv[]) { // Ensure proper usage // TODO #1 // Check command-line arguments if (argc != 3) { printf("Usage: ./reverse input.wav output.wav\n"); return 1; } // Open input file for reading // TODO #2 // “read-only” mode FILE *input = fopen(argv[1], "r"); if (input == NULL) { printf("Could not open %s.\n", argv[1]); return 1; } // Read header // TODO #3 WAVHEADER header; fread(&header, sizeof(WAVHEADER), 1, input); // Use check_format to ensure WAV format // TODO #4 if (!check_format(header)) { printf("Not a WAV file.\n"); return 1; } // Open output file for writing // TODO #5 // write mode FILE *output = fopen(argv[2], "w"); if (output == NULL) { printf("Could not open %s.\n", argv[2]); return 1; } // Write header to file // TODO #6 fwrite(&header, sizeof(WAVHEADER), 1, output); // Use get_block_size to calculate size of block // TODO #7 int size = get_block_size(header); // Write reversed audio to file // TODO #8 BYTE buffer[size]; if (fseek(input, size, SEEK_END)) { return 1; } while (ftell(input) - size > sizeof(header)) { if (fseek(input, - 2 * size, SEEK_CUR)) { return 1; } fread(buffer, size, 1, input); fwrite(buffer, size, 1, output); } fclose(output); fclose(input); } int check_format(WAVHEADER header) { // TODO #4 if (header.format[0] == 'W' && header.format[1] == 'A' && header.format[2] == 'V' && header.format[3] == 'E') { return 1; } return 0; } int get_block_size(WAVHEADER header) { // TODO #7 int size = header.numChannels * header.bitsPerSample/8; return size; }
问题排查与修复
- 文件打开模式错误
WAV是二进制文件,你用了文本模式的"r"和"w"打开文件,在Windows系统下,文本模式会自动转换换行符(将\n转为\r\n),这会破坏WAV文件的二进制数据结构,导致check50检测到文件不一致。需要改为二进制模式:
FILE *input = fopen(argv[1], "rb"); FILE *output = fopen(argv[2], "wb");
- 循环条件遗漏最后一个音频块
当前循环条件ftell(input) - size > sizeof(header)会导致当文件指针刚好在sizeof(header) + size位置时,最后一个块不会被处理。应该调整循环条件,确保所有音频块都被读取:
// 初始定位到文件末尾,然后回退一个块大小 if (fseek(input, -size, SEEK_END)) { return 1; } // 只要当前位置大于等于header的大小,就继续读取 while (ftell(input) >= sizeof(header)) { fread(buffer, size, 1, input); fwrite(buffer, size, 1, output); // 回退两个块大小:因为读完一个块后指针已经前进了size,所以需要回退2*size到上一个块的起始位置 if (fseek(input, -2 * size, SEEK_CUR)) { return 1; } }
- 块大小计算的优先级问题
虽然当前计算结果正确,但header.numChannels * header.bitsPerSample/8的运算优先级可能会让人误解,建议加上括号明确顺序:
int size = (header.numChannels * header.bitsPerSample) / 8;
修复以上问题后,check50应该就能正确通过检测了。
内容的提问来源于stack exchange,提问作者Amelia
相关产品推荐
相关产品推荐

