2017-01-15 2 views
1

У меня есть следующие программы и каждый раз, когда я бегу это иногда (большую часть времени) я получаю сообщение об ошибке кучи коррупцииC++ куча была повреждена ошибка при запуске программы

Я не могу ставить мой палец, где его происходит с тех пор, как каждый запуск он появляется в другом месте в моей программе.

Возможно, кто-то положил свет на него, пожалуйста?

PS повреждение кучи также поп, когда я пытаюсь СВОБОДНЫМ 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; 
    } 
} 
+1

Несмотря на то, что ошибки повреждения кучи трудно диагностировать (приветствуем вас на C++!), Вы пробовали ** пропустить ** свой код с помощью отладчика при исследовании значений переменных? EDIT: почему вы используете 'char *' вместо 'std :: string' внутри вашей' struct'? Почему вы передаете указатели на свои объекты, на свои функции, а не на ссылки? –

+1

вы программируете на C++, поэтому облегчайте свою жизнь с помощью классов и STL-контейнера. Использование raw-указателя в большинстве случаев является плохой идеей и создает много проблем. Просто используйте их, когда у вас есть законные причины. – Soeren

+0

Одна потенциальная проблема здесь: for (int i = 0; team-> players [i] .name! = NULL; i ++) '. Если в команде есть полный набор игроков, ни один из них не будет иметь пустого имени. –

ответ

5

Я не рассматривал весь код, но есть инструменты, которые могут помочь вам в этом ситуацию, которая отслеживает использование памяти и указывает, что что-то пошло не так. Одним из примеров является valgrind, который, по крайней мере, доступен для сред Linux. В любом случае, этот инструмент позволил мне найти по крайней мере одну ошибку в вашем коде следующим образом.

  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; 
    } 
    

    Вы создаете массив размера суммы + 1, но итерацию над ней до Team-> maxOfPlayers, которые могут или не могут быть одинаковыми. Это означает, что вы пишете в какую-либо память за пределами массива, который хотите изменить, и поэтому вы пишете где-нибудь в куче, где вы не должны (приводя к кучному повреждению).

Это по крайней мере одна проблема. Повторите 1.-4. пока у valgrind больше нечего жаловаться.

+0

Только один комментарий: не все люди компилируют свой C++ с g ++, и все люди не используют платформу, совместимую с valgrind. Поскольку ОП не описывал платформу, которую они используют, ответ должен либо содержать платформонезависимое, либо предлагать решение проблемы, либо не содержать это предположение на основе предпочтений. –

+0

Я должен признать, что я не знаю, какой инструмент доступен, например. в Visual Studio для этого, но я бы предположил, что кто-то редактирует ответ (или публикует другой), описывая его там. Использование таких инструментов очень помогает, так почему мы должны избегать публикации таких ответов? Тем не менее, я отредактирую ответ, обозначающий платформу. – koalo

+0

Решил мою проблему, Можете ли вы, пожалуйста, направить меня в учебник, объясняющий, как отлаживать это? – Brec

1

Вам нужно больше заботиться о том, как вы обращаетесь к массивам и отслеживаете их размеры.

Как уже отмечалось, 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; 
} 

sum + 1 может легко быть гораздо меньше, чем maxOfPlayers.В этом случае цикл for будет перезаписывать память за пределами массива. Это может быть причиной вашей текущей ошибки повреждения кучи.

Смежные вопросы