CS50x作业:C语言反转WAV音频代码异常求助(音频不清晰)
WAV音频反转代码仅部分生效的问题排查(CS50x PSet4)
我编写了一段用于反转WAV音频文件的C语言代码,代码可正常编译,但反转后的音频无法清晰播放,仅实现了部分反转效果。这是CS50x课程的第4个作业集,我认为问题出在代码的TODO #8部分,请求帮助排查问题。代码如下:
#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("entre input and output file names\n"); return 1; } // Open input file for reading // TODO #2 char *infile = argv[1]; char *outfile = argv[2]; FILE *inptr = fopen(infile, "r"); if (inptr == NULL) { printf("error opening file\n"); fclose(inptr); return 2; } // Read header // TODO #3 WAVHEADER wv; fread(&wv, sizeof(WAVHEADER), 1, inptr); long position = ftell(inptr); // Use check_format to ensure WAV format // TODO #4 if (check_format(wv) == -1) { printf("input is not a wav.h file\n"); fclose(inptr); return 3; } // Open output file for writing // TODO #5 FILE *outptr = fopen(outfile, "wb"); if (outptr == NULL) { printf("error opening output file\n"); fclose(outptr); fclose(inptr); return 4; } // Write header to file // TODO #6 fwrite(&wv, sizeof(WAVHEADER), 1, outptr); // Use get_block_size to calculate size of block // TODO #7 int blsize = get_block_size(wv); // Write reversed audio to file // TODO #8 DWORD bufferSize = wv.subchunk2Size; int16_t *audio = malloc(bufferSize); fseek(inptr, blsize, SEEK_END); fseek(outptr, position, SEEK_SET); for (int i = 0; i < bufferSize / blsize; i++) { fread(&audio[i], blsize, 1, inptr); fseek(inptr, (-2) * blsize, SEEK_CUR); fwrite(&audio[i], blsize, 1, outptr); } fclose(outptr); fclose(inptr); free(audio); } int check_format(WAVHEADER header) { // TODO #4 char elmnts[] = {'W', 'A', 'V', 'E', '\0'}; for (int i = 0; i < 4; i++) { if (elmnts[i] != header.format[i]) { return -1; } } return 0; } int get_block_size(WAVHEADER header) { // TODO #7 int blsize = header.numChannels * (header.bitsPerSample / 8); return blsize; }
问题排查与修正
你的代码在TODO #8部分存在两个关键问题,导致反转不完整或音频损坏:
初始文件指针定位错误
你用fseek(inptr, blsize, SEEK_END);将输入文件指针从末尾向前移动blsize字节,但这里的偏移量应该是负数——因为SEEK_END指向文件末尾,正数偏移会让指针超出文件范围,导致第一次读取失败。正确的初始定位应该是:fseek(inptr, -blsize, SEEK_END);这样指针会落在最后一个音频块的起始位置,确保第一次读取的是最后一个有效块。
音频缓冲区类型不匹配
你使用int16_t *audio作为缓冲区,但blsize(每个音频块的字节数)可能不等于sizeof(int16_t)(比如立体声16位WAV的blsize是4字节)。这会导致&audio[i]每次只移动2字节,读写时覆盖缓冲区的相邻元素,造成数据错乱。应该改用无类型的uint8_t指针来适配任意块大小:uint8_t *audio = malloc(bufferSize);循环边界的指针越界风险
当循环执行到最后一次时,fseek(inptr, (-2)*blsize, SEEK_CUR);会让指针跳到文件开头之前的位置,虽然最后一次读取后不需要再跳转,但可以通过调整循环条件避免不必要的跳转:if (i < (bufferSize / blsize) - 1) { fseek(inptr, -2 * blsize, SEEK_CUR); }
修正后的TODO #8代码片段
// Write reversed audio to file // TODO #8 DWORD bufferSize = wv.subchunk2Size; // 使用uint8_t适配任意块大小 uint8_t *audio = malloc(bufferSize); if (audio == NULL) { fclose(outptr); fclose(inptr); printf("Memory allocation failed\n"); return 5; } // 定位到最后一个音频块的起始位置 fseek(inptr, -blsize, SEEK_END); // 写完header后,outptr已经在音频数据起始位置,不需要额外fseek for (int i = 0; i < bufferSize / blsize; i++) { fread(audio, blsize, 1, inptr); fwrite(audio, blsize, 1, outptr); if (i < (bufferSize / blsize) - 1) { fseek(inptr, -2 * blsize, SEEK_CUR); } } fclose(outptr); fclose(inptr); free(audio);
另外补充两个小细节修正:
printf("entre input and output file names\n");中的entre拼写错误,应为Enter;printf("input is not a wav.h file\n");应为input is not a WAV file,因为检查的是WAV格式而非头文件。
内容的提问来源于stack exchange,提问作者sadhi
相关产品推荐
相关产品推荐

