Quelle est la différence entre char s[] et char *s?
En C, on peut utiliser une chaîne de caractères littérale dans une déclaration comme ceci:
char s[] = "hello";
ou comme ceci:
char *s = "hello";
Quelle est donc la différence? Je veux savoir ce qui se passe réellement en termes de durée de stockage, à la fois lors de la compilation et de l'exécution.
- c-faq.com/aryptr/index.html c-faq.com/charstring/index.html
- char *s="bonjour", ici, peut pointer n'importe quelle autre chaîne au moment de l'exécution, je veux dire qu'elle n'est pas constante pointeur vous pouvez affecter une autre valeur au moment de l'exécution p = "Nishant", alors que la s[] ici s est un pointeur constant....il ne peut pas être reasign une autre chaîne de caractères, mais on peut lui assigner une autre valeur de caractère à s[index].
Vous devez vous connecter pour publier un commentaire.
La différence ici est que
aura lieu
"Hello world"
dans le en lecture seule des parties de la mémoire, et de faires
un pointeur qui fait qu'une opération d'écriture sur cette mémoire illégale.Tout faire:
met la chaîne en mémoire en lecture seule et les copies de la chaîne de mémoire nouvellement allouée sur la pile. Rendant ainsi
juridique.
"Hello world"
est en "lecture seule des parties de la mémoire" dans les deux exemples. L'exemple avec le tableau de points il, l'exemple avec le tableau de copie les caractères pour les éléments du tableau."Hello world"
directement dans un inscriptible section de chargement au démarrage, pour une variable automatique du tableau n'est besoin d'être réinitialisé à chaque fois."... The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. ..."
Il n'est pas "parler" de la 'plaine' séquences de caractères, mais je pense que la même chose s'applique. Je pense également à une mise en œuvre peut ignorer ce bit particulier de la Norme pour des raisons de performances 🙂char msg[] = "hello, world!";
la chaîne se termine dans la initialisé section de données. Lorsqu'ils sont déclaréschar * const
pour finir dans les données en lecture seule section. gcc-4.5.3Tout d'abord, dans les arguments de la fonction, ils sont exactement équivalentes:
Dans d'autres contextes,
char *
alloue un pointeur, alors quechar []
alloue un tableau. D'où vient la chaîne d'aller dans le premier cas, vous demandez-vous? Le compilateur secrètement alloue un statique anonyme tableau pour contenir la chaîne de caractères littérale. Donc:Notez que vous ne devez jamais tenter de modifier le contenu de ce tableau anonyme par le biais de ce pointeur; les effets ne sont pas définis (souvent le sens d'un crash):
À l'aide de la syntaxe de tableau attribue directement à la mémoire. Ainsi, la modification est sûre:
Toutefois, le tableau ne vit que tant que son contenant de la portée, de sorte que si vous le faites dans une fonction ne retourne pas de fuite ou un pointeur vers ce tableau - faire une copie à la place avec
strdup()
ou similaire. Si le tableau est alloué dans la portée globale, bien sûr, pas de problème.Cette déclaration:
Crée un objet d'un
char
tableau de taille 6, appelés
, initialisé avec les valeurs'h', 'e', 'l', 'l', 'o', '\0'
. D'où ce tableau est alloué dans la mémoire, et combien de temps il vit, dépend de l'endroit où la déclaration apparaît. Si la déclaration est à l'intérieur d'une fonction, il va vivre jusqu'à la fin du bloc qu'elle est déclarée, et presque certainement être allouée sur la pile; si c'est en dehors d'une fonction, il va probablement être stocké dans une "initialisation de segment de données" qui est chargé à partir du fichier exécutable en écriture de la mémoire lorsque le programme est exécuté.D'autre part, cette déclaration:
Crée deux objets:
char
s contenant les valeurs'h', 'e', 'l', 'l', 'o', '\0'
, qui n'a pas de nom et a statique de la durée de stockage (ce qui signifie qu'il vit pour l'ensemble de la durée de vie du programme); ets
, qui est initialisé avec l'emplacement du premier caractère que sans nom, en lecture seule matrice.L'anonyme en lecture seule matrice est généralement situé dans le "texte" segment du programme, ce qui signifie qu'il est chargé à partir du disque dans la mémoire en lecture seule, avec le code en lui-même. L'emplacement de la
s
pointeur de la variable dans la mémoire dépend de l'endroit où la déclaration apparaît (comme dans le premier exemple).char s[] = "hello"
cas, la"hello"
est juste un initialiser dire au compilateur comment le tableau doit être initialisé. Il peut ou peut ne pas aboutir à une chaîne correspondante dans le segment de texte - par exemple, sis
a durée de stockage statique, il est probable que la seule instance de"hello"
sera dans le segment des données initialisées - l'objets
lui-même. Même sis
a automatique de la durée de stockage, il peut être initialisé par une séquence de littéral magasins, plutôt qu'une copie (par exemple.movl $1819043176, -6(%ebp); movw $111, -2(%ebp)
)..rodata
, qui le linker script exporte ensuite dans le même segment que.text
. Voir ma réponse.char s[] = "Hello world";
met la chaîne en mémoire en lecture seule et les copies de la chaîne de mémoire nouvellement allouée sur la pile. Mais, votre réponse ne parle à propos de la chaîne littérale mis en mémoire en lecture seule et ignore la deuxième partie de la phrase qui dit:copies the string to newly allocated memory on the stack
. Donc, c'est votre réponse incomplète pour ne pas spécifier la deuxième partie?char s[] = "Hellow world";
est seulement un initialiseur et n'est pas nécessairement enregistrée séparément de la copie en lecture seule à tous. Sis
a durée de stockage statique, alors la seule copie de la chaîne est susceptible d'être en lecture-écriture segment à l'emplacement des
, et même si non, alors le compilateur peut choisir d'initialiser le tableau avec charge immédiate des instructions ou similaire plutôt que de copier à partir d'une chaîne en lecture seule. Le point est que, dans ce cas, l'initialiseur de la chaîne elle-même n'a pas de présence d'exécution.Donné les déclarations
assumer la suite hypothétique carte mémoire:
La chaîne littérale
"hello world"
est un 12-élément de tableau dechar
(const char
en C++) avec la durée de stockage statique, ce qui signifie que la mémoire est allouée lorsque le programme démarre et reste affecté jusqu'à ce que le programme se termine. Tenter de modifier le contenu d'une chaîne de caractères littérale invoque un comportement indéfini.La ligne
définit
s0
comme un pointeur verschar
avec automatique de la durée de stockage (ce qui signifie que la variables0
n'existe que pour le champ dans lequel elle est déclarée) et des copies de la adresse de la chaîne littérale (0x00008000
dans cet exemple) pour elle. A noter que depuiss0
points pour un littéral de chaîne, il ne devrait pas être utilisée comme argument d'une fonction qui permettrait d'essayer de la modifier (par exemple,strtok()
,strcat()
,strcpy()
, etc.).La ligne
définit
s1
12 élément de tableau dechar
(la longueur est prise à partir de la chaîne littérale) avec automatique de la durée de stockage et de copies de la contenu de l'littéral de tableau. Comme vous pouvez le voir à partir de la carte mémoire, nous avons deux copies de la chaîne"hello world"
; la différence est que vous pouvez modifier la chaîne contenue danss1
.s0
ets1
sont interchangeables dans la plupart des contextes, voici les exceptions:Vous pouvez réattribuer la variable
s0
à point à un autre littéral de chaîne ou d'une autre variable. Vous ne pouvez pas réaffecter la variables1
pour pointer vers un autre tableau.C99 N1256 projet de
Il y a deux usages différents de la chaîne de caractères littéraux:
Initialiser
char[]
:C'est "plus de magie", et décrit au 6.7.8/14 "Initialisation":
Donc c'est juste un raccourci pour:
Comme n'importe quel autre réseau régulier,
c
peut être modifié.Partout ailleurs: il génère une:
Donc, lorsque vous écrivez:
Ceci est similaire à:
Note le cast implicite de
char[]
àchar *
, qui est toujours légal.Alors si vous modifiez
c[0]
, vous pouvez également modifier__unnamed
, qui est UB.C'est documentée à 6.4.5 "littéraux de Chaîne":
6.7.8/32 "Initialisation" donne un exemple concret:
GCC 4.8 x86-64 ELFE de la mise en œuvre
Programme:
De compiler et de décompiler:
Sortie contient:
Conclusion: GCC magasins
char*
dans.rodata
l'article, pas dans.text
.Si nous faisons la même chose pour
char[]
:nous obtenons:
de sorte qu'il est stocké dans la pile (par rapport à
%rbp
).Note cependant que la valeur par défaut de l'éditeur de liens script met
.rodata
et.text
dans le même segment, qui a execute, mais pas l'autorisation d'écriture. Cela peut être observé avec:qui contient:
déclare
s
être un tableau dechar
qui est assez long pour contenir l'initialiseur (5 + 1char
s) et initialise le tableau en copiant les membres de la chaîne littérale dans le tableau.déclare
s
être un pointeur sur un ou plusieurs (dans ce cas plus)char
s et des points directement à un fixe (en lecture seule) l'emplacement contenant le littéral"hello"
.s
est un pointeur versconst char
.Ici,
s
est un tableau de caractères, qui peuvent être remplacées si nous le souhaitons.Un littéral de chaîne est utilisé pour créer ces blocs quelque part dans la mémoire de ce pointeur
s
pointe. Nous ne pouvons ici réaffecter l'objet qu'il désigne par changer, mais tant qu'il pointe vers une chaîne littérale du bloc de caractères à laquelle il pointe ne peut pas être changé.Comme une outre, considérer que, comme pour la lecture seule, l'utilisation des deux est identique, vous pouvez accéder à un char de l'indexation, soit avec
[]
ou*(<var> + <index>)
format:
Et:
Évidemment, si vous tentez de le faire
Vous obtiendrez probablement une erreur de Segmentation, comme vous tentez d'accéder en lecture seule mémoire.
x[1] = 'a';
qui erreur de segmentation ainsi (selon la plate-forme, bien sûr).Juste pour ajouter: - vous également obtenir des valeurs différentes pour leurs tailles.
Comme mentionné ci-dessus, pour un tableau
'\0'
sera alloué à l'élément final.Ci-dessus jeux de str à point à la valeur littérale "Bonjour", qui est codé en dur dans le programme de l'image binaire, qui est marqué en lecture seule dans la mémoire, les moyens de tout changer dans cette Chaîne littérale est illégal et que jeter de la segmentation des défauts.
des copies de la chaîne de mémoire nouvellement allouée sur la pile. Ainsi, tout changement dans ce qui est permis et juridique.
va changer la str pour "Mello".
Pour plus de détails, s'il vous plaît aller à travers la question similaire:
Pourquoi j'obtiens une erreur de segmentation lors de l'écriture d'une chaîne initialisée avec "char *s", mais pas "char s[]"?
Dans le cas de:
x est un lvalue - il peut être attribué. Mais dans le cas de:
x n'est pas une lvalue, c'est une rvalue -- vous ne pouvez pas lui attribuer.
x
est un non-modifiable lvalue. Dans presque tous les contextes, mais cependant, il sera remplacé par un pointeur vers son premier élément, et que valeur est une rvalue.À la lumière des commentaires ici, il devrait être évident que : char * s = "bonjour" ;
Est une mauvaise idée, et devrait être utilisé dans le champ d'application très étroit.
Ce pourrait être une bonne occasion pour souligner que "const correctness" est une "bonne chose". Chaque fois et partout où Vous le pouvez, utilisez le mot clé "const pour protéger votre code, "détendu" les appelants ou les programmeurs, qui sont généralement les plus "détendu" lorsque les pointeurs entrent en jeu.
Assez mélodrame, voici ce que l'on peut accomplir quand ornent les pointeurs avec "const".
(Remarque: On a qu'à lire les déclarations de pointeur de droite à gauche.)
Ici sont les 3 façons de vous protéger lorsque vous jouez avec des pointeurs :
— qui est, la DBJ objet ne peut pas être modifié via les p.
— qui est, vous pouvez modifier la DBJ de l'objet via p, mais vous ne pouvez pas modifier le pointeur p lui-même.
— qui est, vous ne pouvez pas modifier le pointeur p lui-même, et vous ne pouvez pas changer la DBJ de l'objet via p.
Les erreurs liées à des tentatives constantes mutations sont pris au moment de la compilation. Il n'y a pas de runtime de l'espace ou de la vitesse de pénalité pour const.
(Hypothèse est que vous utilisez le compilateur C++, bien sûr ?)
--DBJ