Remplacer le cin.getline( )

0/5 (10 avis)

Snippet vu 12 262 fois - Téléchargée 31 fois

Contenu du snippet

Après avoir eu des erreurs de bizarre de comportement avec cin.getline() voici un bout de code :

Source / Exemple :


////////////////////////////////////////////////////////////
//
// LireLigne permet de lire une ligne complète sans poser
// problème comme le GetLine()
//
////////////////////////////////////////////////////////////
string LireLigne()
{
	string sLue;
	char cLu;

	// pour vider le buffer avant de procéder
	// à la lecture
	if (cin.peek() == LF)
		while (cin.get() != LF);

	// lecture de la ligne
	cLu = cin.get();
	while (cLu != LF)
	{
		sLue = sLue + cLu;
		cLu = cin.get();
	}
	return sLue;
}

A voir également

Ajouter un commentaire

Commentaires

victorcoasne
Messages postés
1100
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
17 octobre 2012
3 -
Vecchio56 > J'ai la même solution que toi mais certains sont restés fidèle au NOIR ET BLANC (à croire que la couleur n'a pas été inventé). Mais on peut colorer le texte me direz-vous, donc je peux être plus clair et vous dire que si on fait maintenant des environnement 64bits c'est pas pour retourner sous (Console) DOS !
BruNews
Messages postés
21042
Date d'inscription
jeudi 23 janvier 2003
Statut
Modérateur
Dernière intervention
21 août 2019
13 -
C'est concis et plein de bon sens, surtout que la console pour trouver des clients...
vecchio56
Messages postés
6539
Date d'inscription
lundi 16 décembre 2002
Statut
Modérateur
Dernière intervention
22 août 2010
7 -
Moi j'ai résolu tous ces problèmes en arrêtant de travailler dans la console
victorcoasne
Messages postés
1100
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
17 octobre 2012
3 -
Le string est la manière C d'être fénéant !

Ce qui est encore plus fénéant c'est de donner un code qui n'est pas de soi.

Perso, jamais eu de problème avec getline (sauf si je met un cin.getline puis un cin forcement mais tout se résouds en ajoutant un deuxième getline qui sert à rien sauf à éviter le plantage du cin suivant).

Bonne prog,
@++
cs_lacousine
Messages postés
58
Date d'inscription
mardi 6 janvier 2004
Statut
Membre
Dernière intervention
13 juillet 2007
-
Premièrement : http://support.microsoft.com/default.aspx?scid=kb;EN-US;q240015

Deuxièmement : je ne peux rien dire sur le fait que la réallocation de mémoire. Mais voici une explication détaillée : (qui n'est pas de moi) Et que j'aurais du utiliser peut-être...


-----------------------------------------------------------------------

Le langage C++ offre une variété d'outils d'entrée/ sortie sur des flux de données, et utilise les classes std::istream et std::ostream comme abstractions fondamentales pour représenter (respectivement) les flux en entrée et les flux en sortie. Appliquant héritage et polymorphisme, ceci permet de gérer sur un même pied les entrées/ sorties à la console (avec, en particulier, std::cin, une instance de std::istream liée à l'entrée standard?typiquement le clavier?et std::cout, une instance de std::ostream liée à la sortie standard?typiquement l'écran en mode console), sur un lien de communication, sur un fichier ou sur tout conteneur respectueux de certaines règles de base.

ex :
#include <string>
#include <fstream>
#include
// lit chaque mot d'un fichier texte et les affiche
// à la sortie standard, séparés par des tabulations
int main ()
{
std::string Mot;
std::ifstream fichierEntree ("in.txt");
while (fichierEntree >> Mot)
std::cout << Mot << '\t';
}


Pour l'entrée de chaînes de caractères, on aura tendance à utiliser l'opérateur >> tel que défini sur un opérande de gauche de type std::istream& et sur un opérande de droite de type std::string&, profitant ainsi de la grande souplesse du type std::string, dont les instances ont une capacité d'entreposage capable de croître en fonction des besoins (ce qui élimine les problèmes de dépassement de capacité des zones tampons, aussi nommées Buffer Overflow Problems).

L'opérateur >> sur un flux en entrée et une std::string a pour comportement de lire sur le flux jusqu'à la rencontre du premier caractère d'espacement.

Si on désire lire une ligne à la fois, par exemple dans un cas où les espaces sont significatifs, alors ce n'est pas le meilleur outil.

Dans ces circonstances, on a habituellement recours à std::getline().

Il se trouve que std::getline() est une fonction très efficace qui prend en paramètre un std::istream& et un std::string& et qui lit des caractères du flux jusqu'à un délimiteur de fin de chaîne (on peut décider soi-même de lire jusqu'à un caractère particulier qui soit différent de '\n' en insérant le délimiteur désiré comme troisième paramètre de la fonction).

Il est très fréquent que des étudiants manipulant ces deux outils rencontrent des problèmes à l'usage de std::getline(). En effet, dans un programme comme celui-ci, la lecture de la chaîne s va être escamotée.

On peut comprendre ce qui se passe en allant tracer le code de std::getline(), qui est un template exposé dans le fichier d'en-tête <string>, mais voici en gros ce qui se passe :

- lorsqu'on lit le premier entier (Val), l'entier en soi est lu, mais std::cin garde dans son tampon interne le caractère de nouvelle ligne ('\n') ayant servi à compléter l'entrée de données, parce que ce caractère ne fait pas partie de l'entier lu et parce qu'il pourrait être utile lors de la prochaine lecture (std::cin ne sait pas que nous, le '\n', on n'en veut pas);

- par défaut (et c'est ce qu'on veut), std::getline() lit ce qui apparaît dans le tampon du flux en entrée reçu en paramètre (ici: std::cin) jusqu'à ce qu'apparaisse un premier '\n'. Dans notre cas, s'il traîne un tel caractère dans le tampon, c'est moche;

- le truc élégant est de vérifier au besoin s'il y a, au début du tampon du flux en entrée utilisé pour std::getline() (donc au début du tampon de std::cin), un changement de ligne ('\n') ou un retour de chariot ('\r') qui traîne dans le cas où on sait qu'il est possible qu'on ait laissé traîner un tel caractère, et de l'enlever du flux s'il y a lieu.

Je vous propose donc la version ci-dessous, qui (elle) fonctionne bien:

#include <string>
#include
int main ()
{
std::cout << "Entrez un entier...";
int Val;
std::cin >> Val;
std::cout << "Entrez une ligne de texte...";
std::string s;
char c = std::cin.peek ();
if (c '\n' || c '\r')
std::cin.get (c);
// lire une ligne avec std::cin, la mettre dans s
std::getline (std::cin, s);
std::cout << s << std::endl;
}


L'appel à std::cin.peek() retourne le premier caractère au début du flux en entrée. S'il s'agit d'une fin de ligne, alors on le retire du flux. Il est important de vérifier la présence ou non d'un tel caractère, d'ailleurs, car deux cas sont possibles:

- soit l'usager entre un entier, puis presse <return>, puis entre du texte. Dans ce cas, la lecture de l'entier se terminera au caractère de nouvelle ligne, et ce caractère sera encore au début dans le tampon du flux en entrée juste avant l'appel à std::getline(). Dans un tel cas, retirer le caractère de flux sera important;

- soit l'usager entre un entier puis peut-être un espace puis du texte, puis appuie sur <return>. Dans ce cas, le caractère retourné par l'appel à std::cin.peek() sera le premier caractère suivant l'entier dans le tampon du flux, et ce caractère ne sera manifestement pas un changement de ligne, et risque d'être significatif. Dans un tel cas, il faut laisser ce caractère dans le flux pour que std::getline() en prenne possesion.

Et pour les curieux, voici la fonction getline :

template<class _Elem,
class _Traits,
class _Alloc> inline
basic_istream<_Elem, _Traits>& __cdecl getline(
basic_istream<_Elem, _Traits>& _Istr,
basic_string<_Elem, _Traits, _Alloc>& _Str,
const _Elem _Delim)
{ // get characters into string, discard delimiter
typedef basic_istream<_Elem, _Traits> _Myis;
ios_base::iostate _State = ios_base::goodbit;
bool _Changed = false;
const typename _Myis::sentry _Ok(_Istr, true);

if (_Ok)
{ // state okay, extract characters
_TRY_IO_BEGIN
_Str.erase();
const typename _Traits::int_type _Metadelim =
_Traits::to_int_type(_Delim);
typename _Traits::int_type _Meta = _Istr.rdbuf()->sgetc();

for (; ; _Meta = _Istr.rdbuf()->snextc())
if (_Traits::eq_int_type(_Traits::eof(), _Meta))
{ // end of file, quit
_State |= ios_base::eofbit;
break;
}
else if (_Traits::eq_int_type(_Meta, _Metadelim))
{ // got a delimiter, discard it and quit
_Changed = true;
_Istr.rdbuf()->sbumpc();
break;
}
else if (_Str.max_size() <= _Str.size())
{ // string too large, quit
_State |= ios_base::failbit;
break;
}
else
{ // got a character, add it to string
_Str += _Traits::to_char_type(_Meta);
_Changed = true;
}
_CATCH_IO_(_Istr)
}

if (!_Changed)
_State |= ios_base::failbit;
_Istr.setstate(_State);
return (_Istr);
}

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.