목차5개 항목
출처와 참고
하버드 CS50(부스트코스) 5강(메모리)의 파일 쓰기·읽기 부분과 고무오리 CS 스터디의 CS50 정리 노트를 바탕으로 재구성한 노트다.
C에서 입력과 파일 처리는 모두 포인터를 기반으로 한다. scanf는 값을 저장할 주소를 받고, 파일은 FILE * 포인터로 다룬다.
scanf로 입력받기
#include <stdio.h>
int main(void)
{
int x;
printf("x: ");
scanf("%i", &x); // x의 주소를 넘겨야 그 위치에 값을 써 줄 수 있다
printf("x: %i\n", x);
}문자열은 문자 배열에 받는다.
#include <stdio.h>
int main(void)
{
char s[5];
printf("s: ");
scanf("%4s", s); // 배열 이름은 첫 원소의 주소로 변환되므로 & 없이 넘긴다
printf("s: %s\n", s);
}- 배열 이름이 포인터처럼 쓰이는 것은 컴파일러 기능이 아니라 C 언어 규칙(배열→포인터 변환, array decay)이다.
scanf("%s", s)처럼 폭을 지정하지 않으면 입력이 배열 크기를 넘을 때 버퍼 오버플로우가 발생한다.\0자리를 남겨%4s처럼 최대 길이를 지정하거나fgets를 쓴다.
파일에 쓰기
#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); // printf처럼, 단 파일에 출력
fclose(file);
}| 함수 | 역할 |
|---|---|
fopen(이름, 모드) | 파일을 열고 FILE *를 반환. 실패하면 NULL |
fprintf(file, ...) | 형식 문자열로 파일에 쓰기 |
fread(버퍼, 크기, 개수, file) | 파일에서 바이트 읽기 |
fclose(file) | 파일 닫기 (버퍼 내용 반영, 자원 반납) |
주요 모드: "r" 읽기, "w" 쓰기(기존 내용 삭제), "a" 덧붙이기. 바이너리 파일은 "rb", "wb"처럼 b를 붙인다.
파일 읽기: JPEG 판별하기
JPEG 파일은 항상 FF D8 FF 세 바이트로 시작한다(매직 넘버). 이를 이용해 파일 형식을 추측할 수 있다.
#include <stdio.h>
int main(int argc, char *argv[])
{
if (argc != 2) // 파일명이 없거나 인자가 너무 많으면 오류
{
return 1;
}
FILE *file = fopen(argv[1], "rb");
if (file == NULL) // fopen, malloc 등은 실패 시 NULL 반환
{
return 1;
}
unsigned char bytes[3]; // 0~255 범위로 다루기 위해 unsigned
fread(bytes, 3, 1, file); // 3바이트짜리 덩어리 1개 읽기
if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff)
{
printf("Maybe\n");
}
else
{
printf("No\n");
}
fclose(file);
}stdio 아래: 시스템 콜과 버퍼링
fopen·fread·printf는 C 표준 라이브러리(stdio)다. 유닉스 계열에서는 그 아래에서 POSIX 시스템 콜 open·read·write·close가 파일을 파일 디스크립터(fd)라는 정수로 다루고, FILE *는 fd와 사용자 공간 버퍼를 감싼 것이다. open 플래그, read의 반환값 처리, stdio 버퍼링 모드(fflush, setvbuf)는 UNIX 파일 입출력과 파일 디스크립터에 정리했다.
핵심 정리
scanf에는 저장할 주소를 넘긴다. 문자열은 폭 제한(%4s)으로 오버플로우를 막는다.- 파일은
fopen→ 읽기/쓰기 →fclose순서로 다루고,NULL검사를 잊지 않는다. - 바이너리 데이터는
unsigned char배열과fread로 읽는다. FILE *아래에는 fd와 시스템 콜이 있고, stdio는 버퍼를 거쳐 출력한다.
관련 노트: UNIX 파일 입출력과 파일 디스크립터, 파일 시스템, C 디버깅 도구, Java 입출력과 직렬화