C 外部字符**环境和外部字符*环境[]之间的区别是什么

C 外部字符**环境和外部字符*环境[]之间的区别是什么,c,linux,C,Linux,我想打印所有环境,但无法打印。 我将extern char*environ[]更改为extern char**environ,它可以打印所有环境。 更改代码输出后: Environment variables: envp[0]: GH#þ Extern实际上提供了对所有程序文件可见的全局变量的引用 指针指向指针它将赋值或内存分配保留在函数调用之外。第一个指针用于存储第二个指针的地址,因为它被称为双指针 extern char**environ:表示环境列表(即双指针) extern ch

我想打印所有环境,但无法打印。
我将
extern char*environ[]
更改为
extern char**environ
,它可以打印所有环境。
更改代码输出后:

Environment variables:  
envp[0]: GH#þ 

Extern实际上提供了对所有程序文件可见的全局变量的引用

指针指向指针它将赋值或内存分配保留在函数调用之外。第一个指针用于存储第二个指针的地址,因为它被称为双指针

  • extern char**environ
    :表示环境列表(即双指针)
  • extern char*environ[]
    :它表示指针数组

  • char**environ
    是指向地址的指针,地址是指向
    char
    的指针。
    char*environ[]
    是指向
    char
    的指针数组

    以下是一个例子:
    char-array[]=“foo”
    =>
    array[1]
    将获取
    array
    的地址,并在之后移动1个字符
    char*pointer=“bar”
    =>
    指针[1]
    将获取指针所指向的地址,并在

    所以指针和数组是密切相关的,但不同


    检查。关于指针有一个非常完整的解释,远不止这个小答案。

    作为一个全局声明
    extern char*environ[]
    声明指向
    char
    的指针数组,它与
    extern char**环境截然不同声明指向
    char
    指针的指针

    可能令人困惑的是,这两种语法可以互换地用于函数参数,以声明指向
    char
    指针的指针,如下所示:

    Environment variables:
    envp[0]: XDG_SESSION_ID=8
    envp[1]: TERM=xterm
    envp[2]: SHELL=/bin/bash
    envp[3]: SSH_CLIENT=192.168.1.224 1085 22
    envp[4]: SSH_TTY=/dev/pts/0
    ...
    

    一些程序员更喜欢第一种语法,以强调
    argv
    指向字符串数组,而不仅仅是单个字符串。还请注意,也可以指定元素计数,但编译器会完全忽略:

    int main(int argc, char **argv) {
    

    我发现,如果不考虑内存中的实际内容以及内存的组织方式,就无法理解这些内容

    内存中的某个地方有一堆包含环境字符串的数据块--“foo=bar”、“hello=world”等等。为了便于讨论,我们假设“foo=bar”位于地址100,“hello=world”位于地址200

    内存中的另一个地方是另一个数据块,它列出了这些数据块的地址(通常后面跟一个零,所以如果我们事先不知道大小,我们知道列表实际上结束在哪里)

    {100200,0}

    如果我将此数据定义为
    char*env[]
    ,这意味着内存中有一个名为
    env
    的位置,该位置是实际的数据块{100200,0}。也就是说,
    env
    本身的数据将是数字100,这是一个环境字符串的地址。
    env
    之后的下一个位置将包含200,然后是0(好的,我简化了一点)

    如果我将数据块{100200,0}定义为
    char**
    ,这意味着内存中有一个名为
    env
    的位置,其中包含数据块{100200,0}的地址。存储在
    env
    的数据将不是“100”(字符串的地址)。它将是一个指示数据块开始的地址{100200,0}

    在C程序中,环境实际上是一个
    char**
    ,也就是说,称为
    environ
    的东西不是字符串地址列表的开头,而是字符串地址列表的地址。要了解这一点,您可以错误地定义它,然后纠正它,就像在原始代码的这个修改版本中一样:

    int main(int argc, char *argv[2]) { // 2 is ignored
    
    使用
    char*environ[]
    告诉编译器称为
    environ
    的位置(错误地)开始一个指向字符串的指针列表,从该点开始在内存中依次排列。事实上,只有位于确切位置
    environ
    的数据才相关。我们可以将该数据视为
    environ[0]
    ,并将其转换为实际数据类型,即
    字符**


    char**
    char*[]
    之间的差异被削弱了,因此变得混乱,因为C不允许将数组传递给函数。函数的所有参数都是一个数字——要么是一个像整数或浮点这样的基元,要么是某个东西的地址。如果你试图传递数组(即,一个数据块),而是传递块的起始地址。这意味着在大多数代码中,您实际上可以使用
    char**
    char*[]
    就好像它们是一样的东西。当数据以某种方式排列在内存中时,你会遇到问题,就像这个问题一样,除非程序员使用正确的类型声明告诉编译器,否则编译器无法计算出这种方式是什么。

    一个是指针,一个是数组。与普遍的看法相反,数组是不同的作为指针。@interjay——让学习者感到困惑的一个原因是数组类型在函数声明器中被调整为指针类型,即在函数声明器中,
    char*argv[]
    被调整为
    char**argv
    。您能更具体地说明“双指针”和“指向[]数组的指针”之间的区别吗为什么在这种情况下只有一个是正确的?(我想我知道,但OP不知道,我自己也不太确定,无法解释。)第二个是指针数组,而不是指向数组的指针。只有一个环境,而不是“环境列表”@interjay,我的意思是指针数组。我会在我的回答中更正。我发现函数声明器中的这种行为一直是学习者困惑的根源……嗯,Global
    char*environ[];
    int main(int argc, char **argv) {
    
    int main(int argc, char *argv[2]) { // 2 is ignored
    
    extern char *environ[];
    int main(int argc, char *argv[])
    {
        int index = 0;
        char **env = (char **)environ[0];
        printf("Environment variables:\n");
        index = 0;
        while (env[index])
        {
            printf("envp[%d]: %s\n", index, env[index]);
            ++index;
        }
        return 0;
    }