C
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Arrays and Strings
-
Section 5: Pointers
-
Section 6: Memory Management
-
Section 7: Structures and Unions
-
Section 8: The Preprocessor and Build Process
-
Section 9: Standard Library: stdio.h
-
Section 10: Standard Library: stdlib.h
-
Section 11: Standard Library: string.h
-
Section 12: Standard Library: ctype.h and wctype.h
-
Section 13: Standard Library: math.h, complex.h, fenv.h, tgmath.h
-
Section 14: Standard Library: Type and Limit Headers
-
Section 15: Standard Library: Error Handling and Debugging
-
Section 16: Standard Library: Localization and Encoding
-
Section 17: Standard Library: time.h
-
Section 18: Standard Library: Concurrency (C11)
-
Section 19: POSIX and System Programming (unistd.h)
-
Section 20: More Data Structures
-
Section 21: Algorithms in C
-
Section 22: Bitwise Operations
-
Section 23: Command-Line Programs
-
Section 24: Debugging and Best Practices
-
Section 25: Compiler and Language Internals
-
Section 26: Embedded and Cross-Platform Considerations
-
Section 27: Networking Basics
-
Section 28: Practical Projects
-
Section 29: Interview Practice
-
Section 30: C23 Modern Features
-
Section 31: More Practice and Review
144: Working with Environment Variables in C
I've seen this exact crash more times than I care to admit, usually during a late-night debugging session on a production server. You're trying to make your program configurable without hardcoding paths or secrets, so you reach for the environment variables. It seems straightforward, but C doesn't hold your hand here.
# This code looks fine at first glance, right?
#include <stdio.h>
#include <stdlib.h>
int main() {
char *db_url = getenv("DATABASE_URL");
printf("Connecting to database at: %s\n", db_url);
return 0;
}
If you run this on a machine where DATABASE_URL is set, it works perfectly. But the moment you hand this binary to a teammate who hasn't set up their environment, the program crashes with a Segmentation fault. Why? Because getenv() doesn't return an empty string when a variable is missing—it returns NULL. Passing a NULL pointer to printf's %s specifier is a gamble that you're going to lose.
Handling the Missing Variable
The fix is simple, but it's a habit you need to bake into your brain: never trust getenv() to actually find something. You have to validate the pointer before you touch it. I usually handle this by providing a sensible default value so the program can keep running even if the environment isn't perfectly configured.
#include <stdio.h>
#include <stdlib.h>
int main() {
char *db_url = getenv("DATABASE_URL");
// Check for NULL before using the pointer
if (db_url == NULL) {
printf("DATABASE_URL not set. Falling back to localhost...\n");
db_url = "localhost:5432";
}
printf("Connecting to database at: %s\n", db_url);
return 0;
}
Now the program is robust. We've turned a catastrophic crash into a manageable fallback. Note that I didn't use strcpy to move the default value into a buffer; I just pointed db_url to a string literal. This is efficient and safe because we aren't modifying the string.
How C Sees the Environment
Under the hood, the environment is essentially an array of strings, where each string follows the format KEY=VALUE. When you call getenv(), the C standard library searches this array for a string that starts with your key followed by an equals sign. If it finds it, it returns a pointer to the start of the value part of that string.
If you ever need to see everything available to your process—perhaps for a --debug-env flag in your CLI tool—you can't use getenv(). Instead, you use a global variable called environ. It's not defined in a header file, so you have to declare it yourself using extern.
#include <stdio.h>
extern char **environ;
void print_all_env() {
int i = 0;
while (environ[i] != NULL) {
printf("%s\n", environ[i]);
i++;
}
}
Be careful with environ. It's a raw pointer to the environment block. While reading it is safe, trying to modify these strings directly is a recipe for disaster. If you need to change a variable for the current process and its children, use setenv(). It handles the memory allocation and resizing of the environment block for you, which is something you really don't want to do manually in C.
📋 Practical Task
Build a Log-Level Filter Utility
Create a small program that simulates a logging system. The program should behave differently based on an environment variable named APP_LOG_LEVEL.
- If
APP_LOG_LEVELis set to"DEBUG", the program should print:"[DEBUG] Verbose system internals active."and"[INFO] System started." - If
APP_LOG_LEVELis set to"INFO"(or if the variable is not set at all), the program should only print:"[INFO] System started." - If
APP_LOG_LEVELis set to anything else, the program should print an error message:"Invalid log level provided."and exit with a non-zero status.
Requirements:
Use getenv() to retrieve the variable and strcmp() from <string.h> to compare the values. Ensure your code does not crash when the environment variable is missing.
There are no comments for now.