【问题标题】:Should I use char** argv or char* argv[]?我应该使用 char** argv 还是 char* argv[]?
【发布时间】:2010-10-21 06:19:09
【问题描述】:

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

【问题讨论】:

  • 我更喜欢'char **argv',所以我经常看到它,但两者都是正确的,我不会仅仅因为它写成'char *argv[]'而更改声明。
  • +1 因为数组与指针的更深层次的问题对于理解很重要。
  • 非常非常好的问题。谢谢。
  • 阅读comp.lang.c FAQ的第6节;这是我见过的对 C 数组和指针之间关系的最好解释。两个相关点: 1. char **argv 完全等同于 char *argv[] 作为参数声明(并且 only 作为参数声明)。 2.数组不是指针。

标签: c arrays pointers standards


【解决方案1】:

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

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

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

数组作为参数

第二个可能不是很清楚。但是,当您考虑到数组维度的大小是 C 中类型的一部分(并且未给出维度大小的数组具有不完整的类型)时,就会变得很清楚。因此,如果您要创建一个按值获取数组的函数(接收副本),那么它只能针对一种大小执行此操作!此外,数组可能会变大,C 会尽可能快。

在 C 中,由于这些原因,array-values 不存在。如果你想获取一个数组的值,你得到的是一个指向该数组第一个元素的指针。而这里实际上已经存在解决方案。 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;

【讨论】:

  • 不知道这个存在:*argv[static 1]
【解决方案2】:

你可以使用任何一个。它们是完全等价的。请参阅litb 的 cmets 和 his answer

这真的取决于你想如何使用它(在任何情况下你都可以使用):

// 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* argv[] 在用作函数的参数类型时与 char** argv 100% 等效。不涉及“const”,也不是隐含的。两者都是指向字符的指针。您声明的内容有所不同。但是编译器将参数的类型调整为指向指针的指针,即使您说它是一个数组。因此,以下都是相同的: void f(char *p[100]);无效 f(char *p[]); void f(char **p);
  • 在 C89(大多数人使用)中,也没有办法利用您将其声明为数组的事实(因此从语义上讲,是否您在那里声明了一个指针或一个数组 - 两者都将被视为一个指针)。从 C99 开始,您可以从将其声明为数组中受益。下面说:“p 总是非空的,并且指向一个至少有 100 字节的区域”: void f(char p[static 100]);但是请注意,从类型上讲,p 仍然是一个指针。
  • (特别是 &p 会给你一个 char**,而不是一个 char()[100] 如果 p *would 是一个数组,情况就是这样) .我很惊讶没有人在答案中提到。我认为理解这一点非常重要。
  • 我个人更喜欢char**,因为它提醒我它不应该被视为一个真正的数组,就像sizeof[arr] / sizeof[*arr]一样。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            【解决方案8】:

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

            【讨论】:

              【解决方案9】:

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

              【讨论】:

                【解决方案10】:

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

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

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

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

                【讨论】:

                • 这不能回答问题。
                猜你喜欢
                • 2011-07-08
                • 2022-07-14
                • 2017-03-11
                • 1970-01-01
                • 2015-12-21
                • 2015-10-24
                • 1970-01-01
                • 2011-10-24
                • 2011-01-04
                相关资源
                最近更新 更多