Volume
문제 링크
https://cs50.harvard.edu/x/2024/psets/4/volume/
기본 제공 파일 / 의사코드 추가
// 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/
#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/
의사코드 & 실제코드
#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 |