繁体   English   中英

找不到运行时检查失败的根源 #2

[英]Can't find the source of Run-time check failure #2

我的代码有两个问题让我发疯,无法完成。

首先是“运行时检查失败 #2。变量‘等级’周围的堆栈已损坏”

根据我的发现,当某些内容打印在数组边界之外时,这是一个错误。 我已经查看并仔细检查了所有代码并修复了一些可能的问题,但我找不到最后一个触发此代码的代码。

二、用name数组,为什么显示下一行的第一个字母? 它不是在当地人中显示额外的字符,但它仍然以这种方式打印。 我似乎找不到好的解决办法。

编辑:我将 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';
        }
    }
}

名称.txt:

Johnson
Aniston
Cooper
Gupta
Blair
Clark
Kennedy
Bronson
Sunny
Smith
Average

输入数据.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 

代码的输出

图片

好的,所以我浏览了您的代码,它充满了索引错误。 许多循环使用的上限大于相应数组的大小。 示例存在于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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM