ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • CS50 Week4: Problem Set, Reverse
    Programming/CS50 2023. 7. 17. 17:15

    하버드 CS50 강의 4주차 Poblem Set 과제 Reverse 의 풀이 과정을 다룹니다.
    바이너리 파일의 구조를 이해하고 데이터를 의미 있는 단위로 역순으로 처리해야 합니다.
    C언어로 파일 스트림의 위치를 제어하여 조작하는 문제입니다.

    Task

    문제 링크에서 자세한 내용을 확인할 수 있습니다.

    WAV 오디오 파일을 뒤집는 과제

    ./reverse input.wav output.wav

    Template

    템플릿이 주어지며, 필요한 부분을 채워주면 됩니다.

    #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
    
        // Open input file for reading
        // TODO #2
    
        // Read header
        // TODO #3
    
        // Use check_format to ensure WAV format
        // TODO #4
    
        // Open output file for writing
        // TODO #5
    
        // Write header to file
        // TODO #6
    
        // Use get_block_size to calculate size of block
        // TODO #7
    
        // Write reversed audio to file
        // TODO #8
    }
    
    int check_format(WAVHEADER header)
    {
        // TODO #4
        return 0;
    }
    
    int get_block_size(WAVHEADER header)
    {
        // TODO #7
        return 0;
    }

    Code

    Todo #1: Ensure proper usage

    인자 수가 맞는지 확인한다.

    // Ensure proper usage
    if (argc != 3)
    {
        printf("Usage: ./reverse input.wav output.wav\n");
        return 1;
    }

    Todo #2: Open input file for reading

    파일을 열어준다. 이전 과제에서 언급했듯, 윈도우일 경우 "rb"를 사용해야 한다.

    // Open input file for reading
    FILE *inptr = fopen(argv[1], "rb");
    if (inptr == NULL)
    {
        printf("Could not open %s.\n", argv[1]);
        return 1;
    }

    Todo #3: Read header

    헤더를 읽어온다. 첫 8~11 바이트가 헤더이다.

    // Read header
    WAVHEADER header;
    fread(&header, sizeof(WAVHEADER), 1, inptr);

    Todo #4: Use check_format to ensure WAV format

    WAV 파일인지 확인한다.

    // Use check_format to ensure WAV format
    if (!check_format(header))
    {
        printf("Input is not a WAV file.\n");
        fclose(inptr);
        return 1;
    }

    check_format 함수

    헤더는 "WAVE"로 시작한다.

    글자를 비교하기 때문에 작은 따옴표 ' 사용해야 함에 유의.

    bool check_format(WAVHEADER header)
    {
        if (header.format[0] == 'W' &&
            header.format[1] == 'A' &&
            header.format[2] == 'V' &&
            header.format[3] == 'E')
        {
            return true;
        }
    
        return false;
    }

    Todo #5: Open output file for writing

    "wb"를 사용해야 한다.

    // Open output file for writing
    FILE *outptr = fopen(argv[2], "wb");
    if (outptr == NULL)
    {
        printf("Could not create %s.\n", argv[2]);
        fclose(inptr);
        return 1;
    }

    Todo #6: Write header to file

    읽는 것과 반대로 쓰면 된다.

    // Write header to file
    fwrite(&header, sizeof(WAVHEADER), 1, outptr);

    Todo #7: Use get_block_size to calculate size of block

    호출만 하면 된다.

    // Use get_block_size to calculate size of block
    int block_size = get_block_size(header);

    get_block_size 함수

    간단하다. blockAlign 값을 반환하면 된다.

    int get_block_size(WAVHEADER header)
    {
        return (int) header.blockAlign;
    }

    Todo #8: Write reversed audio to file

    파일을 거꾸로 읽어야 한다. 여러 방법을 시도해 보다가 아래 방법을 적용하기로 했다.

    SEEK_END를 써서 마지막 위치를 찾고 거기서부터 블록 사이즈단위로 읽어서 쓰면 된다.

    // Write reversed audio to file
    BYTE buffer[block_size];
    
    long start_position = ftell(inptr);
    
    fseek(inptr, 0L, SEEK_END);
    long end_position = ftell(inptr);
    
    
    for (long pos = end_position - block_size; pos >= start_position; pos -= block_size)
    {
        fseek(inptr, pos, SEEK_SET);
        fread(buffer, block_size, 1, inptr);
        fwrite(buffer, block_size, 1, outptr);
    }
    
    fclose(inptr);
    fclose(outptr);

    댓글