Passer un tableau de chaînes en tant que paramètre à une fonction en C
-
20-08-2019 - |
Question
Je veux une fonction simple qui reçoit une chaîne et retourne un tableau de chaînes après une analyse. Donc, voici ma signature de fonction:
int parse(const char *foo, char **sep_foo, int *sep_foo_qty) {
int i;
char *token;
...
strcpy(sep_foo[i], token); /* sf here */
...
}
Ensuite, je l'appelle comme suit:
char sep_foo[MAX_QTY][MAX_STRING_LENGTH];
char foo[MAX_STRING_LENGTH];
int sep_foo_qty, error;
...
error = parse(foo, sep_foo, &sep_foo_qyt);
...
Ainsi, je reçois un avertissement lors de la compilation:
warning: passing argument 2 of 'parse' from incompatible pointer type
Et puis une erreur de segmentation lors de l'exécution dans la ligne marquée avec / * sf ici * /
Qu'est-ce qui ne va pas dans mon code C?
Merci d'avance
La solution
L’avertissement est tout à fait correct. Votre fonction veut un tableau de pointeurs. Vous lui donnez un tableau de tableaux.
Attendu:
sep_foo: +------+ +-----+ |char**|--> 0: |char*|-->"string1" +------+ +-----+ 1: |char*|-->"string2" +-----+ *sep_foo_qty-1: |... | +-----+
Ce que vous avez fourni:
sep_foo: +--------------------------------+ 0: | char[MAX_STRING_LENGTH] | +--------------------------------+ 1: | char[MAX_STRING_LENGTH] | +--------------------------------+ MAX_QTY-1: | ... | +--------------------------------+
Un tableau avec des éléments de type X
can " decay " dans un pointeur sur - X*
ou MAX_STRING_LENGTH
. Mais la valeur de sep_foo
n'est pas autorisée à changer dans cette conversion. Seule une opération de désintégration est autorisée. Vous auriez besoin que cela se produise deux fois. Dans votre cas, char**
est un tableau de-<-> caractères. La fonction veut que *sep_foo
soit un pointeur sur un caractère. Puisque ce ne sont pas les mêmes, le compilateur vous avertit. Je suis un peu surpris que ce ne soit qu'un avertissement, car rien de ce que le compilateur a permis de faire ne peut être bénéfique.
Dans votre fonction, vous pouvez écrire ce code:
char* y = NULL;
*sep_foo = y;
Ce code est légal car char*
est un y
, donc <=> est un <=>, il en est de même <=>; vous pouvez les assigner. Mais avec ce que vous avez essayé de faire, <=> ne serait pas vraiment être un <=>; il s'agirait d'un tableau de caractères. En réalité, votre code essaierait de le faire:
char destination[MAX_STRING_LENGTH];
char* y = NULL;
destination = y;
Vous ne pouvez pas affecter de pointeur à un tableau. Le compilateur vous avertit que l'appel n'est pas bon.
Il existe deux manières de résoudre ce problème:
-
Modifiez la façon dont vous déclarez et allouez <=> du côté appelant afin qu'il corresponde à ce que la fonction s'attend à recevoir:
char** sep_foo = calloc(MAX_QTY, sizeof(char*)); for (int i = 0; i < MAX_QTY; ++i) sep_foo[i] = malloc(MAX_STRING_LENGTH);
ou, de manière équivalente
char* sep_foo[MAX_QTY]; for (int i = 0; i < MAX_QTY; ++i) sep_foo[i] = malloc(MAX_STRING_LENGTH);
-
Modifiez le prototype de la fonction pour accepter ce que vous lui donnez réellement:
int parse(const char *foo, char sep_foo[MAX_QTY][MAX_STRING_LENGTH], int *sep_foo_qty);
Autres conseils
Le paramètre 2 devrait être
char sep_foo[][MAX_STRING_LENGTH]
Pour clarifier, vous passez un pointeur sur parse () et le traitez comme un pointeur sur un pointeur. Un tableau multidimensionnel en C n'est PAS un tableau de pointeurs. C'est un bloc de mémoire unique pointé par la variable tableau. Vous ne pouvez pas le déréférencer deux fois.
sep_foo
est défini comme un tableau de tableaux. En d'autres termes, lorsque vous utilisez <=>, il pointe vers le début de la mémoire séquentielle. Voici un modèle:
(assume MAX_STRING_LENGTH = 16, MAX_QTY = 2)
sep_foo = &&0000
sep_foo[0] = &0000
sep_foo[0][0] = *&0000 = 12
sep_foo[0][8] = *&0008 = 74
sep_foo[1] = &0010
sep_foo[1][0] = *&0010 = 12
0000 12 34 56 78 9A BC DE F0 74 10 25 89 63 AC DB FE
0010 12 34 56 78 9A BC DE F0 74 10 25 89 63 AC DB FE
Cependant, votre fonction attend un tableau de pointeurs (en fait, un pointeur sur un pointeur). Ceci est modélisé comme tel:
sep_foo_arg = &&0000
sep_foo_arg[0] = *&&0000 = &0010
sep_foo_arg[0][0] = *&*&0000 = 12
sep_foo_arg[0][8] = *(&*&0000 + 8) = 74
sep_foo_arg[1] = *&&0002 = &0020
sep_foo_arg[1][0] = *&*&0000 = 12
0000 0010 0020 xxxx xxxx xxxx xxxx xxxx xxxx
0010 12 34 56 78 9A BC DE F0 74 10 25 89 63 AC DB FE
0020 12 34 56 78 9A BC DE F0 74 10 25 89 63 AC DB FE
Ouais ... La syntaxe peut être un peu déroutant pour mes explications ...
Quoi qu’il en soit, vous pouvez résoudre ce problème en indiquant à votre fonction comment traiter le pointeur pointé. En particulier, vous voudriez le traiter comme un tableau (une séquence de mémoire):
int parse(const char *foo, char (*sep_foo)[MAX_STRING_LENGTH], int *sep_foo_qty);
S'il s'agit de votre code exact, alors je suppose que l'erreur de segmentation résulte du fait que vous n'avez pas alloué de mémoire à la char* token
fonction de votre fonction d'analyse, puis que vous l'utilisez dans votre stratégie.