2013-05-27 126 views
1

读取多种类型文件我有一个看起来像这样的文件:C++在同一条线上

Mike 1200 
John 350 
Jen 1500 
Tara 700 
Michelle 2000 
Kevin 500 
Matt 450 
Kim 200  

我的代码来存储内容:

#include <iostream> 
#include <string> 
#include <fstream> 
#include <iomanip> 
using namespace std; 

const int MAX = 15; 

int main() { 

// declare variables 
string names[MAX]; 
string tempscore; 
float scores[MAX]; 
fstream infile; 

infile.open("winners.txt", ios::in); 

int cc = 0; 

getline(infile, names[cc], ' '); 

infile.ignore(0, ' '); 

infile >> tempscore; 
infile.ignore(1, '\n'); 

scores[cc] = strtof(tempscore.c_str(), NULL); 

    cout << "'" << names[cc] << "'" << endl; 
    cout << "'" << scores[cc] << "'" << endl; 

int i = 1; 

while (infile) { 

    getline(infile, names[i], ' '); 

    infile.ignore(0, ' '); 

    infile >> tempscore; 
    infile.ignore(1, '\n'); 

    scores[cc] = strtof(tempscore.c_str(), NULL); 


    cout << "'" << names[i] << "'" << endl; 
    cout << "'" << scores[i] << "'" << endl; 
    i++; 
} 
infile.close(); 

return 0; 
} 

大部分的名称都存储正确但没有一个分数是。为什么?我究竟做错了什么?

这是做我想达到的最好方法吗?

回答

3

。在你的代码中的错字。 scores[cc] = strtof(tempscore.c_str(), NULL);应在while循环中为scores[i] = strtof(tempscore.c_str(), NULL);

一些旁注:

  1. 没有必要处理指数0分别
  2. 您应该检查数组边界在while循环。如果可能,考虑使用vector
  3. 由于stefaanv已在下面的the comment中指出,您并未检查返回值getline。如果你想让你的代码保持原样而不使用stringstream考虑改变while条件为while(i < MAX && getline(infile, names[i], ' '))(和ofc,摆脱随后的getline调用请注意,i < MAX检查是在getline之前是重要的,否则有可能是分段故障为names[i]。如果您正在使用C++11getline
  4. 使用,可以考虑使用stof代替strtof,因为它直接作用于string,也没有必要让C-STR它

希望这帮助!

+0

好吧,所以我读了所有的答复, m不熟悉stringstream方法,重新格式化我的文件不是我的选择。因此,我使用了我最熟悉的方法。 我编辑我的代码,它似乎工作,除了现在我在我的名字[]'数组中获得一个额外的(空白)名称和文件(200)最后的分数也被追加两次。一次用于“Kim”,另一个用于空白名称。 任何想法,为什么这是这样吗? –

+0

@EliNahon:你不检查getline(infile,names [i],'');'是否成功。最后一次失败,但你继续。读到tempscore失败,但你继续已经在tempscore。我将举例说明如何使用stringstream方法做到这一点。 – stefaanv

+0

@EliNahon:请参阅编辑。斯特凡诺夫已经指出了问题的原因 –

2

对于基于行的文件解析,首先读取该行并将其放入一个字符串流中,然后直接从该字符串流中读出每个字段,而不将其存储在字符串中并进行转换。

int main() { 
const int MAX = 15; 

// declare variables 
std::string names[MAX]; 
float scores[MAX]; 
std::fstream infile; 

infile.open("winners.txt", std::ios::in); 

int i = 0; 
std::string line; 

while (getline(infile, line)) { 
    std::stringstream input(line); 

    input >> names[i] >> scores[i]; 
    if (input) { 
     std::cout << "'" << names[i] << "'" << std::endl; 
     std::cout << "'" << scores[i] << "'" << std::endl; 
     i++; 
     if (i >= MAX) break; // protect your array or use a vector or deque 
    } 
} 
infile.close(); 

return 0; 
} 
+0

测试。有用。 :)虽然你可能想在你的代码中添加'std ::'到某些类型,就像你已经使用过'std :: string line'一样。 –

+1

谢谢,std :: thing是因为我从问题中的代码开始。有更多的东西,我会改变...... – stefaanv

+0

你现在可以删除'示例未编译或测试的行:D –

1

如果你能够使用getline两次,做getline(infile, names[cc], ' ');getline(infile, score[cc], ' ');

或格式的文本文件是这样的:

Mike 
1200 

John 
350 

Jen 
1500 

在这种情况下,每第三行包含得分,由2开始,名称相同,但是以1开始。计数1,4,7,10等等以及2,5,8,11等,并且您知道,wh ich是名字,哪些是分数。

编辑:它不是主要问题的答案,但可能是一个很好的实现。

1

如果你有文件格式,你可以做到以下几点:

  1. 阅读线
  2. 获得第一个空格字符,你找到的位置(因为这是你的分隔符)
  3. 从该位置拆分字符串。
  4. 将前半部分存储到字符串数组中,然后将调用第二个参数 的函数atoi(secondHalf.c_str())的输出存储为您的分数数组。

如果你不使用实数,我也会将score数组改成int而不是float。

更新: 这是我试图告诉你的示例代码。我使用的矢量这里的名字和分数:

int i = 0; 
for(i=0; i<line.size(); i++) 
{ 
    if(line[i] == ' ') break; //Then we have the position of the space char 
} 
names.push_back(line.substr(0,i)); 
scores.push_back(std::string(atoi(line.substr(i)))); 
1

可以使用C函数从文件中读取格式线:

FILE *fp = NULL; 
int score = 0; 
char name[20]; 
fp = fopen("winners.txt", "r"); 
if(!fp) 
return -1; 

while(tell(fp) != EOF) { 
fscanf(fp, "%s %d", name, &score); 
printf("Name : %s, Score : %d", name, score); 
} 

不要忘记#include <cstdio>