동글c
동글한 스터디룸
동글c
전체 방문자
오늘
어제
  • 분류 전체보기 (14)
    • 입문 (14)
      • CS50X (14)
      • 컴퓨터과학이 여는 세계 (0)
    • 컴퓨터 구조 (0)
      • CSAPP (0)
    • 프로그래밍 (0)
      • SICP (0)
    • 회고 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • Datastructure
  • bubblesort
  • pointers
  • MergeSort
  • tree
  • 반복문
  • LinkedList
  • Harvard CS50
  • Volume
  • problemset2
  • loops
  • Strings
  • Hashtable
  • selectionsort
  • speller
  • computerscience
  • recover
  • int
  • tiedman
  • 포인터
  • DICTIONARY
  • hash
  • scratch
  • 조건문
  • compiling
  • Trie
  • command-line arguments
  • overflow
  • types
  • CS50

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
동글c

동글한 스터디룸

입문/CS50X

[CS50X] 2024 Week4 Memory Problem Set 4 (Volume, Filter, Recover)

2024. 2. 29. 10:40

 

 

Volume

문제 링크

https://cs50.harvard.edu/x/2024/psets/4/volume/

 

Volume - CS50x 2024

Harvard University's introduction to the intellectual enterprises of computer science and the art of programming.

cs50.harvard.edu

 

기본 제공 파일 / 의사코드 추가

// Modifies the volume of an audio file

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

// Number of bytes in .wav header
const int HEADER_SIZE = 44;

int main(int argc, char *argv[])
{
    // Check command-line arguments
    if (argc != 4)
    {
        printf("Usage: ./volume input.wav output.wav factor\n");
        return 1;
    }

    // Open files and determine scaling factor
    FILE *input = fopen(argv[1], "r");
    if (input == NULL)
    {
        printf("Could not open file.\n");
        return 1;
    }

    FILE *output = fopen(argv[2], "w");
    if (output == NULL)
    {
        printf("Could not open file.\n");
        return 1;
    }

    float factor = atof(argv[3]);

    // TODO: Copy header from input file to output file
    // 1. 44byte 크기의 메모리 공간 만들기
    // 2. input header 을 읽고 output header에 쓰기

    // TODO: Read samples from input file and write updated data to output file
    // 1. sample 크기의 메모리 공간 만들기
    // 2.다음 내용을 sample이 다 읽힐때 까지 반복하기
    // 반복 input sample * factor 을 output sample 에 쓰기

    // Close files
    fclose(input);
    fclose(output);
}

 

 

실제 코드 구현

 

// Modifies the volume of an audio file

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

// Number of bytes in .wav header
const int HEADER_SIZE = 44;

int main(int argc, char *argv[])
{
    // Check command-line arguments
    if (argc != 4)
    {
        printf("Usage: ./volume input.wav output.wav factor\n");
        return 1;
    }

    // Open files and determine scaling factor
    FILE *input = fopen(argv[1], "r");
    if (input == NULL)
    {
        printf("Could not open file.\n");
        return 1;
    }

    FILE *output = fopen(argv[2], "w");
    if (output == NULL)
    {
        printf("Could not open file.\n");
        return 1;
    }

    float factor = atof(argv[3]);

    // TODO: Copy header from input file to output file
    typedef uint8_t BYTE;
    // 1. 44byte 크기의 메모리 공간 만들기
    BYTE header[HEADER_SIZE];
    // 2. input header 을 읽고 output header에 쓰기
    fread(&header, sizeof(header), 1, input);
    fwrite(&header, sizeof(header), 1, output);

    // TODO: Read samples from input file and write updated data to output file
    typedef int16_t TBYTE;
    // 1. sample 크기의 메모리 공간 만들기
    // 2.다음 내용을 sample이 다 읽힐때 까지 반복하기
    // 반복 input sample * factor 을 output sample 에 쓰기
    TBYTE sample;
    while (fread(&sample, sizeof(sample), 1, input) != 0)
    {
        sample *= factor;
        fwrite(&sample, sizeof(sample), 1, output);
    }
    // Close files
    fclose(input);
    fclose(output);
}

 

후기

fread(), fwrite() 를 이해하는 것이 생각보다 어려웠는데 

우선 uint8_t , int16_t 등 적절한 타입을 이용하거나

melloc 을 이용해서 메모리를 할당 할 수 있는데

이 할당된 임시 메모리를 버퍼 buffer 라고 한다.

두 방법의 차이점은 헤더 파일이 변하는 경우 melloc 은 동적으로 메모리를 할당 할 수 있지만

uint8_t 같은 경우 버퍼 오버플로우가 발생 할 수 있다.

 

위의 코드처럼 

BYTE header[44];

라고 한다면 44바이트 크기의 header라는 이름을 가진 임시 메모리 버퍼를 생성한 것이다.

fread(버퍼 주소, 크기, 갯수, 파일포인터);

여기서 fread(header, sizeof(header), 1, input); 을 실행하면

input 파일의 headear 사이즈 크기를 1번 버퍼 headear 에 읽히는 것이다.

컴퓨터 메모리 뿐만아니라 파일 또한 메모리로 상상할 수 있어야해서 

더 많이 접하고 고민해봐야할 것 같다.

 

 

 

 

 

 

 

 

 

Filter

문제 링크

https://cs50.harvard.edu/x/2024/psets/4/filter/more/

 

Filter - CS50x 2024

Harvard University's introduction to the intellectual enterprises of computer science and the art of programming.

cs50.harvard.edu

 

 

#include "helpers.h"
#include <math.h>

// Convert image to grayscale
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            int average = round((image[i][j].rgbtRed + image[i][j].rgbtGreen + image[i][j].rgbtBlue) / 3.0);
            image[i][j].rgbtRed = average;
            image[i][j].rgbtGreen = average;
            image[i][j].rgbtBlue = average;
        }
    }
    return;
}

// Reflect image horizontally
void reflect(int height, int width, RGBTRIPLE image[height][width])
{
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width / 2; j++)
        {
            long tempR = image[i][j].rgbtRed;
            long tempG = image[i][j].rgbtGreen;
            long tempB = image[i][j].rgbtBlue;
            image[i][j].rgbtRed = image[i][width-1-j].rgbtRed;
            image[i][j].rgbtGreen = image[i][width-1-j].rgbtGreen;
            image[i][j].rgbtBlue = image[i][width-1-j].rgbtBlue;
            image[i][width-1-j].rgbtRed = tempR;
            image[i][width-1-j].rgbtGreen = tempG;
            image[i][width-1-j].rgbtBlue = tempB;
        }
    }
    return;
}

// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
    RGBTRIPLE copy[height][width];
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            copy[i][j].rgbtBlue = image[i][j].rgbtBlue;
            copy[i][j].rgbtGreen = image[i][j].rgbtGreen;
            copy[i][j].rgbtRed = image[i][j].rgbtRed;
        }
    }

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            int totalR = 0;
            int totalG = 0;
            int totalB = 0;
            int counter = 0;
            for (int k = (i - 1); k <= (i + 1); k++)
            {
                for (int l = (j - 1); l <= (j + 1); l++)
                {
                    if((k >= 0 && k <= (height - 1)) && (l >= 0 && l <= (width - 1)))
                    {
                        totalR += copy[k][l].rgbtRed;
                        totalG += copy[k][l].rgbtGreen;
                        totalB += copy[k][l].rgbtBlue;
                        counter ++;
                    }
                }
            }
            if (counter > 0)
            {
                image[i][j].rgbtRed = (int) round((double) totalR / (double) counter);
                image[i][j].rgbtGreen = (int) round((double) totalG / (double) counter);
                image[i][j].rgbtBlue = (int) round((double) totalB / (double) counter);
            }
        }
    }
    return;
}

// Detect edges
void edges(int height, int width, RGBTRIPLE image[height][width])
{
    // 원본 이미지 가중치에 영향을 주지 않기 위해 temp image 생성
    RGBTRIPLE temp[height][width];
    // Gx, Gy 커널 배열 선언 3x3
    int Gx[3][3] = {{-1,0,1}, {-2,0,2}, {-1,0,1}};
    int Gy[3][3] = {{-1,-2,-1}, {0,0,0}, {1,2,1}};
    // temp image 에 계산된 가중치 값 할당 round, 255상한
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            double Gx_red, Gx_green, Gx_blue, Gy_red, Gy_green, Gy_blue;
            Gx_red = Gx_green = Gx_blue = Gy_red = Gy_green = Gy_blue = 0;
            for (int k = -1; k <= 1; k++)
            {
                for (int l = -1; l <= 1; l++)
                {
                    int new_i = i + k;
                    int new_j = j + l;
                    if (new_i < 0 || new_i >= height || new_j < 0 || new_j >= width)
                    {
                        continue;
                    }
                    Gx_red += image[new_i][new_j].rgbtRed * Gx[k + 1][l + 1];
                    Gx_green += image[new_i][new_j].rgbtGreen * Gx[k + 1][l + 1];
                    Gx_blue += image[new_i][new_j].rgbtBlue * Gx[k + 1][l + 1];

                    Gy_red += image[new_i][new_j].rgbtRed * Gy[k + 1][l + 1];
                    Gy_green += image[new_i][new_j].rgbtGreen * Gy[k + 1][l + 1];
                    Gy_blue += image[new_i][new_j].rgbtBlue * Gy[k + 1][l + 1];
                }
            }
            int red = round(sqrt(pow(Gx_red, 2) + pow(Gy_red, 2)));
            int green = round(sqrt(pow(Gx_green, 2) + pow(Gy_green, 2)));
            int blue = round(sqrt(pow(Gx_blue, 2) + pow(Gy_blue, 2)));

            if (red > 255)
            {
                red = 255;
            }
            if (green > 255)
            {
                green = 255;
            }
            if (blue > 255)
            {
                blue = 255;
            }
            temp[i][j].rgbtRed = red;
            temp[i][j].rgbtGreen = green;
            temp[i][j].rgbtBlue = blue;
        }
    }
    // 원본 이미지에 temp image 값 할당
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            image[i][j] = temp[i][j];
        }
    }
    return;
}

 

 

후기

생각보다 훨씬 어려운 문제였다.

생각보다 꼼꼼함이 요구됐는데 edge 같은 경우 

문제에 대한 접근보다 4중 반복문을 쓰다보니 디버깅이 쉽지 않았다.

2가지 실수를 했는데 

하나는 3x3 격자판을 이용하는 경우 원본 이미지에 가중치를 준 값으로

업데이트 하면 다음 계산에 영향을 미친다는 것을 간과했다.

* 따로 변수를 하나 temp 로 선언해서 보관했어야함

또 하나는 배열의 경계값 부분이다.

격자판 배열을 다룰때 기준은 0,0 으로 해야한다.

for 문의 시작 부분을 바꾸는 것이 낫고 index가 복잡해지는 경우 새 변수를 할당해야겠다.

 

 

 

 

 

 

 

 

Recover

문제링크

https://cs50.harvard.edu/x/2024/psets/4/recover/

 

Recover - CS50x 2024

Harvard University's introduction to the intellectual enterprises of computer science and the art of programming.

cs50.harvard.edu

 

 

 

의사코드 & 실제코드

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main(int argc, char *argv[])
{

    if (argc != 2)
    {
        return 1;
    }
    // 메모리카드 열기
    FILE *card = fopen(argv[1], "r");
    // 메모리 카드가 끝날 때 까지 반복
    uint8_t buffer[512];
    // 버퍼에다가 512 읽히기
    int counter = 0;
    char filename[8];
    FILE *jpg = NULL;
    while (fread(buffer, 1, 512, card) == 512)
    {
        // 버퍼 탐색하는데 만약 JPEG 이면
        if ((buffer[0] == 0xff) && (buffer[1] == 0xd8) && (buffer[2] == 0xff) && ((buffer[3] & 0xf0) == 0xe0))
        {
            if (jpg == NULL)
            {
                //000.jpg 로 파일 만들어서 쓰기
                sprintf(filename, "%03i.jpg", counter);
                jpg = fopen(filename, "w");
                if (jpg == NULL)
                {
                    fclose(card);
                    return 1; // 파일 열기 실패
                }
                fwrite(buffer, 1, 512, jpg);
            }
            else
            {
                // 쓰고 있는 것 닫고 새로 쓰기
                fclose(jpg);
                sprintf(filename, "%03i.jpg", counter);
                jpg = fopen(filename, "w");
                if (jpg == NULL)
                {
                    fclose(card);
                    return 1; // 파일 열기 실패
                }
                fwrite(buffer, 1, 512, jpg);
            }
            counter ++;
        }
        // JPEG 가 아니면
        else
        {
            // 이미 JPEG 파일이 열려있는 경우
            if (jpg != NULL)
            {
                fwrite(buffer, 1, 512, jpg);
            }
        }
    }
    // 파일 닫기
    if (jpg != NULL)
    {
        fclose(jpg);
    }
    fclose(card);
}

 

 

후기

오류처리를 안해서 segmentation fault (core dumped) 오류가 계속 나왔다.

논리적으로 유효한 포인터를 사용한다고 생각 해도 오류 처리를 제대로 안하면 오류가 날 수 있었다.

 

저작자표시 (새창열림)

'입문 > CS50X' 카테고리의 다른 글

[CS50X] 2024 Week5 Data Structures  (1) 2024.03.07
[CS50X] Week3 번외편(Sort 구현 - Selection, Bubble, Merge, 비트연산자 )  (0) 2024.03.05
[CS50X] 2024 Week4 Memory  (0) 2024.02.24
[CS50X] 2024 Week3 Algorithms Problem Set 3 (Sort, Plurality, Tideman)  (0) 2024.02.23
[CS50X] 2024 Week3 Algorithms  (1) 2024.02.23
    '입문/CS50X' 카테고리의 다른 글
    • [CS50X] 2024 Week5 Data Structures
    • [CS50X] Week3 번외편(Sort 구현 - Selection, Bubble, Merge, 비트연산자 )
    • [CS50X] 2024 Week4 Memory
    • [CS50X] 2024 Week3 Algorithms Problem Set 3 (Sort, Plurality, Tideman)
    동글c
    동글c
    깃허브 : https://github.com/asena1006

    티스토리툴바