348 votes

Pourquoi est-ce que j'obtiens une erreur de segmentation lors de l'écriture dans une chaîne?

Le code suivant reçoit un code d'erreur sur la ligne 2:

   char *str = "string";
  str[0] = 'z';
  printf("%s", str);
 

Bien que cela fonctionne parfaitement bien:

   char str[] = "string";
  str[0] = 'z';
  printf("%s", str);
 

Testé avec MSVC et GCC.

288voto

matli Points 7603

Voir la FAQ C, Question 1.32

Q: Quelle est la différence entre ces initialisations?
char a[] = "string literal";
char *p = "string literal";
Mon programme se bloque si j'essaie d'affecter une nouvelle valeur à p[i].

Un: Une chaîne littérale (le terme officiel pour une chaîne de caractères entre guillemets dans C source) peuvent être utilisés dans les deux légèrement différentes façons:

  1. Comme l'initialiseur, pour un tableau de char, comme dans la déclaration de char a[] , il spécifie les valeurs initiales les personnages dans ce tableau (et, si nécessaire, sa taille).
  2. Partout ailleurs, il se transforme en un sans nom, statique tableau de caractères, et ce sans nom de tableau peuvent être stockés dans la mémoire en lecture seule, et qui par conséquent, ne peuvent pas nécessairement être modifié. Dans un contexte d'expression, le tableau est converti en une seule fois pointeur, comme d'habitude (voir la section 6), de sorte la deuxième déclaration initialise p pour pointer vers le sans nom de la matrice de première de l'élément.

Certains compilateurs ont un commutateur contrôler si les littéraux de chaîne sont en écriture ou pas (pour la compilation de vieux le code), et certains peuvent avoir des options pour cause des littéraux de chaîne pour être officiellement traités comme des tableaux de const char (pour mieux erreur de la capture).

123voto

Greg Hewgill Points 356191

Normalement, les littéraux de chaîne sont stockées dans la mémoire en lecture seule lorsque le programme est exécuté. C'est pour vous éviter de changer accidentellement une constante de chaîne. Dans ton premier exemple, "string" est stocké dans la mémoire en lecture seule et *str points pour le premier caractère. L'erreur se produit lorsque vous essayez de modifier le premier caractère d' 'z'.

Dans le deuxième exemple, la chaîne "string" est copié par le compilateur à partir de son en lecture seule à la maison à l' str[] tableau. Puis changer le premier caractère est autorisée. Vous pouvez le vérifier en imprimant l'adresse de chacun:

printf("%p", str);

Aussi, l'impression de la taille d' str dans le second exemple va vous montrer que le compilateur a alloué 7 octets pour:

printf("%d", sizeof(str));

49voto

Bob Somers Points 4186

La plupart de ces réponses sont correctes, mais juste pour ajouter un peu plus de clarté...

Le "read only memory" que les gens font référence à est le segment de texte dans ASM termes. C'est le même endroit de la mémoire où les instructions sont chargées. Il est en lecture seule pour des raisons évidentes de sécurité. Lorsque vous créez un char* initialisé à une chaîne, la chaîne de données est compilé dans le segment de texte et le programme initialise le pointeur dans le segment de texte. Donc, si vous essayez de le changer, kaboom. Erreur de segmentation.

Lorsqu'il est écrit comme un tableau, le compilateur place la initialisée chaîne de données dans le segment de données au lieu de cela, qui est au même endroit que vos variables globales et en direct. Cette mémoire est mutable, car il n'y a pas d'instructions dans le segment de données. Cette fois, lorsque le compilateur initialise le tableau de caractères (ce qui est encore juste un char*) elle est pointée dans le segment de données plutôt que sur le segment de texte, que vous pouvez modifier en toute sécurité au moment de l'exécution.

19voto

Glomek Points 12183

Dans le premier code, "chaîne" est une constante de chaîne et les constantes de chaîne ne doivent jamais être modifiées car elles sont souvent placées dans la mémoire morte. "str" ​​est un pointeur utilisé pour modifier la constante.

Dans le second code, "string" est un initialiseur de tableau, sorte de raccourci pour

 char str[7] =  { 's', 't', 'r', 'i', 'n', 'g', '\0' };
 

"str" ​​est un tableau alloué sur la pile et peut être modifié librement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X