[解決済み】c++でプログラム実行時にヒープが破壊されたエラーが発生する。
2022-02-04 02:54:33
質問内容
以下のプログラムを持っていますが、実行するたびに時々(ほとんどの場合)ヒープ破壊のエラーが発生します。
実行するたびにプログラムの別の場所にポップするので、どこで起こっているのか指をくわえて見ていることはできません。
どなたか、この問題を解決する方法を教えてください。
P.S ヒープ破壊は、私がpを解放しようとしているときにもポップアップします。
ありがとうございました。
#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;
}
}
解決方法は?
私はコード全体をレビューしたわけではありませんが、このような状況で役に立つ、メモリの使用状況を追跡し、何か問題が発生した場合に表示するツールがあります。その一例が、少なくともLinux環境では利用可能なvalgrindです。とにかく、このツールを使って、あなたのコードに少なくとも1つのバグを以下のように見つけることができました。
-
デバッグ情報を入れてコンパイルする。gccを使用している場合は、-gコマンドラインフラグを使用します。
g++ foo.cpp -g -o foo -std=gnu++11
-
valgrindで実行する
valgrind ./foo
-
出力を見る
==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)
-
この出力によると、どうやら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つの問題点です。valgrindが他に文句を言うことがなくなるまで、1.-4.を繰り返してください。
関連
-
[解決済み】非静的メンバ関数への参照を呼び出す必要がある
-
[解決済み】C++ 式はポインタからオブジェクトへの型を持っている必要があります。
-
[解決済み】IntelliSense:オブジェクトに、メンバー関数と互換性のない型修飾子がある
-
[解決済み】エラー。switchステートメントでcaseラベルにジャンプする
-
[解決済み】警告 - 符号付き整数式と符号なし整数式の比較
-
[解決済み] 配列のベクトルを扱う正しい方法
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む
-
[解決済み] 8192個の要素にループをかけると、プログラムが遅くなるのはなぜですか?
-
[解決済み] 関数/メソッドのキーワード 'inline' はいつ書けばよいのですか?
-
[解決済み] プログラムがクラッシュしたときにスタックトレースを自動的に生成する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】 unsigned int vs. size_t
-
[解決済み】C++コンパイルタイムエラー:数値定数の前に期待される識別子
-
[解決済み】致命的なエラー LNK1169: ゲームプログラミングで1つ以上の多重定義されたシンボルが発見された
-
[解決済み】関数名の前に期待されるイニシャライザー
-
[解決済み】浮動小数点例外エラーが発生する: 8
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み】CMakeエラー at CMakeLists.txt:30 (project)。CMAKE_C_COMPILER が見つかりませんでした。
-
[解決済み] 解決済み] `pthread_create' への未定義の参照 [重複] [重複
-
[解決済み】 while(cin) と while(cin >> num) の違いは何ですか?)
-
[解決済み] to_string は std のメンバーではない、と g++ が言っている (mingw)