2

基本的に、この時点で私がやろうとしているのは、クラスを選択するときに 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;
}

次に、Tank、Ranged、Mele と呼ばれる他の 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

変数charname[20]は、最初のfor()を残した後は無効です。

コンストラクター内の配列の値をChampion内の配列にコピーするか、名前に動的にメモリを割り当てる必要があります。

これは1つのオプションです。

#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 に答える
4

すぐに思いつくのは、Champion コンストラクターです。

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

これは、文字配列に対して何も行いません。「name」メンバーを初期化しません。後で名前が渡されたとき、それは null ですか、それとももっと悪いことにゴミですか? おそらく、その引数をメンバー変数にコピーする必要があるため、後で使用できる名前を付けます。

于 2011-04-05T02:17:38.970 に答える
1

ループは 4 回しか実行されないため、最後の Champion ポインターは初期化されません。

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

次のように変更する必要があります。

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

また、Champion クラスのメンバーはコンストラクターで初期化されないため、それらを読み取ると未定義の動作が発生します。

あなたが書いたコードは、多かれ少なかれクラスを持つCです。std::string を調べると、コードがより単純で正確になります。現時点では、プログラムには複数のバッファ オーバーフローの脆弱性とダングリング ポインタが含まれています。

もし私が悪なら、20 文字をはるかに超える名前のタンクを作成し、プログラムをクラッシュさせたり、さらに悪いことに、テキスト セグメントを上書きして任意のコードを実行したりできます。

于 2011-04-05T02:19:40.860 に答える
0

ポインター メンバーを 0 (NULL) に設定することを習慣にしてください。コンストラクターは、ヒープまたはスタック上のいずれのアドレスも指していない場合です。これを行うと、0xcc...無効なアドレスからあなたを救うことができます。ポインターが double ポインターの一部であってもポインターを使い終わった場合は、それが指しているオブジェクトを解放した後、ポインターを 0 に戻します。そうするコードを書くのはあなたの責任です。もう 1 つのオプションは、代わりにマネージ メモリ プログラミング言語を使用することです。

そして、あなたのコードで、それは

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 に答える
0

を確認してください

return name;

Champion::getName()

名前はどこで定義されていますか? 初期化されていますか?


コンストラクターで行う場合name = name1、ポインターをコピーするだけです。プログラムの場合、これは for ループ内のローカル変数へのポインターです。その for ループを終了すると、その変数は範囲外になります。文字列をコピーするには、 std::string::copy()またはstrcpy()を使用する必要があります。

于 2011-04-05T02:24:06.493 に答える