Switch and For Statements, Command Line and File Handling - Command Line Arguments

Chapter chap9 section 4

Under an operating system such as Unix or MSDOS a command may typically be issued by typing something such as

cut -d: -f2,3 data

Here cut is the name of a the command and the assumption is that there is an executable file called cut in a standard system place. The remaining items on the user supplied input are options or flags controlling the precise behaviour of the command. They are known as command line arguments.

A C program can always access the command line arguments associated with its invocation via formal parameters associated with the definition of the function main(). The definition of main() may typically start

main ( int argc, char *argv[] )

the identifiers argc and argv are conventional. The value of argc is the number of command line arguments, including the name of the program and argv is an aggregate of character pointers that point to the actual arguments, each of which is presented to the program as a NUL terminated string. It is a simple matter to write a program such as that given below that simply echoes its command line arguments. The program is called arg1 .

main(int argc, char *argv[])
{
	int	i = 0;
	printf("%d command line arguments\n",argc);
	do
		printf("Argument %d = >>%s<<\n",i,argv[i]);
	while(++i<argc);
}
and typical examples of use
$ arg1 a b c
4 command line arguments
Argument 0 = >>arg1<<
Argument 1 = >>a<<
Argument 2 = >>b<<
Argument 3 = >>c<<
$ arg1 test_data -f -deg
4 command line arguments
Argument 0 = >>arg1<<
Argument 1 = >>test_data<<
Argument 2 = >>-f<<
Argument 3 = >>-deg<<
$ arg1
1 command line arguments
Argument 0 = >>arg1<<
$ 
The symbols ">>" and "<<" are used to make the limits of the strings clear in the output.

It should be understood that the host operating system is likely to manipulate the command line arguments typed by the user into something quite different. Before designing applications that depend on the command line arguments some experimentation is wise. For example typing

arg1 *

on the Unix system used to write these notes gave the result

5 command line arguments
Argument 0 = >>arg1<<
Argument 1 = >>arg1<<
Argument 2 = >>arg1.c<<
Argument 3 = >>arg1.log<<
Argument 4 = >>text<<
whereas under MSDOS (and the Turbo C compiler) the following results were obtained.
2 Command line arguments
Argument 0 = >>.\arg1.exe<<
Argument 1 = >>*<<
The reason for the difference is nothing to do with the C programming language but stems from the fact that the Unix command interpreting shell expands the file naming wild card "*" into a list of file names whereas MSDOS's COMMAND.COM does not and requires the user program to make various subtle system calls to perform this expansion. As stated above the possibility of such differences must be remembered when designing programs that take information from the command line.

A common alternative declaration for the function main() is

main(int argc, char **argv)

and it would be possible to re-write the previous program to read.

main(int argc, char **argv)
{
	printf("%d Arguments\n",argc);
	while(*argv) printf("%s\n",*argv++);
}
The operation is similar to the previous example. Its operation depends, amongst other things, on the fact that argv[argc] is guaranteed by the ANSI standard to be NULL so the loop will terminate properly. The ANSI standard also guarantees that the strings argv[] retain their values throughout the execution of the program. They may also be changed by the program though this is seldom useful or good practice.

A common requirement is to recognise command line arguments, possibly with associated values and set flags that will control the behaviour of parts of the program. Such command line arguments may typically look like

Typical argumentType
-f A "binary" flag. Either present or not present.
-t: A single character value. The argument introduces a value ":" in this case.
-x1234 A flag introducing a numeric value
-ddata A flag introducing a string value

Typical code to recognise flags of these various types is shown in the example below.

int	fflg = 0;	/* 1 implies -f seen */
char	tchar = 'x';	/* character from -t option */
int	xval = 0;	/* value from -x option */
char	filename[50];	/* string from -d option */
main(int argc, char *argv[])
{
	int	i;
	for(i=1;i<argc;i++)
	{
		if(argv[i][0] == '-')
		{
			switch(argv[i][1])
			{
			case 'f' :
				fflg = 1;
				break;
			case 't' :
				tchar = argv[i][2];
				break;
			case 'x' :
				xval = atoi(argv[i]+2);
				break;
			case 'd' :
				strcpy(filename,argv[i]+2);
				break;
			default :
				printf("Unknown option %s\n",argv[i]);
			}
		}
	}
	if(fflg) printf("-f seen\n");
	printf("\"tchar\" is %c\n",tchar);
	printf("x value is %d\n",xval);
	printf("File name is %s\n",filename);
}

and some typical logs
$ arg3 -t^ -x44 -dfred
"tchar" is ^
x value is 44
File name is fred
$ arg3 -ddata -f
-f seen
"tchar" is x
x value is 0
File name is data
$ arg3 -v -t5
Unknown option -v
"tchar" is 5
x value is 0
File name is 
$
You should note that the options are sensed correctly irrespective of their order on the command line and that the variables associated with the options retain their initial values if the options do not appear on the command line.

File Handling