2013-08-16 3 views
3

C에서 다음 3 차원과 같은 n 차원 배열을 선언하고 싶습니다.C에서 n 포인터를 선언하십시오.

printf("please insert n1, n2, n3\n"); 
scanf("%d %d %d", &n1, &n2, &n3); 

int ***nda; 
nda = (int ***)malloc(n1*sizeof(int **)); 

for (i = 0; i < n1; i++) { 
    nda[i] = malloc(n2*sizeof(int *)); 
    for (j = 0; j < n2; j++) { 
     nda[i][j] = malloc(n3*sizeof(int)); 
    } 
} 

나는 매크로를 사용하여이 프로세스를 자동화 및 n- 희미한으로 확장하려는 그리고 내가 이런 포인터를 선언 할 필요가 발견 : 나는 매크로 할 수있는 겉으로 가능한 방법 것 같다

type *...*(n times)typename; 

을 그러나 여기에서 답을 검색 한 후에 매크로가 재귀 적으로 확장되지 않는다는 것을 알았습니다.
C에서이 작업을 수행 할 수있는 임시 해결책이 있습니까?

+2

, 유형 이름의 이용은 무엇 런타임에? – Jiminion

+10

여기 뭔가가 간접 참조의 n 레벨에 대한 포인터를 선언하지 않는다는 것을 알려줍니다. 오히려 처음부터이 작업을 수행하려는 이유가 *있는 것 같습니다. – WhozCraig

+0

혼란을 가져 주어서 죄송합니다. 질문을 변경했습니다. – user2690457

답변

1

이 작업을 수행하는 것은 좋지 않지만, 일 수 있습니다. 여기에는 한 가지 방법이 있습니다.

적절하게 강력한 메타 프로그래밍 라이브러리 인 Order (앞서 언급 한 Boost가 또 다른 가능한 후보 임)을 사용하는 경우 실제로 전처리기에 루프가 생기고 재귀 매크로를 정의 할 수 있습니다. Order를 사용하면 Scheme 또는 ML을 아는 사람이 익숙한 기능적 스타일로 프로그래밍 할 수 있습니다.

루프하려면 for_each 구조를 사용하십시오. 단순히 뭔가 주어진 수를 만들려면 당신은 1, N+1for_each_in_range를 사용할 수 있습니다

ORDER_PP( // within this block Order code runs 
    8for_each_in_range(8fn(8_, 8print((*))), 
         1, 8) 
) 

은 위의 일곱 별을 인쇄합니다. 당신은 정상 전처리 규칙에 따라 기존의 매크로, 내부 metaprogram 블록을 마무리 할 수 ​​있습니다 다음 ORDER_PP 블록 내

// print COUNT stars 
#define STARS(COUNT) ORDER_PP(\ 
    8for_each_in_range(8fn(8_, 8print((*))), 1, 8plus(COUNT, 1)) \ 
) 

을 모두 호출 할 수 있습니다 만 인식 주문 기능을 의미 주문 코드보다는 C 전 처리기 코드로 간주됩니다 (모든 값/전처리 토큰은 raw int이거나 8(val) 구조로 "quoted"여야합니다). 이 중첩 된 표현의 한 부분으로 ORDER_PP 내에서 호출 할 수 있도록 대신 CPP 매크로의 주문 기능으로 stars를 정의하려면, 우리는이처럼 쓸 필요가 :

#define ORDER_PP_DEF_8stars ORDER_PP_FN(\ 
    8fn(8C, 8for_each_in_range(8fn(8_, 8print((*))), 1, 8plus(8C, 1)))) 

ORDER_PP(8stars(7)) // prints 7 stars 

주문이 완전히 투명하게 재귀를 제공하고, 그래서 중첩 초기화 루프를 작성하는 것은 비교적 간단합니다 :

#define ORDER_PP_DEF_8ndim_init ORDER_PP_FN(\ 
    8fn(8N, 8T, 8C, 8I, 8D, \ 
     8do(\ 
      8print(8N (=malloc) 8lparen 8seq_head(8D) (*sizeof) 8lparen 8T 8stars(8minus(8C, 1)) 8rparen 8rparen (;)), \ 
      8if(8equal(8C, 1), \ 
       8print(((void)0;)), \ 
       8do(\ 
        8print((for) 8lparen (int) 8I (=0;) 8I (<) 8seq_head(8D) (;) 8I (++) 8rparen ({)), \ 
        8ndim_init(8adjoin(8N, 8([), 8I, 8(])), 8T, 8minus(8C, 1), 8cat(8I, 8(_K)), 8seq_tail(8D)), \ 
        8print((})) \ 
       ))))) 

호출 ndim_init 같은 :

// print the nested initializer from the question 
ORDER_PP(
    8ndim_init(8(nda), 8(int), 3, 8(i), 8seq(8(n1), 8(n2), 8(n3))) 
) 

ORDER_PP 블록 내에 나타날 때 C 변수 이름 (nda, i 등)을 인용해야하므로 Order가 변수를 평가하려고하는 대신 텍스트로 처리하도록합니다. 마지막 인수는 각 차원의 크기를 포함하는 런타임 변수 목록입니다 (8seq은 목록을 작성하고 8은 C 변수 이름을 다시 인용 함).

STARS의 첫 번째 예제와 마찬가지로 쉽게 액세스 할 수 있도록 일반 사전 처리기 매크로에서 ndim_init의 호출을 패키지화 할 수 있습니다. 단일 호출 선언과 초기화를 방출하는, 이런 식으로 쉽게 선언자 매크로와 결합 할 수 있습니다


#define NDIM(NAME, TYPE, ...) ORDER_PP (\ 
    8lets((8D, 8((__VA_ARGS__))) \ 
      (8C, 8tuple_size(8D)), \ 
     8do(\ 
      8print((TYPE) 8stars(8C) (NAME; {)), \ 
      8ndim_init(8(NAME), 8(TYPE), 8C, 8(_ITER), 8tuple_to_seq(8D)), \ 
      8print((})) \ 
     )) \ 
) 

NDIM(nda, int, n1, n2, n3) // emits declaration and init block for int ***nda 

More Order examples이 (가) 위의 모든 간단한 것 같지 않은 경우 .. 그래서 사람들은 당신이 그것을해서는 안된다고 말합니다. (그랬다면, 당신에게 좋은, 아무도 당신의 코드를 읽을 수있을 것입니다.)

3

지금 당장 무엇을하고있어! 각 레벨의 포인터 간접 지정은 프로그램에 중요한 성능 저하를 추가합니다. 여러분이 만든 것은 다차원 배열이 아니라, 각 배열 요소가 여러 개의 가지에 대한 포인터 인 다시 트리가되는 n- 트리입니다.

size_t dim[...] 

int *nda; 
nda = malloc(sizeof(int) * dim[0] * dim[1] * … * dim[n]); 

여기 가변 길이와 솔루션의이

nda[ dim[0]*(i[1] + dim[1]*(i[2] + dim[…]*(i[…+1])) + i[0] ]; 
+0

C99 기능을 사용하는 것이 옵션이라면 - 2014 년에는 malloc()을 사용하여 VLA를 사용하고 무엇을 추측해야할까요? 이 매뉴얼 인덱스 없이도 기존 인덱싱을 얻을 수 있습니다! – Will

+0

@Will : 이것은 지금까지는 통어론적인 거만함을 읽기가 힘들지 않고서 만 작동합니다. 범위 내에서 VLA로 캐스트 할 수 없습니다. malloc 화 된 메모리 영역을 VLA 형태로 가져 오려면'void foo (size_t dim_a, size_t dim_b, elementtype data [dim_a] [dim_b]) '와 같은 것을 써야합니다. 이것은 매우 융통성이 없으며 당신이 그것을 부르는 것처럼 "벼락치기"는 그것을 작동시키는 것이 그리 어렵지 않습니다. 관용적인데, 각 서브 구문을 파싱하지 않고 (단지 문자로 문자를 읽지 않는 것과 똑같은 방식으로) 충분한 시간을 지나면 그것을 "읽습니다". – datenwolf

+0

예, VLA에 대한 참조를 다른 기능에 전달해야하거나 배열의 여러 "보기"에 유연하게 액세스해야하는 경우 VLA 방식의 장점보다 단점이 더 중요 할 수 있습니다. 여전히 OP의 질문에 대한 대안으로 내 접근법을 추가했습니다. 그것을 찢을지라도 (적어도 찢어 질 만하다면 :). – Will

0

를 사용하는 배열의 요소를 해결하려면 다음

n을 차원 데이터 배열을 만들려면

은이 방법을 배열 (C99 이상 필요). 이 경우 때문에 potentional 된 크기의 VLA가 있지만, 수동 (m/c) ALLOC()과, 스택에 할당되지 않는다 : 코드 컴파일되므로

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#define MAX_DIM_C 10 
#define MAX_DIM_SIZE 100 

// Works for versions of C from C99 onward. 

int main(void) { 
    int dim_c; 
    do { 
     printf("Please input the number of dimensions. " 
       "The minimum value is 1. The maximum value is %d.\n", 
       MAX_DIM_C); 
    } while (scanf("%d", &dim_c) != 1 || dim_c < 1 || dim_c > 100); 
    int dim[MAX_DIM_C]; 
    // Give all dimensions a default size of 1. 
    memset(dim, 1, MAX_DIM_C); 
    for (int i = 0; i < dim_c; i++) { 
     do { 
      printf("Please input the size of dimension %d. " 
        "The minimum value is 1. The maximum value is %d.\n", 
        i, MAX_DIM_SIZE); 
     } while (scanf("%d", dim + i) != 1 || dim[i] < 1 || dim[i] > 100); 
    } 
    // Always allocate a MAX_DIM_C-dimensional array. When the user specifies 
    // a number of dimensions fewer than MAX_DIM_C, the MAX_DIM_C-dim_c 
    // dimensions are basically just dummy dimensions of size 1 
    int (*vla)[dim[1]] 
       [dim[2]] 
       [dim[3]] 
       [dim[4]] 
       [dim[5]] 
       [dim[6]] 
       [dim[7]] 
       [dim[8]] 
       [dim[9]] = 
     calloc(dim[0] * 
       dim[1] * 
       dim[2] * 
       dim[3] * 
       dim[4] * 
       dim[5] * 
       dim[6] * 
       dim[7] * 
       dim[8] * 
       dim[9], sizeof(int)); 
    // 
    // Do something useful here 
    // 
    printf("%d\n", vla[dim[0] - 1] 
         [dim[1] - 1] 
         [dim[2] - 1] 
         [dim[3] - 1] 
         [dim[4] - 1] 
         [dim[5] - 1] 
         [dim[6] - 1] 
         [dim[7] - 1] 
         [dim[8] - 1] 
         [dim[9] - 1]); 
    // To pass the VLA to another function cast it to void (or another simple 
    // type) and also pass the dim array along with it to generate a new 
    // VLA pointer in the called function with matching dimensions 
    return 0; 
} 
관련 문제