初心者の学生です。どうぞ宜しくお願いいたします。
動的確保の課題を解いています。
CSVファイルを読み込んで、GPA(成績データ)でソートして表示する課題です。
送信サーバ(Linux)上の Valgrind というメモリリークをチェックするプログラムにより
課題の送信が阻まれております...
C言語のクラスからC++のクラスに進級した途端、これでチェックされるようになり毎回困っています...
お知恵をお借りできれば幸いです。お時間ありがとうございます。
Valgrindによるエラー画面
画面内のエラーメッセージをGoogle翻訳してみましたが、全く意味がわかりません...
- 条件付きジャンプまたは移動は、初期化されていない値によって異なります
- エラー:読み取られたレコードの数が正しくありません。 データが破損している可能性があります
また、Linuxサーバ上でg++してみたところ、
gpaReport.cpp:(.text+0x5): undefined reference to `sdds::load()' gpaReport.cpp:(.text+0xe): undefined reference to `sdds::display()' gpaReport.cpp:(.text+0x13): undefined reference to `sdds::deallocateMemory()'
と出ました。何か手がかりになりますでしょうか...
ソースコード
C++
1#define _CRT_SECURE_NO_WARNINGS 2#define DATAFILE "students.csv" 3#include <iostream> 4#include <cstring> 5#include <cstdio> 6using namespace std; 7 8namespace sdds { 9 struct Student { 10 char* m_name; 11 int m_studentNumber; 12 double m_gpa; 13 }; 14 15 FILE* fptr; 16 int noOfStudents; 17 Student* students; 18 19 // 学生のGPA順に動的配列を並べ替え 20 void sort(); 21 // ファイルから値を含む学生構造をロード 22 bool load(Student& record); 23 // 学生の動的配列を割り当て、すべてのファイルレコードを配列にロード 24 bool load(); 25 // 学生レコードを表示 (for gpaReport.cpp) 26 void display(); 27 // 学生レコードを表示 28 void displayStudentRecord(); 29 // 最初に生徒をソートしてから、すべての生徒を表示 30 void displayAllStudents(); 31 // 配列の割り当てを解除 32 void deallocateMemory(); 33} 34 35namespace sdds { 36 bool openFile(const char filename[]); 37 void closeFile(); 38 int noOfRecords(); 39 bool readName(char name[]); 40 bool readNumber(int *number); 41 bool readGpa(double *gpa); 42} 43 44namespace sdds { 45 void sort() { 46 int i, j; 47 Student temp; 48 for (i = noOfStudents - 1; i > 0; i--) { 49 for (j = 0; j < i; j++) { 50 if (students[j].m_gpa > students[j + 1].m_gpa) { 51 temp = students[j]; 52 students[j] = students[j + 1]; 53 students[j + 1] = temp; 54 } 55 } 56 } 57 } 58 59 // ファイルから1つの学生レコードを読み取り、学生参照引数にロード 60 bool load(Student& record) { 61 bool ok = false; 62 char name[128]; 63 // 名前の読み取りが成功した場合 64 if (readName(name)) { 65 ok = readNumber(&record.m_studentNumber) && readGpa(&record.m_gpa); 66 if (ok) { 67 int nameSize = 0; 68 nameSize = strlen(name) + 1; // 名前のサイズ+1にメモリを割り当てます 69 record.m_name = new char[nameSize]; // アドレスを参照の名前で保持 70 strcpy(record.m_name, name ); // 名前を新しく割り当てられたメモリにコピー 71 ok = true; // 問題なければ okフラグをtrueに設定 72 } 73 } 74 return ok; 75 } 76 77 // the 0 arg load function 78 bool load() { 79 bool ok = false; 80 int i = 0; 81 if (openFile(DATAFILE)) { 82 noOfStudents = noOfRecords(); // ファイル内のレコード数に設定 83 84 // 学生の配列をグローバルに動的に割り当て 85 students = new Student[noOfStudents]; 86 87 for (i = 0; i < noOfStudents; i++) {// ループ内で学生レコードをファイルから動的配列にロード 88 bool res = load(students[i]); 89 if (res == false) { 90 break; 91 } 92 } 93 // レコードの数が読み取り数と一致しない場合、エラーメッセージを出力 94 if (i != noOfStudents){ 95 cout << "Error: incorrect number of records read; the data is possibly corrupted" << endl; 96 } 97 else { 98 ok = true; 99 } 100 closeFile(); 101 } 102 else { 103 cout << "Could not open data file: " << DATAFILE<< endl; 104 } 105 return ok; 106 } 107 108 // 学生レコードを表示 (for gpaReport.cpp) 109 void display() { 110 displayAllStudents(); 111 } 112 113 // 学生レコードを表示 114 void displayStudentRecord(const Student *record) { 115 cout << record->m_name << ", " 116 << record->m_studentNumber << ": " 117 << record->m_gpa << endl; 118 } 119 120 // 最初に生徒をソートしてから、すべての生徒を表示 121 void displayAllStudents() { 122 int i; 123 sort(); 124 for (i = 0; i < noOfStudents; i++) { 125 cout << i+1 << ": "; 126 displayStudentRecord(&students[i]); 127 } 128 } 129 130 // 最初にstudent要素のすべての名前の割り当てを解除し、次にstudent配列の割り当てを解除 131 void deallocateMemory() { 132 if (noOfStudents <= 0 || students == NULL) { 133 return; 134 } 135 // ループしてstudents配列のすべての要素を調べ、各学生の動的名の割り当てを解除 136 for (int i = 0; i < noOfStudents; i++) { 137 delete [] students[i].m_name; 138 students[i].m_name = nullptr; 139 } 140 delete [] students; // students配列全体の割り当てを解除 141 students = nullptr; 142 } 143} 144 145namespace sdds { 146 bool openFile(const char filename[]) { 147 fptr = fopen(filename, "r"); 148 return fptr != NULL; 149 } 150 int noOfRecords() { 151 int noOfRecs = 0; 152 char ch; 153 while (fscanf(fptr, "%c", &ch) == 1) { 154 noOfRecs += (ch == '\n'); 155 } 156 rewind(fptr); 157 return noOfRecs + 1; // 最終行用に +1 158 } 159 void closeFile() { 160 if (fptr) fclose(fptr); 161 } 162 163 bool readName(char name[]) { // データファイル内の学生名の読み取り 164 char names[256]; 165 int gi = 0; //names index; 166 int i = 0;// name[i] index 167 bool res = fscanf(fptr, "%[^,],", names); 168 if (res) { //csvを文字列の配列に拡散する 169 res = false; 170 while (names[gi]) { 171 name[i++] = names[gi++]; 172 res = true; 173 } 174 } 175 name[i++] = '\0'; 176 name[i] = '\0'; // 文字列の配列を終了する 177 return res; 178 } 179 180 bool readNumber(int *number) { // データファイル内の学生番号の読み取り 181 return fscanf(fptr, "%d,", number) == 1; 182 } 183 184 bool readGpa(double *gpa) { // データファイル内のGPAの読み取り 185 return fscanf (fptr, "%lf\n", gpa) == 1; 186 } 187 188} 189 190using namespace sdds; 191 192int main() { 193 if (load()) { 194 display(); 195 } 196 deallocateMemory(); 197 return 0; 198}
データファイル
CSV
1Abraham Simpson,324543,3.9 2Alice Glick,459608,1.9 3Allison Taylor,747954,3.2 4Apu Nahasapeemapetilon,290816,2.6 5Bart Simpson,753102,3.9 6Bernice Hibbert,242653,3.8 7Carl Carlson,241968,3.7 8Homer Simpson,413084,2.9 9Lisa Simpson,693664,4.0 10Luann Van Houten,737447,2.3 11Martin Prince,575687,3.5 12Maude Flanders,272754,1.7 13Sarah Wiggum,920562,2.0 14Surly Duff,146127,2.6
試したこと
- new の格納先を +1 してみた --> 何も変わりませんでした(追加前と同じエラー)
- delete を追加してみた --> 余計にエラーが増えました...
- コマンドで'valgrind result' と打っても 'command not found' と言われてしまい、行番号すらわかりませんでした...
ご回答をいただき追加で試したこと
- delete [] とした(投稿時のスクショは [] ありのもので、投稿したコードが古かったです、すみません)
- students[i].m_name と students に nullptr を追加
回答1件
あなたの回答
tips
プレビュー