Расположение чтения нарушения доступа 0xcdcdcdcd. C ++ - PullRequest
2 голосов
/ 05 апреля 2011

По сути, на данный момент я пытаюсь создать программу, которая позволит вам выбирать из 3 разных классов (танк, мел, дальний бой), когда вы выбираете класс, вы бы дали ему имя 20 или меньше. символы. После выбора 5 классов и присвоения имени каждому чемпиону будут напечатаны имя и здоровье каждого выбранного вами класса. код выглядит так:

#include "Driver.h"
#include <stdio.h> 
#include "Mele.h"
#include "Ranged.h"
#include "Tank.h"

int main(void)
{

Champion *champ[5];
int i, choice;

printf("Enter the number for which class you would like to add to your team\n");
for(i = 0; i <= 4; i++)
{
    char name[20];
    //printf("Enter the number for which class you would like to add to your team");
    printf("1 = Tank\n");
    printf("2 = Ranged\n");
    printf("3 = Mele\n");
    scanf_s("%d", &choice);
    if(choice == 1)
    {
        printf("Give him a name!\n");
        scanf("%s", name);
        champ[i] = new Tank(name);
    }
    else if(choice == 2){
        printf("Give him a name!\n");
        scanf("%s", name);
        champ[i] = new Ranged(name);
    }
    else if(choice == 3){
        printf("Give him a name!\n");
        scanf("%s", name);
        champ[i] = new Mele(name);
    }
    else
    {
        printf("You did not enter a number between 1 and 3 please try again!\n");
        i = i - 1;
    }
}
for(i = 0; i <= 4; i++)
{
    printf("%s has %f health", champ[i]->getName(), champ[i]->getHealth());
}
return 0;
}

Это основная функция

Класс чемпиона выглядит так:

Champion::Champion(void)
{
}
Champion::Champion(char name1[])
{ 
    name = name1;
}

char* Champion::getName(void)
{   
    return name;
}   

double Champion::getHealth(void)
{
    return health;
}

int Champion::getFluid(void)
{
    return fluid;
}

double Champion::getArmor(void)
{
    return armor;
}

double Champion::getSpecialA(void)
{
    return specialA;
}

double Champion::getDamage(void)
{
    return physDamage;
}

void Champion::setHealth(double health1)
{
    health = health1;
}
void Champion::setFluid(int fluid1)
{
    fluid = fluid1;
} 
void Champion::setArmor(double armor1)
{
    armor = armor1;
}
void Champion::getSpecialA(double specialA1)
{
    specialA = specialA1;
}
void Champion::setDamage(double physDamage1)
{
    physDamage = physDamage1;
}

Тогда у меня есть 4 других класса, которые называются Tank, Ranged и Mele; все они наследуются от Чемпиона и имеют ту же настройку, что и Чемпион. когда я запускаю программу, я получаю это:

'dragons_rage.exe': Loaded 'C:\Users\Tom\Documents\Visual Studio 2010\Projects\dragons_rage\Debug\dragons_rage.exe', Symbols loaded.
'dragons_rage.exe': Loaded 'C:\Windows\SysWOW64\ntdll.dll', Cannot find or open the PDB file
'dragons_rage.exe': Loaded 'C:\Windows\SysWOW64\kernel32.dll', Cannot find or open the PDB file
'dragons_rage.exe': Loaded 'C:\Windows\SysWOW64\KernelBase.dll', Cannot find or open the PDB file
'dragons_rage.exe': Loaded 'C:\Windows\SysWOW64\msvcr100d.dll', Symbols loaded.
First-chance exception at 0x5dfc14cf (msvcr100d.dll) in dragons_rage.exe: 0xC0000005: Access violation reading location 0xcdcdcdcd.
Unhandled exception at 0x5dfc14cf (msvcr100d.dll) in dragons_rage.exe: 0xC0000005: Access violation reading location 0xcdcdcdcd.
The program '[516] dragons_rage.exe: Native' has exited with code -1073741819 (0xc0000005).

Я не совсем уверен, что это за ошибки и что они значат, если я смогу получить какую-то помощь, что было бы замечательно, спасибо !!!!

Ответы [ 5 ]

4 голосов
/ 05 апреля 2011

Переменная char name [20] недопустима после выхода из первого for ()

Вам следует скопировать значение массива в конструкторе в массив внутри Champion или динамически выделить память для имени.

Это один из вариантов:

#include <stdio.h>
#include <string.h>

class Champion {
  char name[20];

 public:

 Champion(const char theName[],int size ){

  for( int i=0;i < size; i++ ){
    name[i] = theName[i];
  }
 }
 const char* getName(){
  return name;
 }
};

int main(int argc, const char* argv[]){

 Champion *c;
 const char name[] = "vamos";
 c = new Champion(name,strlen(name));
 printf("%s",c->getName());
 return 0;
}
4 голосов
/ 05 апреля 2011

Одна вещь, которая бросается в глаза, - это конструктор Champion:

Champion::Champion(char name1[])
{
}

Это ничего не делает с массивом символов - оно не инициализирует ни одного члена "name".Когда имя раздается позже, это ноль или, что еще хуже, мусор?Вероятно, вам нужно скопировать этот аргумент в переменную-член, чтобы у вас было имя, которое вы можете использовать позже.

1 голос
/ 05 апреля 2011

Ваш цикл выполняется только 4 раза, поэтому последний указатель Чемпиона никогда не инициализируется.

for(i = 0; i < 4; i++)

Следует изменить на:

for(i = 0; i < 5; i++)

Также никто из членов вашего Чемпионаclass инициализируются в конструкторе, поэтому их чтение приведет к неопределенному поведению.

Код, который вы написали, более или менее C с классами.Посмотрите std :: string, это сделает ваш код намного проще и правильнее.Как и сейчас, ваша программа содержит множественные уязвимости переполнения буфера и висячие указатели.

Если бы я был злым, я бы создал Танк с именем намного длиннее 20 символов и, вероятно, мог бы вывести из строя вашу программу илихуже, выполнить произвольный код, переписав свой текстовый сегмент.

0 голосов
/ 24 августа 2012

Принятие привычки устанавливать члены-указатели в 0 (NULL) - это конструктор, если они не указывают на какой-либо адрес в куче или в стеке.Это избавит вас от 0xcc ... неверных адресов.Если вы сделали с указателем, даже если указатель является частью двойного указателя, установите его обратно в 0 после освобождения объекта, на который он указывает.Вы несете ответственность за написание кода для этого.Другой вариант - перейти на язык программирования с управляемой памятью.

И с вашим кодом это

Champion** champ = (Champion**)malloc(sizeof(Champion*) * 5);
// or
Champion** champ = (Champion**)calloc(5, sizeof(Champion*));
// or
Champion** champ = new Champion*[5];

Какой способ выбора двойного указателя чемпиона зависит от вас.Я предпочитаю (Champion**)malloc(sizeof(Champion*) * 5), потому что я привык к кодированию в стиле C.

0 голосов
/ 05 апреля 2011

отметьте

return name;

в

Champion::getName()

где определено имя?Это инициализировано?


Когда вы делаете name = name1 в конструкторе, вы просто копируете указатель.В случае вашей программы это указатель на локальную переменную вашего цикла for.Эта переменная выходит из области видимости, как только вы оставите это для цикла.Вы должны использовать std :: string :: copy () или strcpy () , чтобы скопировать вашу строку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...