访问冲突读取位置0xcdcdcdcd。 C ++

时间:2011-04-05 02:11:50

标签: c++ memory unhandled-exception

基本上我在这一点上要做的是构建一个程序,允许你从3个不同的类(Tank,Mele,Ranged)中挑选,当你选择这个类时,你会给它一个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 个答案:

答案 0 :(得分:4)

突然出现的一件事是Champion构造函数:

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

这对字符数组没有任何作用 - 它不会初始化任何“name”成员。如果名字稍后发出,是否为空,或者更糟,垃圾?您可能需要将该参数复制到您的成员变量中,因此您可以使用稍后可以使用的名称。

答案 1 :(得分:4)

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

答案 2 :(得分:1)

你的循环只运行4次,所以最后一个冠军指针永远不会被初始化。

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

应改为:

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

此外,没有任何Champion类成员在构造函数中初始化,因此读取它们将导致未定义的行为。

您编写的代码或多或少是C类。查找std :: string,它将使您的代码更简单,更正确。就像现在一样,你的程序包含多个缓冲区溢出漏洞和悬空指针。

如果我是邪恶的,我会创建一个名称超过20个字符的坦克,可能会导致程序崩溃或者更糟糕的是,通过覆盖文本段来执行任意代码。

答案 3 :(得分:0)

检查

return name;

in

Champion::getName()

名称定义在哪里? 它被初始化了吗?


在构造函数中执行name = name1时,您只是复制指针。 对于程序,这是指向for循环中的局部变量的指针。 一旦你离开那个for循环,那个变量就超出了范围。 您应该使用std::string::copy()strcpy()复制字符串。

答案 4 :(得分:0)

习惯将指针成员设置为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风格编码。