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
186: Parsing Command-Line Arguments with argc/argv
I've seen this exact crash more times than I can count, even from developers who have been writing C for a year or two. You're building a tool that's supposed to take a filename as an argument, you run it, and—boom—Segmentation fault (core dumped). Let's look at the culprit.
# This is broken code. Do not run this without arguments!
# word_count.c
#include <stdio.h>
int main(int argc, char *argv[]) {
// We assume the user passed a filename as the first argument
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
printf("Could not open file.\n");
return 1;
}
printf("File opened successfully!\n");
fclose(file);
return 0;
}
The Segfault When No File is Provided
If you compile this and run it as ./word_count (without any arguments), it will crash. Why? Because you're accessing argv[1] before checking if it even exists.
In C, argv is an array of strings. argv[0] is always the name of the program itself. If the user provides no additional arguments, argv[1] is a NULL pointer. When you pass that NULL pointer directly into fopen(), the program tries to read a memory address that it doesn't own, and the OS shuts you down instantly. This is the classic "trusting the user" mistake.
Guarding Your Array Access with argc
The fix is simple: always check argc (the argument count) before you touch argv. argc tells you exactly how many elements are in the argv array. If you expect one argument from the user, argc must be at least 2 (the program name + the argument).
# The fixed version
# word_count.c
#include <stdio.h>
int main(int argc, char *argv[]) {
// First, verify we actually have the filename
if (argc < 2) {
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return 1;
}
// Now it's safe to access argv[1]
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
perror("Error opening file");
return 1;
}
printf("File %s opened successfully!\n", argv[1]);
fclose(file);
return 0;
}
Notice I used argv[0] in the error message. I do this because the user might have renamed your binary to something else, and it's a professional touch to show them the actual name of the command they typed incorrectly.
Converting String Arguments to Numbers
Here is the tricky part: argv is an array of char*. Everything coming from the command line is a string. If you want your program to take a number—say, a "repeat count" for a print loop—you can't just cast it to an int. You have to parse it.
I usually recommend atoi (ASCII to Integer) for quick-and-dirty tools, though it's not the most robust for production code because it doesn't handle errors well. Still, for most of your learning projects, it's the way to go.
#include <stdio.h>
#include <stdlib.h> // Required for atoi
int main(int argc, char *argv[]) {
if (argc < 3) {
printf("Usage: %s <name> <count>\n", argv[0]);
return 1;
}
char *name = argv[1];
int count = atoi(argv[2]); // Convert string "5" to integer 5
for (int i = 0; i < count; i++) {
printf("%s\n", name);
}
return 0;
}
One last tip: always remember that argv[argc] is guaranteed to be NULL. This is a useful property if you're writing a loop to print out all arguments without knowing the count beforehand, though using argc is the standard, cleaner way to do it.
📋 Practical Task
Build a Command-Line "String Repeater" Utility
Create a program called repeater.c that takes two command-line arguments: a string and a positive integer. The program should print that string to the console the specified number of times, each on a new line.
Your implementation must:
- Check if exactly two arguments (plus the program name) were provided. If not, print a "Usage" message and exit with a non-zero status.
- Convert the second argument from a string to an integer.
- Handle the case where the user provides a number less than or equal to zero (the program should simply print nothing and exit gracefully).
- Use
argv[0]in your usage message to make the tool feel professional.
There are no comments for now.