#include #include #define MAX_WORD 10 #define MAX_LENGTH 80 #define MAX_INDEX 2044 char* Myfgets (char*, int, FILE*); void MakePattern (char*, char*); int IsVowel (char); int Pattern2Index (char*); main(int argc, char** argv) { char word [MAX_LENGTH+1]; char pattern [MAX_LENGTH+1]; int counters [MAX_INDEX]; int index; int i, n, n_copy, length, digit; /* initialize the array of counters */ for (index = 0; index < MAX_INDEX; index++) counters [index] = 0; /* read the input and count the number of occurrences of each pattern. the key is Pattern2Index(), which maps each pattern to a unique integer, allowing us to use a 1-dimensional array of counters for what would otherwise be a 2-dimensional array with non-constant length in both dimensions */ while (Myfgets (word, MAX_LENGTH+1, stdin) != NULL) { if (strlen (word) <= MAX_WORD) { MakePattern (word, pattern); index = Pattern2Index (pattern); counters [index] ++; } } /* we hate this next block of code. the ugly part of it should be hidden off in the boonies somewhere. by "ugly part" i mean the part that translates back from indexes to patterns (see remark above). the problem is the calculation here is based on "length" and "n", the numbers that would be the indexes of the 2-dimensional array mentioned above. to modularize it the way i want, i need a way to determine "length" and "n" as a function of "index". but i was lazy. oh well. */ index = 0; for (length = 2; length <= MAX_WORD; length++) { for (n = 0; n < pow (2, length); n++) { /* first we calculate the pattern that corresponds to the current index (actually, based on "length" and "n"). */ /* need a copy of N that we can destroy */ n_copy = n; /* part 1 is basically to turn N into its binary equivalent, except to use 'c' and 'v' instead of '1' and '0' for its digits. */ pattern[length] = '\0'; i = length-1; while (n_copy) { digit = n_copy % 2; if (digit == 0) pattern[i] = 'v'; else pattern[i] = 'c'; i--; n_copy /= 2; } /* part 2 is to pad the remaining (front) portion of the pattern (whose length is determined by "length") with 'v's. */ while (i >= 0) { pattern[i--] = 'v'; } /* having calculated the pattern, we print the number of occurrences of that pattern, but only if it occurred at all. */ if (counters[index]) printf ("%d words with pattern %s\n", counters[index], pattern); /* finally, increment "index" for the next time through the double-for loop. */ index++; } } exit(0); } /* MakePattern -- makes the "cvcvvc" pattern corresponding to the given word. */ void MakePattern (char* word, char* pattern) { int i; while (*word) { if (IsVowel (*word)) *pattern = 'v'; else *pattern = 'c'; word++; pattern++; } *pattern = '\0'; return; } /* Myfgets -- calls fgets() to read a line from fp, but removes the * potential \n that fgets() could stick in at the end of the string. * returns whatever fgets() returns. */ char* Myfgets (char* word, int length, FILE* fp) { char* temp; temp = fgets (word, length, fp); if (temp != NULL) if (*(word+strlen(word)-1) == '\n') *(word+strlen(word)-1) = '\0'; return temp; } /* IsVowel -- returns true if the character is a vowel (a,e,i,o,u); false otherwise. */ int IsVowel (char ch) { return ((ch == 'a') || (ch == 'e') || (ch == 'i') || (ch == 'o') || (ch == 'u')); } /* Pattern2Index -- converts a "pattern" (string of c's and v's) to * the corresponding "index". The "pattern" is taken as a binary string, * with c's as 1's and v's as 0's. The index that corresponds to a given * pattern is that binary string taken as a number, plus 2^length of the * pattern, minus 4. Weird, yeah, but it gives a 1-1 mapping between * {patterns of length 2..whatever} and {0, 1, 2, ..., whatever-1}. * (Those two "whatever"s are different. The second one is a function of * the first. For example, if you want to do patterns of lengths from 2 * through 5, there are 4+8+16+32+64=124 of these, so "whatever" is 124.) */ int Pattern2Index (char* pattern) { int pos, thisdigit, multiplier=1, number=0; for (pos = 0; pos < strlen(pattern); pos++) { number = 2*number + (pattern[pos]=='c' ? 1 : 0); multiplier += multiplier; } return (number + multiplier - 4); }