사용자에게 입력을 받는 함수는 어떻게 구현할 수 있을까? 파일을 읽고 쓰는 방법을 알아보자.
메모리 구조를 다시 한 번 살펴보면,

메모리 영역
- 머신 코드: 프로그램이 컴파일된 바이너리
- 글로벌: 프로그램 안에서 저장된 전역 변수
- 힙:
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' |
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 |
