2

本质上,我现在要做的是构建一个程序,允许您在选择类时从 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 个职业,分别是坦克、远程和近战;所有这些都继承自 Champion 并具有与 Champion 相同的设置。当我运行程序时,我得到了这个:

'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).

我不确定这些错误是什么以及它们意味着什么,如果我能得到一些帮助,那将是惊人的谢谢!!!!

4

5 回答 5

4

让我印象深刻的一件事是 Champion 构造函数:

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

这对字符数组没有任何作用——它没有初始化任何“名称”成员。当名字稍后分发时,它是空的,还是更糟的是,垃圾?您可能需要将该参数复制到您的成员变量中,这样您就有了一个以后可以使用的名称。

于 2011-04-05T02:17:38.970 回答
4

离开第一个 for() 后,变量 char name[20] 无效

您应该将构造函数中的数组值复制到 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;
}
于 2011-04-05T02:27:25.577 回答
1

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

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

应改为:

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

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

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

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

于 2011-04-05T02:19:40.860 回答
0

检查

return name;

Champion::getName()

名称在哪里定义?是否已初始化?


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

于 2011-04-05T02:24:06.493 回答
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 风格的编码。

于 2012-08-24T08:51:38.430 回答