web-dev-qa-db-fra.com

Différence entre le tableau de passage, le tableau de taille fixe et l'adresse de base du tableau en tant que paramètre de fonction

Je suis confus quant à la syntaxe à utiliser si je veux passer un tableau de taille connue ou inconnue comme paramètre de fonction.

Supposons que j'ai ces variantes dans le but:

void func1(char* str) {
    //print str
}

void func2(char str[]) {
    //print str
}

void func3(char str[10]) {
    //print str
}

Quels sont les avantages et les inconvénients de l'utilisation de chacun d'entre eux?

55
mr5

Toutes ces variantes sont identiques. C vous permet simplement d'utiliser des orthographes alternatives, mais même la dernière variante explicitement annotée avec une taille de tableau se désintègre en un pointeur normal.

Autrement dit, même avec la dernière implémentation, vous pouvez appeler la fonction avec un tableau de taille any:

void func3(char str[10]) { }

func("test"); // Works.
func("let's try something longer"); // Not a single f*ck given.

Inutile de dire que cela devrait pas être utilisé: cela pourrait donner à l'utilisateur un faux sentiment de sécurité ("oh, cette fonction n'accepte qu'un tableau de longueur 10 donc je n'ai pas besoin de vérifier la longueur moi-même ”).

Comme l'a dit Henrik, la bonne façon en C++ est d'utiliser std::string, std::string& ou std::string const& (selon que vous devez modifier l'objet ou que vous souhaitez copier).

71
Konrad Rudolph

Notez qu'en C++, si la longueur du tableau est connue au moment de la compilation (par exemple si vous avez passé un littéral de chaîne), vous pouvez réellement obtenir sa taille:

template<unsigned int N>
void func(const char(&str)[N])
{
    // Whatever...
}

int main()
{
    func("test"); // Works, N is 5
}
20
Morwenn

En C++, utilisez void func4(const std::string& str).

11
Henrik

Ce sont tous fonctionnellement identiques. Lorsque vous passez un tableau à une fonction en C, le tableau est implicitement converti en un pointeur vers le premier élément du tableau. Par conséquent, ces trois fonctions afficheront la même sortie (c'est-à-dire la taille d'un pointeur sur char).

void func1(char* str) {
    printf("sizeof str: %zu\n", sizeof str);
}

void func2(char str[]) {
    printf("sizeof str: %zu\n", sizeof str);
}

void func3(char str[10]) {
    printf("sizeof str: %zu\n", sizeof str);
}

Cette conversion ne s'applique qu'à la première dimension d'un tableau. Un char[42][13] Est converti en une char (*)[13], pas un char **.

void func4(char (*str_array)[13]) {
    printf("sizeof str_array: %zu\n"
           "sizeof str_array[0]: %zu\n", sizeof str_array, sizeof str_array[0]);
}

char (*)[13] est le type de str_array. C'est ainsi que vous écrivez "un pointeur sur un tableau de 13 chars". Cela pourrait également avoir été écrit comme void func4(char str_array[42][13]) { ... }, bien que le 42 soit fonctionnellement vide de sens comme vous pouvez le voir en expérimentant, en passant des tableaux de différentes tailles dans func4.

En C99 et C11 (mais pas C89 ou C++), vous pouvez passer un pointeur vers un tableau de taille variable dans une fonction, en lui transmettant sa taille et en incluant l'identifiant de taille dans le [square brackets]. Par exemple:

void func5(size_t size, char (*str_array)[size]) {
    printf("sizeof str_array: %zu\n"
           "sizeof str_array[0]: %zu\n", sizeof str_array, sizeof str_array[0]);
}

Cela déclare un pointeur sur un tableau de taillechars. Notez que vous devez déréférencer le pointeur avant de pouvoir accéder au tableau. Dans l'exemple ci-dessus, sizeof str_array[0] Évalue la taille du tableau, pas la taille du premier élément. Par exemple, pour accéder au 11e élément, utilisez (*str_array)[11] Ou str_array[0][11].

9
autistic

Pour ajouter, décrivant en points.

1) Comme tout le monde l'a dit, c'est la même chose.

2) Les tableaux sont décomposés en pointeurs lorsqu'ils sont passés dans les arguments de fonction.

3) Le problème fondamental pourrait être de trouver la taille d'un tableau dans la fonction. Pour cela, nous pouvons utiliser des macros comme.

   #define noOfElements(v) sizeof(v)/sizeof(0[v])

   int arr[100]
   myfunction ( arr, noOfElements(arr))

0 [v] ou v [0] peut être utilisé dans la macro, où le premier est utilisé pour éviter que le type de données défini par l'utilisateur ne soit transmis à noOfElements.

J'espère que cela t'aides.

1
Whoami

Dans un tableau unidimensionnel, ils sont tous traités de la même manière par le compilateur. Cependant, pour un tableau à deux dimensions ou plus, (par exemple myArray[10][10]), il est utile car il peut être utilisé pour déterminer la longueur de ligne/colonne d'un tableau.

1
user2301717

En C, les deux premières définitions sont équivalentes. La troisième est essentiellement la même mais elle donne une idée de la taille du tableau.

Si l'impression str est votre intention, alors vous pouvez utiliser n'importe laquelle en toute sécurité. Essentiellement, les trois fonctions reçoivent un paramètre de type char*, Exactement ce dont printf() a besoin pour imprimer une chaîne. Et de peur que vous ne sachiez, malgré ce qu'il peut paraître, tous les paramètres passant en C se font en mode pass-by-value.

Edit: On dirait que je devrai être très rigoureux dans mon choix de mots sur SO dorénavant. Eh bien, dans le troisième cas, il ne donne aucune idée de la taille du tableau à la fonction auquel il est passé car finalement il est réduit à taper char* comme dans les deux premiers cas. Je voulais dire qu'il dit un peu à l'homme qui le lit que la taille du tableau est de 10. En outre, ce n'est pas faux/illégal en C.Mais pour le programme, le faire est aussi bon qu'inutile.Il ne donne aucune idée de la taille du tableau à la fonction à laquelle il est transmis.M. Downvoter, merci d'avoir souligné que l'attitude décontractée et la négligence ne sont pas tolérées sur SO.

1
Rüppell's Vulture