2009-08-17 85 views
90

我知道一点C,现在我正在看C++。 我已经习惯了字符数组用于处理C字符串,但是当我看到C++代码,我看到有同时使用字符串型和字符数组的例子:C++中字符串和char []类型之间的区别

#include <iostream> 
#include <string> 
using namespace std; 

int main() { 
    string mystr; 
    cout << "What's your name? "; 
    getline (cin, mystr); 
    cout << "Hello " << mystr << ".\n"; 
    cout << "What is your favorite team? "; 
    getline (cin, mystr); 
    cout << "I like " << mystr << " too!\n"; 
    return 0; 
} 

#include <iostream> 
using namespace std; 

int main() { 
    char name[256], title[256]; 

    cout << "Enter your name: "; 
    cin.getline (name,256); 

    cout << "Enter your favourite movie: "; 
    cin.getline (title,256); 

    cout << name << "'s favourite movie is " << title; 

    return 0; 
} 

(这两个示例从http://www.cplusplus.com

我想这是一个广泛提出并回答(显而易见的问题),但如果有人能告诉我在C++中处理字符串的两种方式之间的差别(性能,API i整合,每种方式都更好,...)。

谢谢。

+0

这可有助于: [C++的char * VS的std :: string](http://stackoverflow.com/questions/801209/c-char-vs-stdstring ) – 2009-08-17 10:57:23

回答

140

字符数组就是这样 - 一个字符数组:

  • 如果在栈中分配(如在你的例子),它将始终占据例如。 256字节无论它包含的文本多长时间
  • 如果在堆上分配(使用malloc()或new char []),则负责在之后释放内存,并且总是会有堆分配的开销。
  • 如果您将超过256个字符的文本复制到数组中,它可能会崩溃,在您的程序的其他地方产生丑陋的断言信息或导致无法解释的(错误)行为。
  • 要确定文本的长度,必须逐个字符地扫描数组以获得\ 0字符。

字符串是一个类,它包含一个char数组,但会自动为您管理它。大多数字符串实现都有一个由16个字符组成的内置数组(所以短的字符串不会将堆分段),并使用堆来存储更长的字符串。

您可以访问一个字符串的字符数组是这样的:

std::string myString = "Hello World"; 
const char *myStringChars = myString.c_str(); 

C++字符串可以包含嵌入的\ 0字符,知道不计数它们的长度,比堆分配的字符数组更快短文本和保护你从缓冲区溢出。另外,它们更易读易用。

-

然而,C++字符串不(很),适用于跨DLL边界的使用,因为这需要这样的DLL函数中的任何用户,以确保他的使用完全相同的编译器和C++运行时实现,免得他冒着他的班级行为不同的风险。

通常情况下,一个字符串类也会在调用堆中释放其堆内存,所以如果您使用的是运行时的共享(.dll或.so)版本,它将只能再次释放内存。

简而言之:在您的所有内部函数和方法中使用C++字符串。如果您曾经编写.dll或.so,请在公共(dll/so-exposed)函数中使用C字符串。

+3

此外,字符串还有一堆辅助函数,可以非常整齐。 – 2009-08-17 11:18:08

+1

我不相信有关DLL边界的一点。在非常特殊的情况下,它可能会中断((一个DLL与其他DLL的运行时版本是不同的静态链接),更糟糕的情况可能会首先发生在这些情况下),但在一般情况下,每个人都使用默认标准运行时的共享版本(默认)不会发生。 – 2009-08-17 18:00:00

+1

示例:您分发名为libfoo的公用库的VC2008SP1编译的二进制文件,该库在其公用API中包含std :: string&。现在有人下载您的libfoo.dll并执行调试版本。他的std :: string可能会有一些额外的调试字段,导致动态字符串的指针移动。 – Cygon 2009-08-21 20:25:47

6

那么,字符串类型是字符串的完全托管类,而char []仍然是C中的字符数组,它代表了一个字符串。

就API和标准库而言,一切都是以字符串而不是char []来实现的,但是libc中仍然有很多接收char []的函数,所以您可能需要将它们用于这些从那我总是会使用std :: string。

就效率而言,非托管内存的原始缓冲区对于很多事情来说几乎总是会更快,但考虑到比较字符串的情况,例如,std :: string始终具有首先检查它的大小,而char []你需要逐字比较字符。

6

Arkaitz是正确的,string是一个托管类型。这对意味着什么,你不必担心字符串有多长,也不必担心释放或重新分配字符串的内存。

另一方面,上述情况下的char[]表示法将字符缓冲区限制为完全256个字符。如果您试图将超过256个字符写入该缓冲区,则至多会覆盖程序“拥有”的其他内存。在最坏的情况下,你会尝试覆盖你不拥有的内存,并且你的操作系统会当场杀死你的程序。

底线?字符串对程序员更友好,char []对计算机来说效率更高。

+3

最坏的情况下,其他人会覆盖内存并在您的计算机上运行恶意代码。另请参阅[缓冲区溢出](http://cwe.mitre.org/data/definitions/120.html)。 – 2010-03-18 01:12:47

5

我个人看不出有什么理由为什么想使用char *或char [],除了与旧代码的兼容性。 std :: string不会比使用c-string慢,只是它会为你处理重新分配。您可以在创建时设置它的大小,从而避免重新分配。它是索引操作符([])提供了持续时间访问(并且在每个词的意义上与使用c-string索引器完全相同)。使用at方法也可以让你检查安全性,除非你写了它,否则你不会使用c-string。您的编译器通常会优化索引器在发布模式下的使用。使用C字符串很容易;诸如delete vs delete [],异常安全,甚至如何重新分配c字符串等。

而当你必须处理诸如COW字符串和非COW等MT的高级概念时,你需要std :: string。

如果您担心副本,只要您可以使用引用和常量引用,那么不会因为副本而产生任何开销,并且与使用c字符串所做的操作相同。

+0

+1虽然你没有考虑像DLL兼容性这样的实现问题,但你得到了COW。 – 2009-08-17 12:35:22

+0

我知道我的char数组是12字节吗?如果我为它实例化一个字符串,它可能不是真的有效吗? – 2016-08-16 00:17:30

+0

@David:如果你有非常敏感的代码,那么是的。除std :: string成员的初始化之外,您可能会认为std :: string ctor调用是开销。但请记住,不成熟的优化使得许多代码库不必要地使用C风格,所以要小心。 – Abhay 2016-08-17 14:17:10

0

将(char *)视为string.begin()。本质区别在于(char *)是一个迭代器,std :: string是一个容器。如果你坚持基本的字符串(char *)会给你什么std :: string :: iterator。当你想要迭代器的好处并且兼容C时,你可以使用(char *),但这是例外,而不是规则。一如既往,小心迭代器失效。当人们说(char *)不安全时,这就是他们的意思。它和任何其他C++迭代器一样安全。

1

字符串具有辅助函数并自动管理字符数组。您可以连接字符串,对于需要将它复制到新数组的字符数组,字符串可以在运行时更改它们的长度。字符数组比字符串更难管理,某些函数只能接受字符串作为输入,因此需要将数组转换为字符串。最好使用字符串,这样做是为了不必使用数组。如果数组客观上更好,我们不会有字符串。

0

其中一个区别是空终止(\ 0)。

在C和C++中,char *或char []会将指向单个字符的指针作为参数,并沿内存跟踪,直到达到0内存值(通常称为空终止符)。

C++字符串可以包含嵌入的\ 0字符,知道它们的长度而不计算。

#include<stdio.h> 
#include<string.h> 
#include<iostream> 

using namespace std; 

void NullTerminatedString(string str){ 
    int NUll_term = 3; 
    str[NUll_term] = '\0';  // specific character is kept as NULL in string 
    cout << str << endl <<endl <<endl; 
} 

void NullTerminatedChar(char *str){ 
    int NUll_term = 3; 
    str[NUll_term] = 0;  // from specific, all the character are removed 
    cout << str << endl; 
} 

int main(){ 
    string str = "Feels Happy"; 
    printf("string = %s\n", str.c_str()); 
    printf("strlen = %d\n", strlen(str.c_str())); 
    printf("size = %d\n", str.size()); 
    printf("sizeof = %d\n", sizeof(str)); // sizeof std::string class and compiler dependent 
    NullTerminatedString(str); 


    char str1[12] = "Feels Happy"; 
    printf("char[] = %s\n", str1); 
    printf("strlen = %d\n", strlen(str1)); 
    printf("sizeof = %d\n", sizeof(str1)); // sizeof char array 
    NullTerminatedChar(str1); 
    return 0; 
} 

输出:

strlen = 11 
size = 11 
sizeof = 32 
Fee s Happy 


strlen = 11 
sizeof = 12 
Fee 
+0

请注意,您正在回答8年前提出的问题。 – 2017-08-10 07:14:03

+0

@ n.m:是的,我知道。当我经历的时候,大部分的观点都被覆盖了,我又添加了一点,这将有助于在一个地方得到所有答案(最大值)。 – 2017-08-10 07:31:48

相关问题