c언어 malloc과 array, 힙과 스택에 관한 질문
안녕하세요.
c로 대형 배열들을 다수 사용하는 프로그램을 만들고 있습니다.
크기가 sizeof(double)*100000이 넘는 배열들을 2-30개 사용하기 때문에
기본적으로 malloc을 이용하고 있는데요
임시적인 목적으로 중간 중간 함수에서 포인터 변수 double *a등을 정의해 사용하면
자꾸 세그먼트 폴트가 납니다만, 이 변수를 double *a = malloc(sizeof(double))로 바꿔주면
다시 프로그램이 잘 돌아가는 것으로 보아 스택오버플로우인것 같습니다.
모든 포인터를 malloc으로 쓰고 있기 때문에 스택은 쓰고 있지 않습니다만, 포인터 변수 한개를 스택에
넣으면 오버플로우가 나는 이유가 무엇인지 궁금합니다.
1) kldp에 올라온 관련 질문들을 읽으며 생각해보았습니다만,
이하와 같은 메모리 구조가
/-------------------------/ 메모리상에서
| | 높은 구역
| Stack |
| |
/-------------------------/
| |
| Heap |
| |
/-------------------------/
| Uninitialized data |
| ---------Data---------- |
| Initialized data |
/-------------------------/
| |
| Text |
| | 메모리상에서
/-------------------------/ 낮은 구역
힙을 아주 많이 사용하게 되면서 이하와 같은 상태가 되어 스택에 한개만 집어넣어도 오버플로우가 나는지요?
/-------------------------/ 메모리상에서
/--stack(공간이 없음)-------/ 높은 구역
| |
| |
| |
| |
| Heap |
| |
/-------------------------/
| Uninitialized data |
| ---------Data---------- |
| Initialized data |
/-------------------------/
| |
| Text |
| | 메모리상에서
/-------------------------/ 낮은 구역
2) 혹 1)의 가정이 맞다면 저는 앞으로 어떻게 포인터 변수를 쓸 수 있을까요
항상 malloc으로 작은 변수를 선언하기에는 프로그램의 성능이 떨어지게 되어 곤란할 것 같습니다만...
sizeof(double) * 백만 짜리가 30개라
sizeof(double) * 백만 짜리가 30개라 해도, 겨우 256MB 입니다.
가정을 앞세우지 말고,
증상을 재현할 수 있는 가장 작은 코드 조각을 만들어 보세요.
코드
#include
#include
int main(void)
{
double *a01 = malloc(sizeof(double)*1000000);
double *a02 = malloc(sizeof(double)*1000000);
double *a03 = malloc(sizeof(double)*1000000);
double *a04 = malloc(sizeof(double)*1000000);
double *a05 = malloc(sizeof(double)*1000000);
double *a06 = malloc(sizeof(double)*1000000);
double *a07 = malloc(sizeof(double)*1000000);
double *a08 = malloc(sizeof(double)*1000000);
double *a09 = malloc(sizeof(double)*1000000);
double *b01 = malloc(sizeof(double)*1000000);
double *b02 = malloc(sizeof(double)*1000000);
double *b03 = malloc(sizeof(double)*1000000);
double *b04 = malloc(sizeof(double)*1000000);
double *b05 = malloc(sizeof(double)*1000000);
double *b06 = malloc(sizeof(double)*1000000);
double *b07 = malloc(sizeof(double)*1000000);
double *b08 = malloc(sizeof(double)*1000000);
double *b09 = malloc(sizeof(double)*1000000);
double *c01 = malloc(sizeof(double)*1000000);
double *c02 = malloc(sizeof(double)*1000000);
double *c03 = malloc(sizeof(double)*1000000);
double *c04 = malloc(sizeof(double)*1000000);
double *c05 = malloc(sizeof(double)*1000000);
double *c06 = malloc(sizeof(double)*1000000);
double *c07 = malloc(sizeof(double)*1000000);
double *c08 = malloc(sizeof(double)*1000000);
double *c09 = malloc(sizeof(double)*1000000);
double *a; //(1)
// double *a = malloc(sizeof(double));//(2)
*a = 0;
printf("%f\n",*a);
// free(a);//(2)
free(a01);
free(a02);
free(a03);
free(a04);
free(a05);
free(a06);
free(a07);
free(a08);
free(a09);
free(b01);
free(b02);
free(b03);
free(b04);
free(b05);
free(b06);
free(b07);
free(b08);
free(b09);
free(c01);
free(c02);
free(c03);
free(c04);
free(c05);
free(c06);
free(c07);
free(c08);
free(c09);
}
위 코드중 (1)번 부분으로 컴파일을 하면 세그먼트 폴트가 납니다.
또 (1)번 부분을 주석처리한 뒤, (2)번 부분으로 malloc을 이용해 포인터를 선언하면
코드가 문제없이 돌아갑니다.
컴파일 및 실행환경은 ubuntu 10.04 64bit버젼 입니다.
double *a; //(1) *a =
double *a; //(1)
*a = 0;
printf("%f\n",*a);
이거는 당연히 나야되는거 아닌가요? a포인터에 메모리가 할당되어있지 않아보이는데;;
double *a = a01; 하시고 해보세요.
만약에 이게 아니라면
일단 잘은 모르겠지만, NULL 체크는 해보셨나요? malloc은 운영체제에 메모리 할당을 요청하는거라, 운영체제가 맘에 안들면 안줄수도 있어요. ( -_-);
그리고 heap이라 stack overflow는 아닌듯 싶구요.
우선 크나큰 오해를 하고 계신듯 한데, 모든 포인터는
우선 크나큰 오해를 하고 계신듯 한데, 모든 포인터는 스택에 올라갑니다.
(1)의 경우는 (2)의 경우든 변수 a는 스택에 올라갑니다.
포인터도 하나의 변수라는 걸 잊으시면 안됩니다.
따라서 (1)이든 (2)든 지금 스택에 올라간 메모리 양은 완전히 동일합니다.
다음으로 (1)은 안되고 (2)는 되는 이유는, (1)은 포인터가 임의의 값이기 때문입니다.
*a = 0 는 a가 가리키고 있는 곳에 0을 대입합니다.
포인터의 값(*a가 아니라 a의 값입니다)은 포인터가 가리키는 주소값입니다.
그런데 (1)에서 a의 값은 무엇인가요?
초기화하지 않았으므로 쓰레기값이 들어있고, 기본적으로 프로그래머는 시스템으로부터 할당받은 메모리 이외의 곳은 접근할 수 없습니다.
그렇기 때문에 (1)에서 *a=0은 제대로 동작하지 않는 것입니다.
(2)는 a의 값을 malloc으로 할당한 주소로 초기화해주었으므로 정상적으로 작동합니다.
감사합니다.
제가 포인터에 대해 잘못이해하고 있었습니다.
댓글 달기