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.
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 .
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.