c언어에서의 메모리 할당(malloc)와 포인터의 관계... 고수님들

ins878의 이미지

안녕하세요~

다름이 아니라 학교에서 포인터와 메모리 할당에 관하여 토론을 하다가 이상한

것을 발견했는데, 너무나 이상해서 이렇게 글을 올립니다.

고수님들 한번 봐주세요.

###################################
소스 코드
###################################

#include <stdio.h>
#include <stdlib.h>

int main()
{
int *p, *q;

p = (int *)malloc(sizeof(int));

*p = 15;
q = p;

free(p);

*q = 30;

printf("%d ",*p);
printf("%p ",&p);
printf("%p\n",p);

printf("%d ",*q);
printf("%p ",&q);
printf("%p\n",q);

return 0;
}

위 소스에서 포인터 p에 메모리를 할당(malloc)를 하고 바로 해제를 했습니다.
그리고는 포인터 p에 어떤 값이 들어있는가 봤더니, 이전에 메모리를 할당한 곳을 가리키더군요(q와 동일)

분명히~ 메모리를 해제하면 에러가 나거나, 쓰레기 값이 들어가야 하는데,
왜 q와 같은 같이 들어가는가요?

고수님들 궁금해 미치겠습니다.
위 소스 코드에 대해서 자세히 가르쳐 주세요~~ T.T

kslee80의 이미지

OS 에 따라서 문제없이 돌아갈 수도 있습니다.
같은 OS 라도 경우에 따라서 문제없이 돌아갈 수도 있죠.

원칙적으로는 *q 에 값을 대입하는 부분에서 프로그램이 죽어야 겠지만,
OS 에 따라서 틀리게 동작하게 됩니다. OS 의 메모리 사용 방식에 따른 차이죠.

P.S.) 하지만, 명백히 잘못된 코드입니다.
돌아간다고 해서 옳은, 혹은 써도 되는 코드인건 아니죠.

수정) 한가지 답변을 빼 먹었군요.
malloc() 한 메모리 영역을 free() 한다고 해서 그 영역을 가리키는 포인터 값이
초기화 되는것은 아닙니다.
malloc() 로 할당된 영역과, 그 영역의 주소를 가지는 포인터 변수와는 관련성이 없죠.
그리고, free() 한 메모리 영역의 값 역시나 변하지 않습니다.
그것은 garbage 값이라는게 어째서 존재하는지를 생각해 보시면 답을 얻으실 것이라고 생각합니다.

익명 사용자의 이미지

포인터를 번지라고 해보죠.. 특정 집을 가르키는 번지

q,p 번지.. 선언 ( 빈공간을 가르키는 번지죠 )

p번지에 공간을 할당해줍니다..

그리고 p번지의 공간안에 15란 값을 넣습니다..

q 번지의 내용에 p 번지의 내용을 넣습니다..

p 번지의 공간을 해제 합니다 ( p 번지가 사라지는건 아닙니다 )

q 번지의 공간에 30을 넣습니다.. <-- 오류입니다. 공간은 해제됬으니까..

현재 q 와 p는 같은 번지이다..

그러니 같은 내용이 찍히지요..

오류가 안났다고 해서 정상코드가 아닙니다.. 메모리의 상황에

따라서 세그폴트가 날수도 있는 코드입니다..

포인터도 엄연히 4바이트로 된 메모리 공간입니다.

메모리 할당된 공간과는 별개죠 ( 포인터 ) 가르킴..-> ( 공간 ) 입니다..

alwaysN00b의 이미지

ins878 wrote:

int *p, *q;

p = (int *)malloc(sizeof(int));

*p = 15;
q = p;

free(p);

*q = 30;

}

분명히~ 메모리를 해제하면 에러가 나거나, 쓰레기 값이 들어가야 하는데,
왜 q와 같은 같이 들어가는가요?

전 고수는 아니지만 malloc 은 heap 영역을 할당해주는걸로 알고 있습니다.
메모리를 해제한다는건 "할당받았던 그영역을 os가 사용하도록" 하는것입니다.

만약에 다시 malloc 을 하거나 다른 프로세서에서 malloc (혹은 비슷한) 을 한다면 그영역을 사용할수도 있습니다.

메모리의 데이터가 해제했다고 쓰레기 값이 들어가진 않습니다.

free(p);
*q = 30;
....
print(...);

위코드가 실행되는 시간동안 다른 프로세서가 그 영역을 사용하게 된다면 또 다른 값이 찍힐수도 있습니다.

틀린곳이 있다면, 고수님들 지적바랍니다.

ps. 코드는 bbcode를 이용하심이.. :D

언제나 시작

sozu의 이미지

alwaysN00b wrote:
만약에 다시 malloc 을 하거나 다른 프로세서에서 malloc (혹은 비슷한) 을 한다면 그영역을 사용할수도 있습니다.
....
위코드가 실행되는 시간동안 다른 프로세서가 그 영역을 사용하게 된다면 또 다른 값이 찍힐수도 있습니다.

프로세스간에는 주소공간이 다르지 않나요? :)

free() 이후에 초기화 않된 포인터로 잘못된 참조를 막기위해

보통 이런 메크로를 씁니다.

#define SAFE_FREE(p) { if(p) { free((p)); (p)=NULL; } }

-----------
청하가 제안하는 소프트웨어 엔지니어로써 재미있게 사는 법
http://sozu.tistory.com

ins878의 이미지

늘 여기만 오면, 저의 궁금증이 모두 풀려서 좋습니다.^^

고수님들~ 정말로, 정말로 감사드립니다.

alwaysN00b의 이미지

sozu wrote:
alwaysN00b wrote:
만약에 다시 malloc 을 하거나 다른 프로세서에서 malloc (혹은 비슷한) 을 한다면 그영역을 사용할수도 있습니다.
....
위코드가 실행되는 시간동안 다른 프로세서가 그 영역을 사용하게 된다면 또 다른 값이 찍힐수도 있습니다.

프로세스간에는 주소공간이 다르지 않나요? :)

free() 이후에 초기화 않된 포인터로 잘못된 참조를 막기위해

보통 이런 메크로를 씁니다.

#define SAFE_FREE(p) { if(p) { free((p)); (p)=NULL; } }

전 heap 영역을 말하는건데요?

프로세서별로 할당받을수 있는 heap 영역도 정해져있나요? (잘몰라서.. :D )
궁금합니다.

Quote:

free() 이후에 초기화 않된 포인터로 잘못된 참조를 막기위해

보통 이런 메크로를 씁니다.

보통 저도 사용하고 있습니다. :)

언제나 시작

GunSmoke의 이미지

참고로 말씀드리면
몇몇 분이 말씀하신 대상체가 저장되는 공간이 스택 영역이니 힙 영역이니 하는 문제는 사실 C가 상관할 바가 아닙니다. C에는 대상체의 속성과 관련하여 3가지의 기억부류를 가지고 있을 따름입니다.

大逆戰

alwaysN00b의 이미지

GunSmoke wrote:
참고로 말씀드리면
몇몇 분이 말씀하신 대상체가 저장되는 공간이 스택 영역이니 힙 영역이니 하는 문제는 사실 C가 상관할 바가 아닙니다. C에는 대상체의 속성과 관련하여 3가지의 기억부류를 가지고 있을 따름입니다.

코딩하는 사람이 상관할바겠죠. :)

언제나 시작

죠커의 이미지

alwaysN00b wrote:
코딩하는 사람이 상관할바겠죠. :)

코딩하는 사람도 먼저 storage에 대한 이해를 하는게 바릅니다.

moonzoo의 이미지

조금 다른 예를 들어보자면

int p[2]; 과 같이 정의해놓고

p[0]= 0;
p[1]=1;
p[2]=2;
p[3]=3;

이렇게 사용한다면..아주 짧은 프로그램에서는 에러가 나지 않을수도 있습니다.

그렇다고 해서..오 잘되네~ --; 이런 생각을 가지시는 분은 없겠죠.

p[2],p[3]의 영역은 보장되는 영역이 아니므로

프로그램이 조금만 길어진다해도..충돌이 일어나겠죠..

메모리 영역은 다르지만..비슷한 경우라고 생각됩니다.

sozu의 이미지

alwaysN00b wrote:
sozu wrote:
alwaysN00b wrote:
만약에 다시 malloc 을 하거나 다른 프로세서에서 malloc (혹은 비슷한) 을 한다면 그영역을 사용할수도 있습니다.
....
위코드가 실행되는 시간동안 다른 프로세서가 그 영역을 사용하게 된다면 또 다른 값이 찍힐수도 있습니다.

프로세스간에는 주소공간이 다르지 않나요? :)

free() 이후에 초기화 않된 포인터로 잘못된 참조를 막기위해

보통 이런 메크로를 씁니다.

#define SAFE_FREE(p) { if(p) { free((p)); (p)=NULL; } }

전 heap 영역을 말하는건데요?

프로세서별로 할당받을수 있는 heap 영역도 정해져있나요? (잘몰라서.. :D )
궁금합니다.

Heap 이던 Stack 이던 상관없습니다.

User Process 는 독립적인 Process Address Space 를 가지고 있습니다. :)

-----------
청하가 제안하는 소프트웨어 엔지니어로써 재미있게 사는 법
http://sozu.tistory.com

alwaysN00b의 이미지

CN wrote:
alwaysN00b wrote:
코딩하는 사람이 상관할바겠죠. :)

코딩하는 사람도 먼저 storage에 대한 이해를 하는게 바릅니다.

아.. 제가 이해를 잘못했나요? 인용하셨길레 제가 말한 뜻하고 틀린것 같아서 한참을 읽었습니다.
GunSmoke님 말씀이

Quote:
대상체가 저장되는 공간이 스택 영역이니 힙 영역이니 하는 문제는 사실 C가 상관할 바가 아닙니다

그래서, 저는 당연히 storage에 저장되는건 코딩하는 사람이 이해를 하고 있어야 된다는 생각에 적은 말입니다.

-_-;; 뭔가 의사소통에 문제가.. 제가 잘못 이해했다면 용서해주시구요, 틀렸다면 쪼금만 더 지적해주세요

언제나 시작

alwaysN00b의 이미지

sozu wrote:

Heap 이던 Stack 이던 상관없습니다.

User Process 는 독립적인 Process Address Space 를 가지고 있습니다. :)

아.. 감사합니다. 제가 잘못알고 있었군요. :)

언제나 시작

doldori의 이미지

alwaysN00b wrote:
CN wrote:
alwaysN00b wrote:
코딩하는 사람이 상관할바겠죠. :)

코딩하는 사람도 먼저 storage에 대한 이해를 하는게 바릅니다.

아.. 제가 이해를 잘못했나요? 인용하셨길레 제가 말한 뜻하고 틀린것 같아서 한참을 읽었습니다.
GunSmoke님 말씀이

Quote:
대상체가 저장되는 공간이 스택 영역이니 힙 영역이니 하는 문제는 사실 C가 상관할 바가 아닙니다

그래서, 저는 당연히 storage에 저장되는건 코딩하는 사람이 이해를 하고 있어야 된다는 생각에 적은 말입니다.

-_-;; 뭔가 의사소통에 문제가.. 제가 잘못 이해했다면 용서해주시구요, 틀렸다면 쪼금만 더 지적해주세요

C에서 말하는 storage는 다분히 추상적인 개념입니다. 이를 구현할 때
스택이니 힙이니 하는 용어가 등장하는 거죠. 한 마디로 이 둘은 전혀
다른 차원의 용어라는 뜻입니다. 그리고 OP의 질문에 대해서는 C 언어의
차원에서 답변해도 충분하다는 뜻입니다.
그리고 일반적으로는 C 언어의 추상적인 관점에서 프로그래밍 하는 것이
이식성 측면에서 바람직합니다. 이식성을 희생하고 성능을 극도로 추구해야
할 상황이 아니라면요.

dyks의 이미지

alwaysN00b wrote:
sozu wrote:

Heap 이던 Stack 이던 상관없습니다.

User Process 는 독립적인 Process Address Space 를 가지고 있습니다. :)

아.. 감사합니다. 제가 잘못알고 있었군요. :)

모든 프로세스가 각각 독립적인 Process Address Space를 가지고 있다는 것은 맞지만, 그게 alwaysN00b 님이 말씀하신 것을 반박하지는 못합니다. 프로세스 A의 주소 100 이 가르키는 값이 프로세스 B의 주소 100이 가르키는 값과 서로 다르다는 것이, 두 프로세스가 완벽하게 구분된 Physical 메모리를 사용한다는 것을 의미하지는 않으니까요.

가령, VirtualAlloc 등으로 메모리를 할당하고, 그것을 Free했을 경우, 해당 Physical 메모리는 다른 프로세스가 사용할 수 있습니다.(서로 주소값은 다르겠지만요. 뭐 이때 VirtualFree를 호출하고 다시 억세스하려고 하면 Access Violation이 나긴 하겠군요.;; ) Heap의 경우도 마찬가지입니다. 다만 Default Heap은 프로세스마다 고유하게 만들어지며, 컴파일 옵션(링커의 옵션이었던가요. 기억이 잘.-ㅅ-; )으로 사이즈가 조절이 됩니다. 구현은 플랫폼마다 달라질 수도 있겠습니다만(제가 Win32외엔 잘 몰라서요.;; ) 대동소이할거라고 생각됩니다.

sozu의 이미지

dyks wrote:
프로세스 A의 주소 100 이 가르키는 값이 프로세스 B의 주소 100이 가르키는 값과 서로 다르다는 것이, 두 프로세스가 완벽하게 구분된 Physical 메모리를 사용한다는 것을 의미하지는 않으니까요.

가령, VirtualAlloc 등으로 메모리를 할당하고, 그것을 Free했을 경우, 해당 Physical 메모리는 다른 프로세스가 사용할 수 있습니다.(서로 주소값은 다르겠지만요. 뭐 이때 VirtualFree를 호출하고 다시 억세스하려고 하면 Access Violation이 나긴 하겠군요.;; ) Heap의 경우도 마찬가지입니다. 다만 Default Heap은 프로세스마다 고유하게 만들어지며, 컴파일 옵션(링커의 옵션이었던가요. 기억이 잘.-ㅅ-; )으로 사이즈가 조절이 됩니다. 구현은 플랫폼마다 달라질 수도 있겠습니다만(제가 Win32외엔 잘 몰라서요.;; ) 대동소이할거라고 생각됩니다.

다시 읽어보니 제가 주제를 벗어난 답변을 했군요. 지적 감사합니다. :)

-----------
청하가 제안하는 소프트웨어 엔지니어로써 재미있게 사는 법
http://sozu.tistory.com

alwaysN00b의 이미지

doldori wrote:

C에서 말하는 storage는 다분히 추상적인 개념입니다.

이를 구현할 때스택이니 힙이니 하는 용어가 등장하는 거죠.
한 마디로 이 둘은 전혀다른 차원의 용어라는 뜻입니다.

그리고 OP의 질문에 대해서는 C 언어의 차원에서 답변해도 충분하다는 뜻입니다.

그리고 일반적으로는 C 언어의 추상적인 관점에서 프로그래밍 하는 것이
이식성 측면에서 바람직합니다. 이식성을 희생하고 성능을 극도로 추구해야
할 상황이 아니라면요.

아.. 죄송합니다. 제가 무지하여 잘 이해가 되질 않습니다.

질문자의 의도에 필요한 답이 올라왔다고 생각합니다.

언제나 시작

댓글 달기

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