C – tableau de caractères et pointeur de caractères

Pourquoi je ne peux pas définir un tableau

char **pp={ "123", "456", "789" }; 

Mais je peux le définir comme un caractère * [], et l’envoyer à une fonction qui l’acceptera comme un caractère **

 char *pp[]={ "123", "456", "789" }; fun(pp); void fun(char **pointerToPointer) { //++(**pointerToPointer);//error printf("%s", *pointerToPointer); } //output::"123" 

Et pourquoi je ne peux pas augmenter

 ++(**pointerToPointer); 

    Pour répondre à la première question, les principes pourraient être plus clairs si nous utilisons une seule profondeur de pointeur. Ce code est illégal pour la même raison:

     int *ptr = { 1, 2, 3 }; 

    En C, une liste d’initialisateurs contreventés n’est pas un object (surtout pas un tableau). Cela ne peut être considéré que comme une liste d’éléments permettant de lire les initialiseurs lorsqu’un object est en cours d’initialisation.

    ptr est un object, donc au plus un initialiseur pourrait être utilisé, et la forme attendue de cet initialiseur est un pointeur ( 1 n’est pas).

    En fait, ce code est explicitement illégal sous C11 6.7.9 / 11:

    L’initialiseur d’un scalaire doit être une expression unique, éventuellement entre accolades

    Cependant, il existe un bug / une fonctionnalité de gcc qui autorise un nombre excessif d’initialiseurs pour un scalaire et les ignore. De plus, certains compilateurs peuvent “être utiles” et “seulement” émettre un avertissement et initialiser ptr pour qu’il pointe vers l’adresse 1 , où que ce soit.

    “scalaire” signifie un object qui n’est ni une structure ni un tableau.


    Depuis C99, vous pouvez écrire:

     int *ptr = (int []){1, 2, 3}; 

    qui crée un tableau (utilisant la même durée de stockage que ptr ) et pointe ptr sur son premier élément.

    Ce tableau est mutable; pour un non mutable on utilise int const *ptr = (int const[]){1, 2, 3}; au lieu.


    En remplaçant int par char * , nous voyons que vous pourriez écrire:

     char **p = (char *[]){ "123", "456", "789" }; 

    dans ce cas, les pointeurs du tableau sont mutables, mais les éléments sur lesquels ils pointent (c’est-à-dire les littéraux de chaîne) ne le sont toujours pas.

    Notez que vous devez toujours utiliser char const * lorsque vous utilisez des littéraux de chaîne, car ils ne sont pas mutables. Le fait que les littéraux de chaîne ont le type char [N] est une preuve de la veille historique d’avant que const été ajouté à C. Donc:

     char const **pp = (char const *[]){ "123", "456", "789" }; 

    ou avec des pointeurs non mutables vers des chaînes:

     char const *const *pp = (char const *const []){ "123", "456", "789" }; 

    Ici char *pp[]={ "123", "456", "789" }; est correct parce que:

    • Il s’agit ici d’un tableau de pointeurs qui peut être utilisé pour pointer vers un tableau d’éléments de données, chaque élément du tableau de pointeurs pointant vers un élément du tableau de données.
    • Comme nous assignons chaque tableau à un pointeur de caractère, cela fonctionne bien.

    Mais en cas de caractère char **pp={ "123", "456", "789" };

    • Ici, l’initialisation de la mémoire ne se produit pas.
    • Au lieu de cela, la première chaîne est affectée au pointeur, puis le compilateur génère un avertissement indiquant que de nombreuses autres valeurs sont ignorées.

    Comme CoolGuy l’a dit ++(**pointerToPointer) il s’agit d’une erreur car il accède à 1 de la chaîne "123" et tente de modifier la valeur de 1 à 2 ; Vous ne pouvez voir que la valeur d’incrément de print: printf("%c\n", **pointerToPointer+1); qui donnera sortie: 2

    Vous pouvez le résoudre par la solution fournie par CoolGuy dans le commentaire-

    1. En modifiant char *pp[]={ "123", "456", "789" }; to char pp[][100]={ "123", "456", "789" };
    2. En changeant void fun(char **pointerToPointer) vers void fun(char **pointerToPointer) en lieu void fun(char (*pointerToPointer)[100])

    C’est correct car ici la valeur de **pointerToPointer est modifiée.

    Ce sont les raisons pour moi. Et pour l’avertissement:

    warning: excess elements in scalar initializer [enabled by default]

    vous pouvez voir le lien ici qui est la meilleure explication pour moi.