在C中声明一个n指针

在C中声明一个n指针,c,pointers,multidimensional-array,c-preprocessor,C,Pointers,Multidimensional Array,C Preprocessor,在C语言中,我想声明一个n维数组,如下面的3维数组 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;

在C语言中,我想声明一个n维数组,如下面的3维数组

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));
    }
}
我想宏似乎是一种可行的方法,但在这里搜索答案后,我发现宏不会递归展开。

在C语言中有什么解决方法吗?

尽管这样做是个坏主意,但它是可以做到的,所以这里有一种方法

事实上,如果您使用一个适当强大的元编程库(如上文所述),您可以在预处理器中循环并定义递归宏(Boost是另一个可能的候选者)。Order允许您以熟悉Scheme或ML的任何人都熟悉的功能样式进行编程

要循环,请对每个构造使用
。要简单地创建给定数量的内容,您可以使用
为\u范围内的每个\u使用
1,N+1

ORDER_PP(    // within this block Order code runs
    8for_each_in_range(8fn(8_, 8print( (*) ) ),
                       1, 8)
)
上面将打印7颗星。您可以将元程序块封装在常规宏中,这些宏遵循正常的预处理器规则:

// print COUNT stars
#define STARS(COUNT) ORDER_PP( \
    8for_each_in_range(8fn(8_, 8print((*)) ), 1, 8plus(COUNT, 1)) \
)
ORDER_PP
块中,所有内容都假定为订单代码,而不是C预处理器代码,这意味着只能调用已识别的订单函数(并且所有值/预处理标记必须是原始整数,或使用
8(val)
构造“引用”)。要将
stars
定义为顺序函数而不是CPP宏,以便可以从
Order\u PP
中调用它作为嵌套表达式的一部分,我们需要这样编写:

#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
// 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完全透明地提供递归,因此编写嵌套的初始值设定项循环相对简单:

#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( (}) ) \
                )))))
请注意,C变量名(
nda
i
等)在出现在
ORDER\u PP
块中时需要被引用,以便ORDER将其视为文本,而不是尝试对其求值。最后一个参数是包含每个维度大小的运行时变量列表(
8seq
构建一个列表,
8
再次引用C变量名称)

您可以将
ndim_init
的调用打包到一个常规的预处理器宏中,以便于访问,就像第一个使用
STARS
的示例一样;通过这种方式,您可以轻松地将其与declarator宏组合,以便在一次调用中发出声明和初始化:

#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



如果上面的内容看起来一点也不简单。。。这就是为什么人们说你不应该这么做。(如果这样做了,对你有好处,但是没有其他人能够阅读你的代码。)

停止你现在所做的事情!每一级指针间接寻址都会给程序带来显著的性能影响。这里创建的不是多维数组,而是一个n元树,其中每个数组元素都是指向多个分支的指针,这些分支再次展开

如果要为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] ];

这是一个具有可变长度阵列的解决方案(需要C99或更高版本)。在这种情况下,由于其潜在大小,VLA不会在堆栈上分配,而是使用(m/c)alloc()手动分配:

#包括
#包括
#包括
#定义最大尺寸C 10
#定义最大尺寸100
//适用于C99以后的C版本。
内部主(空){
int dim_c;
做{
printf(“请输入尺寸的数量。”
“最小值为1。最大值为%d。\n”,
最大尺寸C);
}而(scanf(“%d”、&dim_c)!=1 | | dim_c<1 | | dim_c>100);
int dim[MAX_dim_C];
//将所有尺寸标注的默认尺寸设置为1。
memset(尺寸1,最大尺寸C);
对于(int i=0;i100);
}
//始终分配一个最大尺寸C维数组。当用户指定
//许多尺寸小于最大尺寸C,最大尺寸C-尺寸C
//尺寸基本上只是尺寸为1的虚拟尺寸
内部(*vla)[dim[1]]
[dim[2]]
[dim[3]]
[dim[4]]
[dim[5]]
[dim[6]]
[dim[7]]
[dim[8]]
[dim[9]]=
calloc(dim[0]*
昏暗[1]*
昏暗[2]*
昏暗[3]*
昏暗[4]*
昏暗[5]*
昏暗[6]*
昏暗[7]*
昏暗[8]*
dim[9],sizeof(int));
//
//在这里做些有用的事
//
printf(“%d\n”,vla[dim[0]-1]
[dim[1]-1]
[尺寸[2]-1]
[尺寸[3]-1]
[尺寸[4]-1]
[尺寸[5]-1]
[尺寸[6]-1]
[尺寸[7]-1]
[尺寸[8]-1]
[dim[9]-1]);
//要将VLA传递给另一个函数,请将其强制转换为void(或另一个简单
//键入)并同时传递dim数组以生成新的
//被调用函数中具有匹配维度的VLA指针
返回0;
}

既然代码是编译的,那么在运行时typename有什么用呢?有些东西告诉我这里的问题不是声明指向n级间接寻址的指针。更确切地说,这似乎是您首先想做这件事的原因。很抱歉造成混淆,我已经更改了问题。@user2690457这确实像是一个问题。谢谢您的快速回答,我会给出我想做的事情的全貌。@Will:这只适用于目前为止,没有深入到难以理解的语法错误。您不能在范围内强制转换为VLA;您必须编写类似于
void foo(size\t dim\u a,size\t dim\u b,elementtype data[dim\u a][dim\u b])
的内容,才能将malloc-ed内存区域转换为VLA形状。这不是很灵活,你所说的“粗制滥造”也不是很难做到。这是惯用的,而且是o
nda[ dim[0]*(i[1] + dim[1]*(i[2] + dim[…]*(i[…+1])) + i[0] ];
#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;
}