/***************************************************************** sample.c A sample C program to demonstrate some points of style. Incidentally, acts like a simple calculator. Written 1999 by Keunwoo Lee. Current status of this code: complete : YES compiles : YES runs : YES known bugs : - scanf(), as always, will do bad things if the user inputs garbage. Fixing this is rather complicated, so we'll leave it for now. Notes: - This program will be more heavily commented than a usual program, for obvious reasons. You will notice that having excessively many comments, as in this file, will tend to obscure the program rather than explain it. That's okay for our current purpose, but not advisable in general. - Observe the "banner" comment (what you're reading now). The big rows of stars and the filename are useful when you want to print hard copy of more than one source file at a time. Not an issue for most of you now, but someday you will have to deal with multi-source-file programs. Make sure, by the way, that the filename in the banner comment stays in sync with the actual filename if you rename the latter! - The "Current status of this code" section is a little dangerous. Since all of the status items will tend to change rapidly, comment skew tends to become a problem. A good guideline is to update those four lines as the last thing you do before your final save at the end of the day. - You will notice that I formatted all my code to fit within an 80-column display. There are three principal virtues to this. First, lines will not wrap or get chopped off on narrow terminals. Second, 80 columns are about how many lines of Courier 10 pt. (to pick a common monospace font) fit across a printed page. Third, studies in graphic design show that people find very wide lines hard to read, and code is no exception. - The "History" section below is more meaningful for communicating changes when you are working with other people on the program. However, it's also helpful when you return to a file some days, weeks, or years after you originally write it. Remember, in six months you will effectively be a different programmer, and your memory of any given program will be very hazy. History: 7 Oct - First cut. *****************************************************************/ /* Put #include and #define directives at the top of the program, above the beginning of main(). */ /* Some directives are so common that any C programmer reading them will immediately understand it. Hence, the following #include does *not* normally merit a comment, because everyone knows what #include stdio.h does. All of the #include directives you'll be using in this class fall under this category. */ #include /*********************/ /* CONSTANTS SECTION */ /*********************/ /* Always define constants for arbitrary values. A good guideline is this: the only sensible hard-coded NUMBERS in a program are 0 and 1 (including 0.0 and 1.0), and occasionally -1; the only sensible hard-coded CHARACTER is newline ('\n'). Any value that is not one of these should be a named constant because it is arbitrary. Incidentally, the following: #define ZERO 0 is a bad idea; behavior of this sort is called "hypercorrectness" and is frowned upon. */ /* Some C compilers will define the following for you; in any case, when you want to flag errors, it's often convenient. To be safe, define them yourself. */ #define TRUE 1 #define FALSE 0 /* Notice that when I have a set of analogous values, I line them up vertically. This is a matter of preference, but I think it makes things easier to read. Use your judgment about which values are "related" enough to merit this visual aid. */ #define OP_ADD 1 #define OP_SUBTRACT 2 #define OP_MULTIPLY 3 #define OP_DIVIDE 4 /* It may seem odd to comment main as in the following comment, since it's obvious what main is and what it does. In fact, in a program of this size, it is silly to comment main. However, in much larger programs that may have many #defines, #includes, and other stuff above main(), a banner comment like the following makes it a little easier to find main() when you're skimming the whole source code. */ /***************/ /* MAIN */ /***************/ int main(void) { double first, second, result; int operation, error; /* Welcome the user if you like. Studies in user interface design note that users get annoyed by excessively cute messages; focus on the user and the tasks (s)he may want to perform. */ printf("Welcome to RISC, the Reduced Instruction Set Calculator.\n"); printf("You can add, subtract, multiply, or divide two numbers.\n"); printf("\n"); /* Get first number. */ printf("Enter first operand: "); scanf("%lf", &first); /* Get operator. Don't be afraid to break something like the following into multiple printf statements. Notice how I use the constants I named above. */ printf("You can choose one of the following operations:\n"); printf(" %d : add\n", OP_ADD); printf(" %d : subtract\n", OP_SUBTRACT); printf(" %d : multiply\n", OP_MULTIPLY); printf(" %d : divide\n", OP_DIVIDE); printf("Enter the operation number: "); scanf("%d", &operation); /* Get second number */ printf("Enter second operand: "); scanf("%lf", &second); /* Perform an operation depending on the input. In the following cascaded "if", we indent all controlled statements and always use braces, even when there's only one statement. */ if (operation == OP_ADD) { result = first + second; } else if (operation == OP_SUBTRACT) { result = first - second; } else if (operation == OP_MULTIPLY) { result = first * second; } else if (operation == OP_DIVIDE) { /* Division is special, since we want to protect from division by zero. Irregular cases like this should be documented. */ if (second == 0) { error = TRUE; printf("Error: attempted to divide by zero.\n"); } else { error = FALSE; result = first / second; } } else { /* Received invalid operation (none of the above) */ printf("Error: invalid operation.\n"); error = TRUE; } /* If no error was encountered, print the result. */ if (error != TRUE) { printf("Result: %f\n", result); } /* Some like to enclose the return value in parenthesis. Honestly it doesn't matter. */ return 0; }