22

在C 中声明指针时,有 3 种变体:

变体 A:

int* ptr;

变体 B:

int *ptr;

变体 C:

int * ptr;
  • 在 A 中,间接运算符已附加到类型。
  • 在 B 中,间接运算符已预先添加到变量中。
  • 在 C 中,间接运算符自由地介于类型和变量之间。

声明指针的方式因我阅读的文档类型而异。一些作者似乎偏爱某些变体,而另一些作者则使用几种。

  • 我是否正确假设不同变体之间的功能没有差异?
  • 如果是,是否有约定在 C 中应该使用哪个变体?
4

8 回答 8

19

没有其他人提到的是

int *ptr;

更接近于语言语法。

  • int *ptr;是一个声明,它包括:
    • 一个声明说明符 int,后跟
    • 一个声明者, *ptr.

(这实际上跳过了许多步骤,但它传达了基本思想。)

由于声明遵循使用,这意味着它*ptr是类型int。由此得出ptr类型为int*

有人可能会争辩说,这使它比

int* ptr;

出于同样的原因

x = y+z;

好于

x=y + z;

当然可以

int* ptr;

并将其读作“ptr是类型int*”。许多程序员都这样做,而且相处得很好(它往往是 C++ 中的首选风格)。编译器不在乎你用哪种方式来做,任何阅读你的代码的人都不应该在理解它时遇到困难。

但无论您选择哪种间距,您都需要了解int *ptr;真正的含义,这样当您看到

int *ptr, i;

在别人的代码中(你不可避免地会这样),你会立即明白那ptr是一个指针并且i是一个 int。

如果您正在与其他程序员一起在一个项目上工作,您应该遵循编码标准中的任何现有约定,或者如果没有,则遵循已经编写代码的方式。我个人更喜欢int *ptr;int* ptr;但混合使用这两种风格远不如始终使用其中一种风格。

于 2012-01-20T21:19:50.920 回答
14

两者在功能上绝对没有区别

int* ptr;

int *ptr;

您使用哪种取决于您,有多种相互冲突的编码样式可供选择。

于 2012-01-20T20:11:36.867 回答
11
T *a;

is the preferred C style for declaring a pointer to T as used in Kernighan & Ritchie's book about C, as well as in ISO/IEC 9899:2018.

T* a;

is the preferred C++ style way to a declare pointer to T as used in Stroustrup's book about C++.

Both notations are equivalent.

于 2012-01-20T21:16:10.847 回答
11

仅当您计划在同一行上声明多个相同类型的变量时才重要。例如,如果你想要多个 int 指针,你需要这样做:

int *a, *b, *c;

但是,从风格上讲,当您只声明一个变量时,这会让人感到困惑。很多人喜欢看类型后跟变量名,而类型应该是指向 int 的指针,而不是 int,所以他们更喜欢:

int* a;
int* b;
int* c;

最终取决于您是否更喜欢一种形式而不是另一种形式。在 20 年的专业 C 编程生涯中,我看到大约 50% 的人选择其中之一。

于 2012-01-20T20:13:41.763 回答
9

他们的意思和其他人说的一样。不过有一个陷阱在等着你。考虑这段代码:

int* a, b;

您可能认为 this 声明了指向int. 不是这样,否则。事实上aint*但是bint。这是许多 C 程序员更喜欢将*next 放在变量而不是类型的原因之一。当这样写时:

int *a, b;

你不太可能被误导什么ab是什么。

说了这么多,许多编码标准坚持每行声明不超过一个变量,即

int* a;
int b;

如果您遵循每行一个变量的规则,那么绝对没有混淆的余地。

于 2012-01-20T20:46:34.730 回答
4

C 声明基于表达式的类型,而不是对象。

如果你有一个指向intnamed的指针pi,并且你想访问它指向的整数值,你必须取消对指针的引用,如下所示:

x = *pi;
printf("%d", *pi);
*pi = 1 + 2;

等等。表达式 *pi的类型是int:因此,声明应该读作

int *pi;

char现在让我们假设你有一个指向;的指针数组。要获取任何字符,您需要先对数组下标,然后取消引用结果:

c = *pc[i];
if (*pc[j] == 'a') {...}

等等。同样,表达式 *pc[i]的类型是char,所以声明读作

char *pc[N];

两者*pi*pc[N]都称为声明符,并指定类型说明符未给出的附加类型信息。IOW,array-ness 和 pointer-nesspc被指定为声明符的一部分,而char-ness 由类型说明符给出。

至于哪种风格合适的问题......

两者都不是“正确的”,但我(和许多其他 C 程序员)更喜欢写T *p而不是T* p,因为它更接近地反映了语言语法(*是声明符的一部分),并且在声明多个项目时有助于避免混淆。我见过太多人们写作T* a, b;并期望b成为指针的例子。

对这种批评的通常反应是“每行不要申报超过一项”。我对该回复的回应是“正确编写你的声明器,你不会有任何问题”。

许多 C++ 程序员有不同的思想流派,他们更喜欢这种T* p风格,我不得不说有一些情况(仅限于 C++)它可以使代码更具可读性。

然而,这只适用于简单的指针T:当你开始处理指针数组、数组指针、函数指针或函数指针数组的指针等时,范式会迅速崩溃。我的意思是,写一些东西喜欢

T* (*(*p)[N])(); // p is a pointer to an array of pointers to functions
                 // returning pointers to T.

只是表示思维混乱。虽然,如果你真的真的觉得你必须遵循T* p范式,你总是可以创建一系列 typedef:

编辑

让我们再试一次:

typedef T* TPtr;                           // pointer to T
typedef TPtr TPtrFunc();                   // function returning pointer to T
typedef TPtrFunc* TPtrFuncPtr;             // pointer to function returning
                                           // pointer to T
typedef TPtrFuncPtr TPtrFuncPtrArray[N];   // N-element array of pointer to function
                                           // returning pointer to T

TPtrFuncPtrArray* p;

看在上帝的份上,不要那样做。

于 2012-01-20T22:33:29.170 回答
1

在 C 中,空格无关紧要,除非在需要分隔标记的地方。您的两个变体在语法上都是正确的。

变体 1 将指针运算符与类型相关联,这足够合乎逻辑。对我来说,如果没有变体 2 有意义的原因,那就足够了。

变体 2 与 C 声明的结构方式一致。在 C 语法中,指针运算符属于声明符(即带有名称),而不是类型。这在同一个声明中声明多个变量时很重要。还有一些更深奥的案例很重要。

因此,对我来说,变体 2 与 C 更一致。但是任何一个变体都是可辩护的,并且两个变体都是常规的。

于 2012-01-20T20:18:20.457 回答
0

您是对的,两者对编译器的含义完全相同。两个语句都会产生一个类型为 的变量(int *)

至于哪个是正确的:蠕虫罐头!这通常是一个辩论话题。如果您在一家公司或 OSS 工作,最好遵循已定义的编码风格。如果没有,我通常会采用 LNT(不留痕迹)风格来匹配这部分代码库中明显使用的任何风格。

可以说,对于读者来说,一个更容易理解。例如int* ptr;*越接近可以int更清楚地传达我们正在谈论的(int *)类型......

于 2012-01-20T20:16:17.253 回答