C++ Command Line Arguments: How to Use argc and argv
Most beginner C++ programs are self-contained: you run them, they ask for input with cin, and that’s it. But real command line tools work differently — you pass them information when you launch them, like grep "error" log.txt or g++ main.cpp -o app. Those extra words after the program name are command line arguments, and C++ hands them to you through two parameters: argc and argv.
This guide explains exactly how they work, how to read them safely, and how to turn them into numbers and flags you can actually use.
The Two Forms of main()
You’ve probably always written main like this:
int main()
{
// ...
}
To receive command line arguments, you use the other legal form of main:
int main(int argc, char* argv[])
{
// ...
}
Both are valid. The second simply asks the runtime to pass in the arguments. The names argc and argv are just convention — the types are what matter — but everyone uses them, so you should too.
What argc and argv Actually Hold
argc(“argument count”) is anint. It’s the number of arguments, including the program’s own name.argv(“argument vector”) is an array of C-style strings (char*). Each entry is one argument as text.
The crucial detail that trips up beginners: argv[0] is the program name, not the first real argument. The arguments the user typed start at argv[1].
So if you run:
./greet Alice 42
You get:
| Index | Value | What it is |
|---|---|---|
argv[0] | ./greet | the program name/path |
argv[1] | Alice | first user argument |
argv[2] | 42 | second user argument |
And argc is 3 — three slots total. That’s why argc is always at least 1.
Printing Every Argument
The simplest useful program just echoes back what it was given. You loop from 0 to argc - 1:
#include <iostream>
int main(int argc, char* argv[])
{
std::cout << "You passed " << argc - 1 << " argument(s).\n";
for (int i = 0; i < argc; ++i)
{
std::cout << "argv[" << i << "] = " << argv[i] << "\n";
}
return 0;
}
Run it as ./program hello world and you’ll see argv[0] (the program name) followed by each argument. Notice we print argc - 1 as the user-supplied count, since the program name doesn’t count as a “real” argument.
If the for loop syntax feels rusty, the C++ loops tutorial is a quick refresher.
Always Validate Before You Read
Here’s the single most important habit with command line arguments: check argc before you touch argv. If you read argv[1] when the user passed nothing, you’re reading memory that doesn’t belong to you — undefined behavior, and a likely crash.
#include <iostream>
int main(int argc, char* argv[])
{
if (argc < 2)
{
std::cerr << "Usage: " << argv[0] << " <name>\n";
return 1; // non-zero signals an error
}
std::cout << "Hello, " << argv[1] << "!\n";
return 0;
}
Two good practices are bundled in here: printing a usage message that uses argv[0] (so it shows the real program name), and returning a non-zero exit code to signal failure. Writing errors to std::cerr rather than std::cout is also the conventional choice for diagnostics.
Converting Arguments to Numbers
Every argument arrives as text, even if it looks like a number. argv[1] being "42" is the three-character string, not the integer 42. To do math, you must convert.
The modern, safe tool is std::stoi (string to int). It throws an exception if the text isn’t a valid number, so you can catch bad input instead of getting silent garbage:
#include <iostream>
#include <string>
int main(int argc, char* argv[])
{
if (argc < 3)
{
std::cerr << "Usage: " << argv[0] << " <a> <b>\n";
return 1;
}
try
{
int a = std::stoi(argv[1]);
int b = std::stoi(argv[2]);
std::cout << a << " + " << b << " = " << a + b << "\n";
}
catch (const std::exception& e)
{
std::cerr << "Both arguments must be whole numbers.\n";
return 1;
}
return 0;
}
For decimals, use std::stod (string to double) the same way. There’s a full breakdown of the conversion options — including stoi, atoi, and stringstream, and why stoi is usually best — in the C++ string to int conversion guide.
Handling Flags and Options
Real tools accept flags like -v or --help. Since each argument is just a string, you compare it against the options you support. The cleanest way is to wrap each argv[i] in a std::string so you can use ==:
#include <iostream>
#include <string>
int main(int argc, char* argv[])
{
bool verbose = false;
std::string filename;
for (int i = 1; i < argc; ++i)
{
std::string arg = argv[i];
if (arg == "-v" || arg == "--verbose")
{
verbose = true;
}
else if (arg == "-h" || arg == "--help")
{
std::cout << "Usage: " << argv[0] << " [-v] <file>\n";
return 0;
}
else
{
filename = arg; // anything else is treated as the file
}
}
if (verbose) std::cout << "Verbose mode on.\n";
std::cout << "File: " << filename << "\n";
return 0;
}
Why convert to std::string? Because comparing raw char* with == compares pointers, not text. Wrapping in std::string gives you real content comparison — a classic beginner trap. If strings in general feel shaky, see the C++ string handling guide.
A Common Pattern: Collect Arguments into a Vector
For anything beyond a couple of flags, it’s tidy to copy the arguments into a std::vector<std::string> once, then work with that:
#include <iostream>
#include <string>
#include <vector>
int main(int argc, char* argv[])
{
std::vector<std::string> args(argv + 1, argv + argc); // skip argv[0]
for (const std::string& arg : args)
{
std::cout << "Got: " << arg << "\n";
}
return 0;
}
The line std::vector<std::string> args(argv + 1, argv + argc) builds the vector from the range starting just after the program name to the end — a neat one-liner that skips argv[0] automatically. From there you have all of std::vector’s conveniences. New to vectors? The C++ vector tutorial covers them from scratch.
How to Pass Arguments When Running Your Program
How you supply arguments depends on how you run the program:
- Terminal (Linux/macOS/Windows): type them after the executable —
./myprogram arg1 arg2(ormyprogram.exe arg1 arg2on Windows). - Visual Studio: Project > Properties > Debugging > Command Arguments.
- VS Code: add an
"args"array to yourlaunch.jsonconfiguration. - CLion / other IDEs: look for a “Program arguments” field in the run configuration.
If you haven’t set up a compiler or IDE yet, start with the C++ setup guide.
Common Mistakes to Avoid
- Forgetting
argv[0]is the program name. User arguments start at index1, not0. - Reading
argvwithout checkingargc. Always validate the count first to avoid out-of-bounds access. - Comparing
char*with==. That compares addresses. Convert tostd::stringfor text comparison. - Assuming arguments are numbers. They’re always text; convert with
std::stoi/std::stodand handle conversion errors. - Ignoring the exit code. Return non-zero on failure so scripts and other tools can detect that something went wrong.
Summary
Command line arguments let your C++ programs take input at launch through main(int argc, char* argv[]). Remember the essentials: argc counts the arguments (program name included), argv holds them as text, argv[0] is the program name, and real input starts at argv[1]. Always check argc before reading, convert text to numbers with std::stoi/std::stod, and compare flags using std::string. With those habits, you can build proper command line tools instead of programs that only talk through cin.
Want every C++ concept explained this clearly, in order, from the ground up?
👉 Get the C++ Better Explained Ebook — $19
Related Guides
- C++ Functions Tutorial: How to Write and Use Functions —
mainis a function too; understand parameters and return values. - C++ User Input with cin: Reading from the Keyboard — the other main way programs take input.
- C++ String to int Conversion: stoi, atoi, and stringstream — turn argument text into numbers safely.
- C++ Vector Tutorial: The Complete Guide to std::vector — store and process a collection of arguments.
- Learn C++ from Scratch: The Complete Beginner Roadmap — the full structured learning path.