CS50课程WAV音频反转代码无法通过check50,求排查问题
反转WAV音频文件的CS50 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 if (argc != 3) { printf("Usage: ./reverse inputfilename.wav outputfilename.wav\n"); return 1; } // Open input file for reading // TODO #2 FILE *input = fopen(argv[1], "r"); if (input == NULL) { printf("Could not open %s.\n", argv[1]); return 1; } // Read header // TODO #3 WAVHEADER *buffer = malloc(1 * sizeof(WAVHEADER)); fread(buffer, sizeof(WAVHEADER), 1, input); // Use check_format to ensure WAV format // TODO #4 if (check_format(*buffer) == 1) { printf("input file format not supported\n"); return 1; } // Open output file for writing // TODO #5 FILE *output = fopen(argv[2], "w"); if (output == NULL) { fclose(input); printf("Could not create %s.\n", argv[2]); return 5; } // Write header to file // TODO #6 fwrite(buffer, sizeof(WAVHEADER), 1, output); // Use get_block_size to calculate size of block // TODO #7 int block_size = get_block_size(*buffer); // Write reversed audio to file // TODO #8 FILE *temp = malloc(block_size); fseek(input, -1 * block_size, SEEK_END); fread(temp, block_size, 1, input); fwrite(temp, block_size, 1, output); while (ftell(input) > 44 || ftell(input) == 44) { fseek(input, -2 * block_size, SEEK_CUR); fread(temp, block_size, 1, input); fwrite(temp, block_size, 1, output); } fclose(input); fclose(output); free(temp); free(buffer); } 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 answer = 0; answer = (header.bitsPerSample / 8) * header.numChannels; return answer; }
问题分析与修正点
- 文件打开模式错误:WAV是二进制文件,必须用二进制模式打开,原代码用
"r"和"w"是文本模式,会在Windows系统中自动转换换行符,破坏二进制数据。需改为"rb"(读二进制)和"wb"(写二进制)。 - 临时缓冲区类型错误:
FILE *temp = malloc(block_size);这里temp是音频数据缓冲区,应该用uint8_t*或char*类型,而非FILE*,类型不匹配会导致内存读写错误。 - 循环条件错误:原循环条件
ftell(input) > 44 || ftell(input) == 44会导致当文件指针在44字节位置(音频数据起始处)时,继续向前偏移-2*block_size,跑到WAV头部区域,读取无效数据。应改为ftell(input) >= sizeof(WAVHEADER),确保只处理音频数据部分。 - 内存分配未检查:
malloc可能返回NULL,需添加检查避免空指针操作。
修正后的代码
#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[]) { if (argc != 3) { printf("Usage: ./reverse inputfilename.wav outputfilename.wav\n"); return 1; } FILE *input = fopen(argv[1], "rb"); if (input == NULL) { printf("Could not open %s.\n", argv[1]); return 1; } WAVHEADER *buffer = malloc(sizeof(WAVHEADER)); if (buffer == NULL) { fclose(input); printf("Memory allocation failed.\n"); return 1; } fread(buffer, sizeof(WAVHEADER), 1, input); if (check_format(*buffer) == 1) { printf("input file format not supported\n"); free(buffer); fclose(input); return 1; } FILE *output = fopen(argv[2], "wb"); if (output == NULL) { free(buffer); fclose(input); printf("Could not create %s.\n", argv[2]); return 5; } fwrite(buffer, sizeof(WAVHEADER), 1, output); int block_size = get_block_size(*buffer); uint8_t *temp = malloc(block_size); if (temp == NULL) { free(buffer); fclose(input); fclose(output); printf("Memory allocation failed.\n"); return 1; } // 定位到最后一个音频块 fseek(input, -block_size, SEEK_END); while (ftell(input) >= sizeof(WAVHEADER)) { fread(temp, block_size, 1, input); fwrite(temp, block_size, 1, output); // 向前跳两个块:当前位置是读完的块的起始位置,跳-2*block_size到前一个块的起始位置 if (ftell(input) > sizeof(WAVHEADER)) { fseek(input, -2 * block_size, SEEK_CUR); } else { break; } } fclose(input); fclose(output); free(temp); free(buffer); return 0; } int check_format(WAVHEADER header) { return (header.format[0] != 'W' || header.format[1] != 'A' || header.format[2] != 'V' || header.format[3] != 'E') ? 1 : 0; } int get_block_size(WAVHEADER header) { return (header.bitsPerSample / 8) * header.numChannels; }
内容的提问来源于stack exchange,提问作者user75470
相关产品推荐
相关产品推荐

