我只是在学习C,并且想知道在我的主要方法中应该使用哪一个。有什么区别吗?哪个更常见?
char **argv
完全等同于char *argv[]
作为参数声明(并且仅作为参数声明)。2.数组不是指针。
我只是在学习C,并且想知道在我的主要方法中应该使用哪一个。有什么区别吗?哪个更常见?
char **argv
完全等同于char *argv[]
作为参数声明(并且仅作为参数声明)。2.数组不是指针。
Answers:
当您刚刚学习C时,我建议您真正地尝试首先理解数组和指针之间的区别,而不是普通的东西。
在参数和数组方面,有一些令人困惑的规则应该在继续之前弄清楚。首先,您在参数列表中声明的内容是特殊的。在某些情况下,将事情作为C中的函数参数没有意义。
第二个也许还不清楚。但是,当您考虑到数组维的大小是C语言中的类型的一部分时(而未给出维大小的数组具有不完整的类型),这一点就变得很清楚。因此,如果您要创建一个函数,该函数需要一个按值作为数组的值(接收一个副本),那么它只能对一个大小执行此操作!另外,数组可能会变大,并且C会尝试尽可能快。
由于这些原因,在C中,不存在数组值。如果要获取数组的值,则获取的是指向该数组第一个元素的指针。解决方案实际上已经在这里。C编译器不会预先绘制无效的数组参数,而是将各个参数的类型转换为指针。记住这一点,这非常重要。该参数不是数组,而是一个指向各个元素类型的指针。
现在,如果您尝试传递数组,则传递的是指向数组第一个元素的指针。
为了完整起见,并且因为我认为这将帮助您更好地理解问题,所以让我们看看尝试将函数用作参数时的事务状态。确实,首先这没有任何意义。参数如何成为函数?嗯,我们当然想要那个地方的变量!那么,当这种情况发生的编译器所做的是,再次,要转变功能为函数指针。尝试传递一个函数将改为传递一个指向该函数的指针。因此,以下内容相同(类似于数组示例):
void f(void g(void));
void f(void (*g)(void));
注意,*g
需要用括号括起来。否则,它将指定一个returning函数void*
,而不是一个指向returning函数的指针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]);
当然,可以在其中放置任何大小都没有多大意义,而只是被扔掉了。因此,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);
最后两行说您将无法在函数中更改“ 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;
您可以使用任何一个。它们完全等效。请参阅litb的评论和他的答案。
这实际上取决于您要使用它的方式(在任何情况下都可以使用):
// 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;
}
至于哪个更常见-没关系。任何有经验的C语言程序员(在适当的条件下)都可以互换代码。就像一位经验丰富的英语讲者一样轻松地读“他们是”和“他们是”。
更重要的是,您学会阅读它们并认识它们的相似之处。您阅读的代码将比编写的更多,并且您需要对两者都同样满意。
char**
因为它提醒我不应将其视为真实数组,例如doing sizeof[arr] / sizeof[*arr]
。
您可以使用两种形式中的任何一种,例如在C数组中,并且指针在函数参数列表中可以互换。请参阅http://en.wikipedia.org/wiki/C_(programming_language)#Array-pointer_interchangeability。