Part 11: structs, argc and argv[]
Since the following subjects are fairly short and simple, this article is going to attempt to cover both in as full detail as should be required. The first topic is sending arguments to your program when you run it. The second topic is a new variable type, which is actually a combination of other variables, called a struct, short for structured. This variable type is actually a user defined variable type and is used often and makes variable use for common elements easier to implement and control.
The main() function is just like any other function. It accepts variables as arguments and returns an integer value, hopefully 0, showing if any error has occurred. All main functions accept the same two arguments, argc, which is an integer and argv, which is a pointer, indicated by the *, to an array, indicated by the brackets following it, of characters, which in effect is an array of null terminated strings.
These arguments store the information entered from the command line when you run your program. The variable argc is an argument count and argv[] stores all the argument strings. An example of using command line input would be:
C:\>format a:
In this instance the argc variable would hold the number 2, since the program name and full path, in this C:\format, are counted as the first argument, and the a: is the second argument. Like all arrays, the first element is 0. Here is a simple program that will take in as many arguments as you give it then display them all on the screen:
/* dsplyarg.c v1.0 (06/29/98) */
#include <stdio.h>
int main(int argc, char *argv[])
{
int x;
printf("argc = %d\n", argc);
for(x = 0; x < argc; x++ ) {
printf("argv[%d] = %s.\n", x, argv[x]);
}
return 0;
}
In this example the first call to printf() displays the value stored in argc, which contains the number of arguments you gave the program when you ran it. If you didn't give it any arguments then argc is 1 since the first argument is always the path and filename of the program. Next it starts a loop from 0 to one less than argc. Inside this loop it displays the appropriate argument string stored in argv[].
The arguments sent to the program are divided by any spaces. If there is an instance where you want to have a string argument which contains more than one word separated by spaces you simply enclose the complete argument in double quotes. Here is an example which you can use with the above program:
C:\displayarg first "second argument" and third
Running that program with this example command line will cause it to display 5 for the number of arguments stored in argc, then each of the arguments. The first argument, stored in argv[0] will be the path and name of the file, the second is simply the word "first", the third argument is the words "second argument" without the quotes. Notice that the quotes are dropped from the argument that is stored in argv[2]. The fourth and fifth arguments are the words "and" and "third" respectively.
When you create a program that accepts and requires arguments, be sure to use error checking to ensure that the arguments are correct in quantity and value. A good programming practice is to display the program's argument requirements if none are entered when the program is run, or if a specific word like "help", is entered. Here is an example:
/* checkarg.c v1.0 (06/29/98) */
#include <stdio.h>
int main(int argc, char *argv[])
{
int x;
if (argc < 2) {
printf("This program requires at least one argument.");
} else {
printf("argc = %d\n", argc);
for(x = 0; x < argc; x++ ) {
printf("argv[%d] = %s.\n", x, argv[x]);
}
}
return 0;
}
Notice how the main part of the program is enclosed within our else section. This is because the program does not want to do anything if it is not given the proper number of arguments. It is possible, however, to exit out of the middle of a program if there is a problem. To do this you would use the exit() function. This function takes as its argument the error status value, and requires you to include the stdlib.h header file.
It is generally accepted that a value of 0 indicates no error, 5 is a warning, 10 an error and 20 a fatal error. Any numbers can be used as long as you know what the values mean to you for your program. In the last example, not supplying the arguments is not really much of an error so you can use a value like 5 or 6 if you wish.
Here is the same program using the exit() function:
/* checkarg.c v2.0 (06/29/98) */
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int x;
if (argc < 2) {
printf("This program requires at least one argument.");
exit(5);
}
printf("argc = %d\n", argc);
for(x = 0; x < argc; x++ ) {
printf("argv[%d] = %s.\n", x, argv[x]);
}
return 0;
}
Since this program uses the exit() function to exit immediately after displaying the warning message, it does not require the following statements to be inside an else block. While this is not a large consideration for a program so small, imagine a program over a thousand lines, all having to be indented and nested inside the else block. Then, should there be any more similar considerations, even deeper nesting. The exit() function takes care of this and exits the program so you don't have to worry about that.
Having covered the use of the argc and argv[] arguments to the main() function of your C program pretty thoroughly, any good book on C can answer any more detailed questions on this subject. Now to continue with explaining the use of structured variable types, also known as structs.
A structured variable type is a user defined variable type that is made up of other variable types. It can contain as many other variable types, and even arrays of other types, as the user wants. They can be declared globally or locally, just like other variables, and variables of the structure's type. A struct is declared in the following manner:
struct name_of_struct {
field_type name_of_field_variable;
};
Here is how a variable of this type would be defined:
struct name_of_struct variable_name;
A structured variable can be defined as you declare it also, like this:
struct person {
char name[256];
int age;
} programmer;
You could also declare an array of a structured type just like other variable types, and this is where their true strength lies. Structured variables are useful for combining fields of variables into records for use in programs like databases. A struct can contain a variable for each of the fields you want to store for the database record, and it would be addressed by the struct variable instead of by each individual element, which would take far longer and not be as organized.
Fields within a structured datatype are accessed using the struct variable name followed by a period then followed by the field name. Here is a simple example:
struct_variable_name.name_of_field_variable
Here is a simple example used in a program:
/* structs.c v1.0 (06/29/98) */
#include <stdio.h>
#include <stdlib.h>
struct MyRecord {
char first_name[25];
char middle_initial;
char last_name[25];
unsigned byte age;
};
int main(int argc, char *argv[])
{
struct MyRecord employee[3];
byte x;
char temp_age[4];
for(x = 0; x < 3; x++ ) {
printf("Employee #%d\n", x);
printf("Enter the first name of the employee : ");
gets(employee[x].first_name);
printf("Enter the middle initial of the employee : ");
getchar(employee[x].middle_initial);
printf("Enter the last name of the employee : ");
gets(employee[x].last_name);
printf("Enter the age of the employee : ");
gets(temp_age);
employee[x].age = atoi(temp_age);
}
for(x = 0; x < 3; x++ ) {
printf("Employee #%d\n", x);
printf("name : %s, %s %c\n", employee[x].last_name, employee[x].first_name, employee[x].middle_initial);
printf("age : %d\n", employee[x].age);
}
return 0;
}
This program example reads in the full name and age of 3 employees then displays them on the screen. Notice that when reading in the age it is read into the string variable temp_age. The variable temp_age is 4 characters long since the age can be 3 number digits plus the required NULL character at the end of the string. Then the string is converted to an integer using the atoi() function and stored in the proper structure field.
Another advantage of structured types is that the computer looks at structs as a single variable, even though it may contain limitless variables within it, including strings. Because of this you can easily copy the complete contents of one structure into another using the assignment operator like these examples:
structure_variable1 = structure_variable2; employee[1] = employee[0];
Using structures with functions is the same as using any other variable type, however the structure must be declared so that each function using it knows exactly what the structured type is. Global declaration of the structured type ensures that all functions understand the struct type and can properly recieve as arguments and return as values the structured type. Also a structure can be made up of any previously known types, including other structures.
Practice using structures, as with everything else, is the best way to fully understand the intricacies of their usage. Their use is not as hard or complex as it first appears, but structured types can easily be as complex and powerful as the user needs for data storage and management. The use of argc and argv[] make sending arguments to programs simplistic and easy. With the power of these tools one can accomplish much.

