3 votes

déclarer un n-pointeur en C

En C, je veux déclarer un tableau à n dimensions comme le tableau suivant 3-dim.

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));
    }
}

Je veux automatiser ce processus en utilisant la macro et l'expansion à n-dim et j'ai découvert que je dois déclarer un pointeur comme ceci :

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

Je suppose que la macro est un moyen apparemment possible de le faire, mais après avoir cherché des réponses ici, j'ai découvert que la macro ne se développe pas de manière récursive.
Existe-t-il des solutions de contournement pour faire cela en C ?

3voto

datenwolf Points 85093

Arrêtez de faire ce que vous faites maintenant ! Chaque niveau d'indirection de pointeur ajoute un impact significatif sur les performances de votre programme. Ce que vous créez ici n'est pas un tableau multidimensionnel, c'est un arbre n-aire, où chaque élément du tableau est un pointeur vers un certain nombre de branches, qui s'étalent à nouveau.

Si vous voulez créer un tableau pour des données à n dimensions, faites-le de cette manière :

size_t dim[...]

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

Pour adresser un élément dans le tableau, utilisez ceci

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

1voto

Leushenko Points 2079

Bien que ce soit une mauvaise idée, cela peut être fait, alors voici un moyen.

Vous pouvez en fait faire des boucles dans le préprocesseur et définir des macros récursives si vous utilisez une bibliothèque de métaprogrammation suffisamment puissante telle que Commandez (comme mentionné ci-dessus, Boost est un autre candidat possible). Order vous permet de programmer dans un style fonctionnel familier à tous ceux qui connaissent Scheme ou ML.

Pour boucler, utilisez un for_each construire. Pour créer simplement un nombre donné de choses, vous pouvez utiliser for_each_in_range con 1, N+1 :

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

Le texte ci-dessus imprimera 7 étoiles. Vous pouvez envelopper les blocs de métaprogrammes dans des macros conventionnelles, qui suivent les règles normales du préprocesseur :

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

Dans le cadre de la ORDER_PP tout est supposé être du code de l'Ordre plutôt que du code du préprocesseur C, ce qui signifie que seules les fonctions reconnues de l'Ordre peuvent être appelées (et que toutes les valeurs/jetons de prétraitement doivent être soit des ints bruts, soit "cités" avec la balise 8(val) construire). Pour définir stars comme une fonction d'ordre au lieu d'une macro CPP, de sorte qu'elle puisse être appelée à partir de l'intérieur de ORDER_PP dans le cadre d'une expression imbriquée, nous devons l'écrire comme ceci :

#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

Order fournit la récursion de manière totalement transparente, de sorte que l'écriture des boucles d'initialisation imbriquées est relativement simple :

#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( (}) ) \
                )))))

Appeler ndim_init comme ça :

// 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)))
)

Remarquez que les noms de variables C ( nda , i etc.) doivent être citées lorsqu'elles apparaissent dans le texte de l'accord. ORDER_PP afin qu'Order les traite comme du texte, au lieu d'essayer de les évaluer. Le dernier argument est une liste des variables d'exécution qui contiendront les tailles pour chaque dimension ( 8seq construit une liste, 8 cite à nouveau les noms des variables C).

Vous pouvez empaqueter l'invocation de ndim_init dans une macro de préprocesseur ordinaire pour un accès facile, tout comme le premier exemple avec STARS ; vous pouvez facilement la combiner avec une macro de déclaration de cette manière, pour émettre la déclaration et l'initialisation en un seul appel :

#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

Autres exemples de commandes


Si ce qui précède ne vous a pas semblé simple du tout... c'est pourquoi les gens disent que vous ne devriez pas le faire. (Si c'est le cas, tant mieux pour vous, personne d'autre ne sera capable de lire votre code cependant).

0voto

Will Points 836

Voici une solution avec des tableaux de longueur variable (nécessite C99 ou une version plus récente). Dans ce cas, à cause de sa taille potentielle, le VLA n'est pas alloué sur la pile, mais manuellement avec (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;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X