【问题标题】:Access violation reading location 0xcdcdcdcd. C++访问冲突读取位置 0xcdcdcdcd。 C++
【发布时间】:2011-04-05 02:11:49
【问题描述】:

基本上我在这一点上要做的是构建一个程序,允许你从 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).

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

【问题讨论】:

    标签: c++ memory unhandled-exception


    【解决方案1】:

    变量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】:

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

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

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

      【讨论】:

      • 也供将来参考 0xcdcdcdcd 通常意味着您指向未初始化的内存。所以这通常是你忘记设置的一个很好的迹象。
      • 您好感谢您帮助实施 string.h 解决了问题以及我没有初始化内存的事实。我最终做的是在冠军构造函数中为名称做一个 malloc 来设置正在实现的字符串名称的大小!谢谢大家的帮助!
      【解决方案3】:

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

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

      应改为:

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

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

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

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

      【讨论】:

      • 不,它仍然运行 5 次 0 到 4 总共运行 5 次,因为你从 0 开始,然后是 1,然后是 2 等等,一直到 4。你必须从 0 到 5,因为所有数组都从 0 而不是 1 开始
      • @Ziekle,您的 for 循环方式只能访问 03,但 4。将其更改为此答案中所说的内容,或更改为&lt;= 4
      • @Zieklecknerizer 不,循环永远不会在 i = 4 的情况下运行,因为您使用的是严格较少的运算符。
      • Zohmahgoodness 你把我带到那里哈哈我总是忘记那个=!谢谢!
      • 不幸的是我按照你说的做了并将它设置为
      【解决方案4】:

      检查

      return name;
      

      Champion::getName()
      

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


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

      【讨论】:

      • 名称在头文件中定义,并在构造函数中初始化。我会在标题中输入,但我不想输入太多信息 lulz
      【解决方案5】:

      如果指针成员不指向堆或堆栈上的任何地址,则将指针成员设置为 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 风格的编码。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-17
        • 1970-01-01
        相关资源
        最近更新 更多