extern char ** environ和extern char * environ 有什么区别

#include <stdio.h> #include <stdlib.h> #include <unistd.h> extern char *environ[]; int main(int argc, char *argv[]) { int index = 0; char **env = environ; printf("Environment variables:\n"); index = 0; while (env[index]) { printf("envp[%d]: %s\n", index, env[index]); ++index; } return 0; } 

输出:

 Environment variables: envp[0]: GH#þ 

我想打印所有的环境,但它不能工作。
我把extern char *environ[]改成了extern char **environ ,它可以打印所有的环境。
更改代码输出后:

 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 ... 

我发现这些东西是不可能的,不考虑记忆中究竟是什么,以及它是如何组织的。

内存中的某处是一堆包含环境字符串的数据块 – “foo = bar”,“hello = world”等等。 假设为了争辩,“foo = bar”在地址100处,“hello = world”在地址200处。

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

{100,200,0}

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

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

在C程序中,环境实际上是char ** ,也就是说,所谓的environ不是字符串地址列表的开始,它是字符串地址列表的地址。 要看到这一点,你可以定义它错误,然后纠正它,就像在这个修改后的原始代码中:

 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; } 

使用char *environ[]告诉编译器(错误地),称为environ的位置开始一个指向字符串的指针列表,从这个点开始一个接一个地排列在内存中。 事实上,只有确切位置environ的数据是相关的。 我们可以将这些数据看作是environ[0] ,并将其转换为真正的数据类型,即char **

char **char *[]之间的区别被削弱了,因此混淆了,因为C不允许将数组传递给函数。 函数的所有参数都是一个单一的数字 – 或者像一个整数或者浮点数的原语,或者某个东西的地址。 如果您尝试传递一个数组(即一个数据块),则会传递该块的开始地址。 这意味着在大多数代码中,实际上可以使用char **char *[] ,就好像它们是相同的东西。 在这个问题中,当数据以某种方式排列在内存中时,会遇到问题,除非程序员使用正确的类型声明来告诉编译器,否则编译器无法确定这种方式。

作为一个全局声明extern char *environ[]; 声明一个指向char的指针数组,这是一个与extern char **environ;非常不同的野兽extern char **environ; 声明一个指向char的指针。

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

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

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

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

 int main(int argc, char *argv[2]) { // 2 is ignored 

Extern实际上给出了所有程序文件都可见的全局变量的引用。

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

  1. extern char **environ :表示环境列表(也就是双指针)。
  2. extern char *environ[] :表示指针数组。

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

下面是一个例子: char array[] = "foo" => array[1]将获得array的地址,并在char *pointer = "bar" => pointer[1]后移动1个字符将得到pointer的地址,然后移动1个字符

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

检查http://c-faq.com/aryptr/index.html 。 关于指针有一个非常完整的解释,不仅仅是这个小小的答案。