![]() |
School of Engineering and
Applied
Science Department of Computer Science CSci 49 -- Introduction to C Computing http://www.seas.gwu.edu/~csci49/spring06 Prof. Michael B. Feldman mfeldman@gwu.edu |
Most problems are not so easily solved. The problem-solving process is more difficult because problem descriptions are often incomplete, imprecise, or ambiguous. The successful problem solver needs to learn the following skills:
This course is concerned with a particular kind of problem solving, namely, developing solutions that use computers to get results. A computer cannot think; therefore, to get it to do any useful work, we must provide a computer with a program that is a list of instructions. Programming a computer is a lot more involved than simply writing a list of instructions. Software development is really an exercise in systematic problem solving. Before we can write a program to solve a particular problem, we must consider carefully all aspects of the problem and then organize its solution.
A software developer is someone who is involved with the design and implementation of reliable software systems. This title emphasizes the fact that programmers, like engineers, are concerned with developing practical, reliable solutions to problems. However, the product that a software developer produces is a software system rather than a physical system.
To highlight the analogy with engineering, some people refer to software engineering and software engineers. To emphasize the fact that one need not be an actual engineer or even an engineering student to develop good software, we instead use the terms software development and software developer.
As was indicated above, the design phase is often the most difficult part of the problem-solving process. When you write an algorithm, you should first list the major steps of the problem that need to be solved (called subproblems). Don’t try to list each and every step imaginable; instead, concentrate on the overall strategy. Once you have the list of subproblems, you can attack each one individually, adding detail or refining the algorithm. The process of solving a problem by breaking it up into its smaller subproblems, called divide and conquer, is a basic strategy for all kinds of problem solving activities.
If you do not develop a proper test plan, you risk just running the program with casually chosen inputs, thereby missing important test cases which, should they arise after the program is completed and delivered, may cause the program to fail unexpectedly. A program’s behavior must be, to the greatest extent possible, predictable, even if the user makes errors in operating it.
The principle of predictable performance requires that a test plan should include cases of “bad” as well as “good” input. An especially tragic, and true, story of unpredictable software is a certain radiation machine that, in treating several cancer patients, responded to some unexpected operator keystrokes by giving the patients lethally high radiation dosages, killing them instead of treating their cancer.
The software development method can be used with any actual programming language; indeed, only the implementation phase really requires detailed knowledge of a language or a particular computer. Even the testing phase is, in industry, often carried out by individuals who do not know programming but specialize in developing good tests of programs.
Now let us look at two examples. The first is a real-life example, changing a flat tire on a car; we will develop a tire-changing algorithm. The second is a small software development problem.
1. Loosen the lug nuts on the flat tire; don’t remove them yet.Because these steps are relatively independent, you might decide to assign subproblem 1 to friend A, subproblem 2 to friend B, subproblem 3 to yourself, and so on. If friend B has used a jack before, the whole process should proceed smoothly; however, if friend B does not know how to use a jack, you need to refine step 2 further.
2. Get the jack and jack up the car.
3. Remove the lug nuts from the flat tire and remove the tire.
4. Get the spare tire, place it on the wheel, and tighten the lug nuts.
5. Lower the car.
6. Secure the jack and flat tire in the trunk.
2.1. Get the jack from the trunk.Step 2.4 requires a bit of decision making on your friend’s part. Because the actual placement of the block of wood depends on whether the car is facing uphill or downhill, friend B needs to refine step 2.4.
2.2. Place the jack under the car near the flat tire.
2.3. Insert the jack handle in the jack.
2.4. Place a block of wood under the car to keep it from rolling.
2.5. Jack up the car until there is enough room for the spare tire.
2.4.1 If the car is facing uphill, then place the block of wood in back of a tire that is not flat; if the car is facing downhill, then place the block of wood in front of a tire that is not flat. This is actually a conditional action: One of two alternative actions is executed, depending on a certain condition.Finally, step 2.5 involves a repetitive action: moving the jack handle until there is sufficient room to put on the spare tire. Often, people stop when the car is high enough to remove the flat tire, forgetting that an inflated tire requires more room. It may take a few attempts to complete step 2.5.
2.5.1. Move the jack handle repeatedly until the car is high enough off the ground that the spare tire can be put on the wheel.
1. Loosen the lug nuts on the flat tire; don’t remove them yet.The algorithm for changing a flat tire has three categories of action: sequential actions, conditional actions, and repeated actions. Steps 2.1 through 2.5 are carried out in the sequence listed. Step 2.4.1 illustrates a conditional action in that placement of the block of wood depends on the angle of inclination of the car. Step 1.5.1 illustrates repetition.
2. Get the jack and jack up the car.2.1. Get the jack from the trunk.3. Loosen the lug nuts from the flat tire and remove the tire.
2.2. Place the jack under the car near the flat tire.
2.3. Insert the jack handle in the jack.
2.4. Place a block of wood under the car to keep it from rolling.2.4.1. If the car is facing uphill, then place the block of wood in back of a tire that is not flat; if the car is facing downhill, then place the block of wood in front of a tire that is not flat.2.5. Jack up the car until there is enough room for the spare tire.2.5.1. Move the jack handle repeatedly until the car is high enough off the ground that the spare tire can be put on the wheel.
4. Get the spare tire, place it on the wheel, and tighten the lug nuts.
5. Lower the car.
6. Secure the jack and flat tire in the trunk.
In general, the order of steps in an algorithm is very important. For example, the car cannot be lowered before it has been raised. Sometimes, there are several sequences for the steps in an algorithm, any one of which will produce a proper result, but in any case the steps cannot be written in a careless, arbitrary order. To succeed in software development, you must be willing to focus on solving problems in a careful, step-by-step fashion.
1. Prompt the user and read in the number of nickels and pennies.Steps 2 and 3 need refinement.
2. Compute the total value in cents.
3. Find the value in dollars and loose change.
4. Display the value in dollars and loose change.
2.1. total cents is 5 times nickels plus pennies.
3.1. dollars is the integer quotient of total cents and 100.
3.2. change is the integer remainder of total cents and 100.
1. Prompt the user and read in the number of nickels and pennies.
2. Compute the total value in cents.2.1. total cents is 5 times nickels plus pennies.3. Find the value in dollars and loose change.3.1. dollars is the integer quotient of total cents and 100.4. Display the value in dollars and loose change.
3.2. change is the integer remainder of total cents and 100.
| Test Case | Nickels | Pennies | Reason | Expected Result |
| 1 | 30 | 77 | typical | $2.27 |
| 2 | 0 | 59 | no nickels | $0.59 |
| 3 | 13 | 0 | no pennies | $0.65 |
| 4 | 0 | 0 | no coins | $0.00 |
| 5 | 13 | -5 | negative | ? |
| 6 | xyz | 4 | bad input | ? |
The last two cases test for out of range input (a negative number when a natural number is required) and “bad” input (letters instead of digits). The question marks indicate that we won’t know the result until we run the test. It is important always to test programs with “bad” as well as “good” input: The programmer cannot control which keys will be pressed by the human user, and a program’s behavior must always be predictable.
This file has the proper basic "structure" for a C application. It has no compilation errors in it, but it does nothing. It's just a starting point.
1.
/*------------------------------------------------------------
2. | CoinCollection.c
3. | Finds the value of a coin collection,
4. | given pennies and nickels
5. | Author: M.B. Feldman, The George Washington University
6. | Last Modified: January 2, 2006
7.
------------------------------------------------------------*/
8. #include <stdio.h>
9. int main()
10. {
11. int
pennies; /*
input - number of pennies */
12. int
nickels; /*
input - number of nickels */
13. int
dollars; /*
output - dollars part of value */
14. int
change;
/* output - cents part of value */
15.
16. int
totalCents; /* internal
variable
*/
17.
18. /* Prompt the user and read in the number of
nickels and pennies. */
19. /* Compute the total value in cents. */
20. /* Find the value in dollars and loose change. */
21. /* Display the value in dollars and loose
change. */
22.
23. return 0; /* indicate that program ended
successfully */
24.
25. }
Here's the listing for the final result:
1.
/*------------------------------------------------------------
2. | CoinCollection.c
3. | Finds the value of a coin collection,
4. | given pennies and nickels
5. | Author: M.B. Feldman, The George Washington University
6. | Last Modified: January 2, 2006
7.
------------------------------------------------------------*/
8. #include <stdio.h>
9. int main()
10. {
11. int
pennies; /*
input - number of pennies */
12. int
nickels; /*
input - number of nickels */
13. int
dollars; /*
output - dollars part of value */
14. int
change;
/* output - cents part of value */
15.
16. int
totalCents; /* internal
variable
*/
17.
18. /* Prompt the user and read in the number of
nickels and pennies. */
19. printf ("How many nickels do you have? ");
20. scanf("%d", &nickels);
21. printf ("How many pennies do you have? ");
22. scanf("%d", &pennies);
23.
24. /* Compute the total value in cents. */
25. totalCents = 5 * nickels + pennies;
26.
27. /* Find the value in dollars and loose change. */
28. dollars = totalCents / 100;
29. change = totalCents % 100;
30.
31. /* Display the value in dollars and loose
change. */
32. printf ("Your collection is worth %d dollars and
%d cents.\n",
33.
dollars, change);
34.
35. return 0; /* indicate that program ended
successfully */
36.
37. }
Line 25 computes the value of an arithmetic expression and stores it in the integer variable totalCents. The asterisk (*) is used in programming to indicate multiplication; the expression is evaluated as though it were written (5 * nickels) + pennies, that is, first the number of nickels is multiplied by 5, then the number of pennies is added in.
Line 28 contains the expression totalCents / 100. The slash (/) is used in programming to indicate division. Because dollars, totalCents, and 100 are all integers (whole numbers), the division operation finds and keeps the quotient of the division, and throws the remainder away. That is, if totalCents is 1256, dollars becomes 12.
Line 29 contains the expression totalCents % 100. The
percent
sign (%) is used in C as
the remainder operation, which is a counterpart to the integer
division operation. The operation
divides
totalCents
by 100, keeps the remainder, and throws away the quotient.That
is, if totalCents is 1256, change becomes 56.
Finally, the statement in lines 32-33 is a call to the output
function printf, which
displays the results on the screen. Between the parentheses are three
items separated by commas. The second and third items are the variables
whose values we wish to display; the first item gives the surrounding
titles. printf
substitutes the value of dollars
for the first %d and the
values of change for thye
second %d.