#include <stdio h>
#include <stdlib.h>
int main(int argc, char *argv[], char *envp[])
{
int i = 0;
while (envp[i] != NULL)
{
if (strstr(envp[i], "SHLVL") != NULL)
printf("%s\n", envp[i]);
i++;
}
setenv("SHLVL", "stackoverflow", 2);
i = 0;
while (envp[i] != NULL)
{
if (strstr(envp[i], "SHLVL") != NULL)
printf("%s\n", envp[i]);
i++;
}
return 0;
}
In this code SHLVL
is an existing environmental variable. When I try to change the value of that variable using setenv
it gives expected output.
SHLVL=1
SHLVL=stackoverflow
In another case: The same code with non-existent environmental variable
int main(int argc, char *argv[], char *envp[])
{
int i = 0;
while (envp[i] != NULL)
{
if (strstr(envp[i], "SHLVL") != NULL)
printf("%s\n", envp[i]);
i++;
}
setenv("arr", "33", 2); // non-exist environmental variable
setenv("SHLVL", "stackoverflow", 2);
i = 0;
while (envp[i] != NULL)
{
if (strstr(envp[i], "SHLVL") != NULL)
printf("%s\n", envp[i]);
i++;
}
return 0;
}
Here the arr
is an non-exist environmental variable. This code give output as
SHLVL=1
SHLVL=1
My question is how the non-existing environmental variable change the output here? Here I am using gcc compiler.
The envp
argument in main
points to the original array with environment variable definitions. When you set en environment variable using setenv()
:
If the variable already exists, the array is not reallocated, only the entry for the variable is changed, hence enumerating the array pointed to by envp
gives the expected output.
If the variable does not exist, the array with all definitions needs to be extended and may need to be reallocated or moved for this purpose, hence the envp
pointer that still points to the original array does not have the current definition strings that are present in the new array, the one used by getenv()
to locate the current definitions. In this case, enumerating the values using envp
will not find the new variable definition and if an existing variable is changed afterwards as in your example, only the new array is modified, the original array pointed to by envp
is not modified so it still has the original definition. This explains what you observe, but this behavior is not guaranteed as, depending on the implementation, the original array might have enough space at the end for the new definition and thus would not need to be reallocated for each new variable.
This behavior is very tricky and has far reaching consequences for the memory management of definition strings. Passing the envp
to main
is not standard and only available on unix systems, but even on these systems, a preferred way of enumerating the environment definitions is to use the global variable environ
that is updated by setenv()
and putenv()
:
extern char **environ;