哪个更合理 - char * string 还是 char* string?

34

我目前正在学习C ++,并且遇到了许多以null结尾的字符串。这使我思考,在声明指针时哪种方式更合理:

char* string
或者
char *string

? 对我来说,char*格式更有意义,因为"string"的类型是指向字符的指针,而不是字符。然而,我通常看到后一种格式。这同样也适用于引用。

请问是否有逻辑上的原因使用后一种格式?


std::wstring,当然。 - Hans Passant
第一种格式更有意义。您正在声明一个名为“string”的变量,其类型为char *,而不是具有char类型的名为“*string”的变量。人们直观地解析代码沿着空格边界,因此合理地格式化代码,使其在解析时具有有意义的读取方式。当然,下面的答案解释了为什么有时会使用违反直觉的约定。 - aroth
13个回答

71
在下面的声明中:

char* string1, string2;

string1是一个字符指针,但string2只是单个字符。因此,声明通常格式化为:

char *string1, string2;

这使得*仅适用于string1,而不是string2。良好的实践是避免在一个声明中声明多个变量,特别是如果其中一些是指针。


5
在我看来,这不应该被认为是最佳答案。考虑到:
  • 我们谈论的是C++。
  • 类型是char*。
  • 你将传递的变量是"string",很少是"*string"。
  • 变量必须尽可能晚地声明,因此根据定义不应与另一个变量在同一行上声明。
  • Bjarne说:“典型的C++程序员编写int* p...我明确更喜欢这种强调,并认为这对于使用C++的更高级部分非常重要。”
  • const char* const string
那么char* string显然更有意义。我甚至更喜欢char * string,因为更清晰易懂。
- Jem
2
我认为在同一行中声明不同类型的变量是没有意义的。 - Chiel
9
这真是胡说八道。为什么每个人都沉迷于这种边缘情况?!在决定如何对齐你的星号时,有更重要的因素需要考虑。 - Lightness Races in Orbit
1
在同一行声明不同类型的变量是一个糟糕的想法,但仍然适用于a)大多数初学者/非C++程序员会将char * string1,string2;解释为两个指针,而且b)星号不是类型说明符本身的修饰符,而是名称的修饰符。将其视为XML:您具有类型属性的声明元素,以及一个或多个带有变量名称的子元素。现在为什么当它仅适用于其第一个子元素时,您会将指针修饰符(*)作为属性添加到类型元素中?话说回来,char *更易读。 :( - AnorZaken

37

Bjarne Stroustrup在他的网站中提到了这个问题:

当人们试图在单个声明中声明多个指针时,会产生关键的混淆:

int* p, p1; // probable error: p1 is not an int*

1
太棒了!Stroustrup同意我!谢谢。 - Skilldrick
2
如果你浏览Stroustup的FAQ,有趣的是看到他在自己的代码中实际使用哪种指针风格。 - otto
2
C++ 核心指南规定运算符应与类型相邻:https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#nl18-use-c-style-declarator-layout - phoenix
6
@otto,如果你确实阅读了他的帖子,你会发现他正在使用他所说喜欢的那种风格。这个回答有些误导,因为它隐藏了实际的上下文和重要的观点:“‘典型的 C++ 程序员’写 int* p; 并解释说 ‘p 是指向 int 的指针’,强调类型。事实上,p 的类型是 int*我明显更喜欢这种强调方式[...]”。 - Tomáš Zato
4
请阅读完整上下文!这句话被完全断章取义,用于表达与Stroustrup实际意思相反的观点! - Apollys supports Monica
显示剩余3条评论

18

从技术上讲,编写代码是有意义的

char *f

因为在这里*f是声明符,而char是指定所有声明符的基本类型的声明说明符。声明符包含像()[]&这样的运算符,可以认为是修改基本类型和实际标识符。

我使用上述形式将*放到标识符中,因为它强调了*f实际上是声明符,而char是基本类型。

在一定程度上,可以认为在应用运算符到标识符时,声明符中的修饰符会使声明说明符中的类型。但这并不总是有效的:

int a, *b, &c = a, d(), e[1], C::*f;

请注意,除了声明引用(因此需要初始化)和指向类成员的指针&cC::*之外,所有a*bd()e[1]都静态解析为int。

这条评论可能会引起争议。尽管Stroustrup扩展了语法的主要部分,但并非Ritchie,如果在声明说明符序列(如const foo)之后放置一个声明符运算符,例如const foo bar,则很容易将其误读为常量(指向foo的指针),而不是指向(常量foo)的指针。要清楚地了解声明语法的复杂性,有必要阅读K&R或Stroustrup的《C ++编程语言》中的语法附录。 - egyik

11

还没有人提到的是以下内容:

char *string

这也可以被解读为声明表达式 *string(即指针 string 应用了间接操作符)的类型为 char。从这个角度来看,这种表示法是非常合理的。

话虽如此,我使用

char * string

我自己 ;)


1
说实话,我使用 char * string。- 我也是,考虑了 'char* ' 和 'char *' 两种格式后,我开始收敛于这种格式,但对它们都不满意... - stefanB
+1,对于本来令人困惑的语法进行了有用的解释! - anton.burger

5
在C++中,将*放在类型标识符(如char*)上是有意义的,因为它是类型本身的一部分。但是,如果您在同一语句中定义多个变量,则会变得模糊和误导。
char* foo, bar;

虽然现在foo的类型是char*,但bar的类型是char。因此许多人更喜欢

char *foo, bar;

为了让这个更清晰明了。


这个情况其实很简单,只要了解编程语言就可以解决。如果一位代码读者被写有工作代码的作者误导或困惑,例如写 char* foo, bar;,那么这是读者自己没有足够了解该语言的责任。 - Pulseczar
作为类型本身的一部分。第二个例子在C++和C中的行为不是相同的吗? - endolith

5

对于大多数用途而言,std::string比char*更好。

我总是将*与类型放在一起,例如char*,因为正如Stroustrup所指出的,这强调了类型。

我从不在一行上声明变量,以避免在此处讨论的常见陷阱。

char* p, q;  // oops, probably not what was meant
// this is mandated by our style guide:
char* p;
char* q;

3

考虑到在一行中可以进行多个声明,对我来说,它更适合属于变量而不是类型,例如:

char *pString, arrString[20];

2
我认为这不是一个好的做法...不太易读。 - Tim
由于类型与变量对应,因此更少出错,而其可读性则不受影响。 - Simon

3
在大多数情况下,std::string strchar *更可取。
话虽如此,我通常会做一些像DataType * ptr这样的事情,以使*更加突出。或者,更常见的是使用std::tr1::smart_ptr<DataType> ptr,或者可能是一个auto_ptr
简单地说,原始指针在很多方面都很危险,如果我要使用一个原始指针,我希望它能够突出显示。

3
我非常喜欢“char* foo”这种说法,因为它将变量类型的所有信息都放在了一个地方。如果“*foo”部分跨越屏幕一半,那么“char *foo”可能会让人感到困惑!
另一方面,我同意其他帖子中的观点,即在一行中声明多个变量时会令人困惑。我尽量不在一行中混合使用不同类型的变量,而且在我的脑海中,charchar*是不同的类型,所以这种情况在我的代码中不太可能出现。

2
问题在于 C 类型系统并不是那样工作的,相反它会将声明的变量或类型放在中间。试着声明一个数组或函数指针就可以看出来了。 - starblue
是的,没错——我的哲学在 C/C++ 中并不适用于所有情况。但是我喜欢以那种方式声明指针和引用,以增加清晰度。 - MattK

3

我的答案是:两者都不应该使用,你应该使用:

char * string;

考虑一下,如果C语言的设计者Dennis Ritchie使用关键字“ptr”代替“*”字符,我们就必须这样说:

char ptr string;

并且没有进行这些讨论。

在我看来,它也更易读。


8
我不喜欢这个,因为它看起来更像乘法运算符... - Skilldrick

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