44 votes

Passer le tableau à une fonction (et pourquoi il ne fonctionne pas en C)

Je suis venu dans du code C qui compile, mais je ne comprends pas pourquoi. Plus précisément, j'ai une bibliothèque C qui a beaucoup de code à l'aide de ce format:

void get_xu_col(int i_start,
                int n,
                double x[n],
                int n_x,
                int n_u,
                int n_col,
                double xu_col[n_col][n_x + n_u]){
    ... 
}

int main(){
    ...
    double xu_col[n_col][n_x + n_u];
    get_xu_col( ..., xu_col );
    ...
}

Ce que je ne comprends pas, c'est pourquoi le compilateur permet de dimensionnement dans les tableaux. Au mieux de ma compréhension, soit la taille doit être fixe (par exemple, xu_col[9][7]) ou non (par exemple, xu_col[][]). Dans le code ci-dessus, il apparaît que les tailles ne sont pas des constantes de compilation.

Est le compilateur simplement ignorer les arguments ici? ou est-il vraiment en train de faire au moment de la compilation vérifier les dimensions?

Si c'est la dernière, alors il semble enclin à l'erreur de passer les dimensions séparément.

La deuxième partie de la question est la suivante:

Pourquoi n'est pas la même version en C++? Quand j'ai littéralement changer l'extension du fichier de .c de .cpp et d'essayer de recompiler, je reçois

candidate function not viable: no known conversion from 'double [n_col][n_x + n_u]' to 'double (*)[n_x + n_u]' for 7th argument
void get_xu_col(int i_start, int n, double x[n], int n_x, int n_u, int n_col, double xu_col[n_col][n_x + n_u]);

Je voudrais savoir dans quel idiome que je devrais utiliser pour convertir ce code en C++, car apparemment la précédente idiome était quelque chose qui fonctionne en C, pas du C++.

59voto

Stephen Docy Points 4430

En C, il est possible d'utiliser des paramètres de fonction pour définir la taille d'un paramètre de tableau de longueur variable tant que la taille passe avant le tableau dans la liste de paramètres. Cela n'est pas pris en charge dans le CMD.

36voto

MSalters Points 74024

La raison pour laquelle il fonctionne en C, mais pas en C est tout simplement parce que c'est le code C et non c. Les deux langues partagent une histoire, pas une grammaire.

La méthode C pour passer des tableaux de taille variable est, probablement par *référence* si vous avez l'intention de modifier le vecteur dans la fonction, ou par référence si vous n'avez pas.

11voto

Jens Harms Points 316

Ce que je ne comprends pas, c'est pourquoi le compilateur permet de dimensionnement dans les tableaux. Au mieux de ma compréhension, soit la taille doit être fixe (par exemple xu_col[9][7]) ou non (par exemple, xu_col[][]). Dans le code ci-dessus, il apparaît que les tailles ne sont pas des constantes de compilation.

Vous avez raison, les tailles ne sont pas des constantes de compilation. Si vous avez un tableau à deux dimensions, x[ligne][col] le compilateur a besoin de connaître le nombre d'éléments dans une ligne pour calculer l'adresse d'un élément. Regardez get_char_2() et get_char_3() exemple de code.

Si vous utilisez une variable de tableaux de longueur (Blaise) comme paramètres de la fonction vous avez pour l'approvisionnement de ces nombre (voir get_char_1 exemple). vous pouvez écrire:

 my_func( x[][width] )

ou vous pouvez écrire

 my_func( x[999][width] )

Est le compilateur simplement ignorer les arguments ici? ou est-il vraiment en train de faire un >moment de la compilation vérifier les dimensions?

Le premier nombre (999) sera ignoré par le compilateur. La seconde est nécessaire. Sans la ligne de taille, le compilateur ne peut pas calculer des adresses à l'intérieur de ces 2D-tableau. Le compilateur ne pas faire au moment de l'exécution ou des contrôles de compilation pour VLAs en C.

/* file: vla.c
 *
 * variable length array example
 *
 * compile with:
 *   
 *    gcc -g -Wall -o vla vla.c 
 *
 */

#include <stdio.h>
#include <wchar.h>


/* 4 Lines - each line has 8 wide-characters */
wchar_t tab[][8] = {
{ L"12345678" },
{ L"abcdefgh" },
{ L"ijklmnop" },
{ L"qrstuvwx" }
};

/* memory layout:   
   0x00:   0x0031  0x0032 0x0033  0x0034  0x0035  0x0036  0x0037  0x0038 
   0x20:   0x0061  0x0062 0x0063  0x0064  0x0065  0x0066  0x0067  0x0068 
   ...

*/



/* get character from table w/o variable length array and w/o type */
char get_char_3(int line, int col, int width, int typesize, void *ptr )
{
char ch = * (char *) (ptr + width * typesize * line + col * typesize ); 

printf("line:%d col:%d char:%c\n", line, col, ch ); 
return ch;
}


/* get character from table w/o variable length array */
char get_char_2(int line, int col, int width, wchar_t *ptr)
{
char ch = (char) (ptr + width * line)[col]; 

printf("line:%d col:%d char:%c\n", line, col, ch ); 
return ch;
}

/* get character from table : compiler does not know line length for 
   address calculation until you supply it (width). 
*/
char get_char_1(int line, int col, int width, wchar_t aptr[][width] )
{
/* run-time calculation: 
   (width * sizeof(char) * line)  + col 
     ???    KNOWN          KOWN     KNOWN
*/
char ch = (char) aptr[line][col];

printf("line:%d col:%d char:%c\n", line, col, ch ); 
return ch;
}


int main(void)
{
char ch;

ch = tab[1][7]; /* compiler knows line length */
printf("at 1,7 we have: %c\n",  ch );

/* sizeof tab[0][0] == sizeof(wchar_t) */ 

ch = get_char_1(1,7, sizeof(tab[0])/sizeof(tab[0][0]), tab);
printf("1 returned char: %c\n", ch );

ch = get_char_2(1,7, sizeof(tab[0])/sizeof(tab[0][0]), (wchar_t*)tab);
printf("2 returned char: %c\n", ch );

ch = get_char_3(1,7, sizeof(tab[0])/sizeof(tab[0][0]),
        sizeof( wchar_t), tab);
printf("3 returned char: %c\n", ch );

printf("table size: %lu, line size: %lu,  element size: %lu\n",
       sizeof(tab),
       sizeof(tab[0]),
       sizeof(tab[0][0])
       );

printf("number of elements per lines: %lu\n",
       sizeof(tab[0])/sizeof(tab[0][0]));


printf("number of lines: %lu\n",
       sizeof(tab)/sizeof(tab[0]));

return 0;
}

5voto

Paul Ogilvie Points 4852

Tout ce qu'il fait (en C) est de vous permettre d'écrire du code d'indexation dans le funcion appelé sans avoir à faire le calcul de l'adresse vous-même, par exemple:

Contre

5voto

supercat Points 25534

Lorsqu'un paramètre est déclaré comme un tableau unidimensionnel de type, C ignore la taille et d'une traite plutôt du paramètre un pointeur vers le type de l'élément. Pour imbriquée (multi-dimensional) des tableaux, un tel traitement n'est appliqué qu'à l'extérieur de la matrice. En C89, dimensions intérieures devaient avoir de dimensions fixes, mais en C99 les dimensions peuvent être des expressions. Si les paramètres qui sont nécessaires pour calculer une matrice de taille, ne sont pas répertoriés jusqu'à ce que après le tableau, il sera nécessaire d'utiliser un curieux mélange d'ancien et de nouveau la syntaxe pour déclarer la fonction, par exemple

int findNonzero(short dat[*][*], int rows, int cols);
int findNonzero(dat, rows, cols)
    int rows,cols;
    short dat[static rows][cols];
{
    for (int i=0; i<rows; i++)
        for (int j=0; j<cols; j++)
            if (dat[i][j] != 0) return i;
    return -1;
}

Notez que le tableau des tailles sont spécifiés en tant que * dans le prototype de fonction, et que la définition de la fonction ne précise pas les types dans la liste d'arguments, mais au lieu de cela décrit tous les types des paramètres entre la liste des arguments et l'accolade d'ouverture. Notez également que si le compilateur est susceptible d'ignorer le nombre de lignes dans le tableau de déclaration, mais une smart compilateur peut être en mesure de l'utiliser pour faciliter l'optimisation. Effectivement, l'étrange "statique" de la syntaxe invite le compilateur de lire toutes les pièces de la matrice, jusqu'à la taille, comme il l'entend, si oui ou non les valeurs sont lues par le code. Cela peut être utile sur certaines plates-formes où le code pourra bénéficier de traitement de plusieurs éléments de la matrice à la fois.

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