【问题标题】:What's char* const argv[]?什么是 char* const argv[]?
【发布时间】:2011-10-24 23:26:33
【问题描述】:

我在学习linux C++编程的时候看到

int execve(const char *path,
           char *const argv[],
           char *const envp[]);

我不明白 char *const argv[] 是什么。我知道char *const foo 是一个指向 char 的 const 指针。 const char *foo 是一个指向 const char 的指针。但是char *const argv[] 是什么?

是指向 char 的 const 指针数组还是指向 const char 的指针数组?

我现在有一个vector<string>,如何将其转换为char *const argv[]?

【问题讨论】:

    标签: c++ pointers char constants exec


    【解决方案1】:

    是指向 char 的 const 指针数组还是指向 const char 的指针数组?

    从右到左读取类型:
    const 总是绑定到左边(除非它在最左边)

    char *const argv[]
    
                    ^^ Array of
          ^^^^^        const
         ^             pointer to
    ^^^^               char
    

    "const pointer" 到 char 的数组

    所以不能修改数组中的指针。
    但他们指向的内容是可以修改的。

    注意:正如史蒂夫在下面指出的那样。因为这被用作参数。它实际上衰减为“指向 "const pointer" 的指针到 char”或“char* const *”。

    我现在有一个vector,如何将它转换为char *const argv[]?

    int execve(const char *path,
           char *const argv[],
           char *const envp[]);
    
    int main()
    {
        std::vector<std::string>   data;  /// fill
        std::vector<char*>         argv;
        std::vector<char*>         envp;
    
        for(std::vector<std::string>::iterator loop = data.begin(); loop != data.end(); ++loop)
        {
            argv.push_back(&(*loop)[0]);
        }
    
        // I also bet that argv and envp need to be NULL terminated
        argv.push_back(NULL);
        envp.push_back(NULL);
        execve("MyAppName", &argv[0], &envp[0]);
    }
    

    【讨论】:

    • char *const argv[]确实是数组类型,但是在这个上下文中是函数参数,类型不是char *const argv[],而是char *const *argv。
    【解决方案2】:

    cdecl.org 说:

    char *const argv[]
    

    将argv 声明为const 指向char 的指针的数组

    【讨论】:

    • 以及如何将vector&lt;string&gt; 转换为char *const argv[]?
    • @MrPhone:也许把它作为一个单独的问题发布。这很简单,但写出的不仅仅是评论。
    【解决方案3】:
    // says: argv is a constant pointer pointing to a char*
    int main(int c, char *const argv[]);
    

    您将无法在函数中更改“argv”。

    由于你刚刚学习 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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-30
      • 2018-01-06
      • 2011-08-14
      • 1970-01-01
      • 2012-07-21
      • 2022-07-14
      • 1970-01-01
      • 2015-10-24
      相关资源
      最近更新 更多