在 C++ 中获取 "corrupted size vs. prev_size"

Getting "corrupted size vs. prev_size" in C++

我正在尝试创建一个程序来在从文件中读取数据后打印二维矩阵。

如果 2D 矩阵是 X 和 Y 值相等的正方形,我的程序运行良好,但如果它是矩形,例如 x=8,我会收到“损坏的大小与 prev_size”错误y=10.

这是一个示例,如果 运行 成功(其中 x 为 8,y 为 8):

  # # # # # # # # # # # 
8 #     2 2           # 
7 #     2 2       1   # 
6 #                   # 
5 #                   # 
4 #                   # 
3 #   3 3 3           # 
2 #   3 3 3           # 
1 #   3 3 3           # 
0 #                   # 
  # # # # # # # # # # # 
    0 1 2 3 4 5 6 7 8   

当我尝试使用 x 为 8 且 y 为 10 的配置文件时,出现如下错误:

Please enter your choice : 1

[ Read in and process a configuration file ]
Please enter config filename : TestCases_Config.txt

Reading in GridX_IdxRange : GridX_IdxRange=0-8 ... done!
Reading in GridY_IdxRange : GridY_IdxRange=0-10 ... done!

Storing data from input file :
*** Error in `./csci251_a1.exe': corrupted size vs. prev_size: 0x08e63d40 ***
Aborted (core dumped)

这是我的代码的样子:

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm> // To use unique function
#include <iomanip> // For setprecision
#include <vector> // To use vectors

using namespace std;

// Struct to store the maximum grid values from config file
struct gridSize
{
    int gridXHighestVal;
    int gridYHighestVal;

    string toString();
};

// Struct object to store individual grid tile details
struct gridTileDetails
{
    int x, y;
    bool isOccupied;
    int cityID;
    string cityName;
    int cloudIndex, singleCloudIndex, pressureIndex, singlePressureIndex;
    char cloudLMH, pressureLMH;

    string toString();
};

gridSize gridSize; // Global gridSize struct to be used to obtain maximum X & Y values
gridTileDetails **grid; // Global pointer-to-pointer variable to be used for dynamically allocating 2D array

// All function/method prototypes
// Functions for reading of data (Menu option #1)
gridTileDetails processConfigFile();
gridTileDetails readCityFile(string);
gridTileDetails readCloudFile(string);
gridTileDetails readPressureFile(string);

// Functions for menu options #2 - #7
void displayCityMap(int, int);
void displayCloudMap(int, int);
void displayCloudMapLMH(int, int);
void displayPressureMap(int, int);
void displayPressureMapLMH(int, int);
void generateWeatherReport(int, int);

// Helper functions
void safelyDeallocateMemory (int arrayCols, gridTileDetails **grid);
vector<string> tokenizeString(string, string);
vector<int> removeDuplicates(vector<int> &vec);
char getLMH(int);
int printCity(int, int, vector<int> , int);
double calculateRain(char, char);
void printRain(double);

int main() 
{
    
    int userChoice;

    // Main menu to run constantly until user enters 8
    while (userChoice != 8) 
    {
        cout << "Welcome to Weather Information Processing System!" << endl;

        cout << endl;

        cout << "1)\tRead in and process a configuration file" << endl;
        cout << "2)\tDisplay city map" << endl;
        cout << "3)\tDisplay cloud coverage map (cloudiness index)" << endl;
        cout << "4)\tDisplay cloud coverage map (LMH symbols)" << endl;
        cout << "5)\tDisplay atmospheric pressure map (pressure index)" << endl;
        cout << "6)\tDisplay atmospheric pressure map (LMH symbols)" << endl;
        cout << "7)\tShow forecast summary report" << endl;
        cout << "8)\tQuit" << endl;

        cout << endl;

        cout << "Please enter your choice : ";
        cin >> userChoice;

        cout << endl;

        switch (userChoice) 
        {
            case 1:
                // Process configuration file
                **grid = processConfigFile();
                break;
            case 2:
                // Display city map
                displayCityMap(gridSize.gridXHighestVal, gridSize.gridYHighestVal);
                break;
            case 3:
                // Display cloud coverage map (cloudiness index)
                displayCloudMap(gridSize.gridXHighestVal, gridSize.gridYHighestVal);
                break;
            case 4:
                // Display cloud coverage map (LMH symbols)
                displayCloudMapLMH(gridSize.gridXHighestVal, gridSize.gridYHighestVal);
                break;
            case 5:
                // Display atmospheric pressure map (pressure index)
                displayPressureMap(gridSize.gridXHighestVal, gridSize.gridYHighestVal);
                break;
            case 6:
                // Display atmospheric pressure map (LMH symbols)
                displayPressureMapLMH(gridSize.gridXHighestVal, gridSize.gridYHighestVal);
                break;
            case 7:
                // Show weather forecast summary report
                generateWeatherReport(gridSize.gridXHighestVal, gridSize.gridYHighestVal);
                break;
            case 8:
                // Message to be shown for quiting program
                cout << "Thank you for using the Weather Information Processing System!" << endl;
                break;
            default:
                cout << "Please enter a valid input!" << endl << endl;
        }
    }
    
    safelyDeallocateMemory (gridSize.gridXHighestVal, grid);

    return (0);
}

// Begin reading of files
gridTileDetails processConfigFile() 
{
    string filename;

    cout << "[ Read in and process a configuration file ]" << endl;
    cout << "Please enter config filename : ";
    cin >> filename;

    cout << endl;

    // Create fstream object
    fstream input_file(filename.c_str(), fstream::in);

    string aline;
    string gridX = "GridX_IdxRange";
    string gridY = "GridY_IdxRange";

    while (getline(input_file, aline)) // With input_file as the source, store each "line" into our string variable aline;
    {

        if (aline.find(gridX) != string::npos) // If "GridX_IdxRange" is found within aline
        {
            string numString = aline.substr(15); // Obtain only the number range portion of string

            vector<string> individualNums = tokenizeString(numString, "-"); // Use "-" as delimiter to obtain individual numbers
            
            int gridX = stoi(individualNums[1]); // Convert string to an int variable       
            
            gridSize.gridXHighestVal = gridX; // Store grid X maximum value into custom struct object

            cout << "Reading in GridX_IdxRange : " << aline << " ... done!" << endl;
            individualNums.clear();
        }

        if (aline.find(gridY) != string::npos) // If "GridY_IdxRange" is found within aline
        {

            string numString = aline.substr(15); // Obtain only the number range portion of string

            vector<string> individualNums = tokenizeString(numString, "-"); // Use "-" as delimiter to obtain individual numbers

            int gridY = stoi(individualNums[1]); // Convert string to an int variable

            gridSize.gridYHighestVal = gridY; // Store grid Y maximum value into custom struct object

            cout << "Reading in GridY_IdxRange : " << aline << " ... done!" << endl;
            individualNums.clear();
        }
        
        if (gridSize.gridXHighestVal != 0 && gridSize.gridYHighestVal != 0) // Break out of the while-loop if both X & Y values are populated, to continue processing
        {
            break;
        }
    }

    cout << endl;

    // Dynamic memory allocation for 2D array
    grid = new gridTileDetails * [gridSize.gridXHighestVal + 1];
    for (int i = 0; i < gridSize.gridYHighestVal + 1; i++)
    {
        grid[i] = new gridTileDetails[gridSize.gridYHighestVal + 1];
    }

    // Putting x (columns) and y (rows) values into 2D array
    for (int col = 0; col < gridSize.gridXHighestVal + 1; col++) 
    {
        for (int row = 0; row < gridSize.gridYHighestVal + 1; row++) 
        {
            grid[col][row].x = col;
            grid[col][row].y = row;
        }
    }
    
    
    int fileCounter = 0; // File counter variable to decide which file method to use
    cout << "Storing data from input file :" << endl;

    while (getline(input_file, aline)) 
    {

        if (aline.find(".txt") != string::npos) // If aline contains ".txt" at the end, we know it is one of the configuration files
        {
            
            switch (fileCounter)
            {
                case 0: // Get city details
                    **grid = readCityFile(aline);
                    cout << aline << " ... done!" << endl;
                    break;
                case 1: // Get cloud details
                    **grid = readCloudFile(aline);
                    cout << aline << " ... done!" << endl;
                    break;
                case 2: // Get pressure details
                    **grid = readPressureFile(aline);
                    cout << aline << " ... done!" << endl;
                    break;
            }
            fileCounter++;
        }
        
    }
    cout << endl;

    cout << "All records successfully stored. Going back to main menu ..." << endl;

    cout << endl;
    
    return **grid;
}

// Method for reading city file
gridTileDetails readCityFile(string filename) 
{
    
    // Create fstream object
    fstream input_file(filename.c_str(), fstream::in);

    string aline;

    while (getline(input_file, aline)) 
    {
        if (aline == "")
        {
            break;
        }

        vector<string> allConfigInfo = tokenizeString(aline, "-"); // Separates all data with delimiter "-" Eg. [1,1] 3 Big_City

        string gridString = allConfigInfo[0]; // Gets part of vector storing grid info
        string cityID = allConfigInfo[1];
        string cityName = allConfigInfo[2];
        
        gridString = gridString.substr(1, gridString.size() - 2); // Removes [ and ] brackets
        
        vector<string> gridValues = tokenizeString(gridString, ", "); // Get individual grid values

        // Get grid values
        int gridX = stoi(gridValues[0]);
        int gridY = stoi(gridValues[1]);
        
        // Get city ID
        int intCityID = stoi(cityID);

        // Inserting values into 2D array
        grid[gridX][gridY].cityID = intCityID;
        grid[gridX][gridY].isOccupied = true;
        grid[gridX][gridY].cityName = cityName;

    }
    return **grid;
}

我怀疑问题在于读取其他文件并用其数据(城市、云、压力文件)填充二维数组,但我似乎无法理解哪里出错了。

我尝试注释掉 processConfigFile 的底部,只是为了查看是否正确创建了 2D 数组而不向每个图块插入任何信息,尽管对齐有点混乱,有效(其中 x 为 8,y 为 10):

  # # # # # # # # # # # 
10 #                   # 
9 #                   # 
8 #                   # 
7 #                   # 
6 #                   # 
5 #                   # 
4 #                   # 
3 #                   # 
2 #                   # 
1 #                   # 
0 #                   # 
  # # # # # # # # # # # 
    0 1 2 3 4 5 6 7 8   

我没有包括读取其他文件的代码,因为它们大部分相同,只是做了一些小的调整。

如有任何帮助,我们将不胜感激!

好吧,让我们来解决这个明显的错误。我敢打赌这不是这个程序的唯一问题,因为通过它我看到了对内存、指针使用和对象生命周期的反复误解。

无论如何,这里有:

grid = new gridTileDetails * [gridSize.gridXHighestVal + 1];
for (int i = 0; i < gridSize.gridYHighestVal + 1; i++)
{
    grid[i] = new gridTileDetails[gridSize.gridYHighestVal + 1];
}

请注意,您分配了一个可以保存 gridSize.gridXHighestVal + 1 值的指针数组,但是您随后用 gridSize.gridYHighestVal + 1 值填充了该数组。如果尺寸不是正方形,那么您要么分配太少 sub-arrays,要么溢出缓冲区并将指针写入您没有业务写入的内存。

所以循环应该是:

for (int i = 0; i < gridSize.gridXHighestVal + 1; i++)