2017-10-15 18 views
2

J'ai actuellement un problème de navigation dans un fichier txt pour que je puisse le lire dans un tableau. Le programme compile très bien, mais quand je le lance retourne dans le terminal:Le programme ne peut pas trouver de retour chariot ou de retour à la ligne. Renvoie hors de portée

terminate called after throwing an instance of 'std::out_of_range' 
    what(): basic_string::erase: __pos (which is 18446744073709551615) > this->size() (which is 14) 
Aborted (core dumped) 

Voici le code:

#include<cstdlib> 
#include<cmath> 
#include<fstream> 
#include<sstream> 
#include<iomanip> 
#include<iostream> 
#include<string> 
#include<cstring> 
#include<cassert> 
#include<ctime> 
#include<cctype> 
#include<algorithm> 
#include<locale.h> 
#include<stdio.h> 
#include<functional> 
#include<math.h> 

using namespace std; 

int main(int argc, char**argv) 
{ 
    int r=0; 
    int p=0; 
    int c=0; 
    string names[20]; 
    double scores[20][10]; 

    ifstream infile; 
    infile.open("./bowlers.txt"); 

    for(int r=1;r<=10;r++) 
    { 
     getline(infile,names[r]); 

     p=names[r].find_first_of("\n") ; 
     names[r].erase(p,2); 

     for(c=1;c<=5;c++) 
     { 
     infile>>scores[r][c]; 
     } 
     infile.ignore(100,'\n'); 
    } 
    infile.close(); 

    for(int r=1;r<=10;r++) 
    { 
     cout<<fixed<<setprecision(2)<<endl; 
     cout<<names[r]<<endl; 

    } 

    return 0; 
} 

Le fichier txt que je utilise ressemble à ceci:

charles 
123 
321 
222 
rose 
432 
515 
123 
Greg 
123 
553 
136 

Donc, voici ce que j'ai découvert dans la recherche de ce problème moi-même:

  1. Les EOL sont gérés différemment par Unix et Windows.
  2. Une partie de mon problème est que:

    p=names[r].find_first_of('\n') ; 
        names[r].erase(p,2); 
    

    est à l'origine de la question, parce que \n ne se trouve jamais elle renvoie -1, et vous ne pouvez pas .erase -1?

J'ai essayé d'utiliser tous les imaginables de \r,\n, \r\n, etc. et je reçois toujours à peu près la même sortie. J'ai également essayé de changer l'encodage du fichier .txt. La seule différence est dans (which is 14). Le nombre fluctue en fonction de la façon dont je code le fichier .txt. J'ai également ouvert le fichier .txt dans vim et :set list pour voir les caractères de nouvelle ligne. Donc je sais qu'ils sont là.

Ceci est juste le code partiel d'un projet beaucoup plus grand pour l'école, et je ne suis pas très expérimenté avec C++ encore. Est-ce que quelqu'un peut-il me montrer la bonne direction? J'ai l'impression qu'une fois que j'ai compris cette partie de mon code, je devrais pouvoir terminer le projet. REMARQUE: le fichier txt est juste un exemple, donc ne pas trop penser à la taille de mes tableaux ou aux paramètres de ma boucle for. J'ai triplé la taille de mes tableaux pour m'assurer qu'il n'y avait aucun problème avec moi essayant de lire dans une rangée qui n'existait pas.

+2

La réponse ici est la même réponse que "pourquoi l'eau est humide" et "pourquoi le ciel est bleu". Le but de 'getline()' est de lire la ligne suivante du flux d'entrée, et de l'enregistrer dans le fichier 'std :: string' * à l'exclusion de la nouvelle ligne *. Vous n'obtiendrez jamais un '\ n' dans la chaîne remplie par' std :: getline() ', *** par définition ***. C'est ainsi que 'std :: getline()' fonctionne. –

+0

Peut-être que vous êtes confus parce que vous êtes habitué à 'fgets()' en C, ce qui maintient le saut de ligne dans la chaîne. Mais C++ 'getline()' ne le fait pas. – Barmar

+0

18446744073709551615 est 2 à la puissance 64 moins 1. Il s'agit de l'entier 64 bits non signé maximum. Une façon courante d'obtenir cela est de faire passer -1 dans une variable en attendant un entier non signé de 64 bits. Les chances sont bonnes que quelque part vous essayez de regarder le début de l'un des éléments de «noms». – user4581301

Répondre

1

Vérifiez toujours le retour de la valeur des fonctions de recherche. Exemple:

size_t p = names[r].find_first_of("\n"); 
if (p != string::npos) 
    names[r].erase(p, 2); 

Si \n ne se trouve pas, la valeur de retour est string::npos (il pourrait être 0xFFFFFFFF ou 0xFFFFFFFFFFFFFFFF) qui est l'indice invalide. Tenter d'accéder à cet index entraîne une erreur. Comme noté dans les commentaires, names[r] ne contient pas \n dans ce cas. p est toujours string::npos et cette opération n'est pas requise.

for(c=1;c<=5;c++) 
{ 
infile>>scores[r][c]; 
} 

Vous avez seulement 3 entiers en dessous de chaque nom, vous devez donc compter jusqu'à 3, et non 5. Ce code devrait fonctionner:

for(int r = 1; r <= 10; r++) 
{ 
    getline(infile, names[r]); 
    for(int c = 1; c <= 3; c++) 
     infile >> scores[r][c]; 
    infile.ignore(100, '\n'); 
} 

Ou vous pouvez ajouter un contrôle d'erreur, par exemple if (!(infile >> scores[r][c])) break;

0

Je ne sais pas pourquoi vous devez détecter le retour à la ligne. Si vous êtes à la recherche pour extraire les noms et numéros, vous pouvez effectuer les opérations suivantes

string word; 
int i(0); 
while (infile >> word){ 
    if(!(i%4)){ 
     //name 
     std::cout << word << endl; 
    }else{ 
     //number 
    } 
    ++i; 
} 

Prenez avantage de connaître le format exact de votre fichier. Le fichier est déjà parfaitement et facilement manipulable. Aussi, si vous ne connaissez pas la taille de vos données. Je vous encourage à utiliser le vecteur sur un tableau de taille fixe.