c++ char * initialisation dans le constructeur
Je suis juste curieux, je veux savoir ce qui se passe ici:
class Test
{
char * name;
public:
Test(char * c) : name(c){}
};
1) Pourquoi ne pas Test(const char * c) : name(c){}
travail? Parce que char * name
n'est pas const? Mais ce:
main(){
char * name = "Peter";
}
name
est de type char*, mais "Peter"
est const char*, non? Alors, comment fait-que l'initialisation de travail?
2) Test(char * c) : name(c){ c[0] = 'a'; }
- ce qui bloque le programme. Pourquoi?
Désolé pour mon ignorance.
- Que voulez-vous dire
name(c)
ne fonctionne pas? Définir des "œuvres". - invalid conversion from const char* char*
"Peter"
estconst char[6]
, pasconst char *
.- Sur une note pratique, ce que vous voulez, au contraire, est
std::string name
- c'est pour un examen, je ne pense pas que nous sommes autorisés à utiliser std::string parce que ce n'est pas une partie de la formation
Vous devez vous connecter pour publier un commentaire.
Correcte.
C++ littéral de chaîne est de type
char const[]
(voir ici, plutôt que de simplementchar[]
en C, comme elle n'a pas laconst
mot-clé1). Cette cession est considérée comme obsolète en C++, mais il est encore permis2 pour la compatibilité descendante avec C.Ce que vous êtes de passage à
Test
lors de l'initialisation d'elle? Si vous êtes de passage d'une chaîne littérale ou illégale d'un pointeur, fairec[0] = 'a'
n'est pas autorisé.1 L'ancienne version du langage de programmation C (comme décrit dans le K&R livre publié en 1978) ne comprend pas les
const
mot-clé. Depuis, C ANSI emprunté l'idée deconst
à partir de C++.2 Valide en C++03, n'est plus valide en C++11.
char* c = "hello"; Test t(c);
ou tout simplementTest t("hello");
les deux crash'a'
.const
mot-clé dans C, et a toujours été autant que je sache (c'est certainement en C89, et toujours en C11.)Une conversion à
const
est une rue à sens unique, pour ainsi dire.Vous pouvez convertir
T *
àT const *
implicitement.Conversion de
T const *
àT *
nécessite un cast explicite. Même si vous avez commencé à partirT *
, puis converti enT const *
, la conversion de retour àT *
nécessite un cast explicite, même si c'est vraiment juste "restaurer" l'accès vous aviez au départ.On remarque que,
T const *
etconst T *
sont précisément équivalent, etT
signifie "certains type arbitraire" (char
dans votre exemple, mais pourrait tout aussi bien être autre chose commeint
oumy_user_defined_type
).De l'initialisation d'un
char *
à partir d'une chaîne littérale (par exemple,char *s = "whatever";
) est autorisée même si elle viole cette règle générale (le littéral lui-même est fondamentalementconst
, mais vous êtes en train de créer un non-const pointeur). C'est tout simplement parce qu'il y a beaucoup de code qui dépend de cela, et personne n'est disposé à casser ce code, de sorte qu'ils ont une règle pour autoriser. Cette règle est obsolète, bien que, en théorie du moins, l'avenir compilateur pourrait rejeter code qui en dépend.Depuis le littéral de chaîne elle-même est fondamentalement
const
, toute tentative de modification il en résulte un comportement indéfini. Sur la plupart des systèmes modernes, cela va se traduire dans le processus d'être interrompue, parce que la mémoire de stockage de la chaîne de caractères littérale sera marqué en "lecture seule". Ce n'est pas le seul résultat possible. Juste pour exemple, à l'époque de MS-DOS, il serait souvent réussir. Il pourrait encore avoir bizarre effets secondaires si. Pour un exemple, beaucoup de compilateurs "savait" que les littéraux de chaîne étaient censés être en lecture seule, alors qu'ils avaient "fusion" à l'identique les littéraux de chaîne. Donc si vous aviez quelque chose comme:Le compilateur aurait "fusionné"
a
etb
à fait le point à la même mémoire -- alors, quand vous avez modifiéa
, que le changement n'affecte également lesb
, de sorte qu'il aurait l'impression de "Pater" au lieu de "Pierre".Noter que les littéraux de chaîne n'a pas besoin d'être totalement identique pour cela, soit. Aussi longtemps que l'on était identique à la fin de l'autre, ils pourraient être fusionnés:
Imposant un comportement n'est pas logique, donc, le résultat était (et est) simplement pas défini.
Tout d'abord c'est le C++, vous avez
std::string
. Vous devriez vraiment envisager de l'utiliser.Concernant votre question,
"Peter"
est un caractère littéral, par conséquent, il est inmodifiable et sûrement vous ne pouvez pas écrire sur elle. Vous pouvez:const char *
variable de membre et l'initialiser comme vous le faitesname(c)
, en déclarant"Peter"
commeconst
char *
variable de membre et de copier le contenu, par exemple,name(strdup(c))
(et n'oubliez pas de le publier à l'destructeur.Correcte.
"Peter" est généralement stocké dans une mémoire en lecture seule de l'emplacement (en fait, cela dépend de quel type d'appareil que nous sommes sur) parce que c'est un littéral de chaîne. Il n'est pas ce qui se passe lorsque vous essayez de modifier une chaîne littérale (mais vous pouvez probablement deviner que vous ne devriez pas).
Vous devez utiliser
std::string
de toute façon.1a) Droit
1b)
"Peter"
n'est pasconst char*
, son estchar*
mais il ne peut être modifié. La raison en est pour la compatibilité avec fois avant deconst
existé dans la langue. Beaucoup de code qui existait déjà ditchar* p = "fred";
et qu'ils ne pouvaient pas juste faire ce code illégal pour la nuit.2) ne Peux pas dire pourquoi ce serait de planter le programme, sans en voir la façon dont vous utilisez ce constructeur.
"Peter"
est unchar const[6]
, pas unchar*
.char const[6]
alors comment est -char *name = "Peter";
juridique?Test(const char* c){ name = new char[strlen(c)+1]; strcpy(name,c);}
si j'écrisTest t("Peter");
, le constructeur attend const char*, mais"Peter"
est de type char* ? 2) Test t("Bonjour");