brunch

매거진 Sinclair

You can make anything
by writing

C.S.Lewis

by Sinclair Aug 01. 2016

Advanced Pointer I

록 삼총사와 친구들 III




void * calloc(size_t , size_t) ;


malloc() 함수처럼 heap 메모리 영역에 개체 단위로 메모리를 할당하는 함수입니다. 인자로 넘겨야 할 두 개의 사이즈 중 앞에 있는 것이 할당할 개체의 개수이고 뒤에 있는 것이 한 개체의 사이즈입니다. 메모리를 할당하고 할당된 메모리 공간의 모든 비트를 0으로 초기화합니다. 초기화하는 것 때문에 속도 면에서는 malloc() 함수에 비해 느리다고 알려져 있습니다. malloc() 함수처럼 메모리가 부족하여 공간이 할당되지 않는 등 문제가 발생하게 되면 널 포인터를 리턴 합니다.  



#include <stdio.h>

#include <stdlib.h>

/*

* copyleft (l) 2006 - 2017 programmed by Sinclair

*/

// prototypes

int getMemory3(register void * , size_t , size_t , size_t) ;

//         잡을 공간 묶음개수 데이터개수 타입사이즈

#define M_USLEEP_TIME    300

#define M_DOING_AGAIN     5

#define M_ERROR_MSG     "돈이 엄써서 메모리도 몬사고.. 죄송합니데이.."


int getMemory3(register void * pp , size_t n , size_t m , size_t t) {

    register int i ;

    register int tag = 0 ;

    while( !( *(char***)pp = (char **)malloc(sizeof(void*) * n) ) ) {

        perror(M_ERROR_MSG) ;

        if( ++tag > M_DOING_AGAIN) {

            return 1 ;

        } // end if

        usleep(M_USLEEP_TIME) ; // 0.3ms 동안 쉬어라~ <- 비표준 함수

    } // end while


    tag = 0 ;

    for( i = n /* 위에서 잡을 때 사용한 값 */ ; i > 0 ; ) {

     while( !( *(*(char***)pp + --i) = (char*)calloc(m , t) ) ) {

            perror(M_ERROR_MSG) ;

            if( ++tag > M_DOING_AGAIN ) {

                register int j ;

                for ( j = n ; j > i ; ) {

                 free(*(*(char***)pp + --j)) ; // 해제

                } // end inner for

                free(*(char***)pp) ;

                return – ++i ; // == -(i+1) == -i - 1    

            } // end if

            usleep(M_USLEEP_TIME) ;

        } // end while

    } // end for

#ifdef __EASIER___

    for( i = 0 ; i < n /* 위에서 잡을 때 사용한 값 */ ; ++i ) {

     while( !( *(*(char***)pp + i) = (char*)calloc(m , t) ) ) {

            perror(M_ERROR_MSG) ;

            if( ++tag > M_DOING_AGAIN ) {

                register int j ;

                for ( j = i-1 ; j >= 0 ; --j ) {

                 free(*(*(char***)pp + j)) ; //해제

                } // end inner for

                free(*(char***)pp) ;

                return -i - 1     ;

            } // end if

            usleep(M_USLEEP_TIME) ;

        } // end while

    } // end for

#endif

    return 0 ;

}  // end getMemory3()

/*

Usage:

type ** pointer ;

if( getMemory3( &pointer , 4 , 5 , sizeof(type)) ) {

        // 에러 처리 여기에서~

} // end if

// 이렇게 잡으면 int pointer[4][5]의 효과

*/   




자, 동적 할당의 아름다움을 잘 보셨나요? 이제 우리는 앞서 다른 글타래에서 동적 할당을 못해서 그냥 최대값을 지정한 뒤 일차원 배열을 사용하여 작성했던 마방진 프로그램을 확장해 보겠습니다.     



홀수 마방진을 만들어 주는 프로그램 ii: 동적 할당 1


#include <stdio.h>

/*

* copyleft (l) 2006 - 2017 programmed by Sinclair

*/

// prototypes

// 이 함수들은 고칠 것이 없습니다.  from https://brunch.co.kr/@sinclairo/29

extern int onlyInt(int *) ;  

extern int fgets4(register char * , int) ; 

extern int magic(register int * , int);

extern int presentation(register const int * , int) ;


extern int getMemory2(void * , size_t) ;  


int main() {

    //int matrix[19*19] ;

    int * matrix ;

    int digit ;

    char toBeContinue ;

    while(1) {

        toBeContinue = 0 ;

        while (1) {

            if( toBeContinue++ > 5 ) {

                puts("정녕 마방진을 구하구 싶은 게냐? 콱 이걸 증말...") ;

                exit(-1) ;

            } // end if

            puts("마방진 구해드립니다.. 3 이상의 홀수를 입력하세요..") ;

            if(onlyInt(&digit)) {

                puts("어허~ 숫자가 아닌 걸 입력하면 아니 되오..") ;

                continue ;

            } // end if

            // if( !(digit % 2) || (digit < 3 || digit > 20 ) ) {

            if( digit < 3 || !(digit % 2) ) {    

                puts("한글 못 읽어요? 홀수 몰라? odd number말야~") ;

                continue ;

            } // end if

            break ;

         } // end inner while

        /**************************************************/

        // append from Sinclair 200Y.MM.DD HH:MM

        // free(matrix) ;

        if( getMemory2( &matrix , sizeof(int) * digit * digit ) ) {

             puts("메모리가 부족하여 프로그램이 더 이상 진행되지 못합니다.\n"

                            /* 콤마나 다른 것 없이 일부러 한번 갈라봤습니다. */

                            "죄송합니다. 다음에 다시 이용해주세요.\n\n") ;

                 return -1 ;

        } // end if

        /**************************************************/

        magic(matrix , digit) ;

        presentation(matrix , digit) ;

        free(matrix) ; // here!!!!!!

        puts("한 번 더 해드릴까요?(y/any key) 웬만하면 좀 그만두시죠..") ;

        fgets4( (char*)&digit , 2/*sizeof digit*/) ;

        if( tolower(*(char*)&digit) != 'y' ) break ;

        system("clear") ; // on DOS system("cls") ;

    } // end outer while

    return 0 ;

} // end main()   




제가 왜 처음에 일차원 배열을 사용했는지 이제는 이해가 되나요? 아직 잘 모르겠다면 프로그램을 좀 더 많이 짜봐야 합니다. 매일 프로그램 한 개씩 백 일 동안 총 백 개의 프로그램을 작성해 본다면 어느 순간 모든 것이 마음 속 깊이 이해 되는 순간을 맞이 할 수 있습니다. 그냥 코딩을 하더라도 저절로 적절한 메모리 구조를 선택하는 그날이 분명 다가올 겁니다. 오랫동안 삼성전자에서 연구원들을 가르치면서 느낀 것이 누구나 한번쯤 그런 결심을 굳게 하지만 그것을 실행에 옮기는 사람이 매우 적다는 것입니다. 제가 이 이야기를 하면 매번 자신은 다를 거라고 믿어 달라고 합니다. 그러나 몇 달 후 지나가다 멀리서 보게 되면 제가 어떻게 됐냐고, 프로그램은 몇 개나 짰냐고 물어볼까 봐 두려운지 확 쌩까고 지나갑니다. 그런데 사실 고백하자면 저도 잘 못하는 부분입니다. 늘 마음으로는 멋지게 살아야지 하면서 부끄럽게도 실제로 행동에 옮긴 것이 얼마 되지 않습니다. 저도 뭐 여러분들과 똑 같은 사람입니다. 그러니 앞으로 이젠 쌩까지 않아도 됩니다.

만약에 이중 포인터를 써보고 싶다면 magic() 함수와 presentation() 함수를 바꿔야 합니다. 그다지 권하고 싶지는 않지만 굳이 원하신다면 한 번 주의 깊게 살펴보시길 바랍니다.    



홀수 마방진을 만들어 주는 프로그램 iii: 동적 할당 2  


#include <stdio.h>

/*

* copyleft (l) 2006 - 2017 programmed by Sinclair

*/

// prototypes

extern int onlyInt(int *) ;

extern int fgets4(register char * , int) ;

extern int getMemory3(register void * , size_t , size_t , size_t) ;


int magic2(register int ** , int);

int presentation2(register const int * , int) ;  

int main() {

    //int matrix[19*19] ;

    //int * matrix ;

    int ** matrix ;

    int digit ;

    char toBeContinue ;

    while(1) {

        toBeContinue = 0 ;

        while (1) {

            if( toBeContinue++ > 5 ) {

                puts("정녕 마방진을 구하구 싶은 게냐? 콱 이걸 증말...") ;

                exit(-1) ;

            } // end if

            puts("마방진 구해드립니다.. 3 이상의 홀수를 입력하세요..") ;

            if(onlyInt(&digit)) {

                puts("어허~ 숫자가 아닌 걸 입력하면 아니 되오..") ;

                continue ;

            } // end if

            //if( !(digit % 2) || (digit < 3 || digit > 20 ) ) {

            if( digit < 3 || !(digit % 2) ) {    

                puts("한글 못 읽어요? 홀수 몰라? odd number말야~") ;

                continue ;

            } // end if

            break ;

         } // end inner while

        // free(matrix) ;

        if( getMemory3(&matrix , digit , digit , sizeof(int)) ) {

             puts("메모리가 부족하여 프로그램이 더 이상 진행되지 못합니다.\n"

                            "죄송합니다. 다음에 다시 이용해주세요.\n\n") ;

                 return -1 ;

        } // end if

        magic2(matrix , digit) ;

        presentation2(matrix , digit) ;

        // free here!!!!!!

        for( i = digit ; i > 0 ; )

            free(matrix[--i]) ;

        free(matrix) ;

        puts("한 번 더 해드릴까요?(y/any key) 웬만하면 좀 그만두시죠..") ;

        fgets4((char*)&digit , 2/*sizeof digit*/) ;

        if( tolower(*(char*)&digit) != 'y' ) break ;

        system("clear") ; // on DOS system("cls") ;

    } // end outer while

    return 0 ;

} // end main()  


int magic2(register int ** m , int n) {

    // Thanks for 신권영( http://user.chollian.net/~brainstm/ )

    register i , j , num = 1 ;

    int seed = n * 3 / 2 ;

    for(i = 0; i < n ; i++)

        for(j = 0 ; j < n ; j++)

            m[((j-i+seed)%n)][(i*2-j+n)%n] = num++ ;

    return 0 ;

} // end magic2()  


int presentation2(register const int ** m , int n) {

    register i , j ;

    for ( i = 0 ; i < n ; i++ )     {

        for ( j = 0 ; j < n ; j++ )         {

            printf("%5d" , m[i][j]) ;

        } // end inner for

        putchar('\n') ;

    } // end outer for

    putchar('\n') ;

    return 0 ;

} // end presentation2()    








#Sinclair #씽클레어 #싱클레어 #씽클레어도씨 #씨언어 #씨프로그래밍  #C언어 #Cprogramming #C_Programming #C #Programming #Clanguage #C_Language

매거진의 이전글 Advanced Pointer I
작품 선택
키워드 선택 0 / 3 0
댓글여부
afliean
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari