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

Kre*_*dns 122 c arrays standards pointers

我只是在学习C,并且想知道我应该在我的主要方法中使用哪一个.有什么区别吗?

编辑:那么哪一个更常用?

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)

  • 精彩的回答.谢谢. (11认同)
  • 不知道这个存在吗:* argv [静态1] (2认同)

ram*_*ion 12

你也可以使用它,这取决于你想要如何使用它. char* argv[]是(大部分)相当于char ** argv.这两种形式都是指向char的指针,唯一的区别是char *argv[]你告诉编译器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;
}
Run Code Online (Sandbox Code Playgroud)

至于哪个更常见 - 没关系.任何有经验的C程序员阅读您的代码都会看到两者都是可以互换的(在合适的条件下).就像一位经验丰富的英语演讲者同样容易读"他们是"和"他们".

更重要的是,你要学会阅读它们并认识它们有多相似.你会阅读比你写的更多的代码,你需要同样适应两者.

  • 当用作函数的参数类型时,char*argv [] 100%等效于char**argv.不涉及"const",也不是含蓄的.两者都是指向字符指针的指针.它与你声明的内容有所不同.但是编译器将参数的类型调整为指向指针的指针,即使你说它是一个数组.因此,以下都是相同的:void f(char*p [100]); void f(char*p []); void f(char**p); (7认同)
  • (特别是,&p会给你一个char**,但不是char(*)[100],如果p*将*是一个数组就是这种情况).我很惊讶在答案中没有人提到过.我认为理解非常重要. (5认同)
  • 在C89(大多数人使用)中,也没有办法从你将*声明为它作为一个数组的事实中获益(所以在语义上你是否在那里声明一个指针或数组并不重要 - 两者都将被采用作为指针).从C99开始,您可以将其声明为数组.以下说:"p始终为非null并指向至少有100bytes的区域":void f(char p [static 100]); 注意,在类型方面,p仍然是*指针. (4认同)

lot*_*har 9

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


Zif*_*fre 8

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