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

How to initialize a private char * in a Class constructor with user input upon instantiation

本文关键字:初始化 构造函数 char 输入 实例化 用户      更新时间:2023-10-16

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

我哪里错了?这个想法是接受用户输入的品牌名称,并将这个名称的类实例化为_brand。

编辑:请不要建议使用std::string类,因为我在这个问题上坚持使用c-string。这是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;
}

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

解决方法很简单:

_brand = new char[strlen(b)+1]; // Reserve memory chunk for your copied string. Add +1 for string terminator ''
strcpy(_brand, b); // "CRASHES HERE" should be gone now
通过输入new, _brand变量现在指向一个有效的内存块(由你的程序拥有),足够大来存储你复制的字符串。

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

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

在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 
}
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;
}

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

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