如何初始化类中的char指针?

时间:2012-04-23 15:04:21

标签: c++

在处理char指针时我感到困惑。请看下面的代码:

class Person
{
    char* pname;
public:
    Person(char* name)
    {
        //I want to initialize 'pname' with the person's name. So, I am trying to
        //achieve the same with different scenario's

        //Case I:   
        strcpy(pname, name); // As expected, system crash.

        //Case II: 
        // suppose the input is "ABCD",  so trying to create 4+1 char space
        // 1st 4 for holding ABCD and 1 for '\0'.
        pname = (char*) malloc(sizeof(char) * (strlen(name)+1) );
        strcpy(pname, name);

        // Case III: 
        pname = (char*) malloc(sizeof(char));
        strcpy(pname, name);
    }

    void display()
    {
        cout<<pname<<endl;
    }
};

void main()
{
    Person obj("ABCD");
    obj.display(); 
}

对于案例I: 正如所料,系统崩溃。

案例II的输出:

  

ABCD

案例III的输出:

  

ABCD

所以,我不确定Case II&amp;三是产生相同的输出!!!! ..... 我应该如何在类中初始化char指针?

7 个答案:

答案 0 :(得分:10)

第三种情况调用未定义行为,因此在这种情况下可能会发生任何事情 在这种情况下,您正在写超出已分配内存的范围,这可能会或可能不会崩溃但是是UB。

如何在C ++中以正确的方式执行此操作?
完全不使用char *! 只需使用 std::string 即可。

请注意,std::string为您提供了 c_str()函数,该函数可以获取基础字符串。除非,您对将char *的所有权传递给c风格的api感到困扰,否则您应该始终在c ++中使用std::string

答案 1 :(得分:5)

第三种选择也是错误的,因为你没有为它分配足够的内存。您正在尝试将大小为5的字符串复制到大小为1的缓冲区,这意味着pname[1]之后的数据被错误地覆盖并消失了。

如果您很幸运,您可能会看到运行时错误,例如内存访问违规,或者您不会看到任何内容,但背后的数据已损坏,例如您的银行帐户,而您永远不会知道直到...

正确的方法是始终分配足够的内存来复制到。正如Als所指出的,在C ++中更好的方法是使用std::string,因为它可以让你免于手动管理内存(分配,增长,释放等)。

如,

class Person
{
    std::string pname;
public:
    Person(char* name)
    {
        pname = name;
    }

    void display()
    {
        cout << pname << endl;
    }
};

void main()
{
    Person obj("ABCD");
    obj.display(); 
}

答案 2 :(得分:4)

您必须为成员变量pname分配内存,但是,当您只使用char*时,我不知道您为何要使用string

std::string pname;

//...

pname = std::string(name);

如果您有充分的理由必须使用char*,那么请执行以下操作:

// initialize the pname
pname = new char[strlen(name)];

// copy the pname
strcpy(pname, name);

您不需要在字符串末尾为null分配额外空格的原因 - 终止是因为使用双引号"blah"会自动生成null - 终止字符串。

答案 3 :(得分:3)

如果您从事C ++业务,那么是时候代表STL字符串转储char指针了:

#include <string>

class Person
{
    std::string the_name;
public:
    Person(std::string name) : the_name(name)
    { ...

同样使用cout。

答案 4 :(得分:2)

在你的案例III中,你做了pname = (char*) malloc(sizeof(char));,它为单个字符分配了足够的内存。但是,strcpy无法知道这一点,并且在该字节之后直接写入任何内存,直到它完成对传递给函数的所有char *的复制。这被称为缓冲区溢出,虽然这可能会立即起作用,但它可能会破坏一些东西。如果您只想复制char *的一个子部分,可以查看strncpy,其复制长度为(API reference here)。如果你使用它,请务必自己添加空终止字符,因为如果只复制部分字符串,strncpy将不包括它。

答案 5 :(得分:2)

pname = (char*) malloc(sizeof(char));工作很巧合,对strcpy的调用会写入尚未分配的内存中,因此可能会导致程序崩溃。

初始化缓冲区的一种更简单的方法是:

pname = strdup(name);

pname = strndup(name, strlen(name));

请参阅http://linux.die.net/man/3/strdup

此外,您必须考虑通过在类析构函数中调用free(pname);来释放分配的内存。

总而言之,所有这些都可以通过使用C ++ std :: string类来避免,正如每个人所提到的那样。

答案 6 :(得分:2)

正确的是案例II!

是的,如果我错了,它会崩溃,因为你要将数据复制到一个非初始化的指针。

案例III也是错误的,但它现在有效,因为你的测试字符串很小!如果你尝试使用更大的字符串,它会破坏内存,因为你正在将一个大字符串复制到一个小的分配空间。

在某些系统中,malloc使用集群,因此它通过分配内存块而不是逐字节分配来工作。这意味着当你使用malloc来分配单个字节时(就像你在案例III中所做的那样),它会分配一些以达到它可以处理的最小内存块,这就是为什么你可以移动超过1个字节而不会崩溃的原因系统。