指向const char的指针 vs 字符数组 vs std::string

9

我这里有两行代码

const char * s1 = "test";
char s2 [] = "test";

两行代码的行为相同,因此我看不出是否应该更喜欢s1还是s2。除了s1和s2之外,还有使用std::string的方法。我认为使用std::string的方法最优雅。在查看其他代码时,我经常看到人们要么使用const char *,要么使用char s []。因此,我的问题现在是,何时应该使用const char * s1char s []std::string?它们之间有什么区别,应在哪些情况下使用哪种方法?

2
它们的行为不同 :-) 第一个只将指向常量字符串的指针放入堆栈中,而第二个则将整个可变字符串放入堆栈中。 - Kos
FYI) 未加前缀的'字符串字面值',例如"abc",是'const char数组',即const char[N](N为包括空终止符的字符串大小)。至少目前在C和C++中都是如此。补充一下Kos上面的评论,字符串字面值具有'静态存储期'(持续整个程序的运行时间)。正如标准或答案所引述的。 - starriet
7个回答

11
POINTERS
--------

char const* s1 = "test";  // pointer to string literal - do not modify!

char* s1       = "test";  // pointer to string literal - do not modify!
                          //   (conversion to non-const deprecated in C++03 and
                          //       disallowed in C++11)

ARRAYS
------

char s1[5]     = "test";  // mutable character array copied from string literal
                          //    - do what you like with it!

char s1[]      = "test";  // as above, but with size deduced from initialisation



CLASS-TYPE OBJECTS
------------------

std::string s1 = "test";  // C++ string object with data copied from string
                          //    literal - almost always what you *really* want

9
const char * s1 = "test";
char s2 [] = "test";

这两者并不相同。s1是不可变的:它指向常量内存。修改字符串字面值是未定义的行为。
而且,在C++中,您应该优先使用std::string

有没有什么原因,为什么我经常看到人们使用const关键字?没有const关键字,我得到相同的行为,所以char * s1 =“test”;。它可以正常工作,没有任何编译器错误... - System.Data
1
请参考Lightness的回答中的@System.Data。默认转换现在已经过时,我认为不应该再允许它存在。如果您尝试修改它仍然是未定义的行为。 - Luchian Grigore
@System.Data:这是因为您在构建设置中未使用足够的警告。将 const char* 转换为字符串字面值的 char* 在旧版 C 中是允许的(当时它根本没有 const 的安全性),但在 C++ 中逐渐被淘汰。因此,在 C++98/C++03 中,它已被弃用...而在 C++11 中则完全非法。这很危险,因为它使您在语法上能够修改字符串中的数据,而实际上它是常量数据。 - Lightness Races in Orbit
5
作为一种更普遍的协议,你应该始终使用const,除非你知道你不想使用它......而不是相反。这是一个设计缺陷,源于 C++ 的默认值为可变而不是不可变,这与向后兼容有关。 - Lightness Races in Orbit

3
第一个是常量,第二个不是。std::string是一个类类型,实现了许多有用的字符串操作函数和方法,使其更易于使用和友好。使用字符指针的C风格“字符串”难以控制、操作,而且经常会引起错误,但它们没有std::string的额外开销。通常最好使用std::string,因为它们更容易维护。

3
你需要关注的两者之间唯一的区别是:
你的项目已经使用了哪一个?

这个说法有一定的道理,但远远不是主要因素。 - Lightness Races in Orbit
其实,不幸的是,通常它确实是唯一的因素,因为你很少有机会改变项目政策。是的,我有点失望。 - DevSolar
1
开发团队的政治是本问题范畴之外,这是关于编程语言的问题。如果你没有机会引导开发策略,那么你可能是一个非常年轻的大团队中的菜鸟,或者是在一份糟糕的工作中。(也可能两者兼备。) - Lightness Races in Orbit
我的意思是 - 一致性是代码库中最有价值的东西之一。无论个人对此持何种观点,一致性甚至胜过像const正确性这样的东西。 - x10

3
这两个变量的行为不同。`s1` 是一个简单的指针,它被初始化为指向某个(通常是只读的)内存区域。另一方面,`s2` 定义了一个大小为 5 的局部数组,并将其填充为该字符串的副本。
严格来说,你不允许修改 `s1`,也就是不能执行像 `s1[0] = 'a'` 这样的操作。特别地,在奇怪的情况下,这可能会导致程序中所有其他的 `“test”` 变成 `“aest”`,因为它们都共享同一块内存。这就是现代编译器在写下如下代码时报错的原因:
char* s = "test";

另一方面,修改s2是被允许的,因为它是一个本地副本。
换句话说,在以下示例中,
const char* s1 = "test";
const char* s2 = "test";
char s3[] = "test";
char s4[] = "test";
s1s2可能指向内存中的同一地址,而s3s4是相同字符串的两个不同副本,并位于内存的不同区域。
如果您正在编写C ++,请使用std :: string,除非您绝对需要字符数组。如果您需要可修改的字符数组,请使用char s []。如果您只需要一个不可变字符串,请使用const char *

0

使用哪一个取决于您的需求。指针提供更多的灵活性,但在某些情况下会存在漏洞。字符串是一个安全的选择,并且它们提供迭代器支持。


字符串“提供STL支持”的方式是什么? - Lightness Races in Orbit
它们允许您使用STL函数,例如搜索,操作(如赋值),可以测试诸如==,!=等条件。 - Rohit Vipin Mathews
赋值和比较与STL无关。但是C++标准库的算法是相关的,因为std::string具有迭代接口。 - Lightness Races in Orbit

0

除非您知道为什么需要使用字符数组/字符指针,否则请使用 std::string


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接