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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 11:42:31