简体   繁体   English

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

[英]C++ - char** argv vs. char* argv[]

What is the difference between char** argv and char* argv[] ? char** argvchar* argv[]什么区别? in int main(int argc, char** argv) and int main(int argc, char* argv[]) ?int main(int argc, char** argv)int main(int argc, char* argv[])

Are they the same?他们是一样的吗? Especially that the first part does not have [] .特别是第一部分没有[]

They are entirely equivalent. 它们完全相同。 char *argv[] must be read as array of pointers to char and an array argument is demoted to a pointer, so pointer to pointer to char , or char ** . char *argv[]必须被读作char的指针数组,并且数组参数被降级为指针,因此指向charchar **指针。

This is the same in C . 这在C中是相同的。

They are indeed exactly the same. 它们确实完全一样。

The golden rule of arrays to remember is: 要记住的数组的黄金法则是:

"The name of an array is a pointer to the first element of the array." “数组的名称是指向数组第一个元素的指针。”

So if you declare the following: 因此,如果您声明以下内容:

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

Then the variable "text" is a pointer to the first char in the array of chars you've just declared. 然后变量“text”是指向你刚刚声明的字符数组中第一个字符的指针。 In other words, "text" is of type char * . 换句话说,“text”的类型为char * When you access an element of an array using [ index ], what you're actually doing is adding an offset of index to the pointer to the first element of the array, and then dereferencing this new pointer. 当您使用[ index ]访问数组的元素时,您实际在做的是将索引的偏移量添加到指向数组的第一个元素的指针,然后取消引用此新指针。 The following two lines will therefore initialize both variables to 't': 因此,以下两行将两个变量初始化为't':

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

Using the square brackets is a convience provided by the language that makes the code much more readable. 使用方括号是一种由语言提供的便利性,使代码更具可读性。 But the way this works is very important when you start thinking about more complex things, such as pointers to pointers. 但是当你开始考虑更复杂的事情时,例如指针指针,这种方法非常重要。 char** argv is the same as char* argv[] because in the second case "the name of the array is a pointer to the first element in the array". char** argvchar* argv[]相同,因为在第二种情况下“数组的名称是指向数组中第一个元素的指针 ”。

From this you should also be able to see why it is that array indexes start from 0. The pointer to the first element is the array's variable name (golden rule again) plus an offset of... nothing! 从这里你也应该能够看到为什么数组索引从0开始。指向第一个元素的指针是数组的变量名(再次是黄金法则)加上偏移量......没有!

I've had debates with a friend of mine as to which is better to use here. 我和我的一个朋友讨论过哪个更好用。 With the char* argv[] notation it may be clearer to the reader that this is in fact an "array of pointers to characters" as opposed to the char** argv notation which can be read as a "pointer to a pointer to a character". 使用char* argv[]符号,读者可能会更清楚这实际上是一个“指向字符的指针数组”而不是char** argv符号,它可以被读作“指向指针的指针”字符”。 My opinion is that this latter notation doesn't convey as much information to the reader. 我的观点是,后一种符号并没有向读者传达那么多信息。

It's good to know that they're exactly the same, but for readablity I think that if the intention is an array of pointers then the char* argv[] notation conveys this much more clearly. 很高兴知道它们是完全相同的,但是为了可读性,我认为如果意图是一个指针数组,那么char* argv[]表示法会更清楚地传达这一点。

For all practical purposes, they're the same. 出于所有实际目的,它们是相同的。 This is due to C/C++'s handling of arrays passed as arguments, where an array decays to a pointer. 这是由于C / C ++处理作为参数传递的数组,其中数组衰减为指针。

For the first part of the question: 对于问题的第一部分:

  • char** argv: pointer to a pointer to a char char ** argv:指向char的指针
  • char* argv[]: pointer to an array char * argv []:指向数组的指针

So the question is whether a pointer to a type C and an array C[] are the same things. 所以问题是指向类型C和数组C []的指针是否相同。 They are not at all in general, BUT they are equivalent when used in signatures . 它们一般都不是,但在签名中使用时它们是等价的

In other words, there is no difference in your example, but it is important to keep in mind the difference between pointer and array otherwise. 换句话说,您的示例没有区别,但重要的是要记住指针和数组之间的区别。

The bracket form is only useful in statement declarations like: 括号形式仅在语句声明中有用,例如:

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

Because it knows at compile time the size of the array. 因为它在编译时知道数组的大小。 When you pass a bracket form as parameter to a function (main or some other one), the compiler has no idea what the size of the array would be at runtime, so it is exactly the same as char **a. 将括号形式作为参数传递给函数(main或其他函数)时,编译器不知道数组在运行时的大小,因此它与char ** a完全相同。 I prefer char **argv since it's clearer that sizeof wouldn't work like it would on the statement declaration form. 我更喜欢char ** argv,因为更清楚的是sizeof不会像声明声明表单那样工作。

This is a simple example I came up with, which have two functions (Main_1, Main_2) take the same arguments as the main function.这是我想出的一个简单示例,其中有两个函数(Main_1、Main_2)采用与主函数相同的参数。

I hope this clear things up..我希望这能解决问题..

#include <iostream>

void Main_1(int argc, char **argv)
{
    for (int i = 0; i < argc; i++)
    {
        std::cout << *(argv + i) << std::endl;
    }
}

void Main_2(int argc, char *argv[])
{
    for (int i = 0; i < argc; i++)
    {
        std::cout << *(argv + i) << std::endl;
    }
}

int main()
{

    // character arrays with null terminators (0 or '\o')
    char arg1[] = {'h', 'e', 'l', 'l', 'o', 0};
    char arg2[] = {'h', 'o', 'w', 0};
    char arg3[] = {'a', 'r', 'e', '\0'};
    char arg4[] = {'y', 'o', 'u', '\n', '\0'};

    // arguments count
    int argc = 4;

    // array of char pointers (point to each character array (arg1, arg2, arg3 and arg4)
    char *argPtrs[] = {arg1, arg2, arg3, arg4};

    // pointer to char pointer array (argPtrs)
    char **argv = argPtrs;

    Main_1(argc, argv);
    Main_2(argc, argv);

    // or

    Main_1(argc, argPtrs);
    Main_2(argc, argPtrs);

    return 0;
}

Output :输出 :

hello
how
are
you

hello
how
are
you

hello
how
are
you

hello
how
are
you

There is a difference between TYPE * NAME and TYPE NAME[] in both C and C++. C和C ++中的TYPE * NAMETYPE NAME[]之间存在差异。 In C++ both types are not interchagneable. 在C ++中,这两种类型都不可交叉。 For example following function is illegal (you will get an error) in C++, but legal in C (you will get warning): 例如,以下函数在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;
}

To make it legal just change signature to int some (int (*a)[3]) (pointer to array of 3 ints) or int some (int a[][3]) . 为了使其合法,只需将签名更改为int some (int (*a)[3]) (指向3个int的数组)或int some (int a[][3]) The number in last square brackets must be equal to an argument's. 最后一个方括号中的数字必须等于一个参数。 Converting from array of arrays to an array of pointers is illegal. 从数组数组转换为指针数组是非法的。 Converting from pointer to pointer to array of arrays is illegal too. 从指针转换为指针到数组数组也是非法的。 But converting pointer to pointer to an array of pointers is legal! 但是将指针转换为指向指针数组的指针是合法的!

So remember: Only nearest to dereference type signature doesn't matter, others do (in the context of pointers and arrays, sure). 所以请记住: 只有最接近解除引用类型签名并不重要,其他人 (在指针和数组的上下文中,确定)。

Consider we have a as pointer to pointer to int: 考虑我们有一个as指针指向int:

int ** a;
&a     ->     a    ->    *a    ->    **a
(1)          (2)         (3)          (4)
  1. You cannot change this value, the type is int *** . 你不能改变这个值,类型是int *** May be taken by function as int **b[] or int ***b . 可以通过函数作为int **b[]int ***b The best is int *** const b . 最好的是int *** const b
  2. The type is int ** . 类型是int ** May be taken by function as int *b[] or int ** b . 函数可以作为int *b[]int ** b Brackets of the array declaratin may be leaved empty or contain any number. 阵列声明的括号可以留空或包含任何数字。
  3. The type is int * . 类型是int * May be taken by function as int b[] or int * b or even void * b 函数可以作为int b[]int * b甚至void * b
  4. Should be taken as int parameter. 应该作为int参数。 I don't want to fall into details, like implicit constructor call. 我不想陷入细节,比如隐式构造函数调用。

Answering your question: the real type of argumets in main function is char ** argv , so it may be easily represented as char *argv[] (but not as char (*argv)[] ). 回答你的问题: main函数中真正的争论类型是char ** argv ,因此它可以很容易地表示为char *argv[] (但不能表示为char (*argv)[] )。 Also argv name of main function may be safely changed. 也可以安全地更改主要功能的argv名称。 You may check it easily: std::cout << typeid(argv).name(); 您可以轻松检查它: std::cout << typeid(argv).name(); (PPc = pointer to p. to char) (PPc = p。指向char的指针)

By the way: there is a cool feature, passing arrays as references: 顺便说一句:有一个很酷的功能,将数组作为引用传递:

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

Moreover pointer to anything may be implicitly accepted (converted) by function as void pointer. 此外,指向任何事物的指针可能被函数隐式接受(转换)为void指针。 But only single pointer (not pointer to pointer etc.). 但只有单个指针(不是指针指针等)。

Further reading: 进一步阅读:

  1. Bjarne Stroustrup, C++, chapter 7.4 Bjarne Stroustrup,C ++,第7.4章
  2. C pointers FAQ C指针常见问题

Both are same for your usage except for the following subtle differences: 两者的用法相同,但以下细微差别除外:

  • Sizeof will give different results for both Sizeof将为两者提供不同的结果
  • Also second one may not be reassigned to new memory area since it's an array 另外,第二个可能不会重新分配给新的内存区域,因为它是一个数组
  • With second one you can use only those indexes which are valid. 对于第二个,您只能使用那些有效的索引。 It's unspecified by C/C++ if you try to use an array index beyond array length. 如果您尝试使用超出数组长度的数组索引,则未指定C / C ++。 However with char** you can use any index from 0 to ... 但是使用char **你可以使用0到...之间的任何索引
  • Second form can only be used as formal parameters to a function. 第二种形式只能用作函数的形式参数。 While first can even be used to declare variables within a stack. 虽然第一个甚至可以用于在堆栈中声明变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM