如何在实例化时使用用户输入初始化类构造函数中的私有char *

时间:2015-10-16 20:57:43

标签: c++ pointers c++11 constructor

以下程序在构造函数定义中崩溃。显然我不能使用构造函数将给定字符串复制到品牌变量中的私有类变量_brand。

我在哪里错了?我们的想法是获取品牌名称的用户输入,并将该名称实例化为_brand。

编辑:请不要建议使用 std :: string 类,因为我在这个问题上遇到了c字符串。这是中级C ++大学课程的一小部分作业。在我们进入STL字符串类之前,教授希望我们在C字符串中有一个基础。该指令明确禁止使用std :: string。 THX。

#include <iostream>
#include <cstring>

class Cheese {
    char * _brand;
public:
    Cheese(const char *); // constructor declaration
    char * getBrand();
};
Cheese::Cheese(char const * b) { // constructor definition
    strcpy(_brand, b); // CRASHES HERE
}
char * Cheese::getBrand() {
     return _brand;
}
int main(int argc, const char * argv[]) {
    const char * brand = "Cabot";
    Cheese * cheddar = new Cheese(brand);
    std::cout << cheddar -> getBrand();
    return 0;
}

4 个答案:

答案 0 :(得分:3)

_brand只是一个指针,在创建类时没有在其后面分配内存。当您尝试strcpy时,它可能是NULL或指向您的程序无法访问的内存,因此它会崩溃。您可以使用strdup来分配内存,但之后您必须free,例如在析构函数中。最好是使用标准C ++ std::string

答案 1 :(得分:3)

正如其他人所指出的那样,_brand只是一个指针。它不存储字符串,它指向字符串开始的内存地址。那个记忆空间是你必须保留的东西。

解决方案非常简单:

_brand = new char[strlen(b)+1]; // Reserve memory chunk for your copied string. Add +1 for string terminator '\0'
strcpy(_brand, b); // "CRASHES HERE" should be gone now

通过说 new ,_brand变量现在指向一个有效的内存块(由程序拥有),大到足以存储复制的字符串。

最后,不要忘记免费 _brand以避免内存泄漏。

答案 2 :(得分:1)

在C和C ++中,指针指向内存中的某个位置。访问指针允许您从它指向的位置读取和写入。在您的程序中,成员_brand是一个尚未初始化的指针,它没有定义它所指向的位置。读取和写入未初始化的指针是未定义的行为,这意味着一切都没有发生。这通常意味着程序会崩溃,但由于行为未定义,结果可能会更糟 - 例如,它可能真正写入内存中的随机位置。

您需要实际内存而不仅仅是指针。以下是3种合理的方式:

阵列

#include <iostream>
#include <cstring>

class Cheese {
    char _brand[256];
public:
    Cheese(const char *); // constructor declaration
    char * getBrand();
};
Cheese::Cheese(char const * b) { // constructor definition
    strncpy(_brand, b, sizeof(_brand)); // copies up to 255 characters, plus terminating \0
}
char * Cheese::getBrand() {
     return _brand;
}
int main(int argc, const char * argv[]) {
    const char * brand = "Cabot";
    Cheese * cheddar = new Cheese(brand);
    std::cout << cheddar -> getBrand();
    delete cheddar;
    return 0;
}

指针

#include <iostream>
#include <cstring>

class Cheese {
    char * _brand;
public:
    Cheese(const char *); // constructor declaration
    ~Cheese(); // destructor declaration
    char * getBrand();
};
Cheese::Cheese(char const * b) { // constructor definition        
    _brand = new char[strlen(b)+1];
    strcpy(_brand, b);  
}
Cheese::~Cheese() { // destructor definition 
    if (_brand != nullptr) // if you add another constructor that doesn't set _brand, make sure to set _brand to nullptr
        delete _brand; // if we don't free here there's a memory leak
}
char * Cheese::getBrand() {
     return _brand;
}
int main(int argc, const char * argv[]) {
    const char * brand = "Cabot";
    Cheese * cheddar = new Cheese(brand);
    std::cout << cheddar -> getBrand();
    delete cheddar; 
    return 0;
}

智能指针

#include <iostream>
#include <cstring>
#include <memory>

class Cheese {
    std::unique_ptr<char> _brand; 
public:
    Cheese(const char *); // constructor declaration
    char * getBrand();
};
Cheese::Cheese(char const * b) { // constructor definition        
    _brand = new char[strlen(b)+1]; // smart pointer will free any memory assigned to it on destruction
    strcpy(_brand, b);  
}
char * Cheese::getBrand() {
     return _brand.get();
}
int main(int argc, const char * argv[]) {
    const char * brand = "Cabot";
    Cheese * cheddar = new Cheese(brand);
    std::cout << cheddar -> getBrand();
    delete cheddar;
    return 0;
}

答案 3 :(得分:0)

您无法复制数据,因为在您的类声明中您刚刚保留了一个指针,但您没有将其设置为指向任何指针。我的意思是当你调用构造函数时,对象在内存中只有4个字节的大小,它将保存一个指向无处的指针。

要解决此问题,您可以将brand变量的声明更改为char[]数组,但这是一个糟糕的解决方案。