简体   繁体   English

如何在一个类中初始化一个char指针?

[英]how to initialize a char pointer in a class?

I have a confusion while dealing with char pointers. 我在处理char指针时感到困惑。 Please have a look at following code: 请看下面的代码:

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(); 
}

For Case I: As expected, system crash. 对于情况一:如预期的那样,系统崩溃。

Output for Case II: 案例二的输出:

ABCD A B C D

Output for Case III: 案例三的输出:

ABCD A B C D

So, I am not sure why Case II & III are producing the same output !!!!..... How I should initialize a char pointer in a class? 所以,我不确定为什么案例II和案例III会产生相同的输出!!!! .....我应该如何在类中初始化char指针?

The third case invokes Undefined Behavior and so anything might happen in that case. 第三种情况调用了Undefined Behavior ,因此在这种情况下可能会发生任何事情。
You are writing beyond the bounds of allocated memory in this case which may or maynot crash but is a UB. 在这种情况下,您正在写的内容超出了分配的内存范围,这可能会崩溃也可能不会崩溃,但它是UB。

How to do this the right way in C++? 如何在C ++中以正确的方式做到这一点?
By not using char * at all! 通过根本不使用char *
Just simply use std::string . 只需使用std :: string即可

Note that std::string provides you with c_str() function which gets you the underlying character string. 请注意, std::string为您提供了c_str()函数,该函数可为您提供基础字符串。 Unless, You are bothered about passing ownership of a char * to a c-style api you should always use std::string in c++. 除非,您不愿意将char *所有权传递给C风格的api,否则您应始终在c ++中使用std::string

The third option is also wrong as you haven't allocated enough memory for it. 第三个选项也是错误的,因为您没有为其分配足够的内存。 You're trying to copy a string of size 5 to a buffer of size 1, which means the data after pname[1] are incorrectly overwritten and gone.. 您正在尝试将大小为5的字符串复制到大小为1的缓冲区中,这意味着pname[1]之后的数据被错误地覆盖并消失了。

If you're lucky, you may see a runtime error such as memory access violation, or you won't see anything but the data behind it is corrupted, eg, your bank account, and you never know about it until.. 如果幸运的话,您可能会看到诸如内存访问冲突之类的运行时错误,或者您将看不到任何东西,但背后的数据已损坏,例如您的银行帐户,直到那时您才知道。

The correct way to go is to always allocate enough memory to copy to. 正确的方法是始终分配足够的内存以进行复制。 A better way in C++ is to use std::string , as Als points out, because it'll free you from manual management of memory (allocation, growing, deallocation, etc). 正如Als指出的那样,在C ++中更好的方法是使用std::string ,因为它将使您摆脱对内存的手动管理(分配,增长,释放等)。

Eg, 例如,

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

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

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

You have to allocate memory for your member variable pname , however, I don't know why you want to use a char* when you can just use a string : 您必须为成员变量pname分配内存,但是,我不知道为什么只能使用string时要使用char*

std::string pname;

//...

pname = std::string(name);

If there is a good reason why you must use a char* , then do something of the sort: 如果有充分的理由为什么必须使用char* ,请执行以下操作:

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

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

The reason why you don't need to allocate an extra space at the end of the string for null -termination is because using the double quotes "blah" automatically produces a null -terminated string. 之所以不需要在字符串末尾为null终止分配额外的空间,是因为使用双引号"blah"自动生成一个以null终止的字符串。

If you are into C++ business, then it's time to dump char pointers on behalf of STL string: 如果您从事C ++业务,那么该代表STL字符串转储char指针了:

#include <string>

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

Also cout is used the same. 同样,cout也被使用。

In your Case III, you do pname = (char*) malloc(sizeof(char)); 在案例III中,您执行pname = (char*) malloc(sizeof(char)); , which allocates enough memory for a single char . ,它为单个char分配足够的内存。 However, strcpy has no way of knowing that, and writes over whatever memory comes directly after that byte, until it has finished copying over all of the char* you passed into the function. 但是,strcpy无法知道这一点,并且会直接写入该字节之后的所有内存,直到它完成对传递给函数的所有char *的复制为止。 This is known as a buffer overflow , and while this might immediately work, it could possibly break something down the road. 这被称为缓冲区溢出 ,尽管这可能立即起作用,但可能会破坏某些东西。 If you are looking to copy only a subsection of the char*, you could look into strncpy , which copies up to some length (API reference here) . 如果您只想复制char *的一部分,则可以查看strncpy ,该副本最多复制一定长度(此处有API参考) If you use that, be sure to add the null-terminating character yourself, as strncpy will not include it if you copy only part of the string. 如果使用该选项,请确保自己添加以null结尾的字符,因为如果仅复制部分字符串,strncpy将不包括该字符。

That pname = (char*) malloc(sizeof(char)); pname = (char*) malloc(sizeof(char)); works is coincidental, the call to strcpy writes into memory that hasn't been allocated, so it could crash your program at any time. Works是偶然的,对strcpy的调用将写入尚未分配的内存,因此它可能随时使您的程序崩溃。

A simpler way to initialize your buffer would be: 初始化缓冲区的更简单方法是:

pname = strdup(name);

or 要么

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

See http://linux.die.net/man/3/strdup . 参见http://linux.die.net/man/3/strdup

Also, you must think about freeing the memory allocated by calling free(pname); 同样,您必须考虑释放通过调用free(pname);分配的内存free(pname); in the class destructor. 在类析构函数中。

All in all, all of this can be avoided by the use of the C++ std::string class, as mentioned by everyone. 总而言之,所有这些都可以通过使用C ++ std :: string类来避免,这是每个人都提到的。

Correct is case II! 情况二是对的!

Yes, case I is wrong, it will crash since you are copying data to a non initialized pointer. 是的,如果我错了,由于将数据复制到未初始化的指针,它将崩溃。

Case III is also wrong, but it works now because your test string is small! 情况三也是错误的,但是现在可以使用,因为您的测试字符串很小! If you try with a bigger string it will corrupt memory since you are copying a big string to a small allocated space. 如果尝试使用较大的字符串,则将损坏内存,因为您将大型字符串复制到较小的分配空间中。

In some systems malloc works with clusters so it works by allocating chuncks of memory instead of allocating byte-by-byte. 在某些系统中,malloc适用于群集,因此它通过分配内存块来工作,而不是逐字节分配。 This means that when you used malloc to alocate a single byte (like you did in case III), it allocates some more up to reach the minimum block of memory it can handle, that's why you could move more then 1 byte to it without crashing the system. 这意味着,当您使用malloc分配单个字节时(如在案例III中所做的那样),它会分配更多的空间以达到它可以处理的最小内存块,这就是为什么您可以向其中移动多于1个字节而不会崩溃的原因系统。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM