|
|
The descriptions that follow use the line numbers within testcase to indicate their location. This is an example of correct programming structure.
1 #include <stdio.h> 2 #include <ctype.h> 3 #include <string.h> 4 5 /* Manifests for state machine to parse input line. */ 6 #define WORD 0 7 #define IGNORE 1 8 9 /* Globals, used by both subroutines. */ 10 char *Words[BUFFERSIZE/2]; /* Worst case, single letters. */ 11 int WordCount; 12 13 /* Walk through the array of words, find those with the 14 * matching character, printing them on stdout. Note that 15 * the null character will match all words. */ 16 void PrintWords(wc, match) 17 int wc; /* Number of words in Words[] */ 18 char match; /* Attempt to match this character. */ 19 { 20 register int ix; /* Index in Words[]. */ 21 register char *cp; /* Pointer for searching. */ 22 for (ix = 0; ix < wc; ix++) { 23 cp = Words[ix]; 24 /* Try to match the given character. 25 * Scan the word, attempting to match, 26 * or until the end of the word is found. */ 27 while ((*cp) && (*cp++ != match)) 28 ++cp; 29 if (*cp == match) /* Found a match? Write the word on stdout. */ 30 (void) printf("%s\n", Words[ix]); 31 } 32 return; 33 } 34 35
36 /* Find words in the given buffer. The Words[] array is set 37 * to point at words in the buffer, and the buffer modified 38 * with null characters to delimit the words. */ 39 int GetWords(buf) 40 char buf[]; /* The input buffer. */ 41 { 42 register char *cp; /* Pointer for scanning. */ 43 int end = strlen(buf); /* Length of the buffer. */ 44 register int wc = 0; /* Number of words found. */ 45 int state = IGNORE; /* Current state. */ 46 /* For each character in the buffer. */ 47 for (cp = &buf[0]; cp < &buf[end]; cp++) { 48 /* A simple state machine to process 49 * the current character in the buffer. 50 */ 51 switch (state) { 52 case IGNORE: 53 if (!isspace(*cp)) { 54 Words[wc++] = cp; /* Just started a word? Save it. */ 55 state = WORD; /* Reset the state. */ 56 } 57 break; 58 case WORD: 59 if (isspace(*cp)) { 60 *cp = '\0'; /* Just completed a word? terminate it. */ 61 state = IGNORE; /* Reset the state. */ 62 } 63 break; 64 } 65 } 66 return wc; /* Return the word count. */ 67 } 68 69 70 71 int main(argc, argv) 72 int argc; 73 char *argv[]; 74 { 75 char buf[BUFFERSIZE], match; 76 /* Check command line arguments. */ 77 if (argc < 2) 78 match = ' '; 79 /* No command line argument, match all words. */ 80 else 81 match = *++argv[1]; /* Match the char after the first - */ 82 /* Until no more input on stdin. */ 83 while (gets(buf) != (char *)NULL) { 84 WordCount = GetWords(buf); /* Parse the input buffer. */ 85 PrintWords(WordCount, match); /* Print the matching words. */ 86 } 87 return(0); /* Return success to the shell. */ 88 }
There are some rules about the order in which header files are included; see ``Header files''. Application-specific header files should always be included after the standard header files.
Each subroutine should have a block comment preceding it to describe the subroutine and provide information about any non-obvious coding that may have been used. Well-written comments will significantly reduce the effort required to maintain the code in the future. Good C programming style dictates that block comments are not spread over several lines to the right of the actual code. Comments can be put on the line with the code, but these should be short comments that are specific to that line of code, such as shown in lines 17 and 18.