Posez votre question Signaler

C++lire un fichier string dans un tableau ... [Résolu]

philipal - Dernière réponse le 16 avril 2009 à 18:59
slt a tous,
Voila mon probleme j'ai un travail a rendre en c++. c'est un travail assez consequant dans lequel il faut gérer plusieurs classes avec des menus et sous menus. J'ai créé une classe "salles" qui me permet d'ajouter les nom de salles dans un fichier string. je voudrai maitenant pouvoir supprimer une ligne de se fichier. Ligne que l'utilisateur aurait lui meme taper en réponse a la question "quel ligne voulez-vous effacée?"
Le prof m'a dit que la meilleur solution qd on gere des string est de: 1. lire le fichier ligne par ligne, 2. taper le tt dans un tableau de string ( dynamique de préférence), 3. effacer la ligne désirée et enfin réécrire le contenu du tableau dans le fichier.
je cherche sur le net depui 15 jours pour trouver des codes qui pourrai m'aider ou des sites reprenant les fonctions membre de la libréries string. Rien, enfin si mais ses sites ne sont pas complets ou trop complex et les mec dans les forum disent quoi faire mais pas une trace de code a titre d'exemple. Y a aussi que je suis un débutant et donc si on me montre le prototype d'une fonction je sais pas l'écrire sans faute il me faut absolument du code bien claire avec commentaire pour que je puisse comprendre.
Enfin voici ma fonction "supprimer" faisant partie de la classe "salles" ce que je veux faire est assez explicite je crois avec les commentaire:
void salles::suppr(string nom,string batiment,string ligne,int b)
{
fstream fichier("salles.txt", ios::out | ios::in | ios::ate); // On ouvre le ficher en lecture-écriture
if(fichier) // si l'ouverture a réussie
{
string nom;
string batiment;
string ligne;
// il fo initialiser un tablau dynamique de string (je sais pas comment on fait)
int b;
b=0;
while(getline(fichier, ligne)) // tant que l'on peut mettre une ligne du fichier dans "ligne"
{
//on la charge dans un tableau
}
cout << "Veuillez entrer la ligne a effacer:" << "\n" << endl;
cin >> b ; // l'utilisateur saisi un numéro de ligne qu'il veut éffacer
// fonction membre string pour éffacer la ligne saisie
// on réécri le reste du tableau dans le fichier
fichier.close();
}
else // sinon
{
cerr << "Erreur à l'ouverture !" << endl;
}
}
s'il vous plait aider moi je ne sais plus coi faire, je suis completement démoralisé
Lire la suite 
Réponse
+0
moins plus
Salut.
Déjà tu as de la chance, tu as le droit à la STL.
Partant de là, tu peux utiliser les différents conteneurs. vector ou list.
http://www.cppreference.com/wiki/stl/start
Les fonctions pour effacer sont assez chiante à utiliser, mais moins que si tu doit le faire toi même.
tu déclare une liste de string :
#include <list>
list<string> liste_str;
//tu rempli avec chaque ligne de ton fichier
getline(fichier,line);
liste_str.push_back(line);//tu met ta ligne à la fin de ta liste
Ensuite, tu supprime là, c'est plus complexe, il faut lire la doc:
liste_str.erase(liste_str.bgin()+nb_ligne_suppr);
philipal- 14 avril 2009 à 10:32
slt

meci bcp, entre tps on m'a filer une austre solution
je l'essay j'utiliserai la tienne (en tentinet plus compliquer) en dernier recours

si jamais g des question je reviendrais ici



encore merci




a+
Répondre
Ajouter un commentaire
Réponse
+0
moins plus
ça aurait été sympa de donner la solution qu'on t'avais donner. Je suis toujours à la recherche d'une solution plus simple pour supprimer un élément d'une liste.
philipal- 14 avril 2009 à 12:08
slt je vien de l'essayer elle marche pas

m'ennerve

v essayer la tienne
Répondre
Ajouter un commentaire
Réponse
+0
moins plus
Donne toujours l'astuce qu'on t'a donnée, peut être que ça me donnera d'autres idées.
philipal- 14 avril 2009 à 14:45
slt

voici la solution que l'on ma donné je t'ai mis les erreur que le compilateur mettait ds mes ligne de code avec les "<---------"

void salles::suppr(string ligne,string tab)
{
ifstream myfileopen("salles.txt", ios::in); // on ouvre en lecture

if(myfileopen)
{
string ligne;
string tab[100];
while(getline(myfileopen, ligne)) // tant que l'on peut mettre la ligne dans "ligne"
{
for(int i=0;i<=99;i++)
{
tab[i]=ligne;//on écrit les lignes dans le tableau de string
}
}
myfileopen.close();
}
else // sinon
{
cerr << "Erreur à l'ouverture !" << endl;
}

for(int i=0;i<=99;i++)// on affiche le tableau pour contrôler <-----------------------error: using obsolete binding at 'i'
{
cout << tab[i] << endl;
}
cout << "Veuillez indiquer la ligne que vous voulez effacer:" << "\n" << endl;
cin >> i;//<--------------------------------------------------------------------------error: name lookup of 'i' changed for new iso 'for' scoping
ligne.erase(tab[i]);

fstream myfilesave("salles.txt", ios::in | ios::out | ios::ate);// on ouvre en lecture écriture

if(myfilesave)
{
while(getline(myfilesave, ligne))
{
for(int i=0;i<=99;i++)
{
myfilesave << tab[i] << endl;//on ecrase le contenu du fichier avec celui du tablau
}
}
myfilesave.close();
}
else
{
cerr << "Erreur à l'ouverture !" << endl;
}
Répondre
Ajouter un commentaire
Réponse
+0
moins plus
Ok, je comprends mieux. La méthode ne peux pas fonctionné, car erase ne s'utilise pas comme ça.
void salles::suppr(string ligne,string tab)
{
ifstream myfileopen("salles.txt", ios::in); // on ouvre en lecture
int i;// il faut déclarer une variable i pour l'utiliser plus tard.
list<string> l_str;

if(myfileopen)
{
 string ligne;
 string tab[100];
 i=0;
 while(getline(myfileopen, ligne)) // tant que l'on peut mettre la ligne dans "ligne"
 {
     tab[i++]=ligne;
     l_str.push_back(ligne);
 }
 myfileopen.close();
}
else // sinon
{
   cerr << "Erreur à l'ouverture !" << endl;
   return ;
}

for(int i=0;i<100;i++)// on affiche le tableau pour contrôler 
{
cout << tab[i] << endl;
}
cout << "Veuillez indiquer la ligne que vous voulez effacer:" << "\n" << endl;
cin >> i;
l_str.remove(tab[i]);

fstream myfilesave("salles.txt", ios::in | ios::out | ios::ate);// on ouvre en lecture écriture

if(myfilesave)
{

 for(list<string>::iterator it=l_str.begin();it!=l_str.end();it++)
  {
  myfilesave <<*it << endl;//on ecrase le contenu du fichier avec celui du tablau
  }
 myfilesave.close();
}
else
{
cerr << "Erreur à l'ouverture !" << endl;
}
L'inconvénient c'est que si tu as plus de 100 lignes dans ton fichier, ça plante !
philipal- 14 avril 2009 à 16:57
salutation,

merci de m'avoir corriger.

je vais faire un malloc pour allouer un tableau de string dynamiquement; c pas tres optimiser mais je connais que ca g fait un peu de c avant.
Répondre
philipal- 14 avril 2009 à 18:45
slt

il y a encore une erreur dans ma fonction a la ligne:"l_str.remove(tab[i] );"

g fais des reccherche dans la doc que tu ma mise plus haut et g modifier la ligne comme suis:

l_str.remove( const string &tab[i] );

mais il me dit:

error: expected primary-expression before "const"

franchement je sais pas ce qu'il manque
Répondre
Ajouter un commentaire
Réponse
+0
moins plus
Il te mets quoi comme erreur ?
Ce que tu mets n'est pas satisfaisant.
Pour un tableau dynamique, en C++, mieux vaut utiliser new :
string *tab;
tab=new string [N];
quelle erreur est retourné par "l_str.remove(tab[i] );" ? Car j ne vois pas ce qui cloche.
philipal- 15 avril 2009 à 10:50
slt

il mais ceci

error: invalid conversion from `char' to `const char*'

error: initializing argument 1 of `std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]'|
Répondre
Ajouter un commentaire
Réponse
+0
moins plus
Je ne comprends pas pourquoi il te parle de char !
string est bien le type std::string inclu grace à #include <string> ?
normalement, tab[i] est de type string et non char, en plus, si tu fait list<string>, il devrait attendre un string et non un const char*
philipal- 15 avril 2009 à 12:06
franchement je pige pas non plus (ca c pas une nouvelle lol)

qd je vais voir dans la doc sur les list il mettent ça:
#include <list>
void remove( const TYPE &val );


// Create a list that has the first 10 letters of the alphabet
list<char> charList;
for( int i=0; i < 10; i++ )
charList.push_front( i + 65 );
// Remove all instances of 'E'
charList.remove( 'E' );

est ce que ca ve dire que je doit mettre : remove(const string &tab[i])?
si c le cas ben il dit qu'il manque un truck avant le const("error: expected primary expression befor const")
Répondre
Ajouter un commentaire
Réponse
+0
moins plus
montre ce que tu as taper exactement.
TU ne doit pas mettre "remove(const string &tab[i])" , si tu as fait comme j'ai écris, il n'y a rien à mettre devant tab.
Ou alors, j'ai fait une erreur.
Ajouter un commentaire
Réponse
+0
moins plus
je pense avoir compris.
Ta fonction a comme argument "string tab", et ensuite, on redéfini une variable tableau du nom de tab -> conflit.
En plus, il faut sortir "string tab[100]" de la porté du if, sinon il risque d'y avoir des soucis aussi.
Ajouter un commentaire
Réponse
+0
moins plus
Il y a beaucoup plus simple.

1) Au niveau de l'ouverture du fichier déjà :

a) pour ouvrir un fichier en lecture :
#include <fstream>
#include <iostream>

int main(){
  const char *filename = "plop.txt";
  std::ifstream ifs(filename);
  if(!ifs){
    std::cerr << "can't read " << filename << std::endl;
    return 1;
  }

  // ...

  ifs.close();

  // ...

  return 0;
}

b) Pour ouvrir un fichier en écriture, même chose avec un std::ofstream

2) Pour stocker ton fichier, il suffit d'utiliser une std::vector<std::string> ou éventuellement une std::map<unsigned,std::string> qui associe à chaque numéro de ligne le contenu de la ligne. Lorsque tu lis ton fichier ligne par ligne il suffit juste d'utiliser la méthode push_back si tu utilises un vector et directement l'opérateur [] si tu utilises une map.
std::vector<std::string> v;
std::string line;
while(std::getline(ifs, line)){
  v.push_back(line);
}

A présent v[i] contient bien la ligne i (ou 0 désigne la première ligne du fichier). Pour supprimer une ligne il suffit donc d'écrire pour j allant de i+1 à v.size()-1 la case [j+1] dans la case j et de redimensionner le std::vector avec la méthode resize :
void remove_line(std::vector<std::string> & v,std::size_t no_line){
  std::size_t n = v.size();
  for(std::size_t j=no_line+1;j<n;++j) v[j] = v[j+1];
  v.resize(n-1);
}

Pour écrire ton fichier il ne reste plus qu'à ouvrir un std::ofstream et écrire le contenu du vector dedans :
int main(){

  //...

  // Ouvrir le fichier en écriture
  const char *filename_out = "plop2.txt";
  std::ofstream ofs(filename_out);
  if(!ofs){
    std::cerr << "can't write " << filename_out << std::endl;
    return 2;
  }

  // Écrire le fichier
  {
    std::size_t n = v.size();
    for(std::size_t i=0;i<n;++i) ofs << v[i] << std::endl;
  }

  return 0;
}

Bonne chance
philipal- 15 avril 2009 à 13:21
slt

merci de ttetes indication je vais essayer de faire tt ca

voici ma fonction telle que je l'ai maitenant:

void salles::suppr(string ligne,string tab,int i,int b,int N)
{
ifstream myfileopen("salles.txt", ios::in); // on ouvre en lecture
list<string> l_str;

if(myfileopen)
{
string ligne;
string* tab=new string[N];
int i;
int b;
i=0;
while(getline(myfileopen, ligne)) // tant que l'on peut mettre la ligne dans "ligne"
{
tab[i++]=ligne;
l_str.push_back(ligne);
}
myfileopen.close();
}
else // sinon
{
cerr << "Erreur à l'ouverture !" << endl;
return ;
}

for(int i=0;i<N;i++)// on affiche le tableau pour contrôler
{
cout << tab[i] << endl;
}
cout << "Veuillez indiquer la ligne que vous voulez effacer:" << "\n" << endl;
cin >> b;
l_str.remove(const string &'tab[b]');

fstream myfilesave("salles.txt", ios::in | ios::out | ios::ate);// on ouvre en lecture écriture

if(myfilesave)
{
for(list<string>::iterator it=l_str.begin();it!=l_str.end();it++)
{
myfilesave <<*it << endl;//on ecrase le contenu du fichier avec celui du tablau
}
myfilesave.close();
}
else
{
cerr << "Erreur à l'ouverture !" << endl;
}
}
Répondre
Ajouter un commentaire
Réponse
+0
moins plus
Si tu ne suis pas mes indications ça ne peut pas marcher. Ouvre le fait que tu continues à trimballer des flags pour ouvrir tes fichiers (ce qui ne sert à rien si tu fais comme je t'ai indiqué), la structure de liste ne convient pas car les lignes ne sont pas indexées. Du coup pour supprimer le ième maillon tu es obligé de parcourir la liste (soit i itérations pour trouver le maillon) au lieu d'y accéder immédiatement comme avec un vector.

A la limite pourquoi pas, c'est moins pas forcément plus coûteux que de décaler les cases d'un vecteur. Cependant, il faut alors que chaque maillon de la liste soit un std::pair<unsigned,std::string>, c'est-à-dire un couple (numéro de ligne, contenu de la ligne) qu'il faudra réindexer à chaque suppression de ligne.

Si tu ne connais pas les iterators lis au préalable :
http://www.commentcamarche.net/faq/sujet 11255 introduction a la stl en c standard template library#les iterators

Ainsi, la liste en question se construit comme suit :
std::list<std::pair<unsigned,std::string> > l;
std::string line;
for(unsigned no_line = 0;std::getline(ifs, line);++no_line){
  l.push_back(std::make_pair(no_line,line));
}

... et la suppression :
void remove_line(std::list<std::pair<unsigned,std::string> > & l,std::size_t no_line){
  unsigned j;
  std::list<std::pair<unsigned,std::string> >::iterator
    lerase(l.begin()),
    lit   (l.begin()),
    lend  (l.end());
  for(std::size_t j=0;lit!=lend;++j,++lit){
    if(j == no_line){
      lerase = lit;
    }else if(j > no_line){
      --(lit->first); // on décrémente l'index des maillons situé après
    }
  }
  l.erase(lerase);
}

Le principal intérêt de la std::list est que tu pourras traiter de très gros fichiers car ta structure ne sera pas allouée sur une plage mémoire continue.

Je passe sur les "mauvaises" habitudes qui consiste à omettre le std:: via un using namespace std; ou l'utilisation de headers antiques de la STL (genre <list.h> au lieu de <list>). En fait le seul cas où tu peux utiliser un using namespace std; "proprement" est dans un fichier .cpp. En tout cas, il ne faut jamais le faire dans un header (.hpp).

Le principal défaut de ton ton programme est qu'il utilise un tableau alloué statiquement avec N cases, or le jour ou ce N est inférieur au nombre de ligne du fichier, ça ne marche plus. Si au contraire tu utilises des push_back, tu peux t'affranchir.

Bonne chance
philipal- 15 avril 2009 à 13:56
je vais faire avec un vector c plus simple il me semble meme si c est compliquer lol

je te montre ce que g fait des que g fini
Répondre
Ajouter un commentaire
Réponse
+0
moins plus
Comme tu préfères mais là c'est déjà presque cuit avec le code que je t'ai donné. Merci de soigner l'orthographe dans tes messages.

Bonne chance
Ajouter un commentaire
Réponse
+0
moins plus
J'avais bien pensé à vector, mais il y a le problème de suppression qui n'est pas évident.
L'idéale serait d'avoir un conteneur vector où l'on puisse faire v.erase(i).
Le problème de list c'est qu'on n'y accède pas facilement avec un index.Bref, rien de parfait.
L'idéal serait un QStringList
Ajouter un commentaire
Réponse
+0
moins plus
voila le code que j'ai réussi à faire selon tes indications

1. dois-je rajouter quelque choses dans l'entête de ma fonction "suppr"? je parle de ce qu'il y a entre ( )

2. puis-je supprimer les "std::" qu'il y a un peu partout sachant qu'au début de mon programme j'ai écris:
"using namespace std" ?

3. je ne comprend pas bien quand il s'agit de supprimer une ligne. Après que j'ai poser la question à l'utilisateur:"quelle ligne voulez-cous supprimer" juste en-dessous je met un "cin >>...." . quelle variable dois-je mettre pour qu'il prenne en compte le numéro de la ligne à supprimer?

void salles::suppr(string line)
{
//lecture du fichier et mise des lignes dans le vecteur
const char *filename = "salles.txt";
ifstream ifs(filename);
if(!ifs)
{
std::cerr << "can't read " << filename << std::endl;
return 1;
}
else // sinon
{
std::vector<std::string> v;
std::string line;
while(std::getline(ifs, line))
{
v.push_back(line);
}
ifs.close();
}

//suppression d'une ligne au choix de l'utilisateur
cout << "Veuillez indiquer la ligne que vous voulez effacer:" << "\n" << endl;
cin >> //je sais pas ce que je dois mettre comme variable;
void remove_line(std::vector<std::string> & v,std::size_t no_line)
{
std::size_t n = v.size();
for(std::size_t j=no_line+1;j<n;++j) v[j] = v[j+1];
v.resize(n-1);
}

//ecriture du vecteur dans le fichier
const char *filename_out = "salles.txt";
std::ofstream ofs(filename_out);
if(!ofs)
{
std::cerr << "can't write " << filename_out << std::endl;
return 2;
}
else
{
std::size_t n = v.size();
for(std::size_t i=0;i<n;++i) ofs << v[i] << std::endl;
}
}

désolé pour les fautes plus haut.
n'hésite pas à me communiquer les erreurs de mon code

merci
Ajouter un commentaire
Réponse
+0
moins plus
mais il y a le problème de suppression qui n'est pas évident.

Cher char sniper... si c'est simple et voici comment faire :
http://www.commentcamarche.net/forum/affich 11989094 c lire un fichier string dans un tableau?#17

Pas besoin de QT pour un programme aussi simple pourquoi pas une bombe nucléaire ;-) Avec le recul la meilleure solution c'est les listes comme j'ai indiqué dans mon message précédent, mais si le fichier est de taille raisonnable, on s'embête pas et on peut directement faire un vector.
Char Snipeur 9188Messages postés vendredi 23 avril 2004Date d'inscription ContributeurStatut 3 juillet 2015 Dernière intervention - 15 avril 2009 à 15:11
C'est bien ce que je dit, c'est pas évident : il faut créer sa propre fonction. C'est plus lourd qu'un simple v.erase(i);
Mais si j'avais eu à résoudre le problème, je pense que je serait passé par les vector.
Ou par QT, car je suis en plein dedans en ce moment (une fois partis à faire du QT pour interfaces graphiques, autant l'utiliser, même si c'est lourd)
Répondre
Ajouter un commentaire
Réponse
+0
moins plus
je viens de compiler

voici mon code avec les erreurs marquées avec les "<--------------------"

pour la 2e erreurs v est il un entier ou un string? ou autre chose?

la 1ere erreur je sais pas du tout de quoi il s'agit.

void salles::suppr(string line,int j)
{
//lecture du fichier et mise des lignes dans le vecteur
const char *filename = "salles.txt";
ifstream ifs(filename);
if(!ifs)
{
std::cerr << "can't read " << filename << std::endl;
return;
}
else // sinon
{
std::vector<std::string> v;
std::string line;
while(std::getline(ifs, line))
{
v.push_back(line);
}
ifs.close();
}

//suppression d'une ligne au choix de l'utilisateur
cout << "Veuillez indiquer la ligne que vous voulez effacer:" << "\n" << endl;
cin >> j; // est ce la bonne variable?
void remove_line(std::vector<std::string> & v,std::size_t no_line)
{//<-----------------------------------------------------------------------------error: a fonction-definition is not allowed here before '{' token
std::size_t n = v.size();
for(std::size_t j=no_line+1;j<n;++j) v[j] = v[j+1];
v.resize(n-1);
}

//ecriture du vecteur dans le fichier
const char *filename_out = "salles.txt";
std::ofstream ofs(filename_out);
if(!ofs)
{
std::cerr << "can't write " << filename_out << std::endl;
return;
}
else
{
std::size_t n = v.size();//<-------------------------------------------------error: 'v' was not declared in this scope
for(std::size_t i=0;i<n;++i) ofs << v[i] << std::endl;
}
}
Ajouter un commentaire
Réponse
+0
moins plus
Ton code n'est pa très compréhensble, utilise les balises de code pour mettre le source.
Comme je t'ai dit : attention au problèmes de conflit et de porté, ce n'est pas du fortran, pas besoin de redéfinir les variables passées en paramètre.
tu as string line en paramètre, et plus loin tu redéfini une variable line !
écris nous un code plus propre prenant en compte toutes les remarques faites ici et ailleurs.
Ajouter un commentaire
Réponse
+0
moins plus
slt

mamiemando ma dit de suivre ces instruction si non ca marcherai pas

maitenant chui encore plus perdu qu'avan
Ajouter un commentaire
Réponse
+0
moins plus
Là tu m'énerves !
tes erreurs sont dues à ce que je te répète depuis un moment (porté).
perdu ? efface tout et recommence.
Ajouter un commentaire
Réponse
+0
moins plus
j'ai refais le code si tu savais le regarder et me dire comment supprimer avec les vector

ça serai cool je cherche de mon coter aussi

void salles::suppr(string ligne)
{
//lecture du fichier et mise des lignes dans le vecteur
ifstream fichier("salles.txt", ios::in);
if(fichier)
{
vector<string> v;
string ligne;
while(getline(fichier, ligne))
{
v.push_back(ligne);
}
fichier.close();
}
else // sinon
{
cerr << "Erreur à l'ouverture !" << endl;
}

//suppression d'une ligne au choix de l'utilisateur
cout << "Veuillez indiquer la ligne que vous voulez effacer:" << "\n" << endl;
cin >> ; //je sais pas ce que je dois mettre comme variable;
//je sais pas comment on supprime avec les vector;


//ecriture du vecteur dans le fichier
ofstream file("salles.txt", ios::out | ios::app);
if(file)
{
size_t n = v.size();
for(size_t i=0;i<n;++i) file << v[i] << std::endl;
}
else
{
cerr << "Erreur à l'ouverture !" << endl;
}
}
Ajouter un commentaire
Réponse
+0
moins plus
tt le monde appren a un moment donné

j'essay de comprendre mais c pas evident
Ajouter un commentaire
Ce document intitulé «  C++lire un fichier string dans un tableau ...  » issu de CommentCaMarche (www.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.

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.

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