【问题标题】:Key Value Pair implementation C键值对实现 C
【发布时间】:2015-02-02 20:45:17
【问题描述】:

我有一个.txt 文件,其中存储了学生姓名以及他们的两个最好成绩。如果学生由于某种原因(例如辍学)未能通过课程,则不记录任何分数。

我的文件是这样的

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

【问题讨论】:

  • @Silicomancer,不,这不是家庭作业。只是自学和学习,如果是家庭作业,我会向我的讲师寻求帮助
  • 您可以只使用 getline 读取行和 stringstream 将读取的数据分配给名称和数字。您可以使用带有字符串的 unordered_map 作为映射到值向量(双精度值)的键。希望这会有所帮助。
  • @learningToCode,没有stringstreamvectors 有没有办法做到这一点?
  • -1 因为寻求代码高尔夫解决方案并不能解决“实际的、真正的问题”。
  • +1 因为编码就像写作,你必须阅读很多内容才能写出来。

标签: c++ char double key-value keyvaluepair


【解决方案1】:

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

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

然后将其粘贴到 std::vector&lt;Record&gt; 之类的东西或它们的数组中

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;

这将像您希望的那样解析输入,用于单行。完成此操作后,您可以将整个事情包装在一个循环中,同时将您获得的值粘贴到我已经描述过的某种数据结构中。

希望能给你一些关于去哪里的想法!

【讨论】:

  • 感谢您的回答。我会将此视为替代答案,但是如果您能使用我的istream 而不是vectors 帮助我解决它,我将不胜感激。如果你能帮助我,那将意义重大
  • @SamThers 你根本不需要向量,一旦你得到它,向量就在那里存储数据。如果你真的想的话,你可以使用一个数组。我建议向量的唯一原因是您可以继续增长它们而不必担心空间不足。
  • 感谢更新的答案。只存储有效数字怎么样。我不想存储任何空白,也不想将它们保留为0
  • @SamThers 您可以从您使用的任何数据结构中完全省略它们(因此没有学生被录取的记录),或者您可以添加一个布尔标志来判断是否学生失败了。
【解决方案2】:

这是一个策略:

首先你需要实现一个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 值,为此您可以使用与char* 一起使用的atof() 函数。 bool hasMarks 可以帮助您了解学生是否定义了分数,如果没有,您可以为struct 的标记字段定义虚拟值,例如 -1。

我认为这很适合您的情况...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-28
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多