Command-Line Arguments
Introduction
Command-line arguments are a great way to give a program input right
as the program begins executing. The convention to do this is to give
your main function two arguments, argc
and argv. argc is an integer related to the
number of arguments passed in to the program, and argv
is an array of strings related to those arguments, and thus is
declared as char* argv[].
Textbook Reading
The necessary background details on processing command-line arguments in C first comes from the textbook. Read
- King: Section 13.7, pp. 300-304
String Processing
Because arguments are given as strings, we introduce or review several important string-processing mechanisms in C.
- Characters and Substrings
- Conversion to numbers
- Command-string processing
All examples that follow may be found in the C-program,
string-processing.c
Characters and Substrings
Extraction of a character
In C, a string is an array of characters, and each character can be accessed directly through in index within the array.
char myArray[17] = "computer science";
int length = strlen (myArray);
for (int i = 0; i < length; i++)
printf ("\tmyArray[%d] = %c\n", i, myArray[i]);
Extraction of a substring
Given a string, a common task is to extract a substring from a string. For example, in Scheme, one might use the substring function:
(substring str start end)
According to the
Scheme
R5 documentation, Substring
returns a newly allocated
string formed from the characters of string beginning with
index start (inclusive) and ending with index end
(exclusive).
In C, there is not a function with the name substring,
but the function strncpy accomplishes the same result;
one copies end-start characters from str,
starting with the offset start. If the extracted string
does not go to the end of str, then one must remember to
add a null character at the end.
The header of strncpy reads:
char * strncpy(char * dest, const char * src, int n);
In addition to copying the characters from src
to dest, the function returns a pointer
to dest.
Several examples follow.
/* extracting substrings from a string */
/* the example uses myArray from above as the starting point */
printf ("extracting substrings from a string\n");
char subArray[20]; /* for a string copy, remember to have allocated space! */
strncpy (subArray, myArray, 8);
subArray[8] = 0; /* null terminate array */
printf ("\t extract the first 8 characters (plus the null): %s\n", subArray);
/* extra bytes past end of myArray pads subArray with nulls*/
strncpy (subArray, myArray+3, strlen(myArray));
printf ("\t extract all characters after the first 3: %s\n", subArray);
int start = strlen(myArray) - 8;
strncpy (subArray, myArray+start, 8);
subArray[8] = 0; /* null terminate array */
printf ("\t extract the last 8 characters (plus the null): %s\n", subArray);
Breaking a string into pieces
Some applications require a string to be separated into pieces. For example, consider the string
"January,February,March,April,May,June,July,August,September,October,November,December"
We might want to break it into a sequence of substrings, separated by a given separator or delimiter. This task is accomplished by the following function:
char * strtok(char * strptr, const char * delimiter);
The first call to strtok returns the first string before
the given delimiter. For subsequent calls, a null string is used for
the strptr parameter, and these calls return the next
elements in the sequence. When no more elements are
present, strtok returns NULL.
Warnings:
-
Calls to
strtokcan change the first parameter. -
Because
strtokchanges the parameter, standard practice is to copy the original string first and use the copy when callingstrtok -
The function
strsepis now preferred overstrtok.
The following example places the months given above into an array of 12 string points:
char year[] = "January,February,March,April,May,June,July,"
"August,September,October,November,December" ;
/* copy original array */
char* yearCopy = malloc (sizeof(char)*(strlen(year) + 1));
strcpy (yearCopy, year);
/* array to receive the string pieces, including space for NULL strtok at end */
char* months[13];
/* loop puts strings into successive elements of months array */
months[0] = strtok(yearCopy, ",");
i = 1;
while ((months[i] = strtok(NULL, ","))) /* continue as long as token != NULL */
i++;
printf ("result of using strtok to break up a string of months\n");
for (i = 0; i < 12; i++)
printf ("\t month %d: %s\n", i, months[i]);
printf ("original year array: %s\n", year);
Conversion to numbers
Input from a command line (and input from scanf
using %s format) is a string. The stdlib.h
library contains several functions to convert strings to numbers:
-
convert a character string to an
intint atoi (const char * strptr); /* converts a string to an int */ -
convert a character string to a
doubledouble atof (const char * strptr); /* converts a string to a double */
| Function call | Result | Comments | |
|---|---|---|---|
atoi("1234") |
1234 | int type returned
| |
atoi("3.14") |
3 |
int type returned; digits after the decimal point
ignored
|
|
atof("1234") |
1234.0 | double type returned |
|
atof("3.14") |
3.14 | double type returned |
Note that more recent (C99) library functions strtol
and strtod feature more robust error checking and are to be
preferred over atoi and atof.
Command-string processing
We might combine string-processing and the command-line arguments into a
method for dictating actions to the robot. Toward this end, our
command-line arguments will be character-number pairs where the
leading character would indicate some command, and the trailing
number would be a single numeric parameter for that command. For
instance, the argument f2 might signifiy moving forward
for two seconds.
The following code exerpt may accomplish this by iterating over each command-line argument, extracting the first character of the string, then converting the subsequent characters in the string to its numeric equivalent.
/* robot commands */
printf ("robot commands entered from the command line\n");
printf ("\t this program: %s\n", argv[0]);
for (int i = 1; i < argc; i++)
{
printf ("\t full robot command: %s\n", argv[i]);
/* process 1-character robot commands */
if (strlen(argv[i])>= 2 && isalpha (argv[i][0]) && isdigit (argv[i][1]))
{
char command1 = argv[i][0];
int value1 = atoi (argv[i]+1);
printf ("\t\t command letter: %c\n", command1);
printf ("\t\t integer value: %d\n", value1);
}
}
