直接赋值与char * string的动态分配

时间:2016-05-25 14:48:17

标签: c++ c string pointers

我现在已经使用C ++很长一段时间了,但有一个基本概念是我无法理解的。首先,我将列出两种将文本字符串分配给char *的方法。

方法1:

char * str = "Hello World";

方法2:

char * str = new char [12];
strcpy(str,"Hello World");

我对方法2非常熟悉。方法1让我头疼。我的问题是

  1. 这两种方法的根本区别是什么?有什么优点/缺点?
  2. 我应该为方法1手动清理内存吗?
  3. 方法1中字符串的生命周期是多少?只要指针仍然有效,我可以信任它吗?我可以更改内容吗(前提是我没有在' \ 0'结尾处运行)?
  4. 我读过无数的C ++教科书和文章。他们都告诉我方法1的工作没有详细说明反响。我自己的实验并没有产生令人信服的结果。

    谢谢(也许请原谅我的英语不好)

    修改的: 实际上我在VS2015中使用带有tchar字符串的WinAPI编程,方法1编译完美。使用Unicode处理std :: string非常糟糕。

    想象一下,解决方案中有两个项目,一个是Unicode,另一个是多字节,这两个项目使用相同的库。在这个库里面,最好使用tchar。 std string你必须明确告诉它是哪个版本。

    我必须这样做,因为多字节项目是我需要注入另一个应用程序的DLL。 DLL的unicode版本将使应用程序崩溃,只有多字节工作。

5 个答案:

答案 0 :(得分:5)

char * str = "Hello World";

在C ++中已弃用,因为它违反了const正确性。 "Hello World"const char[],并使用char*指向std::stringundefined behavior的邀请,因为您可以尝试修改它。如果你想在C ++中使用字符串,我建议你使用char str[] = "Hello World"; 来防止你陷入c-strings所带来的众多陷阱。

如果你确实需要一个c字符串,那么你可以使用

std::wstring

这将创建一个正确长度的char数组,并允许您修改内容。

  

编辑:实际上我在VS2015中使用带有tchar字符串的WinAPI编程,方法1编译完美。使用Unicode处理std :: string非常糟糕。

没有什么能阻止编译大多数编译器的方法,但是如果你想要符合标准,那么你需要停止使用它。它已被弃用,最终(希望)编译器支持将被删除。

如果您需要Unicode支持,请使用包含wchar_t*

的{{1}}

答案 1 :(得分:3)

我的回答是关于c ++。一些细节与c。

不同
  
      
  1. 这两种方法的根本区别是什么?有什么优点/缺点?
  2.   

让我们来看看你的第一个代码:

char * str = "Hello World";

这是形成不良的。您不能将字符串文字分配给非const指针。至少不是因为c ++ 11。在此之前,转换仅被弃用。

此:

const char* str = "Hello World";

是对的。但是,如果你需要修改字符串,那么这不是一个选项。

  

编辑:实际上我在VS2015中使用带有tchar字符串的WinAPI编程,方法1编译得很完美。

即使您的编译器支持转换,这样做也是非常危险的,因为您可能会意外地最终修改字符串文字,这是不好的,因为

让我们看看你的第二个代码:

<击>

<击>
char * str = new char [12];
strcpy(str,"Hellow World");

这会调用未定义的行为。字符串文字长度为13个字符(因为空终端字符),strcpy溢出分配的数组。

编辑:现在修复了相关代码,但这很好地说明了为什么手动指定大小容易出错。

我建议采用更简单的方法:

char str[] = "Hello World";

这更简洁,不会使用错误大小的数组。它也比动态分配更有效,但不如直接使用字符串文字有效。但是,与字符串文字不同,您可以修改此数组。

如果数组是本地的,那么它在范围的末尾被销毁。此外,您无法调整阵列的大小。如果需要可调整大小的字符串,则需要动态分配。如果您需要动态分配,我建议std::string

std::string str("Hello World");
  
      
  1. 我应该为方法1手动清理内存吗?
  2.   
不,你不应该。字符串文字有静态存储。

  
      
  1. 方法1中字符串的生命周期是多少?只要指针仍然有效,我能相信它能持续吗?
  2.   

您可以相信字符串文字会在整个程序执行过程中退出。

  

我可以更改内容(假设我最后没有在'\ 0'上运行)吗?

修改字符串文字会有未定义的行为。您不希望程序附近的任何地方出现未定义的行为。

  

使用Unicode处理std :: string非常糟糕。

std::string具有与普通字符数组完全相同的unicode处理。

  

想象一下,解决方案中有两个项目,一个是Unicode,另一个是多字节,这两个项目使用相同的库。在这个库里面,最好使用tchar。 std string你必须明确告诉它是哪个版本。

除了处理Windows API时,我会避免使用tchar。但如果您确实使用它并需要std::string的细节,那么您只需使用std::basic_string<tchar>

答案 2 :(得分:2)

在此声明中

char * str = "Hello World";

对C有效且对C ++无效,会创建两个对象。

首先,编译器使用字符串文字"Hello World"的静态存储持续时间创建一个以零结尾的字符数组。

Ib C字符串文字具有非常量字符数组的类型,而在C ++中字符串文字具有常量字符数组的类型。

然而,无论是在C还是在C ++中,您都可以修改字符串文字。任何修改字符串文字的尝试都会导致未定义的行为。

这也意味着您可能无法清除字符串文字所占用的内存。编译器为字符串文字保留内存。

在C中,声明中使用的字符串文字的类型为char[12],而在C ++中,它的类型为const char[12]

因此在C ++中,声明看起来像

const char * str = "Hello World";

在声明中创建的第二个对象是名为str的指针,指向字符串文字的第一个字符。指针本身可以更改,也可以重新分配。

如果指针在代码块中声明,则它具有自动存储持续时间。指针的存储持续时间不会影响上面提到的静态存储持续时间的字符串文字的存储持续时间。

答案 3 :(得分:1)

如果是第一种方法

 char * str = "Hello World";

您正在将string literal的地址存储到给定指针中。但是,由于类型const char[]char *不匹配,此构造是非法的。

请记住,不应修改内存地址的内容,尝试这样做会调用undefined behavior。此外,您不需要免费任何内容,因为您没有分配任何动态内存。

在第二种方法中,

char * str = new char [12];
strcpy(str,"Hellow World");

您正在为指针分配动态内存,并使用字符串文字的内容填充它。这个数组是完全可写的。但是,请注意,对于维度12,您没有空终止符的空间。您可能希望使大小至少为13,以便为null终止符留出空间。最后,您需要在使用后释放分配的内存。

答案 4 :(得分:0)

  

方法1中字符串的生命周期是多少?

对于字符串文字本身,程序的生命周期;程序启动时(甚至一旦程序加载到内存中)就会分配文字的存储空间,并在程序退出时释放。

  

只要指针仍然有效,我可以信任它吗?

无论指针变量str的生命周期如何,您都可以信任该文字。

  

我可以更改内容(前提是我没有在&#39; \ 0&#39;结尾处运行)?

没有。 C ++字符串文字是const char的数组,这意味着它们不能被修改(这会破坏它们作为文字的整个目的;它在逻辑上与更改内容相同42)。

  

这两种方法的根本区别是什么?

第一种方法不会留出任何新内存,str指向的内容可能无法修改。

第二种方法动态分配一个新的内存块,并将字符串文字的内容复制到它;您可以根据自己心中的内容修改已分配区块的内容。

  

任何优点/缺点?

使用第一种方法为字符串文字创建符号常量(你想要做什么 - 我已经多次错误拼写文字而被烧毁)。

第二种方法没有很多好的用例;如果您需要操作文本数据,请使用std::string类型而不是char数组。 C风格的字符串处理是屁股中的巨大痛苦,而std::string类型在这方面使生活更多更容易。如果您需要创建和存储多个字符串,请使用标准容器,如std::vector