C ++ - char ** argv与char * argv []

时间:2011-03-04 09:44:17

标签: c++ main arguments

char** argvchar* argv[]之间有什么区别?在int main(int argc, char** argv)int main(int argc, char* argv[])

它们是一样的吗?特别是第一部分没有[]

7 个答案:

答案 0 :(得分:53)

它们完全等同。必须将char *argv[]读作指向char的指针数组,并将数组参数降级为指针,因此指针指向charchar **

C中的情况相同。

答案 1 :(得分:23)

他们确实完全一样。

要记住的数组的黄金法则是:

“数组的名称是指向数组第一个元素的指针。”

因此,如果您声明以下内容:

char text[] = "A string of characters.";

然后变量“text”是指向你刚刚声明的字符数组中第一个字符的指针。换句话说,“text”的类型为char *。当您使用[ index ]访问数组的元素时,您实际在做的是将 index 的偏移量添加到指向数组的第一个元素的指针,然后解除引用这个新指针。因此,以下两行将两个变量初始化为't':

char thirdChar = text[3];
char thirdChar2 = *(text+3);

使用方括号是一种由语言提供的便利性,使代码更具可读性。但是当你开始考虑更复杂的事情时,例如指针指针,这种方法非常重要。 char** argvchar* argv[]相同,因为在第二种情况下,“数组的名称是指针到数组中的第一个元素”。

从这里你也应该能够看到为什么数组索引从0开始。指向第一个元素的指针是数组的变量名(再次是黄金法则)加上偏移量......没有!

我和我的一个朋友讨论过哪个更好用。使用char* argv[]符号,读者可能会更清楚这实际上是一个“字符指针数组”而不是char** argv符号,它可以被读作“指向指针的指针”一个人物”。我的观点是,后一种符号并没有向读者传达那么多信息。

很高兴知道它们完全一样,但是为了可读性,我认为如果意图是一个指针数组,那么char* argv[]符号可以更清楚地传达这一点。

答案 2 :(得分:3)

出于所有实际目的,它们是相同的。这是由于C / C ++对作为参数传递的数组的处理,其中数组衰减为指针。

答案 3 :(得分:3)

问题的第一部分:

  • char ** argv:指向char的指针
  • char * argv []:指向数组的指针

所以问题是指向类型C和数组C []的指针是否相同。它们一般都不是,但它们是equivalent when used in signatures

换句话说,你的例子没有区别,但重要的是要记住指针和数组之间的区别。

答案 4 :(得分:2)

括号形式仅在语句声明中有用,如:

char *a[] = {"foo", "bar", "baz"};
printf("%d\n", sizeof a / sizeof *a);
// prints 3

因为它在编译时知道数组的大小。将括号形式作为参数传递给函数(main或其他函数)时,编译器不知道数组在运行时的大小,因此它与char ** a完全相同。我更喜欢char ** argv,因为更清楚的是sizeof不会像声明声明表那样工作。

答案 5 :(得分:-1)

C和C ++中TYPE * NAMETYPE NAME[]之间存在差异。在C ++中,这两种类型都不可交叉。例如,以下函数在C ++中是非法的(您将收到错误),但在C中是合法的(您将收到警告):

int some (int *a[3]) // a is array of dimension 3 of pointers to int
{
    return sizeof a;
}

int main ()
{
    int x[3][3];
    std::cout << some(x)<< std::endl;
    return 0;
}

要使其合法,只需将签名更改为int some (int (*a)[3])(指向3个整数的数组)或int some (int a[][3])。最后一个方括号中的数字必须等于一个参数。从数组数组转换为指针数组是非法的。从指针转换为指针到数组数组也是非法的。但是将指针转换为指向指针数组的指针是合法的!

所以请记住:最接近解除引用类型签名无关紧要,其他人(在指针和数组的上下文中,确实如此)。

考虑我们有一个as指针指向int:

int ** a;
&a     ->     a    ->    *a    ->    **a
(1)          (2)         (3)          (4)
  1. 您无法更改此值,类型为int ***。可以按int **b[]int ***b的功能使用。最好的是int *** const b
  2. 类型为int **。可以按int *b[]int ** b的功能使用。数组声明的括号可以留空或包含任何数字。
  3. 类型为int *。可以通过int b[]int * b或甚至void * b
  4. 的功能来执行
  5. 应该作为int参数。我不想陷入细节,比如隐式构造函数调用。
  6. 回答您的问题:主要功能中的实际类型char ** argv,因此可以很容易地表示为char *argv[](但是不是char (*argv)[])。此外,argv主要功能的名称可能会safely更改。 您可以轻松检查:std::cout << typeid(argv).name();(PPc =指向p。指向char的指针)

    顺便说一句:有一个很酷的功能,将数组作为引用传递:

    void somef(int (&arr)[3])
    {
        printf("%i", (sizeof arr)/(sizeof(int))); // will print 3!
    }
    

    此外指向任何事物的指针可能被函数隐式接受(转换)为void指针。但只有单个指针(不是指针指针等)。

    进一步阅读:

    1. Bjarne Stroustrup,C ++,第7.4章
    2. C pointers FAQ

答案 6 :(得分:-2)

除了以下细微差别外,两者的用法相同:

  • Sizeof将为两者提供不同的结果
  • 第二个可能不会被重新分配到新的内存区域,因为它是一个数组
  • 使用第二个,您只能使用那些索引 有效。如果您尝试使用超出的数组索引,则未指定C / C ++ 数组长度。但是使用char **,您可以使用0到...
  • 之间的任何索引
  • 第二种形式只能用作函数的形式参数。虽然第一个甚至可以用于在堆栈中声明变量。