CODE 1
#include<stdio.h>
int main(int argc, char *argv[])
{
int j;
printf("%d", argv[1][0]);
return 0;
}
CODE 2
#include<stdio.h>
int main(int argc, char **argv)
{
int j;
printf("%d", argv[1][0]);
return 0;
}
CODE 1 et CODE 2 donnent tous deux la même sortie. mais argument 2 de la fonction principale dans CODE 1 et CODE 2 sont différents. Un tableau de pointeurs est créé au-dessus de la section de données au moment de la compilation. argv est un tableau de pointeurs. Ensuite, nous devons déclarer l'argument dans la fonction principale comme un pointeur vers un pointeur vers un caractère, c'est-à-dire ** argv. Comment est-il correct de déclarer comme dans CODE 1?
Il est fondamental de c que char** x
et char* x[]
sont deux façons d'exprimer la même chose. Les deux déclarent que le paramètre reçoit un pointeur vers un tableau de pointeurs. Rappelez-vous que vous pouvez toujours écrire:
char *parray[100];
char **x;
x = &parray[0];
puis utilisez x à l'identique.
Fondamentalement, char * argv [] signifie tableau de pointeurs char, tandis que char ** argv signifie pointeur vers un pointeur char.
Dans tout tableau, le nom du tableau est un pointeur vers le premier élément du tableau, c'est-à-dire qu'il contient l'adresse du premier élément.
Ainsi, dans le code ci-dessous, dans le tableau de caractères x, x est un pointeur sur le premier élément, "1", qui est un caractère. C'est donc un pointeur vers un personnage.
Et dans le tableau arr, arr est le premier élément du pointeur, x, qui est lui-même un pointeur sur un caractère. Il s'agit donc d'un pointeur vers un autre pointeur.
Par conséquent, x est char * et arr est char **.
Lors de la réception de quelque chose dans une fonction, la règle de base est que vous devez indiquer le type de la chose que vous recevez. Donc, soit vous dites simplement que vous souhaitez recevoir un caractère **, soit vous pouvez également dire caractère * arr [].
Dans le premier cas, nous n'avons pas besoin de penser quoi que ce soit de complexe. Nous savons simplement que nous recevons un tableau de char *. Ne le savons-nous pas? Donc, nous le recevons et l’utilisons.
Dans le second cas, c'est simple, comme je l'ai expliqué plus haut que arr est un caractère **, vous pouvez le mettre tel quel et le recevoir en toute sécurité. Maintenant que le système connaît le type de choses que nous avons reçues, nous pouvons accéder aux éléments suivants en utilisant simplement l'annotation de tableau. C'est comme, nous avons reçu l'adresse de départ du tableau, nous pouvons sûrement passer aux éléments suivants, et comme nous savons que c'est le type, nous savons ce qu'il contient et comment nous pouvons l'utiliser plus loin. Nous savons qu'il contient un pointeur sur char, nous pouvons donc également y accéder légalement.
void func1(char* arr[])
{
//function body
}
void func2(char** arr)
{
//function body
}
int main()
{
//x, y and z are pointer to char
char x[3]={'1', '2', '3'};
char y[3]={'4', '5', '6'};
char z[3]={'7', '8', '9'};
//arr is pointer to char pointer
char* arr[3]={x, y, z};
func1(arr);
func2(arr);
}
Ce sont exactement les mêmes. Le §5.1.2.2.2 de la norme C11 stipule:
La fonction appelée au démarrage du programme est nommée
main
. L'implémentation ne déclare aucun prototype pour cette fonction. Il doit être défini avec un type de retour deint
et sans paramètres:int main(void) { /* ... */ }
ou avec deux paramètres (appelés ici
argc
etargv
, bien que tous les noms puissent être utilisés, car ils sont locaux à la fonction dans laquelle ils sont déclarés):int main(int argc, char *argv[]) { /* ... */ }
ou équivalent;dix) ou d'une autre manière définie par l'implémentation.
10) Ainsi,
int
peut être remplacé par un nom de typedef défini commeint
, ou le type deargv
peut être écrit commechar ** argv
, etc.
Il est clair que l'intention est que les deux déclarations soient identiques. De plus, la règle est décrite au §6.7.6.3/7:
Une déclaration d'un paramètre comme '' tableau de type '' doit être ajustée à '' pointeur qualifié vers type '', où les qualificateurs de type (le cas échéant) sont ceux spécifié dans le
[
et]
de la dérivation de type tableau. ...
déclarer un tableau comme celui-ci
char array[]
le rend const ce qui signifie que vous NE POUVEZ PAS avoir le code suivant
char array[] = "hello";
array = "hey";
même si la deuxième chaîne est plus petite et devrait vous convenir, vous obtenez cette erreur
erreur: le type de tableau 'char [6]' n'est pas assignable
si tu as **argv
tu peux écrire
main(int argc, char **argv)
{
char **other_array;
/*
* do stuff with other_array
*/
argv = other_array;
}
si tu as *argv[]
puis
main(int argc, char *argv[])
{
char **other_array;
/*
* do stuff with other_array
*/
argv = other_array;
}
vous donne cet avertissement
avertissement: l'affectation à 'const char **' de 'char **' supprime les qualificatifs dans les types de pointeurs imbriqués
c'est donc techniquement une petite optimisation comme si vous aviez écrit const