왜 이코드가 에러가 안나죠????(동적할당관련)

sisbn의 이미지

#include <stdio.h>
#include <unistd.h>

typedef struct _Card Card;
struct _Card{

  int number;
  char shape;
    
};

int main()
{
    Card* cards[3];
    cards[0] = (Card*)malloc(sizeof(Card));
    cards[0]->number  = 3;
    cards[0]->shape  = 'b';
    cards[0]->shape  = 'c';
    cards[0]->shape  = 'd';
    cards[0]->shape  = 'k';
    
    printf("card shape is %c\n", cards[0]->shape);
}

분명히 Card의 크기인 5Byte만큼만 할당을 받은 상태인데,

저렇게 하게 되면, 8byte가 되는데 말이죠.

게다가 찍어보면 k가 찍힙니다. 정말루 희안하군요..

혹시 아시는분 계시나요? 부탁드립니다

feelpassion의 이미지

크기 이상의 값을 주면 영역을 깨고 계속 쓸 수 있습니다. 그러나 깨진 영역의 데이터는 보장하지 못하죠

남으로 창을 내겠소.
밭이 한참갈이 괭이로 파고 호미론 김을 메지요.
구름이 꼬인다 갈리있소. 새들의 노래는 공으로 들으랴오.
강냉이가 익거든 와자셔도 좋소.
왜 사냐건 웃지요.

버려진의 이미지

cards[0]->shape = 'b';
cards[0]->shape = 'c';

이런건 메모리를 할당하지 않습니다.
그냥 할당된 곳에 값을 넣을 뿐이죠.

그리고 사실 할당도 5바이트가 아니라 더 크게 할당됐을겁니다.

그리고 free()를 해주는 습관, free된 곳은 NULL로 해주는 습관을 들이는 것이 좋습니다.

사용하지 않는 포인터가 두개네요.

없어도 되기는 하지만 리턴값이 없는것도 아시죠?

그리고 malloc()은 stdlib.h에 정의되어 있습니다.

cinsk의 이미지

malloc(N)을 한다고 해서, 정확히 N byte가 할당되는 것은 아닙니다. 구현 문제상 촙5님이 말씀하신 것처럼, 실제로는 N 이상의 값이 할당될 수 있습니다. 그러나 이 것에 의존하는 코드를 만드는 것은 정말 잘못된 습관입니다. feelpassion님이 말씀하신 것처럼, 실제로 정확히 N byte가 할당되었는데, 그 뒤에 (다른 목적으로 쓰이고 있을 수 있는) 공간에 써 버릴 수도 있는 문제입니다. 즉, 'undefined behavior'가 항상 segmentation fault로 이어지는 것은 아닙니다. 실제로는 아무 문제 없이 동작할 수도 있습니다.

이러한 문제는 매우 debugging하기 힘듭니다. valgrind나 electric fence(efence)등을 쓰면 쉽게 해결될 수 있습니다만, 100% 보장은 못합니다.

왜 정확히 N byte가 아니고 N 이상이 할당될 수 있는가? 가 궁금하시면,
(glibc malloc의 시초였던 dlmalloc의 저자) Doug Lee씨가 쓴 글을 읽어 보시기 바랍니다:

http://gee.cs.oswego.edu/dl/html/malloc.html

copyrei의 이미지

cinsk님께 질문~

valgrind는 잘 사용하고 있는데..
e-fence에 대한 자료(홈페이지)는 어디서 볼 수 있나요?
찾아봐도 잘 없네요..

둘다 써보신거 같은데.. valgrind랑 비교해서 어때요??

(ㅠ.ㅠ 인용하는거 어떻게 하는거예요? 박스로 딱 나오는거..

으.. 초보티 팍 나네요. ㅠ.ㅠ)

cinsk의 이미지

Electric fence의 official homepage입니다.

http://perens.com/FreeSoftware/

(x86에서만 동작하는)valgrind가 좀 더 많은 버그를 잡아주죠 일반적으로.

valgrind를 쓸 수 있으면 궂이 efence를 쓸 필요는 없습니다만,

전 efence를 오래도록 써 와서 웬지 친밀감이 느껴져서.. ^^;

valgrind를 쓸 수 있다면 valgrind를 쓰도록 하세요..

익명 사용자의 이미지

sisbn wrote:

분명히 Card의 크기인 5Byte만큼만 할당을 받은 상태인데,
저렇게 하게 되면, 8byte가 되는데 말이죠.

alignment 관련 문제입니다.
malloc 은 어떤 데이터 타입에 대해서도 제대로 align되도록
충분히 크게 할당하는 것입니다.
-fpack-struct 같은 옵션이나 attribute 를 줘서 5바이트로
만들 수 있지만 권장하지 않습니다.
Quote:

게다가 찍어보면 k가 찍힙니다. 정말루 희안하군요..

당연히 마지막에 k를 대입했으니 k가 찍히죠?
litdream의 이미지

-> 연산자를 혹시 stack 의 push 정도로 오해하신게 아닌가 싶습니다만..

삽질의 대마왕...

electr의 이미지

제생각으로는 윗분들의 답변처럼 "malloc의 메로리 할당에 대한 문제"가 아닌듯 합니다..
우선 첫번째로 int + char = 5byte인데 왜 8Byte가 할당되는가에 대한 답변입니다.
=============================================================

struct aaa{
int a
char b;
};

처럼 구조체를 생성하고 sizeof(struct aaa) 를 하면 8이 리턴됩니다. (malloc과는 관계가 없습니다. 실제로 malloc 호출하기 전에 한번 sizeof() 연산자를 이용해서 크기를 확인해 보시기 바랍니다.)컴파일러의 Alignment 때문에 이런일이 생기는데요.. 인텔 펜티엄과 32비트 CPU는 1바이트를 처리하는 것보다 4바이트 단위로 데이터를 처리할 때 가장 효율이 좋습니다.

때문에 현대의 대부분의 컴파일러는 위와 같은 구조체를 생성할때 4바이트 단위로 멤버를 정렬해서 처리합니다. 한가지 예로...

struct aaa{
int a; /*여기서 4바이트 할당..*/
char b; /*여기서 4바이트 할당 , 그중 첫번째 바이트 사용*/
char c; /*여기서는 위에서 할당된 4바이트중 두번째 바이트 사용*/
/*나머지 두바이트는 사용안함..*/
};

와 같이 해도 크기는 8입니다. 다음 두 구조체는 멤버는 같은데 멤버를 나열한 순서가
다를 뿐입니다. 하지만 구조체의 크기는 달라집니다.

struct aaa{
int a; /*4바이트 할당..*/
char b; /*4바이트 할당 , 그중 첫번째 바이트 사용*/
char c; /*위에서 할당된 4바이트중 두번째 바이트 사용*/
/*나머지 두바이트는 사용안함..*/
int d; /*4바이트*/
short e; /* 4바이트 할당하고 처음 두바이트 사용*/
/*두바이트 사용안함*/
};

메모리 구조는 다음과 같습니다.
===========================================
Low High (Memory Address)
a a a a | b c - - | d d d d | e e - -|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
===========================================
총 16바이트가 됩니다.

멤버는 같지만 정렬을 다르게 해보면 또 크기가 달라집니다.

struct aaa{
int a; /*4바이트 할당..*/
char b; /*4바이트 할당 , 그중 첫번째 바이트 사용*/
char c; /*위에서 할당된 4바이트중 두번째 바이트 사용*/
short e; /* 나머지 두 바이트 사용*/
int d; /*4바이트 할당*/
};

===========================================
Low High (Memory Address)
a a a a | b c e e | d d d d |
1 2 3 4 5 6 7 8 9 10 11 12
===========================================
총 12바이트가 됩니다.

하지만 단순히
struct aaa{
char a;
};
처럼 멤버가 하나뿐인 경우에는 그 멤버의 크기가 그대로 리턴됩니다.

이같은 바이트 정렬은 일반 응용 프로그램을 개발할때는 그리 신경쓰지 않아도
될 것 같긴 합니다만.. 소켓이나 시스템프로그래밍을 하신다면 알아두는 것이
도움이 됩니다.

컴파일러 최적화 옵션을 잘 사용하면 강제적으로 1바이트씩 할당하게 할수도
있습니다.

============================================================
두번째로 마지막 값이 "k"인데요..

너무 당연한 결과같습니다.-,.ㅡ;;;

int a;
a=4;
a=5;
a=6;

하면 당연히 a값은 6이 됩니다.ㅡㅡ;;;

cards[0]->shape='a';
cards[0]->shape='b';
cards[0]->shape='c';

할당된 메모리에 값을 넣는 것이지.매번 새로운 공간을 할당하기는 것은 아니겠죠.

cards[0]->shape='a';
cards[0]->shape='b';
cards[0]->shape='c';
cards[0]->shape='d';

처럼 4 번 값을 대입해서 여기에 4바이트가 새로 할당되는 것이 아니라
위처럼 컴파일러에 의해서 미리 4바이트가 할당되어 있고 , 그중에 첫번째 바이트의 값을 4번 바꾸는 겁니다.

..

sisbn의 이미지

제가 늦게 들어오게 되었네요. 답변 해주신 분들 모두께 감사드립니다.^^

댓글 달기

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