Modifier const char * en C

Je pratique pour des entrevues. Le problème que je suis actuellement bloqué est l’inversion d’une chaîne constante en C. Je sais que, puisque str2 est const, je peux modifier l’emplacement indiqué par str2, mais pas sa valeur. J’ai une fonction ci-dessous appelée reverse_const. Il inversera le caractère constant * str_const en place et l’imprimera. Cependant, lorsque j’essaie d’imprimer st2 après une inversion de la méthode principale, la chaîne n’est plus inversée. C’est comme si reverse_const () changeait temporairement l’emplacement mémoire de str2. Qu’est-ce que je fais mal ici?

#include  #include  void reverse(char *str){ int c_size = strlen(str); char *c_begin = str, *c_end = str + (c_size - 1); int i; for(i = 0; i < c_size / 2; i++){ *c_begin ^= *c_end; *c_end ^= *c_begin; *c_begin ^= *c_end; c_begin++; c_end--; } } void reverse_const(const char *str_const){ int c_size = strlen(str_const); char str[c_size]; strcpy(str, str_const); char *c_begin = str, *c_end = str + (c_size - 1); int i; for(i = 0; i < c_size / 2; i++){ *c_begin ^= *c_end; *c_end ^= *c_begin; *c_begin ^= *c_end; c_begin++; c_end--; } str_const = str; printf("%s\n", str_const); } int main(){ char str1[] = "Indiana"; char *str2 = "Kentucky"; printf("TESTS:\nString 1 pre-reversal: %s\n", str1); reverse(str1); printf("String 1 post-reversal: %s\n", str1); printf("Constant string 2 pre-reversal: %s\n", str2); reverse_const(str2); printf("Constant string 2 post-reversal: %s\n", str2); } 

    Si vous voulez que la str2 inversée revienne dans main() , vous devrez soit passer un buffer de taille adéquate à reverse_const pour contenir la chaîne inversée, soit allouer de manière dynamic le stockage correspondant dans reverse_const (un tableau de longueur variable local gagné). t faire):

     #include  ... void reverse_const (const char **str_const) { int c_size = strlen (*str_const); char *str = calloc (c_size + 1, sizeof *str); strcpy (str, *str_const); char *c_begin = str, *c_end = str + (c_size - 1); int i; for (i = 0; i < c_size / 2; i++) { *c_begin ^= *c_end; *c_end ^= *c_begin; *c_begin ^= *c_end; c_begin++; c_end--; } *str_const = str; printf ("%s\n", *str_const); } int main (void) { char str1[] = "Indiana"; char *str2 = "Kentucky"; printf ("TESTS:\nString 1 pre-reversal: %s\n", str1); reverse (str1); printf ("String 1 post-reversal: %s\n", str1); printf ("Constant string 2 pre-reversal: %s\n", str2); reverse_const ((const char **)&str2); printf ("Constant string 2 post-reversal: %s\n", str2); free (str2); return 0; } 

    Sortie

     $ ./bin/revconststr TESTS: Ssortingng 1 pre-reversal: Indiana Ssortingng 1 post-reversal: anaidnI Constant ssortingng 2 pre-reversal: Kentucky ykcutneK Constant ssortingng 2 post-reversal: ykcutneK 

    Rendre le pointeur

    Vous avez une option supplémentaire pour renvoyer le pointeur sur str à affecter à str2 dans main() . C’est plutôt ce que vous vous attendez normalement à voir. Faites moi savoir si vous avez des questions:

     char *reverse_const2 (const char **str_const) { int c_size = strlen (*str_const); char *str = calloc (c_size + 1, sizeof *str); strcpy (str, *str_const); char *c_begin = str, *c_end = str + (c_size - 1); int i; for (i = 0; i < c_size / 2; i++) { *c_begin ^= *c_end; *c_end ^= *c_begin; *c_begin ^= *c_end; c_begin++; c_end--; } //*str_const = str; printf ("%s\n", *str_const); return str; } int main (void) { char str1[] = "Indiana"; char *str2 = "Kentucky"; printf ("TESTS:\nString 1 pre-reversal: %s\n", str1); reverse (str1); printf ("String 1 post-reversal: %s\n", str1); printf ("Constant string 2 pre-reversal: %s\n", str2); str2 = reverse_const2 ((const char **)&str2); printf ("Constant string 2 post-reversal: %s\n", str2); free (str2); return 0; } 

    Lorsque vous passez par des arguments, la fonction obtient une copie. str_const = str; assigne à cette copie. Vous pouvez passer un pointeur à un pointeur pour pouvoir changer la valeur d’un pointeur en dehors de votre fonction. Cependant, vous allouez la copie de chaîne sur la stack. Par conséquent, la copie de chaîne devient non valide une fois que vous quittez la scope de reverse_const . ça n’a pas de sens ici.

    Si vous voulez une copie de chaîne qui survit à la fin de reverse_const , reverse_const le tableau avec malloc ou faites à la fois l’allocation et la copie avec strdup . Que vous deviez renvoyer le pointeur malloc'ed manière ou d’une autre (par une valeur de retour de via un pointeur à un argument pointeur) et que l’appelant aura alors la responsabilité de free cette mémoire malloc une fois que cela sera fait.

    Vous devez écrire votre fonction afin de pouvoir retourner l’argument modifié.

    Une de ces solutions est la référence par référence :

     void reverse_const(const char **str_const){ const char *in = *str_const; char *out = malloc(strlen(in)+1); /* write to out */ *str_const = out; } 

    Mais un meilleur moyen serait d’utiliser la valeur de retour:

     char *reverse_const(const char *str_const){ const char *in = str_const; char *out = malloc(strlen(in)+1); /* write to out */ return out; } 

    Le type de retour peut être const char * , mais il s’agit d’une ressortingction inutile, car vous savez que la chaîne renvoyée peut être modifiée en toute sécurité.

    Notez que les deux exemples utilisent malloc . Les tableaux ne peuvent pas être renvoyés, de cette manière, en C, car ils existent dans la stack et sont détruits à la sortie de la fonction.

    Chaque fois qu’un programme de longue durée utilise malloc , il devrait exister une correspondance free quelque part dans le code, sinon vous aurez une fuite de mémoire. C’est une douleur, mais quelque chose que tous les programmeurs C doivent maîsortingser.

    Le problème ici est que vous modifiez l’argument transmis à reverse_const , mais les arguments en C sont passés par valeur, ce qui signifie qu’ils sont copiés. La variable que vous modifiez dans la fonction est une copie du pointeur d’origine. Changer une copie ne modifiera évidemment pas l’original.

    C n’a pas passe par référence qui est nécessaire ici, mais il peut être émulé en utilisant des pointeurs. Dans le cas de votre fonction, vous devez passer un pointeur sur le pointeur, puis utiliser l’opérateur de déréférencement * pour modifier l’object du pointeur. le pointeur pointe sur, et utilise l’adresse-de l’opérateur & lors de l’appel de la fonction.