#include #include /* The following vote-counting code does not follow the framework provided by Daniel Horn as the framework does not pay proper mind to the necessary modularity and structure necessary to write vote counting software that is extensible and provably accurate. */ /* The code here has undergone 12 phases of testing (2 for each modularized routine, 3 for the main vote-counting loop, as documented therein, and one for the entire program) to prove its irrefutable accuracy. */ #define PHASE *12* /* While the length of this program is much greater than the framework, over half of it is debugging options and comments. If you really care more about brevity than accuracy, feel free to ignore the comments. You deserve what you get. */ /* There must be at least one candidate and the final code must be "" for unknown votes */ char *candidates[] = { "K", "Kerry", "B", "Bush", "N", "Nader", "", "Other"}; /* Return the index of the candidate given a vote character. The returned value is certain to be between 0 and the number of candidates with unknown values returned as the maximum value */ locate( char vote) { /* testing PHASE 1: iterate over all input values and verify unique return for each value testing PHASE 2: iterate over each candidate and verify sequential index output */ short cnum = 0; while (candidates[cnum*2][0]) { if (vote == candidates[cnum*2][0]) break; cnum++; } return (cnum); } /* Given a pointer to the vote tally array (containing at least as many elements as the number of candidates, zero all the vote counts */ zero( long *tally) { /* testing PHASE 1: call with tally all zeros and verify output testing PHASE 2: call with tally all -1 and verify output */ short cnum = 0; while (1) { tally[cnum] = 0; if (candidates[cnum*2][0] == 0) break; cnum++; } } /* Given a candidate index (presumably from the locate() routine, and a vote tally array and a pointer to a longword for counting total votes, increment the tally for the given candidate and the total count */ record( short vote, long *tally, long *total) { /* testing PHASE 1: call with sequential values and verify all tallies as 1 and total testing PHASE 2: call with known set and verify tallies */ tally[vote] += 1; (*total)++; } /* Given the vote tally array, output the counts in the required format with the candidate name */ output( long *tally) { short cnum = 0; while (1) { printf ("%s: %ld\n", candidates[(cnum*2)+1], tally[cnum]); if (candidates[cnum*2][0] == 0) break; cnum++; } } int main() { short testing = 0; char x; long total = 0; long white = 0; long votes[10]; zero( votes); while ((x = getchar()) != EOF) { short cnum = 0; /* The design goal in the main loop is to minimize the code to simplify the process of analyzing the code that processes each vote. This is the area most prone to error and fraud, so, there are only two lines of code. One that looks up the candidate or determines that the input is whitespace and another that records the vote and increments the total if the input was not whitespace. Since we don't want to obfuscate this important code with debugging options, a separate PHASE 1 and PHASE 3 testing version will need to be made to show how the system reacts to missing votes. Three phases of testing are recommended to assure detection of input errors. Find and replace the correct code shown below with the code shown under PHASE 1 to demonstrate the effect of lost votes. In PHASE 2, use the production (correct) code and add votes to the input to demonstrate added votes. In PHASE 3, use both the PHASE 1 code AND add votes to simulate vote substitution. The production code fragment to be replaced is: /* Input is space, use -1, otherwise locate() */ /* locate() guaranteed not to return -1 */ (isspace(x) ? testing PHASE 1: /* WARNING! PHASE 1 TESTING CODE */ /* Ignores every other input item */ (total%2)) ? testing PHASE 2 & 3: //\\ Use code from production then phase 1 //\\ */ /* Input is space, use -1, otherwise locate() */ /* locate() guaranteed not to return -1 */ (isspace(x) ? (cnum = -1) : (cnum = locate(x))); /* Only if input was space, count as space */ /* For all non-space input record vote for candidate */ ((cnum == -1) ? (++white) : (record(cnum, votes, &total))); } /* Normal output */ output( votes); /* For testing only, show vote total and whitespace as well */ if (testing) printf ("Total: %ld\n", total); if (testing) printf ("Whitespace: %ld\n", white); }