Question

Dans le code C ++ suivant, j'ai réalisé que gcount () renvoyait un nombre plus important que je ne le voulais, car getline () consomme le caractère de fin de ligne final, mais ne le fait pas. t pas l'envoyer au flux d'entrée.

Ce que je ne comprends toujours pas, c’est la sortie du programme. Pour les entrées "Test \ n", pourquoi je reçois & "; est \ n " ;? Comment se fait-il que mon erreur affecte le premier caractère de la chaîne plutôt que d'ajouter des déchets indésirables à la fin? Et comment se fait-il que la sortie du programme soit en contradiction avec l'apparence de la chaîne dans le débogueur ("Test \ n", comme je le pensais)?

#include <fstream>
#include <vector>
#include <string>
#include <iostream>

using namespace std;

int main()
{
    const int bufferSize = 1024;
    ifstream input( "test.txt", ios::in | ios::binary );

    vector<char> vecBuffer( bufferSize );
    input.getline( &vecBuffer[0], bufferSize );
    string strResult( vecBuffer.begin(), vecBuffer.begin() + input.gcount() );
    cout << strResult << "\n";

    return 0;
}
Était-ce utile?

La solution

J'ai également dupliqué ce résultat, Windows Vista, Visual Studio 2005 SP2.

Quand je saurai ce qui se passe, je vais mettre à jour ce post.

modifier : Bon, c'est parti. Le problème (et les différents résultats que les gens obtiennent) viennent de \ r. Qu'est-ce qui se passe est que vous appelez input.getline et mettez le résultat dans vecBuffer. La fonction getline supprime le \ n, mais laisse le \ r en place.

Vous transférez ensuite le vecBuffer vers une variable chaîne, mais utilisez la fonction gcount de input, ce qui signifie que vous obtiendrez un caractère de trop, car la variable d'entrée contient toujours le \ n, et le vecBuffer n'en contient pas.

Le résultat strResult obtenu est:

-       strResult   "Test"
        [0] 84 'T'  char
        [1] 101 'e' char
        [2] 115 's' char
        [3] 116 't' char
        [4] 13 '␍'  char
        [5] 0   char

Alors, "Test" est imprimé, suivi d'un retour à la ligne (place le curseur au début de la ligne), d'un caractère nul (écrasant le T) et enfin du \ n, qui place correctement le curseur sur la nouvelle ligne.

Vous devez donc soit effacer le \ r, soit écrire une fonction qui obtient la longueur de la chaîne directement à partir de vecBuffer, en recherchant les caractères nuls.

Autres conseils

J'ai dupliqué le problème de Tommy sur un système Windows XP Pro Service Pack 2 avec le code compilé à l'aide de Visual Studio 2005 SP2 (en réalité, il est indiqué "Version 8.0.50727.879"), conçu comme un projet de console.

Si mon fichier test.txt ne contient que "Test" et un CR, le programme crache " est " (notez l’espace au début) lors de l’exécution

Si je devais me lancer à l'aventure, je dirais que cette version de l'implémentation a un bogue qui traite le caractère de nouvelle ligne de Windows comme il convient de le traiter sous Unix (comme un "aller au début de même ligne "), puis le premier caractère est effacé pour contenir une partie de la prochaine invite ou autre chose.

Mise à jour: Après avoir joué un peu avec cela, je suis convaincu que c'est ce qui se passe. Si vous regardez strResult dans le débogueur, vous verrez qu'il a copié une valeur décimale 13 à la fin. C’est CR, qui dans Windows-land est '\ n', et partout ailleurs, est "retour au début de la ligne". Si je change plutôt votre constructeur pour lire:

chaîne strResult (vecBuffer.begin (), vecBuffer.begin () + input.gcount () - 1);

... (afin que le CR ne soit pas copié), il imprime alors "Test". comme on peut s'y attendre.

Je suis à peu près sûr que le T est en train de s'écrire puis d'être écrasé. L'exécution du même programme dans une fenêtre rxvt (cygwin) produit le résultat attendu. Vous pouvez faire quelques choses. Si vous vous débarrassez de ios :: binary dans votre open, il convertira automatiquement \ r \ n en \ n et les choses fonctionneront comme vous le souhaitez.

Vous pouvez également ouvrir votre fichier texte dans l'éditeur binaire en cliquant sur la petite flèche vers le bas du bouton Ouvrir de la boîte de dialogue Ouvrir un fichier, puis en sélectionnant Ouvrir avec ... - & b. éditeur binaire. Cela vous permettra d’examiner votre fichier et de confirmer qu’il a bien \ r \ n et pas seulement \ n.

Modifier: J'ai redirigé la sortie vers un fichier qui est en train d'écrire:

Test\r\0\r\n

La raison pour laquelle vous obtenez le \ 0 est que gcount renvoie 6 (6 caractères ont été supprimés du flux) mais que le dernier délimiteur n’est pas copié dans le tampon, mais "\ 0". lorsque vous construisez la chaîne, vous lui dites en fait d'inclure le '\ 0'. std :: string n'a pas de problème avec le 0 incorporé et le sort comme demandé. Certains shells produisent apparemment un caractère vierge et écrasent le T, tandis que d'autres ne font rien et le résultat est correct, mais il est probablement toujours faux car il contient le '\ 0' intégré

cout << strResult.c_str() << "\n";

Si vous changez la dernière ligne, cela s'arrête sur le \ 0 et vous obtenez le résultat attendu.

J'ai testé votre code avec Visual Studio 2005 SP2 sous Windows XP Pro SP3 (32 bits) et tout fonctionne correctement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top