如何从文本文件输出数据?(学生成绩单计划)
How to output data from text file? (Student Report Card Program)
我目前正在编写一个程序,其中包括输出学生的ID,姓名,课程,学分和分数。数据全部在此文本文件中:
"学生记录.txt">
12546 Amy CS1 4 81
13455 Bill CS1 4 76
14328 Jim CS1 4 64
14388 Henry CS3 3 80
15667 Peter CS3 3 45
12546 Amy CS2 4 90
13455 Bill CS2 4 85
14328 Jim CS2 4 71
12546 Amy CS3 3 90
13455 Bill CS3 3 75
14328 Jim CS3 3 69
下表用于计算GPA(仅供参考(:
Range Grade:
90 -- 100 > 4.0
80 -- 89 > 3.0
70 -- 79 > 2.0
60 -- 69 > 1.0
0 -- 59 > 0.0
我现在遇到的问题是我的输出。我试图让它与我的预期输出相匹配,但我似乎无法弄清楚。
这可能与第二个 for 循环中缺少的一些 else if(( 语句有关。如果有人能为我提供一些关于如何让我的输入工作并显示我预期输出的建议/提示,我将不胜感激!
我当前的代码:
#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;
struct Student
{
int ID = -1;
string Name = "";
string Course = "";
int Credit = -1;
int Score = -1;
};
const int SIZE = 99;
int main()
{
ifstream inputFile;
string fileName = "StudentRecords.txt";
Student studArr[SIZE];
inputFile.open(fileName.c_str(), ios::in);
int n = 0;
if (inputFile.is_open())
{
while(!inputFile.eof())
{
Student st;
inputFile >> st.ID;
inputFile >> st.Name;
inputFile >> st.Course;
inputFile >> st.Credit;
inputFile >> st.Score;
studArr[n] = st;
n++;
}
inputFile.close();
}
else
{
cout << "File cannot be opened.";
return 1;
}
// sorts the array by ID and Course
for (int i = 0; i < n; i++)
{
for(int j = i + 1; j < n; j++)
{
if(studArr[i].ID > studArr[j].ID)
{
Student temp = studArr[i];
studArr[i] = studArr[j];
studArr[j] = temp;
}
else if(studArr[i].Course > studArr[j].Course)
{
Student temp = studArr[i];
studArr[i] = studArr[j];
studArr[j] = temp;
}
}
}
int check = 0;
float dividend = 0;
float divisor = 0;
for(int i = 0; i < n; i++)
{
if(studArr[i].ID != studArr[check].ID)
{
cout << "======================nGPA "
<< round((dividend / divisor)) << endl << endl;
}
else if(i == 0)
{
cout << studArr[i].ID << " " << studArr[i].Name
<< endl << endl;
dividend = 0;
divisor = 0;
}
float gradepoints;
if(studArr[i].Score < 60)
{
gradepoints = 0.0;
}
else if(studArr[i].Score < 70)
{
gradepoints = 1.0;
}
else if(studArr[i].Score < 80)
{
gradepoints = 2.0;
}
else if(studArr[i].Score < 90)
{
gradepoints = 3.0;
}
else if(studArr[i].Score < 100)
{
gradepoints = 4.0;
}
dividend += gradepoints * studArr[i].Credit;
divisor += studArr[i].Credit;
cout << studArr[i].Course << " "
<< studArr[i].Score << " "
<< gradepoints << ".0" << endl << endl;
}
cout << "======================nGPA "
<< round((dividend / divisor)) << endl << endl;
cout << endl << endl;
return 0;
}
我当前的输出:
12546 Amy
CS1 81 3.0
CS2 90 4.0
CS3 90 4.0
======================
GPA 4
CS1 76 2.0
======================
GPA 3
CS2 85 3.0
======================
GPA 3
CS3 75 2.0
======================
GPA 3
CS1 64 1.0
======================
GPA 3
CS2 71 2.0
======================
GPA 3
CS3 69 1.0
======================
GPA 2
CS3 80 3.0
======================
GPA 3
CS3 45 0.0
======================
GPA 2
预期输出:
12546 Amy
CS1 4 81 3.0
CS2 4 90 4.0
CS3 3 90 4.0
======================
GPA 3.64
======================
13455 Bill
CS1 4 76 2.0
CS2 4 85 3.0
CS3 3 75 2.0
======================
GPA 2.36
======================
14328 Jim
CS1 4 64 1.0
CS2 4 71 2.0
CS3 3 69 1.0
======================
GPA 1.36
======================
14388 Henry
CS3 3 80 3.0
======================
GPA 3
======================
15667 Peter
CS3 3 45 0.0
======================
GPA 0
有许多领域使事情变得更加困难,但最大的问题涉及您的输入尝试。当您使用以下方法进行输入时,您的输入肯定会失败:
while(!inputFile.eof())
{
Student st;
inputFile >> st.ID;
inputFile >> st.Name;
inputFile >> st.Course;
inputFile >> st.Credit;
inputFile >> st.Score;
studArr[n] = st;
n++;
}
请参阅:为什么!循环条件中的 eof(( 总是错误的。本质上,在读取最后一个 VALIDinputFile >> st.Score;
后,eofbit
没有设置,因此您在inputFile >> st.ID;
失败的地方再次循环,使st
中的所有值都不确定,您不检查每个输入的结果,因此您分配studArr[n] = st;
损坏您的studArr
。
确保您不会落入该陷阱的一种方法是继续写入>>
重载来处理结构的输入。在这种情况下,很容易做到:
struct Student {
int ID = -1;
std::string Name = "";
std::string Course = "";
int Credit = -1;
int Score = -1;
/* overloading the >> and << to read and write your struct helps */
friend std::istream& operator >> (std::istream& is, Student& s) {
is >> s.ID >> s.Name >> s.Course >> s.Credit >> s.Score;
return is;
}
...
};
现在,读取和验证所有输入变得非常简单:
#define MAXS 99 /* if you need a constant, #define one (or more) */
...
int main (int argc, char **argv) {
Student studArr[MAXS], tmp;
size_t n = 0;
std::ifstream f(argc > 1 ? argv[1] : "dat/StudentRecords.txt");
while (n < MAXS && f >> tmp)
studArr[n++] = tmp;
...
如果按照建议,您将 STL 容器(如std::vector
(用于学生存储,而不是基本数组类型,则验证将进一步简化为while (f >> tmp)
(您还将使用不同的方法(如.push_back(tmp)
而不是直接分配(
整理输入后,虽然您可以对数组进行排序,但实际上没有必要。一个简单的方法是遍历您的学生数据并在另一个数组(或向量等(中收集唯一的ID
值。然后,您只需将唯一 ID 作为外循环进行循环,并将学生数组的元素作为内循环进行循环,并处理 ID 与当前外循环值匹配的每个学生。重写您的 GPA 映射逻辑和一个函数来循环您的学生数组,执行所描述的操作可以按如下方式完成:
/* simple map GPA function that returns grade points given score */
int mapgpa (int score)
{
if (score < 60)
return 0;
else if (score < 70)
return 1;
else if (score < 80)
return 2;
else if (score < 90)
return 3;
else if (score >= 90)
return 4;
return 0;
}
以及为每个学生找到 GPA 的逻辑:
/* a function to handle outputting the student grades
* in your desired format.
*/
void dogrades (Student *s, size_t n)
{
int uniqueID[MAXS] = {0}; /* array to hold unique IDs */
size_t seen = 0; /* number of unique IDs seen */
for (size_t i = 0; i < n; i++) { /* loop collecting unique IDs */
for (size_t j = 0; j < seen; j++)
if (uniqueID[j] == s[i].ID)
goto next;
uniqueID[seen++] = s[i].ID;
next:;
}
for (size_t j = 0; j < seen; j++) { /* loop ever unique IDs */
int heading = 0, /* simple flag indicating name printed */
sumcredits = 0, /* variable to hold sum of credits */
sumpoints = 0; /* variable to hold sum of gradepoints */
for (size_t i = 0; i < n; i++) { /* loop over each stuct element */
int gradepts = 0; /* var to map score->gradepoits */
if (s[i].ID == uniqueID[j]) { /* if struct element == ID */
if (!heading) { /* if no heading output, do it */
std::cout << s[i].ID << " " << s[i].Name << "nn";
heading = 1; /* set flag indicating done */
}
gradepts = mapgpa(s[i].Score); /* get gradepts from score */
/* output current course and gradepoints */
std::cout << s[i].Course << " "
<< s[i].Credit << " "
<< s[i].Score << " "
<< gradepts << ".0nn";
sumcredits += s[i].Credit; /* sum credits */
sumpoints += s[i].Credit * gradepts; /* sum gradepoints */
}
}
std::cout.precision(3); /* set precsion and output GPA */
std::cout << "======================nn"
<< "GPA " << (double)sumpoints/sumcredits << "nn"
<< "======================nn";
}
}
在dogrades
函数中处理逻辑后,main()
减少到:
int main (int argc, char **argv) {
Student studArr[MAXS], tmp;
size_t n = 0;
std::ifstream f(argc > 1 ? argv[1] : "dat/StudentRecords.txt");
while (n < MAXS && f >> tmp)
studArr[n++] = tmp;
dogrades (studArr, n);
}
把它放在一个可以编译的示例中,该示例将要读取的数据文件的名称作为第一个参数(或默认情况下从"dat/StudentRecords.txt"
读取(,您可以执行以下操作:
#include <iostream>
#include <iomanip>
#include <fstream>
#define MAXS 99 /* if you need a constant, #define one (or more) */
struct Student {
int ID = -1;
std::string Name = "";
std::string Course = "";
int Credit = -1;
int Score = -1;
/* overloading the >> and << to read and write your struct helps */
friend std::istream& operator >> (std::istream& is, Student& s) {
is >> s.ID >> s.Name >> s.Course >> s.Credit >> s.Score;
return is;
}
friend std::ostream& operator << (std::ostream& os, const Student& s) {
os << std::setw(5) << s.ID << " "
<< std::setw(8) << std::left << s.Name << " "
<< std::setw(5) << s.Course << " "
<< s.Credit << " "
<< std::setw(3) << s.Score << 'n';
return os;
}
};
/* simple map GPA function that returns grade points given score */
int mapgpa (int score)
{
if (score < 60)
return 0;
else if (score < 70)
return 1;
else if (score < 80)
return 2;
else if (score < 90)
return 3;
else if (score >= 90)
return 4;
return 0;
}
/* a function to handle outputting the student grades
* in your desired format.
*/
void dogrades (Student *s, size_t n)
{
int uniqueID[MAXS] = {0}; /* array to hold unique IDs */
size_t seen = 0; /* number of unique IDs seen */
for (size_t i = 0; i < n; i++) { /* loop collecting unique IDs */
for (size_t j = 0; j < seen; j++)
if (uniqueID[j] == s[i].ID)
goto next;
uniqueID[seen++] = s[i].ID;
next:;
}
for (size_t j = 0; j < seen; j++) { /* loop ever unique IDs */
int heading = 0, /* simple flag indicating name printed */
sumcredits = 0, /* variable to hold sum of credits */
sumpoints = 0; /* variable to hold sum of gradepoints */
for (size_t i = 0; i < n; i++) { /* loop over each stuct element */
int gradepts = 0; /* var to map score->gradepoits */
if (s[i].ID == uniqueID[j]) { /* if struct element == ID */
if (!heading) { /* if no heading output, do it */
std::cout << s[i].ID << " " << s[i].Name << "nn";
heading = 1; /* set flag indicating done */
}
gradepts = mapgpa(s[i].Score); /* get gradepts from score */
/* output current course and gradepoints */
std::cout << s[i].Course << " "
<< s[i].Credit << " "
<< s[i].Score << " "
<< gradepts << ".0nn";
sumcredits += s[i].Credit; /* sum credits */
sumpoints += s[i].Credit * gradepts; /* sum gradepoints */
}
}
std::cout.precision(3); /* set precsion and output GPA */
std::cout << "======================nn"
<< "GPA " << (double)sumpoints/sumcredits << "nn"
<< "======================nn";
}
}
int main (int argc, char **argv) {
Student studArr[MAXS], tmp;
size_t n = 0;
std::ifstream f(argc > 1 ? argv[1] : "dat/StudentRecords.txt");
while (n < MAXS && f >> tmp)
studArr[n++] = tmp;
dogrades (studArr, n);
}
(注意:还添加了<<
运算符的重定向,以简化原始结构信息的输出,如果您发现需要(
示例使用/输出
$ ./bin/studentrecords
12546 Amy
CS1 4 81 3.0
CS2 4 90 4.0
CS3 3 90 4.0
======================
GPA 3.64
======================
13455 Bill
CS1 4 76 2.0
CS2 4 85 3.0
CS3 3 75 2.0
======================
GPA 2.36
======================
14328 Jim
CS1 4 64 1.0
CS2 4 71 2.0
CS3 3 69 1.0
======================
GPA 1.36
======================
14388 Henry
CS3 3 80 3.0
======================
GPA 3
======================
15667 Peter
CS3 3 45 0.0
======================
GPA 0
======================
仔细查看,如果您有疑问,请告诉我(并认真考虑使用可用的 STL 容器,如std::vector
和std::map
(
- 如何让C++'tally up'结果并制定计划?
- C++窗口的计划问题
- 回复计划游戏结果不会显示
- 我正在努力处理多维数组输入和输出,我管理输入,但是打印无法按计划工作
- 如何从文本文件输出数据?(学生成绩单计划)
- 为什么在此计划中,我在所有情况下都获得 0%?
- Windows 并发运行时任务计划,但有例外
- C++航班预订计划
- 如何计划在将来时间运行的操作
- 自动(toCast)显式转换是否计划在未来C++标准?
- 任务计划程序库的预处理不起作用 - 多定义错误
- GLES计划资源索引/位置与统一索引/位置
- 我应该如何使用C++创建 Google 行动行动计划履行端点?
- 多米诺骨牌计划。我不知道如何将我的矢量拉到空白中以打印出来
- C++计划持续时间内(字体)资源的分配
- 是否有任何计划将"expects"添加到 std::optional?
- 我可以在计算数据计划上修复该C 程序的任何建议吗?
- 任务计划程序:设置运行级别时拒绝访问
- 基本C++计划提前结束
- 驾驶执照考试计划.无法将 std:: 字符串转换为 std :: 字符串和其他错误