1580, 9/79 회원가입  로그인  
   sihun1113
   [C기초] 11 - 함수 매개변수로 배열을 넘기려면?

http://www.hackerschool.org/HS_Boards/zboard.php?id=Free_Lectures&no=1747 [복사]


출저= 때릴꺼야
*----------------------------------------------------------------------------------------------------------*

이 카테고리는 그동안 배웠던것이라던가 공부하면서 알게된 내용들을 중심으로 혹여 참고가 될 수 있을까 싶은 내용들을

모아둔 곳입니다. 따라서 이 글들을 대상이 되는 분들은.. 프로그래밍을 갓 시작했거나 개념이 마구마구 흔들리시는 분들

정도가 되겠습니다. 그러니 너무 욕하지는 말아주세요 =_=;;;



혹시 제가 잘못 알고 있는 부분들이라던가 궁금한 것이 있으면 쪽지 남겨주시거나 리플을 달아주시면 감사하겠습니다.

*----------------------------------------------------------------------------------------------------------*



-- 앞에 쓰는 P.S ----------------------------------------------------------------------------------------------------

이 스터디를 작성하기 시작한게... 작년 12월 초쯤이었으니.... 무려 5개월만에 이걸 끝내게 됐군요 ㅡ,.ㅡ;;;

반성해야겠습니다 ㅜㅜ.. 아무튼.. 그동안에 좀 일이 많았었습니다.. 일본도 다녀오고.. 집도 이사 가고... 쭈뼛쭈뼛.. =_=;;

다음 스터디 주제는 전혀 정해진바가 없네요. 언제 또 연재 할 수 있을런지 모르겠습니다만..

어떻게든 되겠죠 뭐.. (무책임.. 퍽!!)

--------------------------------------------------------------------------------------------------------------------



지난 스터디에서 언급한대로 함수에 다차원배열 매개변수를 넘길때의 주의할 사항을 짚어보도록 하겠습니다.



다차원 배열.. 사용법만 알면 매우 간단하지만 그게 그리 쉬운일이 아니죠. 그래서 다들 다차원 배열을 쉬쉬하고 넘어가는 것일테구요.

일반적으로 다차원 배열은 아래와 같이 선언하여 사용합니다.



int badook[19][19];



위에 선언된 2차원 int 배열인 badook 변수를 매개변수로 함수에 전달하는 것을 연습해 보겠습니다.



--------------------------------------------------------------------------------

#include <stdio.h>



#define WHITE true
#define BLACK false



void set_stone( int board, int x, int y, bool color )
{
    if( color )    board[x][y] = 1;
    else           board[x][y] = -1;
}



void main()
{
    int badook[19][19] = {0,};

    set_stone( &badook, 9, 9, BLACK );
}

--------------------------------------------------------------------------------





위 코드는 바둑판 위의 x,y 좌표에 color의 돌을 올려놓는 프로그램을 간략화 한것입니다.

그리고 아래 코드는 10,10(index는 9,9) 좌표에 흑돌을 올려두려는 시도겠지요?

자, 이 프로그램이 제대로 작동 될까요? 물론 안됩니다.



먼저, set_stone 함수에서 분명 board는 int형 변수인데 [] 첨자를 이용해서 2차원 접근을 하려고 시도를 하고 있군요. 이건 볼것도 없이 에러가 납니다.



다음으로, 함수 파라미터에는 int board 로 선언했는데 넘겨주려는 badook 판은 [18][18]의 2차원 int형 배열입니다. 따라서 2차원 포인터라는 얘기지요. 그러므로 2차원 포인터를 일반 int형 변수에 대입하려 하는 타입 불일치 오류가 발생합니다.



따라서 이런 에러 메시지가 나오게 됩니다.





--------------------------------------------------------------------------------

test.cpp
...\test.cpp(9) : error C2109: 첨자는 배열 또는 포인터 형식을 사용해야 합니다.
...\test.cpp(11) : error C2109: 첨자는 배열 또는 포인터 형식을 사용해야 합니다.
...\test.cpp(18) : error C2664: 'set_stone' : 매개 변수 1을(를) 'int (*__w64 )[18][18]'에서 'int'(으)로 변환할 수 없습니다.
        변환하려면 reinterpret_cast, C 스타일 캐스트 또는 함수 스타일 캐스트가 필요합니다.


--------------------------------------------------------------------------------





아~! 그렇다면 함수 파라미터 선언부에서 int board를 2차원 포인터인 int** board로 바꾸면 되겠군요? 한번 해 볼까요?





--------------------------------------------------------------------------------

#include <stdio.h>



#define WHITE true
#define BLACK false



void set_stone( int** board, int x, int y, bool color )
{
{
    if( color )    board[x][y] = 1;
    else           board[x][y] = -1;
}}



void main()
{
    int badook[19][19] = {0,};

    set_stone( &badook, 9, 9, BLACK );
}

--------------------------------------------------------------------------------





--------------------------------------------------------------------------------

test.cpp
...\test.cpp(18) : error C2664: 'set_stone' : 매개 변수 1을(를) 'int (*__w64 )[19][19]'에서 'int ** '(으)로 변환할 수 없습니다.
        가리킨 형식이 관련이 없습니다. 변환하려면 reinterpret_cast, C 스타일 캐스트 또는 함수 스타일 캐스트가 필요합니다.
--------------------------------------------------------------------------------





어라? 이건 또 무슨 오류일까요?



이게 다차원 배열변수를 넘길때 실수하는 가장 대표적인 문제입니다.

분명히 badook이라는 변수는 2차원 포인터이고.. 함수에서 받는 것도 2차원 배열입니다. 그리고 목적한바를 이루기 위해서 2차원 포인터의 주소값을 넘겨주었습니다. 그런데? 아뿔싸!.. set_stone( &badook, 9, 9, BLACK ).. 이걸 보니.. 2차원 포인터의 주소, 즉, 3차원 포인터를 넘겨주었네요.

왜냐하면 badook 자체가 2차원 포인터이기 때문이지요. 따라서 그 앞에 &가 붙게 되면 3차원 포인터가 되어버리는 것입니다.

아하~! 그렇다면 set_stone( &badook, 9, 9, BLACK );가 아니고 set_stone( badook, 9, 9, BLACK );라는 말씀이시죠?

수정해 보겠습니다.





--------------------------------------------------------------------------------

test.cpp
test.cpp(18) : error C2664: 'set_stone' : 매개 변수 1을(를) 'int [19][19]'에서 'int ** '(으)로 변환할 수 없습니다.
        가리킨 형식이 관련이 없습니다. 변환하려면 reinterpret_cast, C 스타일 캐스트 또는 함수 스타일 캐스트가 필요합니다.
--------------------------------------------------------------------------------





얼씨구? 똑같은 2차원 포인터인데도 뭔가 다르다고 얘가 난리를 치네요? 이쯤 되면 '뭐가 다차원포인터냐? 다 때려쳐!'라며 포기하는 사람들이 생기기 시작합니다. 도대체가 실마리라도 보여야 뭔가 해결을 해야 할건데 알수가 없네요...라고 생각하시겠죠?



그러나!! 이미 실마리는 다 제공 되어있습니다.



오류코드를 읽어보면 'int [19][19]'라는 변수형과 'int **'형의 차이에서 오는 문제라는 것을 알 수 있겠지요?

차근차근 짚어봅시다.



만약 우리가 아래와 같은 코드를 짠다고 생각해 봅시다.



--------------------------------------------------------------------------------

#include <stdio.h>



#define BLACK true

#define WHITE false



void set_stone( int* line, int xPos, bool color )

{

    if( color )    line[xPos] = 1;

    else           line[xPos] = -1;

}



void main()

{

    int Line[100] = {0,};

    set_stone( Line, 49, BLACK );

}

--------------------------------------------------------------------------------



위의 코드는 우리가 만들려고 했던 바둑판 소스와 별 차이가 없습니다. 단지 2차원 배열에서 1차원 배열로, 포인터 역시 2차원 포인터에서 1차원 포인터로 바뀌었다는 것만이 다를 뿐인데 왜 이런 차이가 생기는 걸까요?



그럼 다시 포인터의 기본으로 돌아가 볼까요?

7번 스터디 포인터의 타입과 접근법에서  포인터에 여러가지 형(Type)이 존재하는 이유는, 참조하는 위치로부터 읽어들여야 할 메모리 범위와 용도를 한정하기 위해서라고 했었습니다.



아래의 코드를 봅시다.

--------------------------------------------------------------------------------

#include <stdio.h>

void main()
{
    int     Num[3][3], i;
    int*    pNum;
    int**  ppNum;



    for( i=0; i<3; i++ )
        printf( "Num[0][0]+%d 의 주소:%d\n", i, &Num[0][0]+i );



    for( i=0; i<3; i++ )
        printf( "Num[0]+%d 의 주소:%d    pNum+%d 의 주소:%d\n", i, &Num[0]+i, i, &pNum+i );


    for( i=0; i<3; i++ )
        printf( "Num+%d 의 주소:%d    ppNum+%d 의 주소:%d\n", i, &Num+i, i, &ppNum+i );

}

--------------------------------------------------------------------------------

실행 결과는 아래와 같습니다

--------------------------------------------------------------------------------

Num[0][0]+0 의 주소:1243000
Num[0][0]+1 의 주소:1243004
Num[0][0]+2 의 주소:1243008

Num[0]+0 의 주소:1243000    pNum+0 의 주소:1243036
Num[0]+1 의 주소:1243012    pNum+1 의 주소:1243040
Num[0]+2 의 주소:1243024    pNum+2 의 주소:1243044

Num+0 의 주소:1243000    ppNum+0 의 주소:1243040
Num+1 의 주소:1243036    ppNum+1 의 주소:1243044
Num+2 의 주소:1243072    ppNum+2 의 주소:1243048

--------------------------------------------------------------------------------



위의 결과를 보면 Num[0][0]+i 의 포인터 연산 결과는 예상대로 4Byte씩 증가합니다.

반면 2차원 포인터인 Num[0]+i 의 포인터 연산 결과는 12Byte씩 증가하는군요. 그러나 역시 2차원 포인터인 그 옆의 pNum+i의 포인터 연산 결과는 Num[0][0]+i 와 마찬가지로 4Byte씩 증가를 합니다.

그 아래의 3차원 포인터인 Num+i 의 연산결과와 ppNum+i의 연산 결과를 비교해 보세요.

뭔가 차이점과 공통점이 보이십니까?



이걸 보시면 확연한 차이를 알 수 있을겁니다.



--------------------------------------------------------------------------------

#include <stdio.h>

void main()
{
    int     Num[3][3], i;
    int*    pNum;
    int**  ppNum;



    printf( "sizeof(Num[0]):%d\tsizeof(Num):%d\n",
              sizeof(Num[0]), sizeof(Num));
    printf( "sizeof(pNum):%d\tsizeof(ppNum):%d\n",
              sizeof(pNum), sizeof(ppNum) );
}

--------------------------------------------------------------------------------

실행 결과는 아래와 같습니다

--------------------------------------------------------------------------------

sizeof(Num[0]):12    sizeof(Num):36
sizeof(pNum):4        sizeof(ppNum):4
--------------------------------------------------------------------------------



이 결과를 보면 우리가 '똑같은' 2차원 포인터라 생각했던 두 포인터가 사실은 전혀 다른 것이라는 것을 알 수 있습니다.

따라서 원하는 결과를 얻기 위해서는 동일한 타입의 포인터를 사용해야 한다는 것을 알 수 있지요



다시 처음으로 돌아가 볼까요?



--------------------------------------------------------------------------------

void set_stone( int** board, int x, int y, bool color )
{
    :

}



void main()

{

    int badook[19][19]

    :

    set_stone( badook, 9, 9, BLACK );

}
--------------------------------------------------------------------------------

test.cpp(18) : error C2664: 'set_stone' : 매개 변수 1을(를) 'int [19][19]'에서 'int ** '(으)로 변환할 수 없습니다.
        가리킨 형식이 관련이 없습니다. 변환하려면 reinterpret_cast, C 스타일 캐스트 또는 함수 스타일 캐스트가 필요합니다.
--------------------------------------------------------------------------------



위 에러에서 두개의 타입이 다르다고 했으니 이제 바꿀 것은 하나로 좁혀졌습니다.

바로 함수 원형의 매개변수 타입입니다. 그럼 이렇게 바꾸어 볼까요?



--------------------------------------------------------------------------------

void set_stone( int board[19][19], int x, int y, bool color )
{

    if( color )    board[x][y] = 1;
    else           board[x][y] = -1;
}



void main()

{

    int badook[19][19] = {0,};

    set_stone( badook, 9, 9, BLACK );

}

--------------------------------------------------------------------------------

----------------------완료----------------------

    빌드: 성공 1, 실패 0, 생략 0

--------------------------------------------------------------------------------



만세!!! 드디어 성공입니다!

실제로 맞게 들어갔는지도 확인 해 봅시다.

이 아래의 코드만 메인함수 마지막에 살~포시 추가해 줍니다.



--------------------------------------------------------------------------------

    for( int i=0; i<19; i++, printf("\n") )
    for( int j=0; j<19; j++ )
        printf( "%3d", badook[i][j] );
--------------------------------------------------------------------------------

  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0 -1  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
Press any key to continue

--------------------------------------------------------------------------------



제대로 입력이 된것을 확인 한 수 있습니다.



오늘의 스터디를 통해 알수 있는 것은, 다차원 배열에서 포인터를 넘기고자 할때, 받는 함수에서의 매개변수형이 전달하는 배열의 형과 일치하여야 한다는 것입니다. 이것만 실수하지 않으면 다차원 배열도 앞으로는 내 마음대로 주무를 수 있는 힘!!!을 가지게 된다는 겁니다 ^^



그럼 여러분 열공 하시고 다음 스터디때 뵙겠습니다.

  Hit : 10574     Date : 2011/05/01 11:34
[불법/스팸글로 신고하기]



    
1420   [펌]Ptrace를 이용한 재미는 해킹.[4]     ^^
02/08 10845
1419   해킹기법? (기발하다고 해야하나,웃기다고 해야하나)[35]     whqkdnf000
07/31 10816
1418   [Reverse Engineering] 리버싱의 기초 - 범용 레지스터와 Assembly(Pop,Mov)     zen0c1de
07/18 10764
1417   [펌]스니핑[1]     loveaaav
03/24 10702
1416   c언어 for문      hacs98
06/15 10672
1415   I. 리눅스 구조 및 일반 명령어.     괴도js
07/04 10617
  [C기초] 11 - 함수 매개변수로 배열을 넘기려면?      sihun1113
05/01 10573
1413   왠만한사람들은다알지도모르겠지만[6]     백룡출해
03/17 10561
1412   C언어(진법)[9]     whqkdnf000
02/25 10534
1411   메모리 덤프(블루 스크린=STOP 스크린) 코드 및 해결[1]     ROK.AF
02/09 10485
1410   네트워크 개념 휘어잡기 7[8]     소유
09/16 10451
1409   리눅스 명령어 한꺼번에(소유님꺼)[11]     ssakura
07/07 10407
1408   알기 어렵게 설명한 Buffer Overflow[4]     blackcoder
02/17 10348
1407   [동강]백트랙을 이용한 재밌는 놀이들![4]     cdpython
09/29 10293
1406   개발자가 알아야할 10가지 보안팁으로 코드를 보호하자.     푸른하늘
09/01 10281
1405   [자작]포렌식을위한NTFS구조[2]     havu
01/11 10273
1404   네트워크 개념 휘어잡기 6[10]     소유
09/15 10265
1403   배열 내에서 랜덤한 n개 추출하기[2]     kjwon15
12/05 10253
1402   D.Dolphin님 질문내용] LAN과 WAN의 차이점과 VAN의 정의[5]     푸른하늘
09/11 10223
1401   원격종료....[39]     bsjzzz
01/02 10155
[1][2][3][4][5][6][7][8] 9 [10]..[79]

Copyright 1999-2021 Zeroboard / skin by Hackerschool.org / Secure Patch by Hackerschool.org & Wowhacker.com