배열을 변수를 이용해서 할당할때 왜 malloc함수를 사용해야 하나요?

bshi02의 이미지

http://dsnight.tistory.com/50를 보다가

int main() {
 
    // 정상적인 배열선언
    int arr[10];
 
    // 비 정상적인 배열선언
    int i = 0;
    scanf("%d", &i);
    int arr[i];
 
    return 0;
}

아래와 같은 배열은 선언하면 컴파일을 하는 동안 i가 4바이트의 크기라는 것을 알 수는 있으나, 그 값이 10으로 초기화 되었다는 사실은 무시하고 넘어간다. 값이 10으로 초기화 되었다는 사실은 실행되는 동안, 즉 런타임에 결정된다.
그렇기 때문에 컴파일러는 arr의 크기가 40바이트가 된다는 사실을 알 수 없다.
int main() {
 
    int i = 10;
    int arr[i];
 
    return 0;
}

라고 써 있네요.

그런데 보다가 의문이 들었는데요

scanf("%d", &i);
 
    int arr[i];

처럼 scanf함수로 직접 변수값을 입력하는 경우는 사용자가 얼마의 수를 i에 입력할지 모르기 때문에 malloc로 힙영역에정확한 메모리의 크기로 할당할수 없는게 당연해보입니다만 그런데 아래 두줄의 소스는 컴파일러는
int i = 10;
 int arr[i];

int형의 바이트수 :4*변수 i의 갯수:10으로 40바이트의 배열이 할당되는 지 왜 모릅니까?

제 생각에는 i=10이라는 정보를 컴파일러가 읽어들이기 때문에 컴파일러가 컴파일하면서 당연히 i=10의 값을 대입해서 arr의 배열의 크기가 40(10*4바이트)라는 사실을 알것 같은데
궂이 런타임에 실행을 하지 않아도 컴파일러가 i값을 알고 있기 때문에 배열의 크기를 컴파일러가 알수 있지 않나요?

이 블로그에는 배열의 갯수를 변수로 할당하는 경우도 배열이 메모리에 어느정도의 메모리를 할당해야 하는지 컴파일러는 모르기 때문에 arr[10]과 달리 malloc 함수로 메모리의 크기를 직접 할당해주어야 한다고 합니다만, 왜 배열의 갯수가 되는 변수의 값이 확실히 나와있는데 컴파일러가 왜 배열에 할당되는 메모리의 크기를 모르는지 그 이유를 자세히 알고 싶네요.

아시는 분 답변 주시면 정말 좋겠네요.

klyx의 이미지

표준은 명세이고 컴파일러는 구현입니다.
왜 표준에서 이런게 금지되어있느냐는 질문에 대해서 나름 답을 생각할 수있는데, 그렇다고 해서 항상 표준이 정답이라는 법은 없습니다.
말씀하신대로 그 경우에는 컴파일러는 i의 값이 10이라는 것을 알 수 있지만, 표준에서 그걸 허용하지 말라고 했으니까 안하는 것입니다.

표준에 들어있는 건 다 할 수 있는 거지만, 표준에 없다는게 기술적으로 불가능하다는 것은 아닙니다.
표준을 제정할 당시에는 할수 없었던 경우도 있고, 또는 표준을 제정할 당시에 생각치 못했던 경우도 있고, 더나아가서는 할수 있지만 복잡하니까 안한다, 이런것도 있습니다.

참고로 사실 크기를 미리 알 수 없으니까 배열의 크기로 쓸수 없다는 것도 답은 아닙니다.
C99부터는 VLA라고 해서 임의의 변수를 배열의 크기로 쓸수 있게 표준자체가 바뀌었으니까요.

bshi02의 이미지

결국 표준을 정한 제작자 마음대로군요.
네이버에도 올렸었지만
답변자님이 아래의 링크를 참조하라는 답변을 받았는데
아직 실력이 모자라서 읽어도 잘 모르겠습니다만 아무래도 원래 정해진 규칙이니, 왜 안되는지 따져보는 것은 생각해봐도 별로 도움이 되지 않는 것 같습니다.
http://flowerexcel.tistory.com/7
답변 감사합니다.많은 도움이 되었습니다.

HDNua의 이미지

나중에 기억해놓으려고 덧글 남깁니다.

저는 이렇게 생각했습니다.

kaeri17의 이미지

C99 부터는 스택을 가변적으로 잡을수 있기 때문에 문제 없는 코드가 되고요, C++에서 만약 const int i = 10; 이라고 했으면 역시나 문제 없는 코드입니다. 예전 C에서는 int i 라고 했을때는, 그 값이 변할지 그렇지 않을지 알 수가 없고, 그 경우 스택을 가변적으로 잡는 방식이 지원되지 않은 운영체제가 많았기 때문에 표준이 그렇게 짜여진 것이죠. 표준이 왜 그런지 의미가 없는 경우도 많지만 이경우는 꽤나 명확한 이유가 있습니다.

twinwings의 이미지

int i = 10;
int arr[i];

와 같이 배열을 선언했을 경우 컴파일이 안되는 것이 당연합니다.

int i = 10;
scanf("%d", &i);
int arr[i];

첫 번째 코드와 두 번째 코드를 컴파일러가 구분할 수 있을까요? 컴파일러에겐 두 코드가 동등합니다.

대신

const int i = 10;
int arr[i];

는 유효합니다.

최신 C에서는 질문자가 말한 그러한 기능이 지원되는걸로 알고 있습니다.

klyx의 이미지

> 첫 번째 코드와 두 번째 코드를 컴파일러가 구분할 수 있을까요? 컴파일러에겐 두 코드가 동등합니다.

전혀 그렇지 않습니다.
컴파일러는 얼마든지 이 코드를 구분할 수 있고, 이런걸 구분하지 못하는 컴파일러는 최적화라는걸 할수도 없습니다.
이게 안되는건 표준에 명시되어있지 않기 때문입니다.

twinwings의 이미지

예. 엄밀히 따지면 구분 가능하게 구현할 수 있겠지요.
하지만 const라는 지정자가 컴파일러의 부담을 덜어주기 위한 표준인데
컴파일러를 이런 사소한것 까지 구현 했어야 할까요.(C99 이전)
const라는 지정자를 쓰면 알아서 최적화를 할텐데요.

비슷한 예로, C++에서 call by const reference와 call by reference의 최적화 정도가 어마어마하게 다르지요.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.