Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当c指针在c指针上时,很难理解它';s自身(第二部分)_C_Pointers - Fatal编程技术网

当c指针在c指针上时,很难理解它';s自身(第二部分)

当c指针在c指针上时,很难理解它';s自身(第二部分),c,pointers,C,Pointers,当我看到实际的乘法运算时,我问了这个问题,每个人都帮助我清楚地理解它(所以我非常感激) 然而,在不同的情况下,这仍然困扰着我 比如, int main(int argc, const char * argv[] ) 为什么上面写的和下面不一样 int main(int argc, const char *argv[] ) 有区别吗?有时我会看到*的一些奇怪的位置,我只是不明白为什么它们有时似乎在它们喜欢的任何地方浮动(或者我猜是谁知道它们在做什么)。您显示的两行代码的含义完全相同。C通常忽

当我看到实际的乘法运算时,我问了这个问题,每个人都帮助我清楚地理解它(所以我非常感激)

然而,在不同的情况下,这仍然困扰着我

比如,

int main(int argc, const char * argv[] )
为什么上面写的和下面不一样

int main(int argc, const char *argv[] ) 

有区别吗?有时我会看到*的一些奇怪的位置,我只是不明白为什么它们有时似乎在它们喜欢的任何地方浮动(或者我猜是谁知道它们在做什么)。

您显示的两行代码的含义完全相同。C通常忽略水平空白;它唯一起作用的是(1)字符串内的文字,(2)当它更改标记的边界时(考虑
++x
++x
),(3)当它控制您是
#定义类似函数还是类似对象的宏时

在类型声明的上下文中,
*
不是二进制乘法运算符,它是指向修饰符的一元指针,并且它总是影响右边的事物。为清楚起见,编写时应始终在左侧留有空格,右侧不留空格,但编译器并不在意


在C++中,将星向左拥抱是错误的,因为它是误导的:<代码> char *a,b < /c>不声明为<代码> a <代码> >代码> b >代码>作为指针。首先在一行上声明变量,这本身就是一个合理的位置,但并不是误导人类读者有关
*
绑定方向的有效借口。然而,这完全是风格问题,编译器也不在乎。)

在这种情况下,空格并不重要。您可以将其写成

char *argv[]

甚至

char*argv[]
所有四种形式都被解析为
char(*argv[])
*
运算符是声明符的一部分(与
[]
运算符一样)

在编译过程中,源代码被分解为标记;非正式地说,标记是程序中最小的有意义的部分(关键字、运算符、标识符、文字、标点符号等)。标记根据语言语法分为表达式和语句

C的标记化算法是“贪婪的”;它将尝试从源文本中形成尽可能长的标记,因此有时需要用空格分隔标记。例如,如果编译器看到文本
“charfoo;”“
”,它会将其标记为
charfoo
(由于
字符不是标识符的一部分,因此
是一个单独的标记)。它不会将
char
识别为单独的标记,因为在此阶段它不会查找特定的关键字。为了将其识别为声明,在
char
foo
之间至少需要一个空格字符:
“char foo;”
.Whitespace与
';“
一样,不是标识符(或任何其他标记)的一部分,因此它将
char
foo
标记相互分离。由于在此阶段,除了分隔标记外,空格没有任何意义,因此使用一个空格、十个空格还是一百个空格都无关紧要;
“char foo;”
也同样有效

不过,将
“*”
字符放入混合字符中,就不需要空白:
“char*foo;”
将被标记为
char
*
foo
,因为
'*'
字符,就像空格和
';
字符一样,不是标识符的一部分。它本身就是一个独特的标记。在这些标记之间添加空格不会有什么坏处,但就编译器而言,它不会改变任何事情

因此,
char*argv[]
被标记为
char
*
argv
[
,和
]
。因为您有
*
分隔
char
argv
,所以它们之间的空格大小无关紧要

此时,编译器使用语言语法确定应如何解释标记序列。
char
是一个类型说明符,因此编译器假定这是声明的开始。由于这是一个声明,
*
运算符被解释为一元间接运算符,而不是二进制乘法运算符

在这一点上,运算符的优先级开始发挥作用。
[]
等后缀运算符的优先级高于一元运算符,因此
*a[N]
被解析为
*(a[N])
a
是指针的
N
-元素数组)。因此,
argv
是指向
char
的指针数组

不幸的是,在这一点上还有一些额外的奇怪之处;C处理数组的方式……不同于其他语言,而这个特定的声明实际上将
argv
声明为指向
char
的指针


然而,这是另一天的问题。

编译器没有什么不同。人们根据自己或团队的偏好选择不同的样式。就编译器而言,您甚至可以编写
char*argv
。底线是编译器足够聪明,能够知道何时使用将
*
视为
乘法
解引用
运算符。可能是重复的谢谢大家的回答。这对我帮助很大,尽管这是我讨厌的类型…一分钟后你认为你学到了一些东西,但后来类似的东西显示出来,这完全把我甩了。谢谢
char      *        argv     [              ]
char*argv[]