2010-12-07 26 views
1

Ceci est un devoir, juste pour tout ce que vous voulez savoir.La chaîne devient indésirable après la conversion en c_str()

Je suis en train d'écrire un traducteur de vocabulaire (anglais -> allemand et vice versa) et je suis censé enregistrer tout ce que l'utilisateur fait pour le fichier. Assez simple.

Voici le code:

std::string file_name(user_name + ".reg"); 
std::ifstream file(file_name.c_str(), std::ios::binary | std::ios::ate); 
// At this point, we have already verified the file exists. This shouldn't ever throw! 
// Possible scenario: user deletes file between calls. 
assert(file.is_open()); 

// Get the length of the file and reset the seek. 
size_t length = file.tellg(); 
file.seekg(0, std::ios::beg); 

// Create and write to the buffer. 
char *buffer = new char[length]; 
file.read(buffer, length); 
file.close(); 

// Find the last comma, after which comes the current dictionary. 
std::string strBuffer = buffer; 
size_t position = strBuffer.find_last_of(',') + 1; 
curr_dict_ = strBuffer.substr(position); 

// Start the trainer; import the dictionary. 
trainer_.reset(new Trainer(curr_dict_.c_str())); 

Le problème est, apparemment, le curr_dict_ qui est censé stocker ma valeur dictionnaire. Par exemple, mon professeur a un fichier de dictionnaire nommé 10WS_PG2_P4_de_en_gefuehle.txt. L'entraîneur importe le contenu du fichier dictionnaire comme ceci:

std::string s_word_de; 
std::string s_word_en; 
std::string s_discard; 
std::string s_count; 
int i_word; 

std::ifstream in(dictionaryDescriptor); 

if(in.is_open()) 
{ 
    getline(in, s_discard); // Discard first line. 
    while(in >> i_word && 
     getline(in, s_word_de, '<') && 
     getline(in, s_discard, '>') && 
     getline(in, s_word_en, '(') && 
     getline(in, s_count, ')')) 
    { 
     dict_.push_back(NumPair(s_word_de.c_str(), s_word_en.c_str(), Utility::lexical_cast<int, std::string>(s_count))); 
    } 
} 
else 
    std::cout << dictionaryDescriptor; 

Et une seule ligne est écrit comme si

1    überglücklich <-> blissful      (0) 

Le curr_dict_ semble importer très bien, mais lors de la sortie j'obtenir ensemble tas de caractères de déchets à la fin du fichier!

J'ai même utilisé un éditeur hexadécimal pour m'assurer que mon fichier contenant le dictionnaire ne contenait pas de caractères en trop à la fin. Ce n'est pas le cas.

Le registre fichier le code supérieur est en train de lire le dictionnaire:

Christian.reg

Christian,abc123,10WS_PG2_P4_de_en_gefuehle.txt 

Qu'est-ce que je fais mal?

+2

Cette déclaration fuit: char * buffer = new char [longueur]; 'prefer' std :: vector buffer (longueur);' –

+2

Ou mieux encore, ne pas lire dans un tampon de char, [lire directement dans une chaîne] (http://stackoverflow.com/questions/116038/what-is-the-best-way-to-slurp-a-file-into-a-stdstring-in-c/116220#116220). (En bonus, cela aurait également empêché ce bug particulier ...) –

+0

@Martin: Merci, et corrigé. @Rudolph: Ça a l'air plutôt mignon. Je vais essayer d'intégrer cela. – IAE

Répondre

1

je ferais ceci:

std::string strBuffer(length, '\0'); 
myread(file, &strBuffer[read], length); // guranteed to read length bytes from file into buffer 

éviter la nécessité d'un tampon complètement intermédiaire.

+0

-1: en s'appuyant sur les composants internes de l'implémentation de std :: string Toute chaîne std :: implémentée par un stockage non contigu échouerait Voir http://stackoverflow.com/questions/760790/is-it-legal-to-write-to-stdstring –

+0

La longueur de la chaîne sera erronée après la lecture –

+0

@Zan Lynx: Je ne suis pas d'accord 1) C++ 03 exige que & str [0] renvoie un pointeur sur [stockage contigu] (http: //herbsutter.wordpress.com/2008/04/07/cringe-not-vectors-are-guaranteed-to-contiguous/# comment-483) 2) La longueur de la chaîne ne sera pas affectée par la lecture (car la chaîne conserve la longueur séparément du chaîne de caractères (c'est-à-dire qu'elle ne dépend pas de la chaîne '\ 0' terminée)). La raison en est que data() c_str() et l'opérateur [] sont faits comme ceci est de permettre (mais pas obliger) l'implémentation de fournir une version comptée de la chaîne. Alors s'il vous plaît supprimer votre erreur -1. –

3

La fonction read (comme dans la ligne file.read(buffer, length);) n'arrête pas le tampon de caractères. Vous devrez le faire manuellement (allouer un caractère de plus, et placer le nul à la position gcount après read ing).

+0

Donc, je n'ai pas encore utilisé gcount, mais d'après ce que cplusplus me dit, il retourne simplement la position du dernier caractère lu. Doux! Comment est-ce que j'utilise ceci pour lire le terminateur null à un char *? – IAE

+1

vous devrez le mettre manuellement (ie quelque chose comme 'buffer [file.gcount()] = 0'. – lijie

+1

qui est aussi pourquoi vous aurez besoin d'allouer un caractère supplémentaire (en utilisant le tampon de caractères ou le vecteur approche) – lijie