释放2d数组时内存泄漏

Memory leak whilst freeing a 2d array

本文关键字:内存 泄漏 数组 2d 释放      更新时间:2023-10-16

我正在创建一个版本的康威的生命游戏。它最终将在Arduino上运行,并将控制led,因此内存占用很重要。似乎我有一个内存泄漏,我相信这个泄漏发生在释放一个二维数组。如果有人能帮我做这件事,我将非常感激。

谢谢,乔

VLD的输出为:

c:projectsgameoflifecppgameoflifecppgameoflifecpp.cpp (72): GameOfLifeCPP.exe!GenerateGrid + 0xA bytes
c:projectsgameoflifecppgameoflifecppgameoflifecpp.cpp (185): GameOfLifeCPP.exe!ProcessGrid + 0x7 bytes
c:projectsgameoflifecppgameoflifecppgameoflifecpp.cpp (46): GameOfLifeCPP.exe!wmain + 0x9 bytes
f:ddvctoolscrt_bldself_x86crtsrccrtexe.c (552): GameOfLifeCPP.exe!__tmainCRTStartup + 0x19 bytes
f:ddvctoolscrt_bldself_x86crtsrccrtexe.c (371): GameOfLifeCPP.exe!wmainCRTStartup
0x7C817077 (File and line number not available): kernel32.dll!RegisterWaitForInputIdle + 0x49 bytes

代码是:

// GameOfLifeCPP.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include <vld.h>
#define WIDTH 75
#define HEIGHT 88
#define GENERATION_COUNT_LIMIT -1
long _generationCount = 0;
// These get set by controls on the table
long _delay = 1000;
bool _run = true;
bool _trail = true;
bool _randomize = false;
char* _colours = "roy";
int _tmain(int argc, _TCHAR* argv[])
{   
system("pause");
short** grid = GenerateGrid(false);
short** trailGrid = GenerateGrid(true); // This is used to record all prev cells
while(_run)
{
    if (_randomize)
    {
        grid = GenerateGrid(false);
        trailGrid = GenerateGrid(true);
        // Fade out LEDs
        // Clear the historical grids that we compare
        _randomize = false;
        _generationCount = 0;
    }
    OutputGrid(grid, trailGrid);
    if (_trail)
        trailGrid = CalculateTrailGrid(grid, trailGrid);
    short** nextGrid = ProcessGrid(grid);
    // Release the old grid
    for(int i = 0; i < sizeof(nextGrid); i++)
    {
        delete(grid[i]);
    }
    delete(grid);
    grid = nextGrid;
    // We don't want to just sleep we need to find out the start and end time
    Sleep(_delay);
    bool foundRecurance = false; 
    // Need to detect recurence, have a buffer of 5-10 prev grids and one 
    // hundredth ago, one thousanth etc that we compare to.
    _generationCount++;
    if (foundRecurance || _generationCount == GENERATION_COUNT_LIMIT)
        _randomize = true;
    _CrtDumpMemoryLeaks();
    //system("pause");
}
return 0;
}
short** GenerateGrid(bool empty)
{
// The coordinates are y,x because it is simpler to output a row of chars 
// when testing in the command line than it is to output a column of chars
short** grid = new short*[HEIGHT];
for(int y = 0; y < HEIGHT; y++)
{
    short* row = new short[WIDTH];
    for(int x = 0; x < WIDTH; x++)
    {
        // There is no point creating random numbers that we aren't going 
        // to use
        if (empty)
            row[x] = 0;
        else
            row[x] = rand() % 5 == 1 ? 1 : 0; 
        // Might want to adjust this or make it random
    }
    grid[y] = row;
}
return grid;
}
void OutputGrid(short** grid, short** trailGrid)
{
// This is terribly inefficent but I don't care since it is only for 
// testing on my laptop
system("cls");
HANDLE hConsole;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
for(int y = 0; y < HEIGHT; y++)
{
    for(int x = 0; x < WIDTH; x++)
    {
        int curState = grid[y][x];
        if (curState == 0 && _trail) // If it isn't alive then show the trail
            curState = trailGrid[y][x];
        switch (curState)
        {
            case 0:  SetConsoleTextAttribute(hConsole, 0); break;
            case 1: SetConsoleTextAttribute(hConsole, GetColour(0)); break;
            case 2: SetConsoleTextAttribute(hConsole, GetColour(1)); break;
            case -1: SetConsoleTextAttribute(hConsole, GetColour(2)); break;
        }
        //if (curState == 1 || curState == 2)
        //  std::cout << "*";
        //else
            std::cout << " ";
    }
    SetConsoleTextAttribute(hConsole, 15);
    std::cout << std::endl;
}
}
int GetColour(int index)
{
int colour = 0;
switch(_colours[index])
{
    case 'r': colour = 12; break;
    case 'o': colour = 6; break;
    case 'y': colour = 14; break;
}
colour = colour * 16;
return colour;
}
int ProcessCell(short** grid, int x, int y)
{
// Get the value for each of the surrounding cells
// We use the formula (x - 1 + WIDTH) % WIDTH because that means that if the
// Current cell is at 0,0 then top left is WIDTH-1,WIDTH-1 and so on.
// This makes the grid wrap around.
// We don't care if the cells value is 1 or 2 it is either live or dead
int topLeft = (
    grid[(y - 1 + HEIGHT) % HEIGHT][(x - 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
int top = (grid[(y - 1 + HEIGHT) % HEIGHT][x] > 0) ? 1 : 0;
int topRight = 
    (grid[(y - 1 + HEIGHT) % HEIGHT][(x + 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
int left = (grid[y][(x - 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
int self = (grid[y][x] > 0) ? 1 : 0;
int right = (grid[y][(x + 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
int bottomLeft = 
    (grid[(y + 1 + HEIGHT) % HEIGHT][(x - 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
int bottom = (grid[(y + 1 + HEIGHT) % HEIGHT][x] > 0) ? 1 : 0;
int bottomRight = 
    (grid[(y + 1 + HEIGHT) % HEIGHT][(x + 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
// Count up the surrounding cells to decide the current cell's state
int liveCount = topLeft + top + topRight + left + 
    right + bottomLeft + bottom + bottomRight;
int live = 0;
if (self > 0)
{
    // Both are alive, just different colours
    if (liveCount == 2)
        live = 1;
    if (liveCount == 3)
        live = 2;
}
else if (liveCount == 3)
{
    // Brought back to life, we don't care that it is the wrong 
    // colour - it looks better
    live = 1; 
}
return live;
}
short** ProcessGrid(short** grid)
{
short** nextGrid = GenerateGrid(true);
for (int y = 0; y < HEIGHT; y++)
{
    for (int x = 0; x < WIDTH; x++)
    {
        nextGrid[y][x] = ProcessCell(grid, x, y);
    }
}
return nextGrid;
}
short** CalculateTrailGrid(short** grid, short** trailGrid)
{
// Any previously live cells are marked
short** nextGrid = GenerateGrid(true);
for (int y = 0; y < HEIGHT; y++)
{
    for (int x = 0; x < WIDTH; x++)
    {
        int state = grid[y][x];
        if (state == 0)
            state = trailGrid[y][x]; // Not alive currently but was
        if (state != 0)
            state = -1;
        nextGrid[y][x] = state;
    }
}
return nextGrid;
}

只需在记事本中快速清理5分钟…我应该给你一些建议……避免任何可能的内存泄漏…

#include "stdafx.h"
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include <vld.h>
#include <vector>
#define WIDTH 75
#define HEIGHT 88
#define GENERATION_COUNT_LIMIT -1
long _generationCount = 0;
// These get set by controls on the table
long _delay         = 1000;
bool _run           = true;
bool _trail         = true;
bool _randomize     = false;
char* _colours      = "roy";
typedef std::vector<std::vector<short>> grid_t; // Use std::vector
int _tmain(int argc, _TCHAR* argv[])
{   
    system("pause");
    grid_t grid         = GenerateGrid(false);
    grid_t trailGrid    = GenerateGrid(true); // This is used to record all prev cells
    while(_run)
    {
        if (_randomize)
        {
            grid = GenerateGrid(false);
            trailGrid = GenerateGrid(true);
            // Fade out LEDs
            // Clear the historical grids that we compare
            _randomize = false;
            _generationCount = 0;
        }
        OutputGrid(grid, trailGrid);
        if (_trail)
            trailGrid = CalculateTrailGrid(grid, trailGrid);
        grid_t nextGrid = ProcessGrid(grid);
        // Release the old grid
        grid = nextGrid;
        // We don't want to just sleep we need to find out the start and end time
        Sleep(_delay);
        bool foundRecurance = false; 
        // Need to detect recurence, have a buffer of 5-10 prev grids and one 
        // hundredth ago, one thousanth etc that we compare to.
        _generationCount++;
        if (foundRecurance || _generationCount == GENERATION_COUNT_LIMIT)
            _randomize = true;
        _CrtDumpMemoryLeaks();
        //system("pause");
    }
    return 0;
}
grid_t GenerateGrid(bool empty)
{
    // The coordinates are y,x because it is simpler to output a row of chars 
    // when testing in the command line than it is to output a column of chars
    grid_t  grid;
    for(int y = 0; y < HEIGHT; y++)
    {
        std::vector<short> row;
        for(int x = 0; x < WIDTH; x++)
            row[x] = empty ? 0 : rand() % 5 == 1 ? 1 : 0; 
        grid.push_back(row);
    }
    return grid;
}
void OutputGrid(const grid_t& grid, const grid_t& trailGrid)
{
    // This is terribly inefficent but I don't care since it is only for 
    // testing on my laptop
    system("cls");
    HANDLE hConsole;
    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    for(int y = 0; y < HEIGHT; y++)
    {
        for(int x = 0; x < WIDTH; x++)
        {
            int curState = grid[y][x];
            if (curState == 0 && _trail) // If it isn't alive then show the trail
                curState = trailGrid[y][x];
            switch (curState)
            {
                case  0: SetConsoleTextAttribute(hConsole, 0);            break;
                case  1: SetConsoleTextAttribute(hConsole, GetColour(0)); break;
                case  2: SetConsoleTextAttribute(hConsole, GetColour(1)); break;
                case -1: SetConsoleTextAttribute(hConsole, GetColour(2)); break;
            }
        }
        SetConsoleTextAttribute(hConsole, 15);
        std::cout << std::endl;
    }
}
int GetColour(int index)
{
    switch(_colours[index])
    {
        case 'r': return 16 * 12;
        case 'o': return 16 * 6;
        case 'y': return 16 * 14;
        default:  return 0;     
    }
}
int ProcessCell(const grid_t& grid, int x, int y)
{
    // Get the value for each of the surrounding cells
    // We use the formula (x - 1 + WIDTH) % WIDTH because that means that if the
    // Current cell is at 0,0 then top left is WIDTH-1,WIDTH-1 and so on.
    // This makes the grid wrap around.
    // We don't care if the cells value is 1 or 2 it is either live or dead
    int topLeft     = (grid[(y - 1 + HEIGHT) % HEIGHT][(x - 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
    int top         = (grid[(y - 1 + HEIGHT) % HEIGHT][x] > 0) ? 1 : 0;
    int topRight    = (grid[(y - 1 + HEIGHT) % HEIGHT][(x + 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
    int left        = (grid[y][(x - 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
    int self        = (grid[y][x] > 0) ? 1 : 0;
    int right       = (grid[y][(x + 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
    int bottomLeft  = (grid[(y + 1 + HEIGHT) % HEIGHT][(x - 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
    int bottom      = (grid[(y + 1 + HEIGHT) % HEIGHT][x] > 0) ? 1 : 0;
    int bottomRight = (grid[(y + 1 + HEIGHT) % HEIGHT][(x + 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
    // Count up the surrounding cells to decide the current cell's state
    int liveCount = topLeft + top + topRight + left + right + bottomLeft + bottom + bottomRight;
    int live = 0;
    if (self > 0)
    {
        // Both are alive, just different colours
        if (liveCount == 2)
            live = 1;
        if (liveCount == 3)
            live = 2;
    }
    else if (liveCount == 3)
    {
        // Brought back to life, we don't care that it is the wrong 
        // colour - it looks better
        live = 1; 
    }
    return live;
}
grid_t ProcessGrid(const grid_t& grid)
{
    grid_t nextGrid = GenerateGrid(true);
    for (int y = 0; y < HEIGHT; y++)
    {
        for (int x = 0; x < WIDTH; x++)     
            nextGrid[y][x] = ProcessCell(grid, x, y);       
    }
    return nextGrid;
}
grid_t CalculateTrailGrid(const grid_t& grid, const grid_t& trailGrid)
{
    // Any previously live cells are marked
    grid_t nextGrid = GenerateGrid(true);
    for (int y = 0; y < HEIGHT; y++)
    {
        for (int x = 0; x < WIDTH; x++)     
            nextGrid[y][x] = state == 0 ? trailGrid[y][x] : -1;     
    }
    return nextGrid;
}