2010-01-04 8 views
3

Comment fonctionnent les expressions de chaîne en C++?const char * en C++

Tenir compte:

#include <iostream> 
using namespace std; 

int main(int argc, char *argv[]){ 

    const char *tmp="hey"; 
    delete [] tmp; 

    return 0; 
} 

Où et comment est le « bon » expression stockée et pourquoi est-il une erreur de segmentation lorsque je tente de le supprimer?

+5

Ce code est un bug. Vous ne pouvez pas supprimer un littéral. –

+1

Je pense que le questionneur comprend beaucoup, Pavel. La question demande * pourquoi *. –

Répondre

17

Où il est stocké est laissé au compilateur pour décider dans ce cas (un peu spécial). Cependant, cela ne vous importe pas vraiment - si vous n'allouez pas de mémoire avec new, il n'est pas très agréable d'essayer de le libérer avec delete. Vous ne pouvez pas delete mémoire allouée de la façon dont vous l'avez alloué.

Si vous souhaitez contrôler le désallocation de cette ressource, vous devez utiliser un std::string ou allouer un tampon en utilisant malloc().

+0

oh ... donc il n'est pas vraiment recommandé d'utiliser des pointeurs sur les données const car je suppose – Pyjong

+4

@Pyjong: Vous êtes libre d'utiliser un pointeur pour référencer les données const char, n'essayez simplement pas de supprimer la mémoire référencée par le pointeur. –

+4

@Nick, j'ajouterais aussi que si vous allouez avec 'malloc', vous devriez aussi être sûr de libérer avec' free'. –

4

Vous ne pouvez pas supprimer les ressources statiques: celles-ci sont en lecture seule.

1

Vous ne pouvez pas supprimer des données constantes. Vous n'appelez que delete[] tmp si vous avez précédemment appelé new char[stringSize].

16

Lorsque vous affectez un pointeur const char * à une chaîne constante telle que "hey" dans l'exemple, la séquence hey\0 est stockée en tant que variable statique dans le binaire lui-même. Il ne peut pas être supprimé et ne doit pas être manipulé. Selon l'architecture/le système d'exploitation, peut segfault lors de la manipulation.

Si vous deviez faire const char[] tmp = "hey" alors les données seraient stockées sur la pile, et peuvent être manipulées (mais pas supprimé, car il sera libéré une fois la pile efface: lorsque la fonction retourne).

Ne pas delete[] tout ce qui n'est pas new[] 'd.

1

Vous n'avez pas appelé new sur la chaîne. C'est une fuite de mémoire potentielle de toute façon, pour chaque new il y a un delete, de même pour malloc et free. Vous avez supprimé une référence de mémoire à un pointeur aussi simple qu'un tableau statique de caractères, au sens du mot.

Espérons que cela aide, Cordialement, Tom.

4

Qu'est-ce qui se passe est-ce.

"hey" signifie chaîne de vente « hey » en image binaire quelque part et me donner une adresse de celui-ci, qui est la valeur de l'expression (« hey »). Il a le type char *. A cette adresse, vous avez 4 octets. 'h', 'e', ​​'y', et 0 (0 est appelé terminateur nul classique (rien à voir avec le terminateur de film) Voici comment les littéraux de chaînes fonctionnent en C.

Vous pouvez transmettre ce littéral . en tant que tel: « une adresse d'une chaîne »

vous ne pouvez pas supprimer

lorsque vous construisez std :: string (« hey »), il prend cette chaîne pointée, et des copies ailleurs - en. nouvelle mémoire allouée.

10

Le "hey" est un littéral de chaîne et est stocké dans le segment de données de l'exécutable, qui est mappé dans la mémoire du processus au moment du chargement. La partie particulière où les littéraux vivent est mappée en lecture seule. Voici un extrait de l'assemblage réalisé à partir de votre code avec g++ -S:


... 
    .section .rodata 
.LC0: 
    .string "hey" 
    .text 
    .align 2 
... 

Ainsi, les données est en effet lecture seule, et tenter de le manipuler avec delete conduit à une erreur de segmentation.

0

La chaîne "hey" a son espace pré-alloué dans le cadre du programme, de sorte qu'il apparaît juste lorsque le programme démarre et disparaît à la fin du programme.

Si vous voulez voir un programme qui alloue de la mémoire, utilise, puis le supprime, puis regardez ceci:

#include <iostream> 
using namespace std; 

int main(int argc, char *argv[]){ 

    const char *hey="hey"; 
    char* tmp=new char[4]; // NB allocate 4 chars for "hey" plus a null terminator 
    strcpy(tmp,hey); // copies the string and null terminator 
    cout << tmp << endl; 
    delete [] tmp; 
    // must not use tmp now as it points to deallocated memory 
    // must not delete hey 

    return 0; 
} 

Remarquez comment je me trouvais supprimer le new « d tmp mémoire à l'aide. Je aurais pu faire ceci:

cout << tmp << endl; 
    hey = tmp; 
    delete [] hey; 

Peu importe si, à la fin, nous soulignons la new « d mémoire avec hey ou tmp, aussi longtemps que nous supprimons correctement pour éviter les fuites de mémoire.