我的代码有两个问题,使我难以完成。
首先是“运行时检查失败#2。变量'grade'周围的堆栈已损坏”
从我发现的情况来看,当在数组范围之外打印某些内容时,这是一个错误。我已经查看并仔细检查了所有代码,并修复了一些可能的问题,但找不到最后一个使该代码跳闸的代码。
第二,为什么要使用名称数组显示下一行的第一个字母?它不是在本地人中显示额外的字符,但仍会以这种方式打印。我似乎找不到很好的解决方法。
编辑:我将Switch语句固定为仅10、9、8、7、6个测试,并删除了不需要的行。
#include<iostream>
#include<iomanip>
#include<string>
#include<fstream>
#include<array>
using namespace std;
void outPut ( double score[][6], char name[][10], char grade[11]);
void dataIn ( double score[][6] ,char name[][10]);
void grades ( double score[][6], char grade[11] );
int main ( )
{
double score[11][6];
char name[11][10], grade[11];
for (int q = 0;q < 12;q++)
for (int w = 0;w < 7;w++)
score[q][w] = 0;
for (int z = 0;z < 12;z++)
for (int x = 0;x < 10;x++)
name[z][x] = 0;
dataIn ( score, name );
grades ( score, grade );
outPut ( score, name, grade );
system ( "pause" );
}
void outPut (double score[][6], char name[][10], char grade[11] )
{
cout << endl;
for (int a = 0;a < 11;a++)
{
for (int c = 0; c < 11;c++)
cout << name[a][c] << " ";
cout << setw ( 6 );
cout << showpoint << fixed << setprecision ( 2 );
for (int b = 0; b < 6;b++)
cout << score[a][b] << " ";
cout << grade[a];
cout << endl;
}
}
void dataIn ( double score[][6],char name[][10] )
{
ifstream inData;
ifstream inData1;
inData1.open ( "inName.txt" );
inData.open ( "indata.txt" );
for (int j = 0; j < 11; j++)
inData1 >> name[j], 11;
for (int row = 0; row < 11;row++)
for (int col = 0; col < 5;col++)
inData >> score[row][col];
}
void grades ( double score[][6], char grade[11] ) //[row][column]
{
double sum = 0, sum1 = 0, avg, avg1;
int avg2;
for (int a = 0;a < 11;a++)
{
sum1 = 0;
for (int b = 0;b < 6;b++)
sum1 = sum1 + score[a][b];
avg = sum1 / 5;
score[a][5] = avg;
}
for (int b = 0;b < 11;b++)
sum = sum + score[b][6];
avg1 = sum / 10;
score[10][5] = avg1;
for (int q = 0;q < 12;q++)
{
avg2 = score[q][5];
switch (avg2)
{
case 100:
case 99:
case 98:
case 97:
case 96:
case 95:
case 94:
case 93:
case 92:
case 91:
case 90:
grade[q] = 'A';
break;
case 89:
case 88:
case 87:
case 86:
case 85:
case 84:
case 83:
case 82:
case 81:
case 80:
grade[q] = 'B';
break;
case 79:
case 78:
case 77:
case 76:
case 75:
case 74:
case 73:
case 72:
case 71:
case 70:
grade[q] = 'C';
break;
case 69:
case 68:
case 67:
case 66:
case 65:
case 64:
case 63:
case 62:
case 61:
case 60:
grade[q] = 'D';
break;
default:
grade[q] = 'F';
}
}
}
inName.txt:
Johnson
Aniston
Cooper
Gupta
Blair
Clark
Kennedy
Bronson
Sunny
Smith
Average
inData.txt
85 83 77 91 76
80 90 95 93 48
78 81 11 90 73
92 83 30 69 87
23 45 96 38 59
60 85 45 39 67
77 31 52 74 83
93 94 89 77 97
79 85 28 93 82
85 72 49 75 63
代码输出
答案 0 :(得分:1)
好的,所以我遍历了您的代码,其中充满了索引错误。许多循环使用的上限大于相应数组的大小。 main()
函数中提供了示例:q < 12
,w < 7
,z < 12
,这些示例将在给定数组的允许范围之外写入。对此完全没有代码检查,并且当您越界书写时,它不一定会在发生时引发运行时错误,而是通常在数组外部的内存为 时显示该错误。可供使用 。了解C或C ++程序的内存布局很重要。每个函数都有一个堆栈,值类型完全存储在堆栈中(如数组)。因此,当您在数组边界之外进行写入时,就会破坏堆栈。通过在允许的边界之外写入并覆盖return pointer
值,实际上就是执行缓冲区溢出攻击的方式。
无论如何,我遍历了您的代码并设法解决了这些问题:
在main()
中:
for (int q = 0;q < 11;q++)
for (int w = 0;w < 6;w++)
score[q][w] = 0;
for (int z = 0;z < 11;z++)
for (int x = 0;x < 10;x++)
在dataIn(...)
中:
for (int j = 0; j < 10; j++)
inData1 >> name[j], 11;
for (int row = 0; row < 10; row++)
for (int col = 0; col < 5;col++)
在grades(...)
中:
for (int a = 0;a < 10;a++)
{
sum1 = 0;
for (int b = 0;b < 5;b++)
sum1 = sum1 + score[a][b];
avg = sum1 / 5;
score[a][5] = avg;
}
/* code between */
for (int b = 0;b < 10;b++)
sum = sum + score[b][5];
/* code between */
for (int q = 0;q < 11;q++)
最后但并非最不重要的一点是要解决您的第二个问题...
在outPut(...)
中:
for (int c = 0; c < 10; c++)
理解C ++中的数组索引很重要。 size = 10
的数组在[0-9]
之间建立索引,而10
在数组的边界之外。那引起了你所有的问题。
我建议您将值11, 10 and 6
设置为文件开头定义的常量,例如:
#define I_COUNT 11 // number of instances
#define N_WIDTH 10 // name size
#define G_COUNT 6 // number of grades (including average for instance)
然后使用常量代替数字:
double score[I_COUNT][G_COUNT];
这样,您可以轻松地更改代码以包含更多实例和等级。而且您不会有此类错误。
或者,我已经编写了一个使用std::vector
的程序,以一种更加简洁的方式来完成您的工作。而且我还使它可以计算每个主题的平均值。 inName.txt
必须从最后一个条目中删除Average
(只是以此方式设计)。它可以接受任意数量的实例(人员名称)及其相应的等级。如果您愿意,成绩也可以高于5。但是它们必须一致(每行相同的编号)。
以下是带有注释的代码:
#include <iostream>
#include <iomanip>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
// type aliases - just to make it easier to read
using Names = std::vector<std::string>;
using Grades = std::vector<std::vector<double>>;
using GradeLetters = std::vector<char>;
char get_grade_letter(double avg);
// function prototypes
Names read_names(const std::string& path);
Grades read_grades(const std::string& path);
GradeLetters calculate_averages(Grades& grades);
void print_out(const Names& names, const Grades& grades, const GradeLetters& grade_letters);
int main()
{
auto names = read_names("inName.txt");
auto grades = read_grades("inData.txt");
auto grade_letters = calculate_averages(grades);
print_out(names, grades, grade_letters);
return 0; // don't forget this
}
// takes file-path input, reads content and returns vector of strings
Names read_names(const std::string& path) {
std::ifstream in(path);
std::vector<std::string> names;
std::string name;
while (std::getline(in, name)) {
if (name != "") // in case there is empty line in the end
names.push_back(name);
}
names.push_back("Average"); // let the program add it instead of having it in file
return names;
}
// takes file-path input, reads grades and stores them in matrix-ish format
Grades read_grades(const std::string& path) {
std::ifstream in(path);
std::vector<std::vector<double>> grades;
std::string grade_line;
while (std::getline(in, grade_line)) {
std::stringstream ss(grade_line);
std::vector<double> p_grades;
double grade;
while (ss >> grade)
p_grades.push_back(grade);
grades.push_back(p_grades);
}
return grades;
}
// calculates averages (per instance, and overall) - returns letter grades vector
GradeLetters calculate_averages(Grades& grades) {
std::vector<char> grade_letters;
std::vector<double> averages; // seperate vector, not yet in grades
int grades_per_instance = grades.at(0).size(); // for avg calc
averages.resize(grades_per_instance + 1); // +1 for the average
for (size_t i = 0; i < grades.size(); i++) {
double i_sum = 0; // instance sum
for (size_t j = 0; j < grades[i].size(); j++) {
i_sum += grades[i][j];
averages[j] += grades[i][j]; /* sum for each subject, for all students
* average of this will be calculated in
* a seperate loop, see below */
}
double i_avg = i_sum / grades_per_instance;
grades[i].push_back(i_avg);
char grade_letter = get_grade_letter(i_avg);
grade_letters.push_back(grade_letter);
}
int total_instances = grades.size();
double all_sum = 0; // for average of averages
for (size_t i = 0; i < averages.size(); i++) {
averages[i] /= total_instances; // can't do this in first loop, it must be over before we do it
all_sum += averages[i];
}
double all_avg = all_sum / grades_per_instance;
averages[averages.size() - 1] = all_avg; // averages is now complete, add it to `grades`
grades.push_back(averages); // we did not add averages row until now
char all_avg_grade_letter = get_grade_letter(all_avg);
grade_letters.push_back(all_avg_grade_letter);
return grade_letters;
}
char get_grade_letter(double avg) {
int avg_simplified = (int)(avg / 10);
switch (avg_simplified)
{
case 10:
case 9:
return 'A'; // [90-100]
case 8:
return 'B'; // [80-90[
case 7:
return 'C'; // [70-80[
case 6:
return 'D'; // [60-70[
default:
return 'F'; // <60 || >100
}
}
void print_out(const Names& names, const Grades& grades, const GradeLetters& grade_letters) {
std::cout << std::showpoint << std::fixed << std::setprecision(2); // can be set just once
// print header
std::cout << std::setw(20) << std::left << "Name:" << '\t';
for (size_t i = 0; i < grades.at(0).size() - 1; i++)
std::cout << "Sub" << i << " ";
std::cout << std::setw(5) << "Avg" << " Letter" << std::endl;
std::cout << "------------------------------------------------------------------------" << std::endl;
// print content
for (size_t i = 0; i < grades.size(); i++) {
std::cout << std::setw(20) << std::left << names.at(i) << '\t';
for (size_t j = 0; j < grades.at(i).size(); j++)
std::cout << std::setw(5) << grades.at(i).at(j) << " ";
std::cout << grade_letters.at(i) << std::endl;
if(i == grades.size()-2)
std::cout << "------------------------------------------------------------------------" << std::endl;
}
}
输出:
Name: Sub0 Sub1 Sub2 Sub3 Sub4 Avg Letter
------------------------------------------------------------------------
Johnson 85.00 83.00 77.00 91.00 76.00 82.40 B
Aniston 80.00 90.00 95.00 93.00 48.00 81.20 B
Cooper 78.00 81.00 11.00 90.00 73.00 66.60 D
Gupta 92.00 83.00 30.00 69.00 87.00 72.20 C
Blair 23.00 45.00 96.00 38.00 59.00 52.20 F
Clark 60.00 85.00 45.00 39.00 67.00 59.20 F
Kennedy 77.00 31.00 52.00 74.00 83.00 63.40 D
Bronson 93.00 94.00 89.00 77.00 97.00 90.00 A
Sunny 79.00 85.00 28.00 93.00 82.00 73.40 C
Smith 85.00 72.00 49.00 75.00 63.00 68.80 D
------------------------------------------------------------------------
Average 75.20 74.90 57.20 73.90 73.50 70.94 C