Setenv in c programming usage?

124 views Asked by At
#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.

2

There are 2 answers

0
chqrlie On BEST ANSWER

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;
0
weshouman On

As mentioned in the comments, you should use getenv, for example

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[], char *envp[])
{
    printf("%s\n", getenv("SHLVL")); // Print the current value of SHLVL

    setenv("SHLVL", "stackoverflow", 1); // Change SHLVL to "stackoverflow"
    
    printf("%s\n", getenv("SHLVL")); // Print the new value of SHLVL

    return 0;
}

The envp parameter in the main function contains a snapshot of the env vars available to the program at the start and changes to the environment using setenv or unsetenv do not affect this array directly. Instead, they change the actual process environment.