Connect - Arguments
As previously mentioned, we never explained what the purpose of the parentheses after the main are. What these are used for is to pass in arguments at the command line at the same time that you are initiating the program.
To do this you need to add to your program so that it includes the following in the parentheses after the word main:
main(int argc, char** argv) {
...
}
Here’s where we learn what argc and argv actually do.
argc (short for argument count) is very simple to understand. It does as its name implies; counts how many arguments there are in the command line (Including the program name!).
So, for example, let's say we wrote a program that translated between Farenheit to Centigrade, or Centigrade to Farenheit (And we compiled it to be called TempConvert). If, at the command line, we typed in this:
> TempConvert Farenheit 78
then when we run the program, argc would be equal to 3; these three arguments are:
- The name of the program (TempConvert),
- the initial temperature type (Farenheit) to translate from, and
- the temperature to translate (78).
Download the tar file args.tar, and uncompress it. It includes a number of test C programs that show the different uses of arguments and pointers. The first test program, args1.c, will help you get a better understanding of the concept of the argument count argc.
argv
As you can see above, argv(argument vector) is declared with a char** meaning that it is a pointer to a char pointer or double pointer (Note: argv can be declared char* as well, but for our purposes we need the double pointer). Before going into detail about argv it's best to get a better understanding about double pointers.
A pointer is just that; it will contain a value that 'points to' a location in memory, where the actual variable value will reside. This is an important point and bears repeating; the pointer doesn't contain the variable value. Instead, it contains the memory location where that value will be stored. Pointers allow us to work with memory that is allocated dynamically (i.e., when the program is run), and we often use it to store more than one of a type of variable (i.e., and array). A typical declaration and memory allocation go as follows:
int *ip;
When a program with the above code is run, it will set aside an area in memory for the pointer; however this won't actually point to anything. It looks like the following:
|
ip is declared as a pointer above, but doesn't point to anything until memory is allocated. |
A location for the variable is determined and memory is set aside for the variable only when a malloc (Short for memory allocation) call is made, such as the following;
ip = (int*)malloc(n*sizeof(int));
Where n is the number of ints that we want to store in the array. If n is 4 in the above declaration, then the malloc would look like the following:
|
The malloc command allocates 4 contiguous integer-sized pieces of memory. The values of those integers are whatever was in memory at the time of the malloc, since the malloc command wasn't called with an initialization value. |
Now here is where things get a little tricky; in a similar fashion, if we wanted an array of pointers we could declare a pointer to a pointer and allocate its memory as follows:
int **ipp;
ipp = (int **) malloc(n * sizeof(int*));
Notice that the allocation is for the size of an int* not an int.
A pointer can be used with one or two dimensional arrays(each row having the same number of columns). The reason why we would use a double pointer is so that we can define arrays where each row can have an independent number of columns. The way this works is that the double pointer has memory allocated to point to a given number of pointers. Each pointer can then be allocated independently to hold a given number of data types.
Try compiling and running args2.c. Also examine the diagram below. In this program ipp is a double pointer pointing to 3 int pointers (see indput.dat). The pointers then point to 4, 2 and 5 ints respectively.
|
ip is allocated 3 integer memory pieces, which are filled with 4, 2 & 5. The double pointer ipp allocates memory for 3 integer arrays, each sized by the values in ip's integers; the first one contains 4 integers, the second has 2 integers, and the 3rd has 5 integers; finally, each of the remaining values in input.dat are placed into the integer memory slots of the arrays of ipp (1 through 11). |
Since argv is a char double pointer, let's examine one more example using char double pointers. In this example we are creating an array of strings. Once the strings have been read in, we can use the double pointer to access each string. The main concept to understand, is that we can dereference the double pointer, to use the single pointer to access each individual char in a particular string. Try compiling and running args3.c.
Now that we have double pointers out of the way, let's finish talking about argv. Argv takes each argument made at the command line. Arguments are separated by a space(spacebar, tab) at the command line. Revisiting the example from argc, if you were to enter
a.out example 5
at the command line, argv would store a.out in the first space of the array, example in the second and 5 in the third(remember that we start indexing 0, 1, 2). Try compiling and running args4.c, which takes each argument entered at the command line and prints it out. It is important to remember that the 5 in the example above is a string. If you wanted to use it in any other fashion it needs to be converted first. The next example program, args5.c allows two numbers to be entered in (remember, they are still strings) after a.out. They are then converted to a float and int respectively and printed out.
The example program args6.c is very similar to args3.c. The main difference is that instead of hardcoding the strings, args6.c takes the strings entered in at the command prompt and prints them out, followed by a print of each individual character of each string.
The final example for this section is args7.c. The first thing done in this example is to check argc, to make sure that the proper number of arguments were made at the command prompt. If not it prints "Usage: a.out -p # -m name" and then exists the program. If the correct number of arguments were made, the program loops over all of the arguments checking for -p and -m. Once -p is found, the argument following it is converted to an int and saved under j. Once -m is found the string is copied over and saved under name. Now those two arguments are ready to be used in the program. In this case they are only printed out. Later their use will become more evident.
|