지난 강의에서는 아래 그림과 같은 메모리 구조에 대해 간략하게 알았다.
머신 코드 영역에는 프로그램이 실행될 때 그 프로그램이 컴파일된 바이너리가 저장된다.
글로벌 영역에는 프로그램 안에서 저장된 전역 변수가 저장된다.
힙 영역에는 malloc
으로 할당된 메모리의 데이터가 저장되고 스택에는 프로그램 내의 함수와 관련된 데이터가 저장된다.
힙 영역에서는 malloc
에 의해 메모리가 더 할당될수록 점점 사용하는 메모리의 범위가 아래로 늘어난다.
마찬가지로 스택 영역에서도 함수가 더 많이 호출될수록 사용하는 메모리의 범위가 점점 위로 늘어난다.
이렇게 메모리 사용 범위가 늘어나다 보면 제한된 메모리 용량 하에서는 기존의 값을 침범하는 상황도 발생할 수 있다. 이를 힙 오버플로우 또는 스택 오버플로우라고 한다.
스택은 우리가 여태껏 많이 사용해왔던 get_int
나 get_string
과 같은 함수에서도 사용된다. 만약 이런 함수들을 직접 구현한다면 아래와 같은 코드가 될 것이다.
#include <stdio.h>
int main(void)
{
int x;
printf("x: ");
scanf("%i", &x);
printf("x: %i\n", x);
}
#include <stdio.h>
// get_string
int main(void)
{
char s[5];
printf("s: ");
scanf("%s", s);
printf("s: %s\n", s);
}
위 코드들에서 scanf
함수는 사용자로부터 형식 지정자에 해당되는 값을 입력받아 저장하는 함수이다.
get_int
코드에서 int x
를 정의한 후에 scanf
에 x
가 아닌 &x
로 그 주소를 입력해주는 부분에 유의하기 바란다.
scanf
함수의 변수가 실제로 스택 영역 안에 x
가 저장된 주소로 찾아가서 사용자가 입력한 값을 저장하도록 하기 위함이다.
반면 get_string
코드에서는 scanf
에 그대로 s
를 입력해주었다. 그 이유는 s
를 크기가 5인 char
자료형의 배열로 정의했기 때문이다.
C 컴파일러는 문자 배열의 이름을 포인터처럼 다루기 때문에 scanf
에 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
이라는 자료형으로 불러올 수 있다.
fopen
함수의 첫 번째 인자는 파일의 이름, 두 번째 인자는 모드로 r
은 읽기, w
는 쓰기, a
는 덧붙이기를 의미한다.
사용자에게 name
과 number
라는 문자열을 입력받고 fprintf
함수를 이용해 printf
에서처럼 파일에 직접 내용을 출력할 수 있다.
작업이 끝난 후에는 fclose
함수로 파일에 대한 작업을 종료해줘야 한다.
마지막으로 입력된 데이터를 처리할 때는 입력된 값의 길이를 미리 충분히 고려해야 한다.
예를 들어 char s[5];
와 같은 배열의 크기를 정할 때는 사용자 입력이 배열의 크기를 초과하지 않도록 해야 한다. 그렇지 않으면 버퍼 오버플로우가 발생할 수 있다.
이를 방지하기 위해 fgets
와 같은 안전한 입력 함수를 사용하는 방법도 있다.
#include <stdio.h>
int main(void)
{
char s[5];
printf("s: ");
fgets(s, sizeof(s), stdin);
printf("s: %s\n", s);
}
fgets
함수를 사용해 버퍼 오버플로우를 방지하고 최대 입력 길이를 지정해 안전하게 문자열을 입력받을 수 있다.
References
'CSE > CS 기초' 카테고리의 다른 글
[CS50] 자료구조 - 배열의 크기 조정하기 (0) | 2024.06.18 |
---|---|
[CS50] 자료구조 - malloc과 포인터 복습 (0) | 2024.06.18 |
[CS50] 메모리 - 메모리 교환, 스택, 힙 (0) | 2024.06.17 |
[CS50] 메모리 - 문자열 비교, 복사, 할당과 해제 (0) | 2024.06.17 |
[CS50] 메모리 - 문자열 (0) | 2024.06.17 |
컴퓨터 전공 관련, 프론트엔드 개발 지식들을 공유합니다. React, Javascript를 다룰 줄 알며 요즘에는 Typescript에도 관심이 생겨 공부하고 있습니다. 서로 소통하면서 프로젝트 하는 것을 즐기며 많은 대외활동으로 개발 능력과 소프트 스킬을 다듬어나가고 있습니다.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!