c언어 malloc과 array, 힙과 스택에 관한 질문

k333ps의 이미지

안녕하세요.

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으로 작은 변수를 선언하기에는 프로그램의 성능이 떨어지게 되어 곤란할 것 같습니다만...

bushi의 이미지

sizeof(double) * 백만 짜리가 30개라 해도, 겨우 256MB 입니다.

가정을 앞세우지 말고,
증상을 재현할 수 있는 가장 작은 코드 조각을 만들어 보세요.

k333ps의 이미지

#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버젼 입니다.

sapsaldog의 이미지

double *a; //(1)

*a = 0;
printf("%f\n",*a);

이거는 당연히 나야되는거 아닌가요? a포인터에 메모리가 할당되어있지 않아보이는데;;

double *a = a01; 하시고 해보세요.

만약에 이게 아니라면

일단 잘은 모르겠지만, NULL 체크는 해보셨나요? malloc은 운영체제에 메모리 할당을 요청하는거라, 운영체제가 맘에 안들면 안줄수도 있어요. ( -_-);

그리고 heap이라 stack overflow는 아닌듯 싶구요.

klara의 이미지

우선 크나큰 오해를 하고 계신듯 한데, 모든 포인터는 스택에 올라갑니다.
(1)의 경우는 (2)의 경우든 변수 a는 스택에 올라갑니다.
포인터도 하나의 변수라는 걸 잊으시면 안됩니다.
따라서 (1)이든 (2)든 지금 스택에 올라간 메모리 양은 완전히 동일합니다.

다음으로 (1)은 안되고 (2)는 되는 이유는, (1)은 포인터가 임의의 값이기 때문입니다.
*a = 0 는 a가 가리키고 있는 곳에 0을 대입합니다.
포인터의 값(*a가 아니라 a의 값입니다)은 포인터가 가리키는 주소값입니다.
그런데 (1)에서 a의 값은 무엇인가요?
초기화하지 않았으므로 쓰레기값이 들어있고, 기본적으로 프로그래머는 시스템으로부터 할당받은 메모리 이외의 곳은 접근할 수 없습니다.
그렇기 때문에 (1)에서 *a=0은 제대로 동작하지 않는 것입니다.
(2)는 a의 값을 malloc으로 할당한 주소로 초기화해주었으므로 정상적으로 작동합니다.

k333ps의 이미지

제가 포인터에 대해 잘못이해하고 있었습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.