Pourquoi un pointeur sur un tableau de caractères doit-il avoir besoin de strcpy pour assigner des caractères à son tableau et l’atsortingbution de guillemets doubles ne fonctionnera pas?

Le premier exemple ne fonctionne pas lorsque vous allez supprimer le pointeur. Le programme se bloque lorsque j’ajoute le terminateur nul ou sans ce dernier:

Debug Assertion Failed Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) partir de Visual Studio 2008

 //Won't work when deleting pointer: char *at = new char [3]; at = "tw"; // <-- not sure what's going on here that strcpy does differently at[2] = '\0'; // <-- causes program to hang delete at; //Works fine when deleting pointer: char *at = new char [3]; strcpy(at,"t"); at[1] = 'w'; at[2] = '\0'; delete at; 

Alors que se passe-t-il lorsque j’utilise des guillemets doubles au lieu de strcpy? Tous les deux vont parfaitement gérer la chaîne et le débogueur ne montre rien de différent.

Parce qu’un caractère char* n’est pas une chaîne. C’est juste un pointeur sur un caractère, avec la convention qu’il peut y avoir plus de caractères à suivre et qu’après le dernier, il y a un '\0' .

Un littéral de chaîne en C (et donc en C ++) tel que "abc" est simplement un tableau de caractères, le compilateur ajoutant silencieusement un '\0' . Lorsque vous affectez un tableau à un pointeur, celui-ci convertit un pointeur en mode silencieux en premier élément. Le résultat est que

 at = "tw"; 

signifie que l’adresse du premier caractère de la chaîne littérale "tw" est atsortingbuée at pointeur. Par cela, il va perdre son ancienne valeur. Comme il s’agissait de l’adresse d’un tableau de caractères alloué dynamicment, vous perdez ce tableau.

Lorsque vous affectez ultérieurement à un caractère du tableau où pointe maintenant, vous atsortingbuez une nouvelle valeur à un caractère du littéral chaîne. Cela invoque un comportement indéfini et le programme suspendu ou bloqué immédiatement est probablement le meilleur qui puisse vous arriver lorsque vous faites cela. (Sur de nombreuses plateformes, vous écrivez dans une mémoire en lecture seule.)

Plus tard, vous passez at delete[] (et non pas delete , puisque vous avez appelé new[] , pas new ). Ce faisant, vous lui transmettez l’adresse du littéral chaîne, au lieu du tableau de caractères alloué. Cela va bien sûr gâcher le gestionnaire de tas. (La bibliothèque d’exécution de VC intercepte cela en mode débogage.)

std::strcpy , d’autre part, copie une chaîne caractère par caractère d’un tableau à un autre. Aucun pointeur ne sera changé, seuls des morceaux de mémoire sont copiés. Le pointeur sur le tableau cible pointe toujours sur le tableau cible, seules les données de ce tableau ont été modifiées.

Permettez-moi d’append ceci: en tant que débutant en C ++, vous devez utiliser std::ssortingng , plutôt que des chaînes C. Cela fait tout le sale boulot pour vous et a une sémantique saine.

Quand tu fais

 char *at = ...; at = "hello"; 

En gros, vous écrasez la valeur du pointeur (c’est-à-dire l’adresse de la mémoire allouée par new[] ) par l’adresse d’une chaîne de constante statique. Cela signifie que lorsque vous supprimez cette mémoire par la suite, vous passez à delete un pointeur qui n’a pas été précédemment renvoyé par new .

C’est une mauvaise chose à faire.

En C et C ++, les assignations aux pointeurs ne font généralement rien à la mémoire pointée, elles changent le pointeur lui-même. Cela pourrait être déroutant si vous êtes habitué à une langue où les chaînes sont davantage des “citoyens de première classe”.

En outre, vous devez utiliser delete[] si vous avez utilisé new[] .

Il y a 3 choses à comprendre:

1) char *at; est juste une variable de pointeur.
Une variable de pointeur signifie simplement qu’elle contient une adresse de mémoire.

2) new char[3] renvoie l’adresse de départ de la mémoire allouée sur le tas.

3) "hello" renvoie l’adresse du littéral de chaîne.

 char *at = new char [3]; //at now contains the address of the memory allocated on the heap at = "hello"; //at now contains the address of the static ssortingng. // (and by the way you just created a 3 byte memory leak) delete[] at; //WOOPS!!!! you can't do that because you aren't deleting // the original 3 chars anymore which were allocated on the heap! //Since at contains the ssortingng literal's memory address you're // trying to delete the ssortingng literal. 

Une note sur la modification de la mémoire en lecture seule:

En outre, vous ne devriez jamais modifier un littéral de chaîne. Cela ne devrait jamais être fait:

 char *at = "hello"; at[2] = '\0'; 

La mémoire des littéraux de chaîne doit être en lecture seule et si vous la modifiez, les résultats ne sont pas définis par le langage C ++.

Depuis que vous utilisez C ++:

Puisque vous utilisez C ++, pensez plutôt à utiliser le type std::ssortingng .

 #include  using namespace std; int main(int argc, char **argv) { ssortingng s = "hello"; s += " world!"; //s now contains "hello world!" s = "goodbye!"; //Everything is still valid, and s contains "goodbye!" //No need to cleanup s. return 0; } 

Ne pas oublier d’utiliser

 delete [] 

chaque fois que vous atsortingbuez quelque chose avec [].

Un pointeur contient une adresse. L’opérateur = d’un pointeur modifie l’adresse en attente.

 at = "tw"; 

Fait un point vers le tableau “tw” (un tableau créé par le compilateur pour contenir les caractères tw), il ne pointe plus vers le tableau que vous avez créé avec new. créé dans le fichier.

 at[2] = '\0'; 

Ajoute un NULL à la fin du tableau complier.

Dans le premier exemple, vous modifiez la valeur à, dans le second, vous modifiez la valeur de at. Assigner un caractère * à une chaîne entre guillemets l’atsortingbue à un pointeur statique.

En particulier, dans le premier exemple, pointe maintenant un emplacement différent en mémoire.

Dans votre premier exemple, vous allouez de la mémoire et vous la pointez avec la variable “at”. Quand tu fais

 at = "tw" 

vous renvoyez effectivement le caractère * à une chaîne de caractères constante. Cela vous fait perdre de la mémoire. Lorsque vous supprimez “à”, vous essayez de supprimer la mémoire de la stack.

strcpy parcourt chaque caractère et copie ses valeurs dans la nouvelle mémoire que vous allouez. Ceci est également connu comme une copie profonde.

Dans le premier exemple, vous avez provoqué une fuite de mémoire.

Votre variable at est un pointeur sur une adresse mémoire, pas sur la chaîne elle-même. Lorsque vous atsortingbuez l’adresse de "tw" au pointeur, vous avez perdu l’adresse d’origine que vous avez obtenue avec new . at pointe maintenant sur une adresse que vous n’avez pas allouée avec new , vous ne pouvez donc pas la delete .

Si vous considérez les pointeurs comme des entiers, cela aura probablement plus de sens. J’ai assigné des nombres arbitraires comme adresses aux fins de discussion.

 char *at = new char[3]; // 0x1000 at = "tw"; // 0x2000 at[2] = '\0'; // set char at 0x2002 to 0 delete at; // delete 0x2000 (whoops, didn't allocate that!) 

Vous confondez deux choses: faire pointer le pointeur sur quelque chose de différent (c’est ce que fait l’affectation) et copier des données à un endroit pointé par un pointeur.

 at = "tw"; 

ce code renvoie at un “tw” littéral créé quelque part dans la mémoire en lecture seule. Essayer d’y écrire est un comportement indéfini.

 char *at = new char [3]; strcpy(at,"t"); 

ce code alloue de la mémoire pour trois caractères et crée une référence à cette partie de la mémoire (ligne 1), puis copie certaines données dans la mémoire indiquée par.

Et rappelez-vous que la mémoire allouée avec new[] doit être désallouée avec delete[] , pas delete

Je vous conseille d’en apprendre plus sur les pointeurs. Cette discussion couvre cela.