[완료] malloc, realloc을 사용한 메모리 할당 문제입니다.

yundorri의 이미지

아래와 같이 프로그램을 했습니다.
구조체를 만들어서 1000개만큼 새로 메모리를 할당받아
임의의 내용을 집어넣는 프로그램입니다.
그런데 실행을 하면 중간에 세그가 납니다.
왜 나는지 도저히 모르겠습니다.
고수님들 도와주십시요~~~~

#include [stdio.h]
#include [string.h]
#include [stdlib.h]
 
typedef struct FILE_STRUCT
{
    char filename[128];
    long filestamp;
} FILE_S;
 
int main( int argc, char** argv )
{
    int count = 0;
    FILE_S* mem;
 
    for( int i = 0; i < 1000; i++ )
    {
        printf( "TP1: File %03d... ", count );
 
        if( ! count )
        {
            mem = (FILE_S*)malloc( sizeof(FILE_S) );
            memset( mem, 0,  sizeof(FILE_S) );
            printf( "size %d bytes created and bzeroed\n", sizeof(FILE_S) );
        }
        else
        {
            mem = (FILE_S*)realloc( mem, sizeof(FILE_S) + sizeof(FILE_S)*count );
            memset( mem, 0, sizeof(FILE_S) + sizeof(FILE_S)*count );
            printf( "size %d bytes re-allocated and bzeroed\n", sizeof(FILE_S) + sizeof(FILE_S)*count );
        }
 
        strcpy( (mem + count*sizeof(FILE_S))->filename, "asdfasdf.txt" );      // 나중에 file명이 들어갑니다.
        (mem + count*sizeof(FILE_S))->filestamp = i+1;                                 // 읽은 파일의 시간스탬프가 들어갑니다. (정렬을 목적으로)
        count++;
    }
 
    for( int i = 0; i < count; i++ )                                                                      // 제대로 저장이 되었나 확인하는 부분입니다.
    {
        printf( "File %03d [%s] = %ld\n", i+1,
                (mem+ i*sizeof(FILE_S))->filename,
                (mem+ i*sizeof(FILE_S))->filestamp );
    }
    free( mem );
 
    return 0;
}

실행결과입니다.

[yundorri@swdev2 filesort]$ ./test
TP1: File 000... size 132 bytes created and bzeroed
TP1: File 001... size 264 bytes re-allocated and bzeroed
TP1: File 002... size 396 bytes re-allocated and bzeroed
TP1: File 003... size 528 bytes re-allocated and bzeroed
TP1: File 004... size 660 bytes re-allocated and bzeroed
TP1: File 005... size 792 bytes re-allocated and bzeroed
TP1: File 006... size 924 bytes re-allocated and bzeroed
TP1: File 007... size 1056 bytes re-allocated and bzeroed
TP1: File 008... size 1188 bytes re-allocated and bzeroed
세그멘테이션 오류
[yundorri@swdev2 filesort]$ 
grassman의 이미지

mem의 type이 FILE_S *이므로 character로 계산하여 sizeof(FILE_S)를 곱해주면 문제가 생깁니다. pointer의 증감 연산은 type의 크기를 계산하므로 sizeof는 불필요합니다.

mem + count*sizeof(FILE_S) -> mem + count
mem + i*sizeof(FILE_S) -> mem + i

appler의 이미지

조기 나중에 파일명 들어갑니다...거기서 부터 아래로

구조체 포인터 호출시에

사이즈는 빼주시면 되겠습니다.

34 strcpy( (mem + count*sizeof(FILE_S))->filename, "asdfasdf.txt" );      // 나중에 file명이 들어갑니다.
35 (mem + count*sizeof(FILE_S))->filestamp = i+1;                                 // 읽은 파일의 시간스탬프가 들어갑니다.
42 (mem+ i*sizeof(FILE_S))->filename,
43 (mem+ i*sizeof(FILE_S))->filestamp );

위 코드에서 *sizeof(FILE_S)를 빼주시면 됩니다.

34번째 줄부터군요..^^;

구조체 포인터 역시

일반 포인터와 마찬가지로 덩어리를 통째로 가는것이 아니라 포인터 주소만 가지므로

각각의 크기연산은 필요없습니다.


laziness, impatience, hubris

不恥下問 - 진정으로 대화를 원하면 겸손하게 모르는 것은 모른다고 말하는 용기가 필요하다.


laziness, impatience, hubris

不恥下問 - 진정으로 대화를 원하면 겸손하게 모르는 것은 모른다고 말하는 용기가 필요하다.

yundorri의 이미지

감사합니다. 두 분 도움으로 일차문제는 해결되었습니다.
그런데, realloc() 이 새로할당 받은 주소에 기존 주소에서 가지고 있던 메모리 내용을 복사해 준다고
되어있던데,

http://www.winapi.co.kr/clec/cpp1/10-3-4.htm

실제로는 복사를 안 해주더군요.
이게 int*나 char* 같이 간단한 경우에는 복사를 잘 해주는데 struct와 같이 복잡한 경우에는 안되는건지
는 잘 모르겠습니다. 그래서 위 코드에 두 분 말씀대로 sizeof를 빼고 했더니 마지막 file만 남는 현상으로
복사가 안된다고 생각을 해서 현재 사이즈만큼 임시변수로 할당받고 백업을 한 뒤 realloc하고 복사를
해 주었더니 잘 되었습니다.

 16     for( int i = 0; i < 1000; i++ )
 17     {
 18         printf( "TP1: File %03d... ", count );
 19         fflush( NULL );
 20
 21         if( ! count )
 22         {
 23             mem = (FILE_S*)malloc( sizeof(FILE_S) );
 24             memset( mem, 0,  sizeof(FILE_S) );
 25             printf( "size %d bytes created and bzeroed\n", sizeof(FILE_S) );
 26         }
 27         else
 28         {
 29             <span>temp = (FILE_S*)malloc( sizeof(FILE_S) * count );                  // 임시로 공간을 만들어서</span>
 30             <span>memcpy( temp, mem, sizeof(FILE_S)*count );                           // 백업을 해 둡니다.</span>
 31
 32             <span>mem = (FILE_S*)realloc( mem, sizeof(FILE_S)*(count+1) );    // 새로 할당받은 후에 </span>
 33             memset( mem,     0, sizeof(FILE_S)*(count+1) );
 34             <span>memcpy( mem, temp, sizeof(FILE_S)*count );                            // 백업한 내용을 복사해 줍니다.</span>
 35             printf( "size %d bytes re-allocated and bzeroed\n", sizeof(FILE_S)*(count+1) );
 36         }
 37
 38         printf( "strcpy( ((mem(%ld)+%ld)(%ld))->filename, \"asdasdf.txt\"\n",
 39                 mem, count*sizeof(FILE_S), (mem+count)->filename );
 40
 41         strcpy( (mem + count)->filename, "asdfasdf.txt" );
 42         (mem + count)->filestamp = i+1;
 43         count++;
 44     }

그런데 이렇게 하면 performance 면에서 많이 불리해 질것 같은데 이럴 수 밖에없는 건지요?
php의 array_sort 기능을 만들어볼라니까 무지하게 힘들군요. T_T

grassman의 이미지

다만 realloc 이후에 memset으로 내용을 지우시더군요.

memset( mem, 0, sizeof(FILE_S) + sizeof(FILE_S)*count );

이 부분은 의도적인 부분으로 생각했습니다만 아니었나보군요.
의도하신대로의 동작을 하려면

memset( mem + count, 0, sizeof(FILE_S) );

가 되어야 합니다.

yundorri의 이미지

제가 잘못 이해했나 보군요!!!

man realloc을 하면 새로 할당되는 부분은 초기화가 되지 않는다 라는 부분이 있어서
memset을 했던건데 그러면 안되는 거였네요.

실~~수!!!

shyblue의 이미지

메모리풀을 만들고, 메모리풀 사용량이 모자랄경우에 다시 realloc을 하는 구조를 사용하시는것이 더 좋을듯합니다.
realloc의 비용은 싸지 않습니다. 특히나 그것이 반복문안에 들어있을 경우... ㅡㅡ;;

처음 충분한 공간의 메모리풀을 확보해서 사용하고, 풀이 모자랄경우, 다시 특정한 용량만큼을 realloc하는 구조로 바꾸시면 perfomance 향상에 도움이 될것입니다.

時日也放聲大哭

時日也放聲大哭

yundorri의 이미지

처음에 만드는 메모리풀 변수명으로 나중에 확장이 가능한가요?
예를 들어,

FILE_S file_list[128];

로 만들었는데 file의 개수가 128개를 초과하여 256개로 늘리고 싶다면...

file_liist를 ...

file_list = realloc( file_list, sizeof( FILE_S ) * 256 );

이렇게 해도 될까요???
실험을 해 보면 알 수 있겠지만.. 아시는 분 계시면 ㅎㅎㅎ
안될것 같은데...

shyblue의 이미지

#define POOL_SIZE 128
int prepare_size = sizeof(FILE_S) * 2
int ext_cnt = 1;
FILE_S *file_list;
file_list = malloc( sizoof(FILE_S) * POOL_SIZE );
 
if(count >= POOL_SIZE - prepare_size )
{
    ext_cnt++
    file_list = realloc( file_list, sizeof(FILE_S) * (POOL_SIZE * ext_cnt );
}

대충 개념상으로 이런식이 되겠죠.
자세한 직접 try 해보시는게 젤 좋습니다. :)
時日也放聲大哭

時日也放聲大哭

yundorri의 이미지

아.. 네. 잘 이해했습니다.

감사합니다.

댓글 달기

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