2014-12-04 103 views
0

我有一个.txt文件,它存储了学生的姓名以及他们两个最好的分数。如果学生出于某种原因,即辍学,未能通过课程,则不记录任何标记。Key Value Pair C

我的文件看起来像这样

Samuel= 90.5, 95.9 
Bill= 25.2, 45.3 
Tim 
Anthony= 99.9, 12.5 
Mark 
Rob 

基本上TimMarkRob失败的过程,因此其商标不被保存。同样为了区分失败的标记和通过标记,我使用了=符号。基本上,我想把所有的名字和相关的值一起存储到内存中。

这是我的实现,但它有缺陷,因为我已经声明double *marks[2]数组存储所有六个标记,当它清楚地只存储3.我无法将值存储到double数组中。

这是我的代码...

istream& operator>> (istream& is, Students& student) 
{ 
    student.names = new char*[6]; 
    for (int i=0; i<10; i++) 
    { 
    student.names[i] = new char[256]; 
    student.marks[i] = new double[2]; 
    is.getline(student.names[i], sizeof(student.names)); 

    for (int j=0; j < 256; j++) 
    { 
     if((student.names[i][j] == '=')) 
     { 
      int newPos = j + 1; 
      for (int k = newPos; k < 256; k++) 
      { 
       student.names[i][k - newPos] = student.names[k]; 
      } 
     } 
     } 
    } 
} 

我该如何去与有效标记存储了学生的价值?请,没有用的vectorsstringstreams,只是纯粹的C/C++ char arrays

+2

@Silicomancer,不,它不是功课。只是自学和学习,如果是作业,我会请我的讲师帮忙 – 2014-12-04 20:15:08

+1

你可以使用getline来读取行和stringstream,以便将读取的数据分配到名称和数字中。您可以使用unordered_map作为映射到值向量(双精度)的字符串作为键。希望这可以帮助。 – learningToCode 2014-12-04 20:17:34

+0

@learningToCode,有没有'stringstream'和'vectors'这样做的方法? – 2014-12-04 20:19:00

回答

0

您有几种选择,你可以使用一个struct像这样

struct Record { 
    std::string name; 
    double marks[2]; 
}; 

,然后坚持到这一点有点像std::vector<Record>或数组他们像

Records *r = new Records[1000]; 

你还可以保存三个不同的阵列(无论是自动分配或动态分配的,甚至std::vector),一个拿着这个名字,两个拿着这个商标。

在每种情况下,您只需指出一些失败,例如标记为零。

此外,您还可以使用

std::string name; 
double first, second; 
std::cin >> name; 
if (name[name.size() - 1] == '=') 
    std::cin >> first >> second; 

和你一样也想为单线,这将解析输入。一旦你完成了,你可以把所有的东西放在一个循环中,同时把你得到的值保存到我已经描述过的某种数据结构中。

希望给你一些想法去哪里!

+0

感谢您的回答。我会认为这是一个替代答案,但是如果你可以用我的'istream'和''vectors'来解决它,我将不胜感激。这将意味着很多,如果你帮我出去 – 2014-12-04 20:27:09

+0

@SamThers你根本不需要矢量,矢量只是在那里存储数据,一旦你得到它。如果你真的想要,你可以使用一个数组。我提出载体的唯一原因是因为你可以继续增长它们而不必担心空间不足。 – randomusername 2014-12-04 20:29:08

+0

感谢您的更新答案。怎么样存储有效的数字。我不希望存储任何空白,我不想让它们成为'0' – 2014-12-04 20:34:46

0

这里有一个策略:

所有你需要实现一个struct来保存键值对的首先,我建议如下:

struct Student { 
    char name[30]; 
    double marks[2]; 
}; 

注意,你可以给的尺寸如果你知道长度永远不会更高,那么在struct内部的char数组。 (在这里给出)

现在你需要的是知道你的ifstream有多少行,你可以做一个is.getline()的呼叫到达那里。(完时,不要忘记调用is.clear()is.seekg(0),是在开始为真正的循环)

当你知道有多少行是在您的ifstream的,你可以动态使用投你struct的阵列与实际文件的长度:

Student * students = new Student[lineCount]; // line count of is 

正如你所看到的,有没有需要有一个std::vector持有的值。考虑到getline()循环可能只是为了获得行数而过度使用,或者您可以在编译时给予学生一段长度的数组,使其长度永远不会超过。 (如Student students[128];

现在你需要解析的线条,我建议你做这样(逐行)的循环:

// int parseLine (char* line, char* name, double* marks) { ... 
bool hasMarks=false; 
int iLine=0; // Line pos iterator 
int iName=0; // Name pos iterator 
char mk1Str[4]; // String buffer, Mark 1 
char mk2Str[4]; // String buffer, Mark 2 

while(line[iLine]!='\0') 
{ 
    if(line[iLine]=='=') 
    { 
     hasMarks=true; 
     name[iLine]='\0'; 

     for(int iMark=0;iMark<4;iMark++) 
     { 
      mk1Str[iMark]=line[iLine+iMark+2]; 
      mk2Str[iMark]=line[iLine+iMark+8]; 
      // ^^ You can harcode the offsets (2,8) since they don't change 
     } 
     break; 
    } 
    name[iName++]=line[iLine]; 
    iLine++; 
} 

现在你需要的是解析标记到double的值,为此,您可以使用atof()函数与char*一起使用。 bool hasMarks可帮助您了解学生是否定义了标记,如果不是,则可以为struct的标记字段定义虚拟值,如-1。

我认为这适用于您的情况很好...

相关问题