argc & argv - Command-Line Arguments
Command-line arguments allow programs to receive input directly when executed. This is essential for creating flexible, scriptable programs.
Understanding argc and argv
The main Function Signature
int main(int argc, char *argv[])
Or equivalently:
int main(int argc, char **argv)
Parameters:
argc (argument count) - Number of command-line arguments, including the program name
argv (argument vector) - Array of strings (character pointers) containing the arguments
How It Works
When you run a program from the command line:
Memory representation:
argc = 4
argv[0] → "./program"
argv[1] → "arg1"
argv[2] → "arg2"
argv[3] → "arg3"
argv[4] → NULL (terminator)
argv[0] always contains the program name (or path). Actual arguments start at argv[1].
Basic Examples
0-whatsmyname.c - Print Program Name
#include <stdio.h>
/**
* main - prints the programs name, followed by a new line
* @argc: int
* @argv: list
* Return: 0
*/
int main(int argc, char const *argv[])
{
(void)argc;
printf("%s\n", argv[0]);
return (0);
}
How it works:
(void)argc - Tells compiler we intentionally don’t use argc
argv[0] - Always contains the program name
- No need to check argc since
argv[0] always exists
Usage:
$ ./whatsmyname
./whatsmyname
$ /usr/bin/whatsmyname
/usr/bin/whatsmyname
1-args.c - Count Arguments
#include <stdio.h>
/**
* main - prints the number of arguments passed into it
* @argc: int
* @argv: list
* Return: 0
*/
int main(int argc, char const *argv[])
{
(void)argv;
printf("%i\n", argc - 1);
return (0);
}
Why argc - 1?
argc includes the program name
- Actual user arguments = total arguments - 1
Examples:
$ ./args
0
$ ./args hello
1
$ ./args hello world test
3
2-args.c - Print All Arguments
#include <stdio.h>
/**
* main - prints the number of arguments passed into the program
* @argc: int
* @argv: list
* Return: 0
*/
int main(int argc, char const *argv[])
{
int i = 0;
while (argc--)
{
printf("%s\n", argv[i]);
i++;
}
return (0);
}
Algorithm:
- Start with
i = 0
- Print
argv[i]
- Decrement
argc and increment i
- Continue until
argc reaches 0
Example:
$ ./args one two three
./args
one
two
three
Alternative approach:
for (int i = 0; i < argc; i++)
printf("%s\n", argv[i]);
Processing Arguments
3-mul.c - Multiply Two Numbers
#include <stdio.h>
#include <stdlib.h>
/**
* main - multiply two numbers
* @argc: int
* @argv: list
* Return: 0
*/
int main(int argc, char const *argv[])
{
(void)argc;
if (argc != 3)
{
printf("Error\n");
return (1);
}
printf("%i\n", atoi(argv[1]) * atoi(argv[2]));
return (0);
}
Key concepts:
-
Argument validation: Check if exactly 2 arguments are provided (argc = 3 including program name)
-
String to integer conversion: Use
atoi() to convert string arguments to integers
-
Error handling: Return 1 on error (convention for failure)
Usage:
$ ./mul 5 7
35
$ ./mul 10 -3
-30
$ ./mul 5
Error
$ ./mul 5 7 9
Error
atoi() has limitations:
- Returns 0 for non-numeric strings
- No error indication
- Cannot distinguish between “0” and invalid input
atoi("42") // Returns 42
atoi("abc") // Returns 0 (no error!)
atoi("0") // Returns 0 (valid)
For robust code, use strtol() instead.
4-add.c - Add Positive Numbers
#include <stdio.h>
#include <stdlib.h>
/**
* isInteger - checks if s is an integer
* @s: string to check
* Return: 0 or 1
*/
int isInteger(const char *s)
{
int i = 0;
while (s[i] != '\0')
{
if (s[i] < '0' || s[i] > '9')
return (1);
i++;
}
return (0);
}
/**
* main - adds positive numbers
* @argc: int
* @argv: list
* Return: 0
*/
int main(int argc, char const *argv[])
{
int sum = 0;
while (--argc)
{
if (isInteger(argv[argc]))
{
printf("Error\n");
return (1);
}
sum += atoi(argv[argc]);
}
printf("%i\n", sum);
return (0);
}
Features:
- Input validation:
isInteger() checks if string contains only digits
- Variable arguments: Handles any number of arguments
- Error handling: Returns error if non-numeric input found
How it works:
- Start with sum = 0
- Process arguments from last to first (
--argc)
- Skip
argv[0] (program name)
- Validate each argument is numeric
- Add to running sum
Examples:
$ ./add 1 2 3 4 5
15
$ ./add 10 20 30
60
$ ./add
0
$ ./add 1 2 x 4
Error
Processing arguments backwards (--argc) is a common pattern:while (--argc) // Stops when argc reaches 0
process(argv[argc]);
This automatically skips argv[0] (program name).
Advanced Argument Parsing
Handling Options and Flags
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int verbose = 0;
int count = 0;
for (int i = 1; i < argc; i++)
{
if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0)
{
verbose = 1;
}
else if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--count") == 0)
{
if (i + 1 < argc)
{
count = atoi(argv[i + 1]);
i++; // Skip next argument (already processed)
}
}
else
{
printf("Unknown option: %s\n", argv[i]);
}
}
if (verbose)
printf("Verbose mode enabled\n");
printf("Count: %d\n", count);
return (0);
}
Usage:
$ ./program -v -c 10
Verbose mode enabled
Count: 10
$ ./program --count 5
Count: 5
Safe String to Number Conversion
#include <stdlib.h>
#include <errno.h>
int safe_atoi(const char *str, int *result)
{
char *endptr;
long val;
errno = 0;
val = strtol(str, &endptr, 10);
// Check for various errors
if (errno != 0 || endptr == str || *endptr != '\0')
return (0); // Conversion failed
// Check for integer overflow
if (val > INT_MAX || val < INT_MIN)
return (0);
*result = (int)val;
return (1); // Success
}
int main(int argc, char *argv[])
{
int num;
if (argc != 2)
{
printf("Usage: %s <number>\n", argv[0]);
return (1);
}
if (!safe_atoi(argv[1], &num))
{
printf("Error: '%s' is not a valid number\n", argv[1]);
return (1);
}
printf("Number: %d\n", num);
return (0);
}
Common Patterns
1. Processing Files
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("Usage: %s <file1> [file2] ...\n", argv[0]);
return (1);
}
for (int i = 1; i < argc; i++)
{
printf("Processing file: %s\n", argv[i]);
// Open and process file
}
return (0);
}
2. Environment Variables
int main(int argc, char *argv[], char *envp[])
{
// envp is array of environment variables
for (int i = 0; envp[i] != NULL; i++)
printf("%s\n", envp[i]);
return (0);
}
3. Help Message
void print_usage(char *program_name)
{
printf("Usage: %s [OPTIONS] [FILES]\n", program_name);
printf("\nOptions:\n");
printf(" -h, --help Show this help message\n");
printf(" -v, --verbose Enable verbose output\n");
printf(" -o FILE Output to FILE\n");
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
print_usage(argv[0]);
return (1);
}
// Process arguments...
return (0);
}
Common Pitfalls
1. Assuming Arguments Exist
// ❌ BAD - may crash
int main(int argc, char *argv[])
{
printf("%s\n", argv[1]); // What if argc == 1?
return (0);
}
// ✅ GOOD - check first
int main(int argc, char *argv[])
{
if (argc > 1)
printf("%s\n", argv[1]);
else
printf("No arguments provided\n");
return (0);
}
2. Off-by-One Errors
// ❌ BAD - counts program name as argument
int arg_count = argc;
// ✅ GOOD - exclude program name
int arg_count = argc - 1;
// ❌ BAD - no validation
int x = atoi(argv[1]);
int result = 100 / x; // Division by zero if argv[1] is "0" or "abc"
// ✅ GOOD - validate
int x = atoi(argv[1]);
if (x == 0)
{
printf("Error: divisor cannot be zero\n");
return (1);
}
int result = 100 / x;
4. Modifying argv Strings
// ❌ BAD - argv strings may be in read-only memory
argv[1][0] = 'X';
// ✅ GOOD - copy to modifiable buffer
char buffer[100];
strcpy(buffer, argv[1]);
buffer[0] = 'X';
Best Practices
-
Always validate argc before accessing argv
if (argc < required_args)
return error;
-
Provide helpful error messages
printf("Usage: %s <input> <output>\n", argv[0]);
-
Use descriptive variable names
char *input_file = argv[1];
char *output_file = argv[2];
-
Validate all inputs
- Check for required number of arguments
- Validate argument format
- Check for valid ranges
-
Return appropriate exit codes
return (0); // Success
return (1); // General error
return (2); // Misuse of command
Key Takeaways
argc counts all arguments including program name
argv[0] is always the program name
- Arguments are passed as strings - convert with
atoi() or strtol()
- Always validate
argc before accessing argv[i]
atoi() returns 0 for invalid input without error indication
- Use
strtol() for robust string-to-number conversion
- Return 0 for success, non-zero for errors
- Process arguments from index 1 (skip program name)