[CS50] 메모리 - 파일 입출력

TIL

사용자에게 입력을 받는 함수는 어떻게 구현할 수 있을까? 파일을 읽고 쓰는 방법을 알아보자.

 

메모리 구조를 다시 한 번 살펴보면,

메모리 영역

  • 머신 코드: 프로그램이 컴파일된 바이너리
  • 글로벌: 프로그램 안에서 저장된 전역 변수
  • 힙: malloc으로 할당된 메모리의 데이터
  • 스택: 프로그램 내의 함수와 관련된 것들

힙 영역에서는 malloc에 의해 메모리가 더 할당될수록 아래로 늘어나고, 스택 영역에서는 함수가 더 많이 호출될수록 위로 늘어난다.

 

제한된 메모리 용량 하에서 점점 늘어나다 보면 기존의 값을 침범하는 상황이 발생하는데, 이를 힙 오버플로우 또는 스택 오버플로우라고 한다.

 

사용자에게 입력 받기

get_int 구현

#include <stdio.h>

int main(void)
{
    int x;
    printf("x: ");
    scanf("%i", &x);
    printf("x: %i\n", x);
}
  • scanf("%i", &x): &x로 주소를 전달
  • scanf 함수가 스택 영역 안에 x가 저장된 주소로 찾아가서 값을 저장

 

get_string 구현

#include <stdio.h>

int main(void)
{
    char s[5];
    printf("s: ");
    scanf("%s", s);
    printf("s: %s\n", s);
}
  • scanf("%s", s): 배열 이름 s를 그대로 전달
  • s는 크기가 5인 문자 배열로 정의
  • clang 컴파일러는 문자 배열의 이름을 포인터처럼 다룸
  • s는 배열의 첫 바이트 주소를 의미

 

파일 쓰기

이제 사용자로부터 입력을 받아 파일에 저장하는 프로그램을 작성할 수 있다.

#include <cs50.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
    FILE *file = fopen("phonebook.csv", "a");
    char *name = get_string("Name: ");
    char *number = get_string("Number: ");
    fprintf(file, "%s,%s\n", name, number);
    fclose(file);
}

 

주요 함수

fopen

FILE *file = fopen("파일명", "모드");
  • 파일을 FILE 자료형으로 불러옴
  • 모드:
    • r: 읽기 (read)
    • w: 쓰기 (write)
    • a: 덧붙이기 (append)

 

fprintf

fprintf(file, "형식", 변수들...);
  • printf처럼 파일에 직접 내용을 출력

 

fclose

fclose(file);
  • 파일 작업 종료
  • 반드시 호출해야 함

 

완성된 예제

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    FILE *file = fopen("phonebook.csv", "a");

    if (file == NULL)
    {
        return 1;  // 파일 열기 실패
    }

    char *name = get_string("Name: ");
    char *number = get_string("Number: ");

    fprintf(file, "%s,%s\n", name, number);

    fclose(file);
    return 0;
}

 

파일 읽기

우리가 사용하는 파일은 텍스트, 이미지, 영상 등 여러 형식이 있다. JPEG 형식의 파일은 그 값 속에 JPEG 파일 형식임을 알려주는 단서가 있다. 파일 내용을 읽고 형식을 구분하는 방법을 알아보자.

JPEG 파일 검사 프로그램

#include <stdio.h>

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        return 1;
    }

    FILE *file = fopen(argv[1], "r");

    if (file == NULL)
    {
        return 1;
    }

    unsigned char bytes[3];
    fread(bytes, 3, 1, file);

    if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff)
    {
        printf("Maybe\n");
    }
    else
    {
        printf("No\n");
    }

    fclose(file);
}

 

코드 분석

1. 명령행 인자 확인:

if (argc != 2)
{
    return 1;
}
  • argc가 2가 아니면 오류
  • 프로그램명 + 파일명 = 2개여야 함

 

2. 파일 열기:

FILE *file = fopen(argv[1], "r");
  • 입력받은 파일명을 읽기 모드로 열기
  • argv[1]은 첫 번째 명령행 인자 (파일명)

 

3. NULL 검사:

if (file == NULL)
{
    return 1;
}
  • 파일이 열리지 않으면 fopen은 NULL 반환
  • 오류 처리

 

4. 파일 읽기:

unsigned char bytes[3];
fread(bytes, 3, 1, file);
  • fread 함수로 파일에서 3바이트 읽기
  • 인자: (배열, 읽을 바이트 수, 읽을 횟수, 읽을 파일)

 

5. JPEG 검사:

if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff)
{
    printf("Maybe\n");
}
  • JPEG 파일은 항상 0xFF 0xD8 0xFF로 시작
  • 이는 JPEG 형식의 약속 (매직 넘버)

 

매직 넘버 (Magic Number)

대부분의 파일 형식에는 특정한 바이트 패턴이 존재하며, 이를 매직 넘버라고 한다.

파일 형식 매직 넘버 설명
JPEG FF D8 FF 파일 시작 부분
PNG 89 50 4E 47 89, 'P', 'N', 'G'
PDF 25 50 44 46 '%', 'P', 'D', 'F'
ZIP 50 4B 03 04 'P', 'K', ...

 

파일 입출력 함수 정리

함수 용도 예시
fopen 파일 열기 fopen("file.txt", "r")
fclose 파일 닫기 fclose(file)
fprintf 파일에 쓰기 fprintf(file, "%s", text)
fread 파일에서 읽기 fread(buffer, size, count, file)
fwrite 바이너리 쓰기 fwrite(data, size, count, file)

 

'TIL' 카테고리의 다른 글

React 객체 state 관리와 useRef 활용하기  (0) 2025.11.08
React로 사용자 입력 관리하기  (0) 2025.11.08
[CS50] 메모리 - 메모리 교환, 스택, 힙  (0) 2025.11.08
[CS50] 메모리 - 메모리 할당과 해제  (0) 2025.11.08
[CS50] 메모리 - 문자열 복사  (0) 2025.11.08
'TIL' 카테고리의 다른 글
  • React 객체 state 관리와 useRef 활용하기
  • React로 사용자 입력 관리하기
  • [CS50] 메모리 - 메모리 교환, 스택, 힙
  • [CS50] 메모리 - 메모리 할당과 해제
고견
고견
개발 자국 남기기
  • 고견
    개발자국
    고견
  • 전체
    오늘
    어제
    • 분류 전체보기 (157) N
      • Frontend (29)
        • Next.js (16)
        • JavaScript (7)
      • CS (19) N
        • 자료구조 (9)
        • 알고리즘 (5)
        • 운영체제 (4) N
        • 네트워크 (1) N
      • TIL (93)
      • Dev Log (16)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    배열
    C
    자료구조
    generic
    useState
    제네릭
    문자열
    Pages Router
    알고리즘
    인터페이스
    Next.js
    App Router
    페이지 라우터
    cs50
    Trouble Shooting
    CS
    emotion diary
    ai 감성 일기장
    react
    트러블 슈팅
    algorithm
    memory
    타입 좁히기
    Spa
    함수 타입
    javascript
    앱 라우터
    바닐라 자바스크립트
    typescript
    클래스
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
고견
[CS50] 메모리 - 파일 입출력
상단으로

티스토리툴바