You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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部分存在两个关键问题,导致反转不完整或音频损坏:

  1. 初始文件指针定位错误
    你用fseek(inptr, blsize, SEEK_END);将输入文件指针从末尾向前移动blsize字节,但这里的偏移量应该是负数——因为SEEK_END指向文件末尾,正数偏移会让指针超出文件范围,导致第一次读取失败。正确的初始定位应该是:

    fseek(inptr, -blsize, SEEK_END);
    

    这样指针会落在最后一个音频块的起始位置,确保第一次读取的是最后一个有效块。

  2. 音频缓冲区类型不匹配
    你使用int16_t *audio作为缓冲区,但blsize(每个音频块的字节数)可能不等于sizeof(int16_t)(比如立体声16位WAV的blsize是4字节)。这会导致&audio[i]每次只移动2字节,读写时覆盖缓冲区的相邻元素,造成数据错乱。应该改用无类型的uint8_t指针来适配任意块大小:

    uint8_t *audio = malloc(bufferSize);
    
  3. 循环边界的指针越界风险
    当循环执行到最后一次时,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 08:06:02