我应该使用 char * * argv 还是 char * argv [] ?

我正在学习 C 语言,想知道在我的主要方法中应该使用哪一个。有区别吗?哪个更常见?

88282 次浏览

您可以使用这两种形式中的任何一种,比如在 C 数组中,函数参数列表中的指针是可互换的。参见 http://en.wikipedia.org/wiki/C_(programming_language)#Array-pointer_interchangeability

其实没什么区别,但后者更易读。给出的是一个字符指针数组,就像第二个版本所说的那样。但是,它可以像第一个版本那样隐式地转换为双字符指针。

这没有什么区别,但我使用 char *argv[]是因为它显示了一个固定大小的可变长度字符串数组(通常是 char *)。

Char * * →指向字符指针的指针,char * argv []表示字符指针的数组。因为我们可以使用指针代替数组,所以两者都可以使用。

两者都可以使用。它们是完全等价的。请参阅 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 程序员阅读您的代码将看到这两者是可互换的(在正确的条件下)。就像一个有经验的说英语的人同样容易读出“ they’re”和“ they are”。

更重要的是,你要学会阅读它们,并认识到它们有多么相似。您阅读的代码将多于编写的代码,并且您需要同样适应这两种情况。

如果需要不断变化或动态的字符串数量,那么使用 char * * 可能更容易。但是,如果字符串的数量是固定的,则首选 char * var []。

由于您正在学习 C 语言,我建议您首先真正尝试理解数组和指针之间的 分歧,而不是 很普通

在参数和数组方面,有一些令人困惑的规则,在继续之前应该弄清楚。首先,在参数列表中声明的内容被视为特殊的。在 C 语言中,有些情况下作为函数参数是没有意义的。这些是

  • 函数作为参数
  • 数组作为参数

数组作为参数

第二种可能性不是很明显。但是,当考虑到数组维度的大小是 C 中类型的一部分时,就很清楚了(没有给出维度大小的数组具有不完整的类型)。因此,如果您要创建一个接受数组 by-value (接收副本)的函数,那么它只能对一个大小执行此操作!此外,数组可以变得很大,而 C 则尽可能地快。

在 C 语言中,由于这些原因,数组值不存在。如果你想得到一个数组的值,你得到的是一个指向该数组第一个元素的指针。这里实际上已经有了解决方案。C 编译器不会预先绘制无效的数组参数,而是将 变形的相应参数类型作为指针。记住,这很重要。参数不是数组,而是指向相应元素类型的指针。

现在,如果尝试传递数组,那么传递的是指向数组第一个元素的指针。

偏移: 作为参数的函数

为了完成,并且因为我认为这将帮助您更好地理解这个问题,让我们看看当您尝试将函数作为参数时的状态是什么。事实上,首先它不会有任何意义。参数怎么可能是函数?我们当然希望那里有个变量!所以当这种情况发生时,编译器所做的就是把函数转换成 函数指针。尝试传递一个函数将会传递一个指向相应函数的指针。因此,下面是相同的(类似于数组示例) :

void f(void g(void));
void f(void (*g)(void));

请注意,需要在 *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]);

当然,放任何尺寸都没有太大意义,它只是被扔掉了。出于这个原因,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”——它已经变成了一个常量指针。但是只有少数 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;

我看不出使用任何一种方法而不是另一种方法有什么特别的优点——使用与代码的其余部分最一致的约定。

我知道这已经过时了,但是如果您只是在学习 C 编程语言,并且没有做任何重要的工作,那么不要使用命令行选项。

如果没有使用命令行参数,也不要使用任何一个参数。只需将 main 函数声明为 int main()即可 如果你

  • 希望您的程序的用户能够将一个文件拖动到您的程序中,以便您可以使用它或
  • 希望处理命令行选项(-help/?或任何其他在终端或命令提示符 program name之后的选项)

使用对你更有意义的方法。 否则,就使用 int main() 毕竟,如果您最终想要添加命令行选项,您可以在以后轻松地编辑它们。

您应该将其声明为 char *argv[],因为声明它的方式有很多种,最接近它的直观含义: 字符串数组。