Argument Processing and Global Variables

Introduction

Several students have used global variables to keep track of command line options. We see things like:

	static int q_flag = 0;      /* store args/opts info in these */
	static int u_flag = 0;
	static char *u_arg = NULL;
	 ....

	int main(int ac, char *av[])
	{
		process_args(ac, av);
		do_work();
	}

	/* read args, load opt vars */
	void process_args(int ac, char *av[])
	{
		int	pos ;

		for( pos = 1; pos < ac; pos++ ){
			if ( strcmp( av[i], "-q" ) )
				q_flag = 1;
			else if ( strcmp(av[i], "-u" ){
				if ( ++i == ac )
					bad_args("missing arg for -u");
				else
				{
					u_flag = 1;
					u_arg = av[i];
				}
			}
			else 
				bad_args("unknown option on command line");
		}
	}
	

This logic works. And you may well argue that the options are provided to main, so they are global to the program, so the variables that hold them may as well be global to the code.

Another Technique

Global variables reduce the flexibility and modularity of code. Another solution is to put all the state variables in a struct and then use that struct as a container for the settings for the operation of the program:

	struct opt_info {       /* store arg/opts info in this */
		int q_flag;
		int u_flag;
		char *u_arg;
	};

	int main(int ac, char *av[])
	{
		struct opt_info params;    /* make a container for opts info */

		process_args(ac, av, &params);
		do_work(&params);
	}

	/* read args, load struct holding opt info */
	void process_args(int ac, char *av[], struct opt_info* parptr)
	{
		int	pos ;

		init_params(parptr);			/* set deflt vals */
		for( pos = 1; pos < ac; pos++ ){
			if ( strcmp( av[i], "-q" ) )
				parptr->q_flag = 1;
			else if ( strcmp(av[i], "-u" ){
				if ( ++i == ac )
					bad_args("missing arg for -u");
				else {
					parptr->u_flag = 1;
					parptr->u_arg = av[i];
				}
			}
			else 
				bad_args("unknown option on command line");
		}
	}
	

This has the same effect but allows the main function to be called with a set of parameters that are not global. If do_work wanted to be recursive, that is doable, now. You just make a copy of the opt_info and pass that revised set downwards.