2017-12-01 2 views
1

가변 개수의 2 차원 문자 배열을 나란히 인쇄하는 C에서 가변 함수를 설정해야합니다. boards 변수를 va_arg()으로 초기화하는 방법을 찾는 데 어려움을 겪고 있습니다.Variadic C 함수가 2 차원 문자 배열을 여러 개 인쇄하는 경우

주요 문제는 다음과 같습니다. boards[i] = va_arg(ap, char*[][BOARDSIZE]);이 줄은 컴파일러 오류 (현재 Second argument to 'va_arg' is of incomplete type 'char *[][10]')를 생성하지만 기본적으로 나는 올바르게 작동하지 않을 것이라고 확신합니다. 그게 뭔지 모르겠습니다. 나는 아무 소용이없는 몇 가지 변형을 시도했다. 코드 의 나머지 부분은이어야합니다.

는 (사전에 어떤 도움을 주셔서 감사합니다.)

#include <stdio.h> 
#include <stdarg.h> 

#define BOARDSIZE 10 

void showBoardVariadic(int numArgs, ...) { 

    va_list ap; 
    va_start(ap, numArgs); 

    // Assign an array of 2-D char arrays. 
    char *boards[numArgs][BOARDSIZE][BOARDSIZE]; 
    for (int i = 0; i < numArgs; i++) 
     boards[i] = va_arg(ap, char*[][BOARDSIZE]); // TODO: Fix this line 

    // Print the 2-D arrays side-by-side 
    for (int row = 0; row < BOARDSIZE; row++) { 
     for (int i = 0; i < numArgs; i++) { 
      for (int column = 0; column < BOARDSIZE; column++) { 
       printf(" %c", *boards[i][row][column]); 
      } 
      printf("\t"); 
     } 
     printf("\n"); 
    } 

    va_end(ap); 
} 

int main() { 

    char *playerBoard[BOARDSIZE][BOARDSIZE]; 
    char *opponentBoard[BOARDSIZE][BOARDSIZE]; 

    // Initialize playerBoard and opponentBoard to all tildes. 
    for (int row = 0; row < BOARDSIZE; row++) { 
     for (int column = 0; column < BOARDSIZE; column++) { 
      playerBoard[row][column] = "~"; 
      opponentBoard[row][column] = "~"; 
     } 
    } 

    showBoardVariadic(2, playerBoard, opponentBoard); 

    return 0; 
} 
+1

당신은 문제가 무엇인지 언급하지 않은 . 컴파일러 오류 메시지? 추락? 'va_arg'에서 잘못된 값이 왔습니까? –

+0

배열을 인수로 전달할 수 없습니다. 항상 포인터를 전달합니다. 배열을 함수 매개 변수로 쓰면 컴파일러는이를 포인터로 읽습니다. 이 점을 염두에두고,'va_arg (ap, char * [] [BOARDSIZE])'에 대해 나쁘다고 생각합니다. 대신 포인터를 읽고 나중에 배열 유형으로 캐스팅하려고합니다. (아니, 사실 나는 또 다른 해결책을 찾으려고 노력할 것이다. var args는 매혹적이지만 멀티 딤 배열과 결합하여 ...) – Scheff

+0

흠 ...'char * boards [numArgs] [BOARDSIZE] [BOARDSIZE]'는 'char *'의 -dim 배열. 귀하의 의견에 따르면, 당신은 대신 2D 배열에 대한 포인터의 배열을 원한다. (나는이 다중 - 희미한 배열 쓰레기를 싫어한다. 그것은 그것을 마스터해야하지만 실제로는 생산적인 가치가 없다.) 단일 희미한 배열과 명시적인 "다중 -dim indexing "은 쉽고 견고하며 유지 보수가 훨씬 쉽습니다.) – Scheff

답변

0

사실, 나는 심지어 다차원 배열 문제를 단지 typedef로 풀지 않는 것을 제외하고는 에릭과 같은 결론에 도달했습니다.

호기심에서, 나는 OP의 작업 버전을 적어 보려고했다. 마침내 나는 내 코드 (Eric Postpischils 응답 외에)를 제시하고자합니다.내가 VS2013에서 해결하려고 문제가 있었다 작업을 도착하기 전에

#include <stdio.h> 
#include <stdarg.h> 

#define BOARDSIZE 10 
#define NCOLS BOARDSIZE 
#define NROWS BOARDSIZE 

typedef char Board[NROWS][NCOLS]; 
typedef char (*PBoard)[NCOLS]; 

void showBoardVariadic(int nArgs, ...) 
{ 
    va_list ap; 
    va_start(ap, nArgs); 
    /* Attention! VLAs are an optional feature of C11. */ 
    PBoard boards[nArgs]; 
    for (int i = 0; i < nArgs; ++i) { 
    boards[i] = va_arg(ap, PBoard); 
    } 
    /* print the 2D arrays side-by-side */ 
    for (int row = 0; row < NROWS; ++row) { 
    for (int i = 0; i < nArgs; ++i) { 
     if (i) putchar('\t'); 
     for (int col = 0; col < NCOLS; ++col) { 
     printf(" %c", boards[i][row][col]); 
     } 
    } 
    putchar('\n'); 
    } 
    va_end(ap); 
} 

int main() 
{ 
    Board playerBoard; 
    Board opponentBoard; 
    /* initialize boards */ 
    for (int row = 0; row < NROWS; ++row) { 
#ifdef CHECK /* for checking */ 
    /* insert some pattern in col 0 for checking */ 
    playerBoard[row][0] = 'a' + row; 
    opponentBoard[row][0] = 'A' + row; 
    for (int col = 1; col < NCOLS; ++col) { 
     playerBoard[row][col] = opponentBoard[row][col] = '~'; 
    } 
#else /* productive code */ 
    for (int col = 0; col < NCOlS; ++col) { 
     playerBoard[row][col] = opponentBoard[row][col] = '~'; 
    } 
#endif /* 1 */ 
    } 
    showBoardVariadic(2, playerBoard, opponentBoard); 
    /* done */ 
    return 0; 
} 

:

그래서, 일부 손보는 후 나는이 작업 버전 testVarArgMDimArray.c을 얻었다. 너무 슬퍼 – VS2013은 VLAs을 지원하지 않습니다. 그러므로 나는 그것을 염두에 두어야 만했다.

내 의견에서 이미 권장했듯이 char* 대신 char을 보드 요소로 선택했습니다. 나는 char*도 해결할 수 있었지만, char*은 OP에서 "우발적 인"선택 일 수 있다고 생각합니다.

typedef char Board[NROWS][NCOLS]; 

더 중요한 두 번째 아마도 :

typedef char (*PBoard)[NCOLS]; 

는 함수 매개 변수의 배열은 항상 기억

에릭의 생각에 따라, 나는 2D 보드 배열의 형태를 만들어 포인터로 컴파일. C는 배열을 인수로 전달하지 않습니다. 따라서 유형이 Board 인 함수를 호출하면 PBoard 유형의 인수가 수신됩니다.

괄호는 *PBoard –입니다. 따라서 PBoard은 배열에 대한 포인터입니다. 당신이 그들을 제거하는 경우 포인터의 배열을 대신 – 큰 차이가 무엇을 의도하지 않습니다.

이것을 숙달하면 showBoardVariadic()의 내용이 다소 쉽게됩니다.

PBoard boards[nArgs]; 

va_arg와 할당은 단순히 :

boards[i] = va_arg(ap, PBoard); 

보드에 대한 액세스는 단순히 :로

보드의 배열이 선언이 힘

printf(" %c", boards[i][row][col]); 

놀랍지 만이 경우 배열에 대한 포인터는 배열 배열처럼 동작합니다. 단지 다른 유형입니다. (예 : 당신은 다른 유형을 적용 할이 경우로 PBoardsizeof을 사용할 수 없습니다.)

을 모든 보드 요소는 개발이 상태에서 같은 내용을 포함, 나는 보드 인덱싱에 문제가 주목 될 수 있는지를 두려워했다 . 따라서 나는 컬럼의 각 첫 번째 요소가 다른 문자를 가져 오는 대체 초기화를 구현했습니다. playerBoard'a' + row의 경우 opponentBoard'A' + row의 경우. 이 테스트 할당은 매크로 CHECK을 정의하여 활성화됩니다. 내 테스트 세션에서, 나는 한번도 -D CHECK으로 컴파일했다.

btw. 내가 왜 NROWSNCOLS을 도입했는지 궁금하다면이 답을 쓰는 동안 OP에서 같은 크기를 가지고 우연히 행과 열을 어딘가에 뒤집 었는지 알지 못한다는 것을 깨달았습니다. 따라서 나는 물건을 분리하고 NROWSNCOLS으로 테스트했습니다. Phew – 여전히 제대로 작동했습니다.

하지 적어도 마지막으로, Cygwin에서 내 샘플 세션 (I 윈도우 10에있어로) :

$ gcc --version 
gcc (GCC) 6.4.0 

$ gcc -std=c11 -D CHECK -o testVarArgMDimArray testVarArgMDimArray.c 

$ ./testVarArgMDimArray 
a ~ ~ ~ ~ ~ ~ ~ ~ ~  A ~ ~ ~ ~ ~ ~ ~ ~ ~ 
b ~ ~ ~ ~ ~ ~ ~ ~ ~  B ~ ~ ~ ~ ~ ~ ~ ~ ~ 
c ~ ~ ~ ~ ~ ~ ~ ~ ~  C ~ ~ ~ ~ ~ ~ ~ ~ ~ 
d ~ ~ ~ ~ ~ ~ ~ ~ ~  D ~ ~ ~ ~ ~ ~ ~ ~ ~ 
e ~ ~ ~ ~ ~ ~ ~ ~ ~  E ~ ~ ~ ~ ~ ~ ~ ~ ~ 
f ~ ~ ~ ~ ~ ~ ~ ~ ~  F ~ ~ ~ ~ ~ ~ ~ ~ ~ 
g ~ ~ ~ ~ ~ ~ ~ ~ ~  G ~ ~ ~ ~ ~ ~ ~ ~ ~ 
h ~ ~ ~ ~ ~ ~ ~ ~ ~  H ~ ~ ~ ~ ~ ~ ~ ~ ~ 
i ~ ~ ~ ~ ~ ~ ~ ~ ~  I ~ ~ ~ ~ ~ ~ ~ ~ ~ 
j ~ ~ ~ ~ ~ ~ ~ ~ ~  J ~ ~ ~ ~ ~ ~ ~ ~ ~ 

$ gcc -std=c11 -o testVarArgMDimArray testVarArgMDimArray.c 

$ ./testVarArgMDimArray 
~ ~ ~ ~ ~ ~ ~ ~ ~ ~  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
~ ~ ~ ~ ~ ~ ~ ~ ~ ~  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
~ ~ ~ ~ ~ ~ ~ ~ ~ ~  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
~ ~ ~ ~ ~ ~ ~ ~ ~ ~  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
~ ~ ~ ~ ~ ~ ~ ~ ~ ~  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
~ ~ ~ ~ ~ ~ ~ ~ ~ ~  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
~ ~ ~ ~ ~ ~ ~ ~ ~ ~  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
~ ~ ~ ~ ~ ~ ~ ~ ~ ~  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
~ ~ ~ ~ ~ ~ ~ ~ ~ ~  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
~ ~ ~ ~ ~ ~ ~ ~ ~ ~  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 

$ 

typedef – 매우 영리 에릭 ...

1

va_arg의 C 사양은 매개 변수 유형는 그러한 지정된 형식 이름이어야한다 "필요로하는 개체에 대한 포인터의 유형이 * ~ 유형을 접두사로 붙이면 지정된 유형의 문자열을 얻을 수 있습니다. "문자열 char*[][BOARDSIZE]은이를 만족하지 않습니다. 유형에 이름을 지정하려면 을 사용해야합니다.

또한 함수 선언의 매개 변수 목록에서 char*[][BOARDSIZE]은 자동으로 char*(*}[BOARDSIZE]으로 조정됩니다. va_arg (또는 typedef)에는 그렇지 않습니다. 조정 된 양식을 사용해야합니다.

typedef char *(*MyType)[BOARDSIZE]; 

당신은 오히려 배열의 배열보다 이들의 배열로 boards을 변경해야합니다 :

그래서, 당신은 charBOARDSIZE 포인터의 배열에 대한 포인터입니다 유형의 이름을 정의해야합니다 :

MyType boards[numArgs]; 

당신은 새로운 형태의 사용 va_arg을 변경해야합니다 :

boards[i] = va_arg(ap, MyType); 

또한 보드의 모든 요소를 ​​문자열 "~"로 설정한다는 점에 유의하십시오. 이것은 문자열 리터럴을 가리 키도록 설정합니다. 이것은 원하는 것과 다를 가능성이 있습니다. 이 문자열 리터럴에서 문자를 수정할 수 없으므로 보드에 포함 된 것을 변경하는 유일한 방법은 다른 문자열을 가리 키도록 변경하는 것입니다.

각 보드 요소가 단일 문자가 될 경우 char * 대신 char을 사용해야합니다. 고정 또는 소수의 복수 문자가 될 경우 char에 대한 포인터 대신 char 배열을 원할 수 있습니다. 상당한 수의 문자가 사용될 경우 char *을 사용하고 각 보드 요소에 공간을 할당 할 수 있습니다.