【问题标题】:Heap corruption using strcat使用 strcat 的堆损坏
【发布时间】:2013-02-03 20:54:10
【问题描述】:

我的一个弱点是在 C++ 中有效地使用字符,这是我现在正在尝试做的。我的游戏中有一个玩家类,在玩家类中,我创建了一个显示各种信息的 playerCard 对象。这适用于播放器对象的单个实例(即播放器播放器),但是当我尝试将播放器对象推回向量时,一切都会出错。

基本上,程序会继续运行,但播放器不会渲染到屏幕上。当我退出程序时,当 main 尝试返回 MSG 时,我得到一个断点错误。关于断点的注释如下:

    /*
     * If this ASSERT fails, a bad pointer has been passed in. It may be
     * totally bogus, or it may have been allocated from another heap.
     * The pointer MUST come from the 'local' heap.
     */
    _ASSERTE(_CrtIsValidHeapPointer(pUserData));

我在这里找到了错误

    strcat(nameCard, nameChar);
    strcat(nameCard, genderChar);
    strcat(nameCard, ageChar);
    strcat(nameCard, cashHeldChar);
    strcat(nameCard, productWantedChar);

在 playerCard 类中,因为当我将其注释掉时,我没有收到错误消息。这是完整的 playerCard 类(同样,它很混乱,可能是错误的处理方式,但我正在尝试使用字符/字符串等来让我的头脑清醒) #include "Headers.h";

class Playercard{

private:

    RECT textbox;
    LPD3DXFONT font;

    std::string nameStr;
    std::string genderStr;
    std::string ageStr;
    std::string cashHeldStr;
    std::string prodWantedStr;

    char nameCard[1000];

public:

    Playercard()
    {
    }

    void load(char* name, bool male, int age, double cash, char* prod)
    {

        if(male)
        {
            genderStr = "Gender: Male\n";
        }
        else
        {
            genderStr = "Gender: Female\n";
        }

        nameStr = "Name: " + static_cast<std::ostringstream*>( &(std::ostringstream() << name))->str() + "\n";
        ageStr = "Age: " + static_cast<std::ostringstream*>( &(std::ostringstream() << age))->str() + "\n";
        cashHeldStr = "Cash Held: " + static_cast<std::ostringstream*>( &(std::ostringstream() << cash))->str() + "\n";
        prodWantedStr = "Product Wanted: " + static_cast<std::ostringstream*>( &(std::ostringstream() << prod))->str() + "\n";

        char * nameChar = new char [nameStr.length()+1];
        char * genderChar = new char [genderStr.length()+1];
        char * ageChar = new char [ageStr.length()+1];
        char * cashHeldChar = new char [cashHeldStr.length()+1];
        char * productWantedChar = new char [prodWantedStr.length()+1];

        strcpy(nameChar, nameStr.c_str());
        strcpy(genderChar, genderStr.c_str());
        strcpy(ageChar, ageStr.c_str());
        strcpy(cashHeldChar, cashHeldStr.c_str());
        strcpy(productWantedChar, prodWantedStr.c_str());

        strcat(nameCard, nameChar);
        strcat(nameCard, genderChar);
        strcat(nameCard, ageChar);
        strcat(nameCard, cashHeldChar);
        strcat(nameCard, productWantedChar);

        diagFile.open("Diag.txt");
        diagFile.write("Test", 100);
        diagFile.close();
    }

    void setUp(int L, int T, int R, int B)
    {
        SetRect(&textbox, L,T,R,B);
    }

    void draw()
    {
        font->DrawTextA(d3dSprite, nameCard, -1, &textbox, DT_LEFT, D3DCOLOR_XRGB(255, 255, 255));
    }

    LPCSTR plCard()
    {
        return nameCard;
    }
};

任何帮助将不胜感激。谢谢。

【问题讨论】:

  • 您使用字符数组和指针而不是连接 C++ 字符串然后使用c_str() 的任何原因?另外,只需使用nameStr = std::string("Name: ") + name + "\n";,或者更好的是,将字符串作为参数。
  • 谢谢,我会改用这个。正如我所提到的......字符串并不出色:/
  • 您不需要所有这些ostringstreams。例如,要构建nameStr,您可以使用nameStr = "Name: "; nameStr += name;nameSTr = std::string("Name: ") + name;。或者你根本做不到,只在你需要的时候生成这些东西。
  • 与通常出现的问题相比,这实际上是一个很好的问题。标题描述了问题,问题被正确地缩小到非常有限的范围,提供了我们需要查看的所有代码,仅此而已,而且,虽然它可能不是第一件值得注意的事情,但 OP 不是当他们真正寻找的答案被给出时,他们不必要地固执。
  • 哦,我刚刚注意到,就提供的代码而言,font 在取消引用 draw() 之前未初始化。您需要确保它已正确初始化。

标签: c++


【解决方案1】:

您的主要问题是 nameCard 未初始化。 strcat 需要一个以 null 结尾的字符串来发挥它的魔力,并且不能保证 nameCard 中的第一个或任何一个字符为 null。

但是,C 字符串是不必要的。一直使用std::string。将nameCard 更改为字符串后,我会将load 更改为(不包括文件写入):

void load(const std::string &name, bool male, int age, double cash, const std::string &prod)
{
    nameStr = "Name: " + name + "\n";
    genderStr = "Gender: " + (male ? "Male" : "Female") + "\n";
    ageStr = "Age: " + std::to_string(age) + "\n";
    cashHeldStr = "Cash Held: " + std::to_string(cash) + "\n";
    prodWantedStr = "Product Wanted: " + prod + "\n";

    nameCard = nameStr + genderStr + ageStr + cashHeldStr + prodWantedStr;
}

我实际上只是将nameCard 设为数据成员,删除其他成员,然后使用它:

nameCard.clear();
nameCard += "Name: " + name + "\n";
//add on other parts

除此之外,让plCard() 返回一个std::string 并在draw() 中使用nameCard.c_str()。我希望这能更清楚地说明你可以用字符串做什么。

但请注意,std::to_string 是 C++11。 C++03有两种常见的解决方案:

std::string str = boost::lexical_cast<std::string>(someNumber);

或者

std::ostringstream oss;
oss << someNumber;
std::string str = oss.str();

我发现三行比单行或两行更具可读性。

【讨论】:

    【解决方案2】:

    您的nameCard 未初始化。将第一个strcat 替换为strcpy,或将其初始化为零字符串。

    现在,单独使用std::string 怎么样?

    【讨论】:

    • 非常感谢!工作:) 是的,我非常清楚这需要一些我现在开始的工作!感谢您的帮助
    猜你喜欢
    • 2010-11-15
    • 2014-03-26
    • 2014-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-03
    • 2011-08-03
    相关资源
    最近更新 更多