CEnvironment Variables

Environment Variables

Environment variables are key-value pairs that live outside your program, in the shell or process environment that launches it. They are a common way to pass configuration into a program without hardcoding values in source code — things like API keys, file paths, feature flags, or the current locale. C provides a small standard library interface for reading them, plus some widely available (but non-standard) functions for setting them.

Reading a Variable with getenv

The standard function for reading an environment variable is getenv, declared in stdlib.h. You give it a variable name and it returns a pointer to the value string, or NULL if the variable is not set.

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

int main(void) {
    char *home = getenv("HOME");

    if (home != NULL) {
        printf("HOME is set to: %s\n", home);
    } else {
        printf("HOME is not set.\n");
    }

    return 0;
}
Warning
Always check the return value of getenv for NULL before using it. Passing NULL to functions like strlen or strcpy is undefined behavior and a very common source of crashes when a variable you assumed would be set turns out not to be (for example, in a CI environment, a container, or a different user's shell).
Setting Environment Variables

Standard C (the C language as defined by ISO/IEC 9899) does not define a portable function for setting environment variables. On POSIX systems (Linux, macOS, BSD), you have setenv and putenv, declared in stdlib.h.

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

int main(void) {
    /* setenv(name, value, overwrite) */
    if (setenv("MY_APP_MODE", "debug", 1) != 0) {
        perror("setenv failed");
        return EXIT_FAILURE;
    }

    printf("MY_APP_MODE = %s\n", getenv("MY_APP_MODE"));
    return EXIT_SUCCESS;
}

Function

Header

Portability

Notes

getenv

stdlib.h

Standard C

Read-only, returns NULL if unset

setenv

stdlib.h

POSIX only

Not available on plain Windows/MSVC

putenv

stdlib.h

POSIX (also on Windows as _putenv)

Takes a "NAME=value" string

Note
setenv and putenv are not part of the ISO C standard — they come from POSIX. Code that uses them will not compile unmodified on every platform (Windows provides differently-named equivalents like _putenv_s). If you need strict standard-C portability, you generally cannot set environment variables at all; you can only read them with getenv.
Practical Use Case: Configuration Without Hardcoding

A very common real-world pattern is reading configuration such as an API key or a database URL from the environment instead of hardcoding it in source code (which would risk committing secrets to version control). Here is a small example that falls back to a default when a variable is missing:

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

int main(void) {
    const char *api_key = getenv("MY_APP_API_KEY");

    if (api_key == NULL) {
        fprintf(stderr, "Warning: MY_APP_API_KEY not set, using default.\n");
        api_key = "demo-key-only";
    }

    printf("Using API key: %s\n", api_key);

    /* ... use api_key to configure an HTTP client, etc. ... */
    return EXIT_SUCCESS;
}
Example

Bash
$ MY_APP_API_KEY=sk-real-secret ./app
Using API key: sk-real-secret
Tip
Keeping secrets in environment variables rather than source files is a widely used practice (it is the core idea behind .env files used by many frameworks). Just remember that anything readable by getenv is also readable by any code running with the same privileges as your process, so environment variables are not a substitute for a real secrets manager in security-sensitive systems.
Summary
  • getenv("NAME") reads a variable, returning NULL if it is not set — always check.

  • setenv/putenv can set variables but are POSIX extensions, not standard C.

  • Reading configuration from the environment is a common way to avoid hardcoding secrets.

  • Environment variables are visible to the whole process, not a secure secrets store.