C는 내가 처음으로 공부했던 컴퓨터 언어이다.
백준 문제도 많이 풀어보고, 게임을 만들거나 자료구조를 시각화하는 등 다양하게 코딩을 했던 것 같다.
오늘은 처음으로 C에 대해서 깊게 공부하게 되었던 "액세스 위반"에 대해 정리를 해보려고 한다.
1. 어떤 경우에 위반이 떴나?
내가 경험했던 경우는 두 가지이다.
1. 메모리 할당이 되지 않은 포인터를 잘못 사용할 경우.
2. 읽기 전용 메모리에 쓰기를 수행할 경우.
1번의 경우는 "할당되지 않은 메모리를 사용하려고 할 때"라고 표현해도 좋을 것 같다.
2. 직접 액세스 위반을 발생시켜보며 공부하자
먼저 "1. 메모리 할당이 되지 않은 포인터를 잘못 사용할 경우."에 대해 공부해보았다.
예제 1-1)
정상적인 오류가 없는 정상적인 코드이다.
#include <stdio.h>
int main() {
int *ptr;
int num = 10;
ptr = #
printf("%d\n", *ptr);
return 0;
}
코드 내에서 어떠한 위반도 발생하지 않았기 때문에 예상했던 출력 그대로 나온다.
예제 1-2)
다음은 액세스 위반이 발생하는 코드이다.
#include <stdio.h>
int main() {
int *ptr;
int a = 10;
ptr[0] = 10;
printf("%d\n", *ptr);
return 0;
}
실행시켜보면 오류가 발생할 것이다.
디버그를 통해 다음과 같은 오류가 발견할 수 있다.
ptr은 메모리가 할당되지 않은 포인터 변수이고, 할당되지 않은 메모리에 index를 사용하여 접근하려고 하기 때문에 참조 액세스 위반이 발생했다.
머리에 확 들어오지 않아서 그림으로 그려보았다.
포인터 변수는 무언가 가리키는 변수이다. 이미 메모리가 할당된 변수를 할당해주거나, 메모리를 직접 할당하여 사용해야 한다.
위 그림의 첫 번째 경우가 예제 1-1의 경우이다.
예제 1-2의 경우는 아무것도 할당되지 않은 ptr변수에 index 연산자를 사용하여 접근하려고 했기 때문에 참조 위반이 발생한 것이구나!
생각보다 어려운 개념은 아닌 것 같다.
다음은 "2. 읽기 전용 메모리에 쓰기를 수행할 경우."에 대해서 공부해보았다.
예제 2-1
#include <stdio.h>
int main() {
char str[10] = "apple";
str[0] = 'B';
printf("%s\n", str);
return 0;
}
위 코드에서 "apple"은 init영역에 존재하는 문자열 리터럴이고, str은 크기가 10으로 할당된 char형 배열이다.
배열 str은 문자여 리터럴 "apple"로 초기화(copy) 되어 stack영역에 저장되기 때문에 인덱스 연산자로 접근 시 문제가 되지 않는다. (읽고 쓰기가 가능한 데이터 영역이다.)
결과는 당연히 "Bapple"이 출력된다. 따로 사진으로 남겨두지는 않았다.
예제 2-2
#include <stdio.h>
int main() {
char *str = "apple";
str[0] = 'B';
printf("%s\n", str);
return 0;
}
위 코드를 실행하면 다음과 같은 액세스 위반이 발생한다.
예제 2-1의 배열 str과 다르게 2-2의 str은 포인터 변수이고 init영역에 존재하는 리터럴 타입 문자열 "apple"을 가리키고 있다.
init영역은 읽기 전용 메모리이기 때문에 init영역에 할당되어있는 변수에는 쓰기 명령으로 접근할 수 없다.
이러한 이유 때문에 액세스 위반이 발생했다고 생각한다.
마무리
C는 공부하면 공부할수록 어려워지는 언어인 것 같다.
다음번엔 string 헤더 파일과 L, R value 등에 대해 정리해 볼 계획이다.
공부에 사용한 코드는 아래 링크에 주석과 함께 올려두었다.
https://github.com/Sungmin-Joo/Codes-for-Beginners/tree/master/C/Memory_Structure_study
'Computer_Language > C' 카테고리의 다른 글
[C] C언어의 Stack_Frame (0) | 2019.10.15 |
---|---|
[C] 인덱스 검사(경계 검사)에 대하여 (0) | 2019.08.31 |