c++运行程序时出现堆已损坏错误



我有下面的程序,每次运行它时(大多数时候)我都会收到堆损坏错误

我无法将我的手指放在它发生的地方,因为每次运行它都会在我的程序中的不同位置弹出。

有人能给它放点灯吗?

当我试图释放p 时,PS堆损坏也会弹出

提前感谢

#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"
#include<iostream>
#include<string.h>
using namespace std;
const int MAX_OF_PLAYERS = 10;
const int SIZE = 100;
struct player_t {
char *name;
int numOfShirt;
};
struct team_t {
char *nameOfTeam;
int maxOfPlayers;
int numOfPlayers;
player_t *players;
};
void readPlayer(player_t *player);
void initTeam(team_t *team);
void addPlayer(team_t *team);
void printTeam(team_t *team);
void freeAll(team_t *team);
player_t** getAllPlayersStartWithA(team_t *team);
void printAteam(player_t **p);
int main()
{
team_t t;
player_t **p;
initTeam(&t);
addPlayer(&t);
addPlayer(&t);
printTeam(&t);
p = getAllPlayersStartWithA(&t);
if (p[0] != NULL)
printAteam(p);
system("pause");
freeAll(&t);
//delete[] p;
}
void readPlayer(player_t *player)
{
char name[SIZE];
cout << " please enter the name of the player " << endl;
cin >> name;
cout << " please enter the num of the shirt " << endl;
cin >> player->numOfShirt;
int size = strlen(name);
char *res = new char[size + 2];
strcpy(res, name);
player->name = res;
}
void initTeam(team_t *team)
{
char name[SIZE];
// get the team name
cout << " please enter your team name" << endl;
cin >> name;
// get the name length
int size = strlen(name);
// allocate new array with length size
team->nameOfTeam = new char[size + 1];
// copy the string to the new array
strcpy(team->nameOfTeam, name);
// get the number of max players
cout << "please enter the number of the max players on your team" << endl;
cin >> team->maxOfPlayers;
// create new players array
player_t *players = new player_t[team->maxOfPlayers];
// initial the players array
for (int i = 0; i < team->maxOfPlayers; i++)
{
players[i] = { 0 };
}
//bind the array to team
team->players = players;
// set current players to 0
team->numOfPlayers = 0;
}
void addPlayer(team_t *team)
{
for (int i = 0; i < team->maxOfPlayers; i++)
{
if (team->players[i].name == NULL)
{
readPlayer(team->players + i);
break;
}
}
}
void printTeam(team_t *team)
{
cout << "Team name: ";
cout << team->nameOfTeam << endl;
cout << "Max Number of players in team: ";
cout << team->maxOfPlayers << endl;
cout << "Current number of players in team: ";
cout << team->numOfPlayers << endl;
cout << "Team Players:" << endl;
for (int i = 0; i < team->maxOfPlayers; i++)
{
if (team->players[i].name)
{
cout << "Player name: ";
cout << team->players[i].name;
cout << ", ";
cout << "Player shirt: ";
cout << team->players[i].numOfShirt << endl;
}
}
cout << endl;
}
void freeAll(team_t *team)
{
for (int i = 0; i < team->maxOfPlayers; i++)
{
if ((team->players + i)->name != NULL)
delete[](team->players + i)->name;
}
delete[] team->players;
}
player_t** getAllPlayersStartWithA(team_t *team)
{
int sum = 0, position = 0;
for (int i = 0; team->players[i].name != NULL; i++)
{
if (team->players[i].name[0] == 'a' || team->players[i].name[0] == 'A')
{
sum++;
}
}
player_t **p = new player_t*[sum + 1];
for (int i = 0; i < team->maxOfPlayers; i++)
{
p[i] = NULL;
}
for (int i = 0; team->players[i].name != NULL; i++)
{
if (team->players[i].name[0] == 'a')
{
p[position++] = team->players + i;
}
}
return p;
}
void printAteam(player_t **p)
{
cout << "Players start with 'A': " << endl;
for (int i = 0; p[i] != NULL; i++)
{
cout << "Player name: ";
cout << (p[i]->name);
cout << ", ";
cout << "Player shirt: ";
cout << (p[i]->numOfShirt) << endl;
}
}

我还没有查看整个代码,但在这种情况下,有一些工具可以帮助您跟踪内存的使用情况,并指示是否出现了问题。一个例子是valgrind,它至少适用于Linux环境。无论如何,这个工具允许我在你的代码中找到至少一个bug,如下所示。

  1. 使用调试信息进行编译。如果您使用的是gcc,请使用-g命令行标志,例如

    g++ foo.cpp -g -o foo -std=gnu++11
    
  2. 使用valgrind 运行

    valgrind ./foo
    
  3. 查看输出

    ==6423== Memcheck, a memory error detector
    ==6423== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
    ==6423== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
    ==6423== Command: ./foo
    ==6423== 
    please enter your team name
    sdfads
    please enter the number of the max players on your team
    3
    please enter the name of the player 
    efwf
    please enter the num of the shirt 
    5
    please enter the name of the player 
    dsfdsa
    please enter the num of the shirt 
    3
    Team name: sdfads
    Max Number of players in team: 3
    Current number of players in team: 0
    Team Players:
    Player name: efwf, Player shirt: 5
    Player name: dsfdsa, Player shirt: 3
    ==6423== Invalid write of size 8
    ==6423==    at 0x4011FF: getAllPlayersStartWithA(team_t*) (foo.cpp:155)
    ==6423==    by 0x400C08: main (foo.cpp:38)
    ==6423==  Address 0x5ab6668 is 0 bytes after a block of size 8 alloc'd
    ==6423==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==6423==    by 0x4011CC: getAllPlayersStartWithA(team_t*) (foo.cpp:151)
    ==6423==    by 0x400C08: main (foo.cpp:38)
    ==6423== 
    ==6423== 
    ==6423== HEAP SUMMARY:
    ==6423==     in use at exit: 72,719 bytes in 3 blocks
    ==6423==   total heap usage: 8 allocs, 5 frees, 74,829 bytes allocated
    ==6423== 
    ==6423== LEAK SUMMARY:
    ==6423==    definitely lost: 15 bytes in 2 blocks
    ==6423==    indirectly lost: 0 bytes in 0 blocks
    ==6423==      possibly lost: 0 bytes in 0 blocks
    ==6423==    still reachable: 72,704 bytes in 1 blocks
    ==6423==         suppressed: 0 bytes in 0 blocks
    ==6423== Rerun with --leak-check=full to see details of leaked memory
    ==6423== 
    ==6423== For counts of detected and suppressed errors, rerun with: -v
    ==6423== ERROR SUMMARY: 2 errors from 1 contexts (suppressed: 0 from 0)
    
  4. 显然,根据的输出,第155行出现了问题

    ==6423== Invalid write of size 8
    ==6423==    at 0x4011FF: getAllPlayersStartWithA(team_t*) (foo.cpp:155)
    

    如果我们仔细观察,我们会看到以下内容:

    player_t **p = new player_t*[sum + 1];
    for (int i = 0; i < team->maxOfPlayers; i++)
    {
    p[i] = NULL;
    }
    

    您创建了一个大小为sum+1的数组,但对其进行迭代,直到team->maxOfPlayers,这可能相同,也可能不同。这意味着您要写入要修改的数组之外的一些内存,因此您要在堆中不应该写入的地方写入(导致堆损坏)。

这至少是一个问题。重复1-4。直到valgrind没有什么可抱怨的了。

您需要更加注意如何访问数组并跟踪它们的大小。

正如已经指出的那样,for (int i = 0; team->players[i].name != NULL; i++)是在自讨苦吃。您应该确保循环受到某些东西的约束,要么是players数组中的条目总数(可能是maxOfPlayers),要么是当前有效玩家的数量(看起来应该是numOfPlayers)。然而,在添加新条目时,您的代码从未实际增加numOfPlayers

来自getAllPlayersStartWithA的以下代码也是一个问题:

player_t **p = new player_t*[sum + 1];
for (int i = 0; i < team->maxOfPlayers; i++)
{
p[i] = NULL;
}

CCD_ 7可以容易地比CCD_ 8小得多。在这种情况下,for循环将覆盖数组末尾以外的内存。这很可能是当前堆损坏错误的原因。

相关内容

最新更新