Joh*_*itb 158
由于您只是学习C,我建议您首先尝试理解数组和指针之间的差异,而不是常见的事情.
在参数和数组领域,有一些令人困惑的规则应该在继续之前清楚.首先,您在参数列表中声明的内容将被视为特殊内容.存在这样的情况,其中事物作为C中的函数参数没有意义.这些是
第二个可能不是立即清楚.但是当你考虑到数组维度的大小是C中类型的一部分时(而且没有给出维度大小的数组具有不完整的类型),就会变得很清楚.因此,如果您要创建一个采用数组按值(接收副本)的函数,那么它只能用于一个大小!此外,数组可能会变大,而C会尽可能快地尝试.
在C中,由于这些原因,不存在数组值.如果要获取数组的值,则获得的是指向该数组的第一个元素的指针.而这里实际上已经是解决方案了.C编译器不会在前面绘制数组参数,而是将相应参数的类型转换为指针.记住这一点,这非常重要.该参数不是数组,而是指向相应元素类型的指针.
现在,如果您尝试传递数组,则传递的是指向数组的第一个元素的指针.
为了完成,并且因为我认为这将有助于您更好地理解这个问题,让我们看看当您尝试将函数作为参数时的状态.的确,首先它没有任何意义.参数如何成为函数?嗯,当然,我们想要一个变量!那么究竟是什么发生这种情况时,编译器,再次以转换函数为函数指针.尝试传递函数将传递指向相应函数的指针.所以,以下是相同的(类似于数组示例):
void f(void g(void));
void f(void (*g)(void));
Run Code Online (Sandbox Code Playgroud)
请注意,*g需要括号.否则,它将指定一个返回的函数void*,而不是指向返回函数的指针void.
现在,我在开始时说过,数组可能有一个不完整的类型 - 如果你还没有给出一个大小,就会发生这种情况.由于我们已经知道数组参数不存在,而是任何数组参数都是指针,因此数组的大小无关紧要.这意味着,编译器将翻译以下所有内容,并且所有内容都是相同的:
int main(int c, char **argv);
int main(int c, char *argv[]);
int main(int c, char *argv[1]);
int main(int c, char *argv[42]);
Run Code Online (Sandbox Code Playgroud)
当然,能够在其中放置任何尺寸并没有多大意义,它只是扔掉了.出于这个原因,C99为这些数字提出了新的含义,并允许在括号之间出现其他内容:
// says: argv is a non-null pointer pointing to at least 5 char*'s
// allows CPU to pre-load some memory.
int main(int c, char *argv[static 5]);
// says: argv is a constant pointer pointing to a char*
int main(int c, char *argv[const]);
// says the same as the previous one
int main(int c, char ** const argv);
Run Code Online (Sandbox Code Playgroud)
最后两行表示你将无法在函数中更改"argv" - 它已成为一个const指针.但是只有少数C编译器支持这些C99功能.但是这些特征清楚地表明"阵列"实际上并不是一个.这是一个指针.
请注意,只有当您将数组作为函数的参数时,我所说的才是真的.如果使用本地数组,则数组将不是指针.它将表现为指针,因为如前所述,数组在读取其值时将转换为指针.但它不应该与指针混淆.
一个典型的例子如下:
char c[10];
char **c = &c; // does not work.
typedef char array[10];
array *pc = &c; // *does* work.
// same without typedef. Parens needed, because [...] has
// higher precedence than '*'. Analogous to the function example above.
char (*array)[10] = &c;
Run Code Online (Sandbox Code Playgroud)
ram*_*ion 12
你也可以使用它,这取决于你想要如何使用它. 实际上,我错了,他们完全等同.请参阅litb的评论和他的回答.char* argv[]是(大部分)相当于char ** argv.这两种形式都是指向char的指针,唯一的区别是char *argv[]你告诉编译器argv的值不会改变(尽管它指向的值仍然可以).
这真的取决于你想要如何使用它(你可以在任何情况下使用):
// echo-with-pointer-arithmetic.c
#include <stdio.h>
int main(int argc, char **argv)
{
while (--argc > 0)
{
printf("%s ", *++argv);
}
printf("\n");
return 0;
}
// echo-without-pointer-arithmetic.c
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
for (i=1; i<argc; i++)
{
printf("%s ", argv[i]);
}
printf("\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
至于哪个更常见 - 没关系.任何有经验的C程序员阅读您的代码都会看到两者都是可以互换的(在合适的条件下).就像一位经验丰富的英语演讲者同样容易读"他们是"和"他们".
更重要的是,你要学会阅读它们并认识它们有多相似.你会阅读比你写的更多的代码,你需要同样适应两者.
您可以使用这两种形式中的任何一种,如在C数组中,指针在函数参数列表中可以互换.见http://en.wikipedia.org/wiki/C_(programming_language)#Array-pointer_interchangeability.