【问题标题】:Getting weird return value from char* in c++在 C++ 中从 char* 获取奇怪的返回值
【发布时间】:2012-09-01 19:20:53
【问题描述】:

我是 C++ 编程的新手,我从我设置的 char* 变量返回一个奇怪的值,这取决于我如何使用它。我显然在做一些非常愚蠢的事情,但我看不到问题所在。接下来的几段描述了设置(很糟糕),但只看输出和代码可能更容易。

基本上,我有几个类 - Menu 和 MenuItem。 MenuItem 类有一个 char* 类型的名称。根据我使用菜单项的方式,当我在 MenuItems 上执行 getName() 时会得到奇怪的结果。

我有一个具有状态 (TestState) 的 Machine 类。此 TestState 创建一个包含 MenuItems 的菜单。当我在我的主函数中创建一个 TestState 并让它打印出菜单时,我得到了我所期望的。当我创建一个包含 TestState 的机器并要求它打印菜单时,它会为菜单中的根项目的名称打印一些奇怪的东西。

输出 - 最后一行我期待 menuItem1,但我得到 HâΔHã=ò

Output direct from TestState Object

Displaying menu state 
menuItem1
root not null 
menuItem1


Output from TestState within Machine

Displaying menu state 
menuItem1
root not null 
Hâ∆Hã=ò

这是我的代码 - Main.cpp

#include "Menu.h"
#include "Machine.h"
#include <iostream>

using namespace std;

Machine m;
TestState t;

int main(void) {
    cout << "Output direct from TestState Object" << endl << endl;
    t = TestState();
    t.print();


    cout << endl << endl << "Output from TestState within Machine" << endl << endl;
    m = Machine();
    m.printCurrentState();
}

Menu.h

#ifndef Menu_h
#define Menu_h

#include <stdlib.h>

class MenuItem {
public:
    MenuItem();
    MenuItem(const char* itemName);
    const char* getName() const ;

protected:
    MenuItem *next;
    const char* name;
};

class Menu {
public:
    Menu(MenuItem *rootItem);
    Menu();
    void setRoot(MenuItem *r);
    MenuItem* getRoot() ;
protected:
    MenuItem *root;
};

#endif

Machine.h

#ifndef MACHINE_H_
#define MACHINE_H_

#include "Menu.h"

class TestState;
class Machine;

class TestState {
public:
    TestState();
    virtual ~TestState();
    void print();
protected:
    Machine* machine;
    MenuItem menuItem1;
    Menu menuMain;
};

class Machine {
public:
    Machine();
    void printCurrentState();
protected:
    TestState testState;
};

#endif /* MACHINE_H_ */

Machine.cpp

#include "Machine.h"
#include <iostream>
using namespace std;

TestState::TestState() {
    menuItem1 = MenuItem("menuItem1");
    menuMain = Menu(&menuItem1);
}

void TestState::print(){
    cout << "Displaying menu state " << endl;
    cout << menuItem1.getName() << endl;

    if (menuMain.getRoot() == NULL) {
        cout << "root is null" << endl;
    } else {
        cout << "root not null " << endl;
        cout << menuMain.getRoot()->getName() << endl;
    }
}

TestState::~TestState() {
    // TODO Auto-generated destructor stub
}

Machine::Machine() {
    testState = TestState();
}

void Machine::printCurrentState() {
    testState.print();
}

任何帮助将不胜感激。我有点失落。 谢谢 戴夫

【问题讨论】:

  • 这不可能是解决问题所需的最少代码量。另外,为什么要同时包含
  • 在发帖之前,您确实应该自己缩小问题范围。这是很多代码要经过。
  • @oldrinb:并不是每个人都在使用 C++11 编译器。 NULL 工作得很好。 nullptr 只是消除了边缘情况下的一些潜在错误。
  • Wug - 对包含的公平评论 - 不需要 stdio.h。至于代码量 - 我已经剥离了原始 Machine 类以减少我的代码量,而 TestState 只是 Machine 可能处于的多种可能状态之一。这些类在这种精简的状态,但它们运行,并证明了我遇到的问题 - 除非我忘记了什么:)
  • pmr - 我尽量缩小范围,同时仍然包含我认为必要的所有代码。我知道这很多,但我认为最好包括太多而不是留下空白。不过,我想我在描述问题方面做得并不好。

标签: c++ char


【解决方案1】:

我怀疑发生了什么是Menu.root 指向某处的临时对象。您会注意到您在 main 函数中复制了您的机器:

// in main():
m = Machine(); // makes a machine, then copies it

那台机器有一个TestState,它有一个MainMenu,它有一个指向MenuItem的指针:

// in MenuItem class definition:
MenuItem *root;

该指针被初始化为原始机器成员的地址。问题是,该对象只存在很短的时间:当复制完成时它被销毁,留下一个悬空指针。

换句话说,您需要确保在复制包含指针的对象时,更新这些指针以反映复制对象的地址,而不是旧的。

您需要添加如下复制构造函数:

Machine::Machine(const Machine& other)
{
    teststate = other.teststate;
    teststate.machine = this; // you will need to expose TestState.machine to Machine
}

TestState::TestState(const TestState& other)
{
    machine = other.machine; // Machine copy constructor modifies this for us

    menuItem1 = other.menuItem1; // these 3 we have to do
    menuItem2 = other.menuItem2;
    menuMain = other.menuMain;

    menuMain.setRoot(&menuItem1); // update pointers to be to persistent copies
    menuItem1.setNext(&menuItem2);
    menuItem2.setNext(NULL);
}

您可能会注意到您的系统相当脆弱。我建议少依赖对象之间的指针,因为这条路是龙。

【讨论】:

  • +1 我为您在所有代码中所做的努力表示赞赏。我不会。
  • Wug,非常感谢您的回答 - 它解决了我的问题,我非常感谢。似乎 C++ 比我意识到的要复杂一些——我什至不知道复制构造函数 :)
【解决方案2】:
TestState::TestState() {
    menuItem1 = MenuItem("menuItem1");
    menuItem2 = MenuItem("menuItem2");
    menuMain = Menu(&menuItem1);
    menuMain.add(&menuItem2);
}

Machine::Machine() {
    testState = TestState();
}

Machine 构造函数构造一个临时的TestState 并将其数据成员复制到Machine::testState。当Machine 构造函数完成后,临时的TestState 消失了,但Machine::testState.menuMain.root 仍然指向临时的成员。

如何解决:

了解初始化变量的各种不同方式的含义,以及如何在构造函数中使用初始化列表。

【讨论】:

  • Oktalist,感谢您提供的信息。关于“如何修复”的公平评论 - 我通常是 Javamonkey,我只将 c++ 用于一个小的一次性项目。我希望能做到这一点,避免做太多严肃的阅读,但我想这开始看起来是个坏主意。是时候看书了:-)
  • @GabbyMoore 与 C++ 没有这样的事情。最好的办法是了解指针如何工作以及位/字节/布局如何工作。您可以使用零指针成功(并在任何地方使用引用),但在这种情况下,您确实需要不使用指针并使用 STL(字符串/双端队列可能会让您解决大多数问题)。
  • 关于使用 STL - 我正在尝试避免这种情况,因为我正在编写一个内存很少的芯片,我担心它会使我的代码膨胀。
【解决方案3】:

不要写Thing name = Thing(ctorParams);,而是将名称设为指针并使用new Thing(ctorParams);。看起来你以为你在使用指针,但它在没有 new 关键字的情况下工作,所以你继续并没有使用它们,这导致了你的错误。

【讨论】:

  • 谢谢酸,虽然我不太明白你在说什么——我仍然认为我在使用指针:-)。但是,我明天会做一些研究,看看我是否能解决这个问题。感谢您的帮助。
  • 在类 TestState Menu menuMain 不是一个指针,你写 menuMain = Menu(&amp;menuItem1); 这是......没有做你认为的那样。
【解决方案4】:

Machine 没有复制构造函数,因此Machine(特别是TestState)内的各种指针和引用都指向垃圾。

【讨论】:

  • 如果没有明确指定复制构造函数,则执行成员复制。
  • @Wug 是这样吗?看TestState的构造函数。
  • @ecatmur:所以......缺少显式复制构造函数并不意味着新实例中的任何指针“指向垃圾”,即未初始化。它们指向复制的指针指向的任何内容。
  • 仅仅拥有复制构​​造函数并不能解决这个问题。在这个特定实例中,默认的复制构造函数是不够的,需要额外的行为来防止指向原始对象的指针在复制后持续存在。您的答案在描述必要行为方面做得很差,所以-1。为了记录,问题只是一个变相的指向临时变量的指针。
  • 感谢您输入 ecatamur
猜你喜欢
  • 2021-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-29
  • 2015-09-30
  • 2020-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多