679

In many C++ IDE's and compilers, when it generates the main function for you, it looks like this:

int main(int argc, char *argv[])

When I code C++ without an IDE, just with a command line compiler, I type:

int main()

without any parameters. What does this mean, and is it vital to my program?

Rodrigo de Azevedo
  • 1,097
  • 9
  • 17
Greg Treleaven
  • 8,124
  • 7
  • 30
  • 30
  • 63
    If your program is going to ignore command line arguments, then what you write is fine. If your program needs to process command line arguments, then the IDE is doing it right. – Jonathan Leffler Jun 11 '10 at 15:57
  • 37
    A hint for hackers: try declaring `int main(int argc, char* argv[], char* envp[])` and printing out the last argument. `;)` – ulidtko Oct 05 '15 at 11:17
  • 9
    @ulidtko it is not good that you are teaching newbies to introduce vulnerability in their programs ;) – Gab是好人 Apr 27 '16 at 12:29
  • 17
    @Gab how's simple printing of environment variables lead to vulnerability? Just don't pass the tainted strings verbatim to `system()` calls, DB queries, etc. As usual with user input. – ulidtko Apr 28 '16 at 11:42
  • 2
    @ulidtko Interesting.. Can you expound why you don't have to pass tainted strings, db queries, etc. while using `char **envp` argument? – Master James Jun 11 '18 at 08:16
  • @ulidtko Is overloading will be invoked when passing command line arguments? – Master James Jun 11 '18 at 09:00
  • 1
    @MasterJames: If you do `sql_query("SELECT FROM mytable WHERE name == " + name_from_env + ";")`, you allow SQL injections. See https://xkcd.com/327/ for a fun example. – Martin Ueding Apr 23 '21 at 08:28

13 Answers13

856

argv and argc are how command line arguments are passed to main() in C and C++.

argc will be the number of strings pointed to by argv. This will (in practice) be 1 plus the number of arguments, as virtually all implementations will prepend the name of the program to the array.

The variables are named argc (argument count) and argv (argument vector) by convention, but they can be given any valid identifier: int main(int num_args, char** arg_strings) is equally valid.

They can also be omitted entirely, yielding int main(), if you do not intend to process command line arguments.

Try the following program:

#include <iostream>

int main(int argc, char** argv) {
    std::cout << "Have " << argc << " arguments:" << std::endl;
    for (int i = 0; i < argc; ++i) {
        std::cout << argv[i] << std::endl;
    }
}

Running it with ./test a1 b2 c3 will output

Have 4 arguments:
./test
a1
b2
c3
user229044
  • 232,980
  • 40
  • 330
  • 338
  • 3
    Thought I should add, this is the same in most systems out there, although they're abstracted some times. For instance, in Pascal/Delphi/Lazarus, you get; ParamStr and ParamCount (if memory serves me right). My point is, when you (if ever) write native applications in other languages/oses, there's a good chance the above is defined for you to use, and, they work perfectly the same (count/string list) in all systems which support them. – Christian Oct 08 '10 at 15:59
  • But then again, if argc is 0 and argv NULL, then surely `argv[argc] = *(NULL + 0) = *NULL = NULL = 0`, right? – Emil Vikström Jan 11 '14 at 21:11
  • 13
    @EmilVikström No, that's a serious error that probably results in a segfault. `*NULL` is definitely not equal to `NULL`. – user229044 Jan 12 '14 at 01:42
  • @EmilVikström You could do `for (char **arg = argv; *arg; arg++) { printf("\t%s\n", *arg);}` The *arg in the for loop insinuates `*arg != NULL` I believe (i.e. while *arg is true). – dylnmc Sep 25 '14 at 16:20
  • The above sample code by @user229044 , my output is: `Have 1 arguments:` . How could he got 4 arguments return while I have only one? – bim May 31 '22 at 07:54
  • 1
    @BiMo You have to pass it 3 CLI arguments in order to produce that output. See the command `./test a1 b2 c3`. – user229044 May 31 '22 at 14:38
63

argc is the number of arguments being passed into your program from the command line and argv is the array of arguments.

You can loop through the arguments knowing the number of them like:

for(int i = 0; i < argc; i++)
{
    // argv[i] is the argument at index i
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
John Boker
  • 82,559
  • 17
  • 97
  • 130
25

Suppose you run your program thus (using sh syntax):

myprog arg1 arg2 'arg 3'

If you declared your main as int main(int argc, char *argv[]), then (in most environments), your main() will be called as if like:

p = { "myprog", "arg1", "arg2", "arg 3", NULL };
exit(main(4, p));

However, if you declared your main as int main(), it will be called something like

exit(main());

and you don't get the arguments passed.

Two additional things to note:

  1. These are the only two standard-mandated signatures for main. If a particular platform accepts extra arguments or a different return type, then that's an extension and should not be relied upon in a portable program.
  2. *argv[] and **argv are exactly equivalent, so you can write int main(int argc, char *argv[]) as int main(int argc, char **argv).
Toby Speight
  • 27,591
  • 48
  • 66
  • 103
  • 3
    If we're being technical, [`basic.start.main/2`](https://timsong-cpp.github.io/cppwp/basic.start.main#2) explicitly allows implementation-defined additional versions of `main()`, provided that the implementation provides the two predefined versions. So, they're not _exactly_ non-conforming. The most common one is `envp`, which is so well-known in both C and C++ that [it's literally the very first entry in section J.5 (Common extensions) of the C standard](http://port70.net/~nsz/c/c11/n1570.html#J.5). – Justin Time - Reinstate Monica Jan 22 '17 at 22:40
  • 1
    Thanks for the nice pedantry @Justin. Answer updated to be more correct. – Toby Speight Jan 23 '17 at 12:34
  • Is the last element of `argv` always `NULL`? I'm reading some code where `argv[1]` is called without checking if `argc > 1`, and the person who wrote the code clearly expected to either have a correct value, or `NULL`. – user276648 Jun 20 '22 at 03:39
  • 2
    @user276648, yes - [The value of `argv[argc]` shall be `0`.](https://eel.is/c++draft/basic.start.main#2.2) – Toby Speight Jun 20 '22 at 07:37
16
int main();

This is a simple declaration. It cannot take any command line arguments.

int main(int argc, char* argv[]);

This declaration is used when your program must take command-line arguments. When run like such:

myprogram arg1 arg2 arg3

argc, or Argument Count, will be set to 4 (four arguments), and argv, or Argument Vectors, will be populated with string pointers to "myprogram", "arg1", "arg2", and "arg3". The program invocation (myprogram) is included in the arguments!

Alternatively, you could use:

int main(int argc, char** argv);

This is also valid.

There is another parameter you can add:

int main (int argc, char *argv[], char *envp[])

The envp parameter also contains environment variables. Each entry follows this format:

VARIABLENAME=VariableValue

like this:

SHELL=/bin/bash    

The environment variables list is null-terminated.

IMPORTANT: DO NOT use any argv or envp values directly in calls to system()! This is a huge security hole as malicious users could set environment variables to command-line commands and (potentially) cause massive damage. In general, just don't use system(). There is almost always a better solution implemented through C libraries.

adrian
  • 1,439
  • 1
  • 15
  • 23
11

Lets consider the declaration:

int main (int argc, char *argv[])

In the above declaration, the type of the second parameter named argv is actually a char**. That is, argv is a pointer to a pointer to a char. This is because a char* [] decays to a char** due to type decay. For example, the below given declarations are equivalent:

int main (int argc, char *argv[]); //first declaration
int main (int argc, char **argv);  //RE-DECLARATION. Equivalent to the above declaration

In other words, argv is a pointer that points to the first element of an array with elements of type char*. Moreover, each elements argv[i] of the array(with elements of type char*) itself point to a character which is the start of a null terminated character string. That is, each element argv[i] points to the first element of an array with elements of type char(and not const char). A diagram is given for illustration purposes:

argv and argc

As already said in other answers, this form of declaration of main is used when we want to make use of the command line argument(s).

Jason
  • 36,170
  • 5
  • 26
  • 60
10

The parameters to main represent the command line parameters provided to the program when it was started. The argc parameter represents the number of command line arguments, and char *argv[] is an array of strings (character pointers) representing the individual arguments provided on the command line.

Azeem
  • 11,148
  • 4
  • 27
  • 40
BlueMonkMN
  • 25,079
  • 9
  • 80
  • 146
  • 3
    Argv[] always has argv[arg] as a null pointer. and Argv[0] is always the (full path)/executableName as a nul terminated string – user3629249 Dec 21 '14 at 08:09
  • 3
    @user3629249: Not necessarily; `argv[0]` is whatever the the program launching the C program gave it as `argv[0]`. In the case of Bash, it is often (maybe always) the pathname of the executable, but Bash is not the only program that executes other programs. It is permissisble, though eccentric, to use: `char *args[] = { "cat", "/dev/null", "/etc/passwd", 0 }; execv("/bin/ls", args);`. On many systems, the value seen by the program as `argv[0]` will be `cat`, even though the executable is `/bin/ls`. – Jonathan Leffler Feb 05 '16 at 03:36
9

The main function can have two parameters, argc and argv. argc is an integer (int) parameter, and it is the number of arguments passed to the program.

The program name is always the first argument, so there will be at least one argument to a program and the minimum value of argc will be one. But if a program has itself two arguments the value of argc will be three.

Parameter argv points to a string array and is called the argument vector. It is a one dimensional string array of function arguments.

Azeem
  • 11,148
  • 4
  • 27
  • 40
moshtagh
  • 221
  • 2
  • 2
3

The first parameter is the number of arguments provided and the second parameter is a list of strings representing those arguments.

Nick Gerakines
  • 1,432
  • 1
  • 11
  • 20
3

Command-line Arguments: main( int argc, char * argv[] )

In Unix, when you pass additional arguments to a command, those commands must be passed to the executing process. For example, in calling ls -al, it executes the program ls and passes the string -al as an argument:

% ls
content.html  index.html  primary.0.html
% ls -al
total 20
drwxr-xr-x 2 dwharder users 4096 Sep 11 16:38 .
drwxr-xr-x 6 dwharder users 4096 Sep 11 16:35 ..
-rwxr-xr-x 1 dwharder users  117 Sep 11 16:38 content.html
-rwxr-xr-x 1 dwharder users 1400 Sep 11 16:37 index.html
-rwxr-xr-x 1 dwharder users  532 Sep 11 16:38 primary.0.html
%

The way a running program accesses these additional parameters is that these are passed as parameters to the function main:

int main( int argc, char *argv[] ) {

Here argc means argument count and argv means argument vector.

The first argument is the number of parameters passed plus one to include the name of the program that was executed to get those process running. Thus, argc is always greater than zero and argv[0] is the name of the executable (including the path) that was run to begin this process. For example, if we run

#include <stdio.h>

int main( int argc, char *argv[] ) {
        printf( "argv[0]:  %s\n", argv[0] );

        return 0;
}

Here we compile this code and first compile and run it so that the executable name is a.out and then we compile it again and run it so the executable name is arg:

% gcc argument.0.c
% ./a.out 
argv[0]:  ./a.out
% gcc -o arg argument.0.c
% ./arg 
argv[0]:  ./arg
%

If more additional command-line arguments are passed, the string of all characters is parsed and separated into substrings based on a few rules; however, if all the characters are either characters, numbers or spaces, the shell will separate the based on spaces and assign args[1] the address of the first, args[2] the address of the second, and so on.

The following program prints all the arguments:

#include <stdio.h>

int main( int argc, char *argv[] ) {
        int i;

        printf( "argc:     %d\n", argc );
        printf( "argv[0]:  %s\n", argv[0] );

        if ( argc == 1 ) {
                printf( "No arguments were passed.\n" );
        } else {
                printf( "Arguments:\n" );

                for ( i = 1; i < argc; ++i ) {
                        printf( "  %d. %s\n", i, argv[i] );
                }
        }

        return 0;
}

Here we execute this program with one and then twelve command-line arguments:

% gcc argument.c
% ./a.out first
argc:     2
argv[0]:  ./a.out
Arguments:
  1. first
% ./a.out first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth
argc:     13
argv[0]:  ./a.out
Arguments:
  1. first
  2. second
  3. third
  4. fourth
  5. fifth
  6. sixth
  7. seventh
  8. eighth
  9. ninth
  10. tenth
  11. eleventh
  12. twelfth
% 

For Fun

Now, you may be wondering what actually happens (and if you don't, you're welcome to skip this). First, when the command is executed, the shell parses the command line and separates the individual pieces by a null character \0. For example, the execution of

% ./a.out first second third fourth fifth

has the shell generate the string ./a.out☐first☐second☐third☐fourth☐fifth☐ where the box represents the null character. Next, memory for an array of six (argc) pointers is allocated and these six pointers are assigned the first character of each of the strings into which the command line was parsed. Finally, memory is allocated for the stack and using 8-byte alignment, the two arguments are placed into the stack. This is shown in Figure 1.

The result of calling ./a.out first second third fourth fifth on the command line

Figure 1. The result of calling ./a.out first second third fourth fifth on the command line.

Further Fun

In Unix, the shell does further processing of the command. For example, if it finds wild cards that indicate files in the current directory, it will attempt to expand those wild cards. These include ? for one unknown character and * for any number of characters.

For example, the following examines the file in the current directory:

% ls
a.out  argument.0.c  argument.1.c  content.html  images  index.html  primary.0.html  src
% ./a.out *
argc:     9
argv[0]:  ./a.out
Arguments:
  1. a.out
  2. argument.0.c
  3. argument.1.c
  4. content.html
  5. images
  6. index.html
  7. primary.0.html
  8. src
% ./a.out *.html
argc:     4
argv[0]:  ./a.out
Arguments:
  1. content.html
  2. index.html
  3. primary.0.html
% ./a.out argument.?.c
argc:     3
argv[0]:  ./a.out
Arguments:
  1. argument.0.c
  2. argument.1.c

Similarly, you can tell the command line to treat spaces as part of one string or ignore wildcards by either using the backslash before the space or wildcard or surrounding the string by single or double quotes.

% ./a.out hi\ there\?
argc:     2
argv[0]:  ./a.out
Arguments:
  1. hi there?
% ./a.out "hi there?"
argc:     2
argv[0]:  ./a.out
Arguments:
  1. hi there?
% ./a.out 'hi there?'
argc:     2
argv[0]:  ./a.out
Arguments:
  1. hi there?
%

Finally, if you surround text with backticks, it will execute that first and then replace that with the output of the command:

% ./a.out `ls *.c`
argc:     4
argv[0]:  ./a.out
Arguments:
  2. argument.0.c
  3. argument.1.c
%

Guess what happens if you enter ./a.out ls -al.

Disclaimer: This above post is directly taken from https://ece.uwaterloo.ca/~dwharder/icsrts/C/05/. It was originally written by Douglas Wilhelm Harder of U Waterloo. If it totally belongs to another person, then why did I put it here? Because I read his post and I learned new things and I liked it so much that I put it here so that other people also get the benefit from it. Again, all hard-work and applauds go to Mr Harder, not me. Thanks.

garakchy
  • 554
  • 10
  • 19
1

Both of

int main(int argc, char *argv[]);
int main();

are legal definitions of the entry point for a C or C++ program. Stroustrup: C++ Style and Technique FAQ details some of the variations that are possible or legal for your main function.

Community
  • 1
  • 1
Chris Becke
  • 34,244
  • 12
  • 79
  • 148
  • 4
    Might want to put void in... `int main()` ==> `int main(void)`... for compatibility and readability. I don't know if all older versions of C allow void functions to have an empty parameter list in declaration. – dylnmc Sep 25 '14 at 16:24
  • 1
    @dylnmc this doesn't give any readability gain, and is exactly equivalent in all C++ versions. Only in C this does have a difference, but only in declarations, not in definition. – Ruslan May 05 '15 at 09:35
  • @Ruslan Sorry, I posted this when I was just learning C, and I might have read that in very early versions of C the `void` is required. Don't quote me on that, and I now know it is a slightly foolish comment. It can't hurt, though. – dylnmc May 07 '15 at 01:41
  • what if argc<3 returns an error? what could possibly went wrong? – AVI Dec 04 '17 at 15:50
0

In case you learn something from this

#include<iostream>
using namespace std;
int main(int argc, char** argv) {
   cout << "This program has " << argc << " arguments:" << endl;
   for (int i = 0; i < argc; ++i) {
      cout << argv[i] << endl;
   }
   return 0;
}

This program has 3 arguments. Then the output will be like this.

C:\Users\user\Desktop\hello.exe
hello
people
0

When using int and char**, the first argument will be the number of commands in by which the programs is called and second one is all those commands

Supergamer
  • 411
  • 4
  • 13
0

Just to add because someone says there is a third parameter (*envp[]), it's true, there is, but is not POSIX safe, if you want your program to use environment variables you should use extern char environ ;D

Jason
  • 36,170
  • 5
  • 26
  • 60
izenynn
  • 23
  • 2