Est-ce que n'importe qui peut m'aider, pourquoi j'obtiens un message d'erreur en essayant de libérer la mémoire allouée? CTR a détecté que l'application écrivait la mémoire après la fin de la mémoire tampon.
char *ff (char *s){
char *s1 = new char [strlen(s)];
strcpy(s1, s);
return s1;
}
int _tmain(int argc, _TCHAR* argv[])
{
char *s = new char [5];
strcpy(s, "hello");
char *s2 = ff(s);
delete []s; // This works normal
delete []s2; // But I get an error on that line
return 0;
}
char *s = new char [5];
strcpy(s, "hello");
Provoque comportement indéfini (UB).
Vous écrivez au-delà des limites de la mémoire allouée. Vous avez alloué suffisamment de mémoire pour les caractères 5
, mais votre chaîne comporte des caractères 6
, y compris le \0
.
Une fois que votre programme a provoqué cet UB, tous les paris sont ouverts et tout comportement est possible.
Vous avez besoin:
char *s = new char [strlen("hello") + 1];
En fait, la la solution idéale consiste à utiliser std::string
et non char *
. Ce sont précisément les erreurs que std::string
évite. Et il n’est pas vraiment nécessaire d’utiliser char *
au lieu de std::string
dans votre exemple.
Avec std::string
:
new
quoi que ce soitdelete
quoi que ce soit &std::string
, que vous faites avec char *
.new char [strlen(s)];
ne compte pas le caractère \0
de fermeture, votre mémoire tampon est donc trop courte d'un caractère.
strcpy
inclut le terminateur nul; strlen
ne le fait pas. Écrire:
char *s1 = new char [strlen(s) + 1];
De l'homme strcpy (3) :
La fonction strcpy () copie la chaîne pointée par src, y compris l'octet nul final ('\ 0'), vers le tampon pointé vers par dest.
Donc vous devez réserver 6
octets 5
pour la chaîne et 1
pour l'octet NULL
char *s = new char [6];
strcpy(s, "hello");
Jusqu'à présent, toutes les réponses ont porté sur la première ou la deuxième attribution. En résumé, il y a deux modifications à effectuer:
char *s1 = new char [strlen(s) + 1];
...
char *s = new char [5 + 1];
Dans les deux cas, vous devez allouer suffisamment d'espace pour la chaîne plus un octet pour le '\ 0' final.
Comme d'autres l'ont déjà souligné, avec c ++, il est plus facile et plus sûr d'utiliser std::string
. Pas de problème avec l'allocation et la libération de mémoire ou en prêtant attention aux octets '\ 0':
std::string ff (const std::string &s){
std::string s1(s);
// do something else with s1
return s1;
}
int main(int argc, char* argv[])
{
std::string s("hello");
std::string s2 = ff(s);
return 0;
}
et s'il ne s'agit que de copier la chaîne:
std::string s("hello");
std::string s2(s);
Vous devez spécifier char *s1 = new char [strlen(s) + 1];
pour libérer de l'espace pour le '\0'
qui termine la chaîne.
Votre chaîne initiale s
ne contient que cinq caractères et ne peut donc pas être terminée par un zéro. "hello"
sera copié par strcpy
, y compris le terminateur nul, mais vous aurez dépassé le tampon. La strlen
a besoin d'être terminée par un null, donc si le null n'y est pas, vous aurez des problèmes. Essayez de changer cette ligne:
char * s = new char [6];
Mieux encore, préférez les fonctions chaîne de style std::string
à C - elles sont tout aussi efficaces, beaucoup plus sûres et plus faciles à utiliser. Aussi, essayez d'éviter new
et delete
à moins que vous ne deviez vraiment les utiliser. Les problèmes que vous rencontrez sont très courants et peuvent facilement être évités.
Vous avez corrompu le pointeur s2 par
strcpy(s, "hello");
Parce que s a la taille 5, bien que vous ayez oublié cette stratégie, elle inclut un terminateur de chaîne.