2014-12-04 106 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。

我認爲這適用於您的情況很好...

相關問題