127

我刚刚学习 C 并且想知道我应该在我的主要方法中使用其中的哪一个。有什么区别吗?哪个更常见?

4

10 回答 10

165

由于您刚刚学习 C,我建议您首先真正尝试理解数组和指针之间的区别,而不是常见的东西。

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

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

数组作为参数

第二个可能不是很清楚。但是,当您考虑到数组维度的大小是 C 中类型的一部分(并且未给出维度大小的数组具有不完整的类型)时,就会变得很清楚。因此,如果您要创建一个按值获取数组的函数(接收副本),那么它只能针对一种大小执行此操作!此外,数组可能会变大,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” - 它已成为 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;
于 2009-04-23T02:59:30.197 回答
13

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

更重要的是你学会阅读它们并认识到它们有多么相似。您将阅读比编写更多的代码,并且您需要对两者都同样熟悉。

于 2009-04-23T01:13:00.483 回答
10

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

于 2009-04-23T01:08:01.137 回答
9

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

于 2009-04-23T01:04:44.793 回答
4

它并没有真正的区别,但后者更具可读性。你得到的是一个字符指针数组,就像第二个版本说的那样。但是,它可以像第一个版本一样隐式转换为双字符指针。

于 2009-04-23T01:05:24.107 回答
2

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

于 2015-02-08T07:41:44.567 回答
1

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

于 2009-04-23T01:10:22.097 回答
0

我认为使用任何一种方法而不是另一种方法没有什么特别的优点——使用最符合您的代码其余部分的约定。

于 2009-04-23T08:25:10.837 回答
-2

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

于 2009-04-23T01:21:38.123 回答
-2

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

如果您不使用命令行参数,也不要使用。只需将 main 函数声明为int main() If you

  • 希望您的程序的用户能够将文件拖到您的程序上,以便您可以使用它来更改程序的结果,或者
  • 想要处理命令行选项(-help,/?或任何其他program name在终端或命令提示符后出现的东西)

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

于 2012-04-02T20:45:33.463 回答