1 <!DOCTYPE HTML PUBLIC
"-//W3O//DTD W3 HTML 2.0//EN">
2 <!-- This collection of hypertext pages is Copyright 1995-7 by Steve Summit. -->
3 <!-- This material may be freely redistributed and used -->
4 <!-- but may not be republished or sold without permission. -->
7 <link rev=
"owner" href=
"mailto:scs@eskimo.com">
8 <link rev=
"made" href=
"mailto:scs@eskimo.com">
9 <title>Assignment #
3 Answers
</title>
12 <H1>Assignment #
3 Answers
</H1>
18 <B>Introductory C Programming
21 UW Experimental College
28 <I>How many elements does the array
31 Which is the first element?
33 </I><p>The array has
5 elements.
34 The first is
<TT>a[
0]
</TT>;
35 the last is
<TT>a[
4]
</TT>.
37 <I>What's wrong with the scrap of code in the question?
38 </I><p>The array is of size
5, but the loop is from
1 to
5,
39 so an attempt will be made to access the nonexistent element
<TT>a[
5]
</TT>.
40 A correct loop over this array would run from
0 to
4.
42 <I>How might you rewrite the dice-rolling program
44 </I><p>About all I can think of would be to declare
11 different variables:
46 int roll2, roll3, roll4, roll5, roll6, roll7, roll8, roll9,
47 roll10, roll11, roll12;
49 sum = d1 + d2; /* sum two die rolls */
62 (Fortunately, we never have to write code like this;
67 is exactly what arrays are for.)
69 <I>What is the difference between a defining instance and an external declaration?
70 </I><p>A
<dfn>defining instance
</dfn>
71 is a declaration of a variable or function
72 that actually defines and allocates space for that variable or function.
73 In the case of a variable,
74 the defining instance may also supply an initial value,
75 using an
<dfn>initializer
</dfn> in the declaration.
76 In the case of a function,
77 the defining instance supplies the body of the function.
78 <p>An
<dfn>external declaration
</dfn>
79 is a declaration which mentions the name and type of a variable
80 or function which is defined elsewhere.
81 An external declaration does not allocate space;
82 it cannot supply the initial value of a variable;
83 it does not need to supply the size of an array;
84 it does not supply the body of a function.
85 (In the case of functions, however,
86 an external declaration may include argument type information;
87 in this case it is an
<dfn>external prototype declaration
</dfn>.)
89 <I>What are the four important parts of a function?
90 Which three does a caller need to know?
91 </I><p>The name, the number and type of the arguments,
94 The caller needs to know the first three.
96 <I>Modify the array-of-squares program to also print cubes.
98 #include
<stdio.h
>
103 int squares[
11]; /* [
0.
.10]; [
0] ignored */
106 for(i =
1; i
<=
10; i = i +
1)
109 cubes[i] = i * i * i;
112 printf(
"n\tsquare\tcube\n");
113 for(i =
1; i
<=
10; i = i +
1)
114 printf(
"%d\t%d\t%d\n", i, squares[i], cubes[i]);
120 <I>Rewrite the simple graphics program to print ``open'' boxes.
121 </I><p>I made a new version of the original
<TT>printsquare
</TT> function
122 called
<TT>printbox
</TT>, like this:
127 for(j =
0; j
< n; j = j +
1)
130 for(i =
0; i
< n-
2; i = i +
1)
133 for(j =
0; j
< n-
2; j = j +
1)
137 for(j =
0; j
< n; j = j +
1)
143 A box of size
1 or
2 doesn't have all three parts.
144 If you want the function to handle those sizes more appropriately,
153 for(j =
0; j
< n; j = j +
1)
156 for(i =
0; i
< n-
2; i = i +
1)
159 for(j =
0; j
< n-
2; j = j +
1)
166 for(j =
0; j
< n; j = j +
1)
174 <I>Write code to sum the elements of an array of
<TT>int
</TT>.
175 </I><p>Here is a little array-summing function:
177 int sumnum(int a[], int n)
181 for(i =
0; i
< n; i = i +
1)
186 Here is a test program to call it:
188 #include
<stdio.h
>
190 int a[] = {
1,
2,
3,
4,
5,
6};
192 int sumnum(int [], int);
196 printf(
"%d\n", sumnum(a,
6));
201 <I>Write a loop to call the
<TT>multbytwo
</TT> function
204 #include
<stdio.h
>
211 for(i =
1; i
<=
10; i++)
212 printf(
"%d %d\n", i, multbytwo(i));
217 <I>Write a
<TT>square()
</TT> function
218 and use it to print the squares of the numbers
1-
10.
219 </I><p>The squaring function is quite simple:
226 Here is a loop and main program to call it:
228 #include
<stdio.h
>
236 for(i =
1; i
<=
10; i = i +
1)
237 printf(
"%d %d\n", i, square(i));
243 <I>Write a
<TT>printnchars
</TT> function,
244 and use it to rewrite the triangle-printing program.
245 </I><p>Here is the function:
247 void printnchars(int ch, int n)
251 for(i =
0; i
< n; i++)
255 Here is the rewritten triangle-printing program:
257 #include
<stdio.h
>
263 for(i =
1; i
<=
10; i = i +
1)
273 <I>Write a function to compute the factorial of a number,
274 and use it to print the factorials of the numbers
1-
7.
275 </I><p>Here is the function:
281 for(i =
2; i
<= x; i = i +
1)
286 Here is a driver program:
288 #include
<stdio.h
>
296 for(i =
1; i
<=
7; i = i +
1)
297 printf(
"%d %d\n", i, factorial(i));
302 <p>The answer to the ``extra credit'' problem is that to
303 portably compute factorials beyond
<TT>factorial(
7)
</TT>,
304 it would be necessary to declare the
<TT>factorial()
</TT>
305 function as returning
<TT>long int
</TT>
306 (and to declare its local
<TT>fact
</TT> variable as
307 <TT>long int
</TT> as well,
308 and to use
<TT>%ld
</TT> in the call to
<TT>printf
</TT>).
309 8! (``eight factorial'') is
40320,
311 type
<TT>int
</TT> is only guaranteed to hold integers up to
32767.
312 <p>(Some machines, but not all,
313 have
<TT>int
</TT>s that can hold more than
32767,
314 so computing larger factorials on those machines would happen to work,
316 Some textbooks would tell you to
317 ``use
<TT>long int
</TT>
318 if your machine has
16-bit
<TT>int
</TT>s,''
319 but why write code two different ways depending on what kind of
320 machine you happen to be using today?
322 ``Use
<TT>long int
</TT>
323 if you would like results greater than
32767.'')
325 <I>Write a function
<TT>celsius()
</TT>
326 to convert degrees Fahrenheit to degrees Celsius.
327 Use it to print a Fahrenheit-to-Centigrade table
328 for -
40 to
220 degrees Fahrenheit, in increments of
10 degrees.
329 </I><p>Here is the function:
331 double celsius(double f)
333 return
5. /
9. * (f -
32);
336 Here is the driver program:
338 #include
<stdio.h
>
340 double celsius(double);
346 for(f = -
40; f
<=
220; f = f +
10)
347 printf(
"%f\t%f\n", f, celsius(f));
353 <I>Modify the dice-rolling program
354 so that it computes the average
355 (and, optionally, the standard deviation)
356 of all the rolls of the pair of dice.
357 </I><p>The new code involves declaring new variables
358 <TT>sum
</TT>,
<TT>n
</TT>, and
<TT>mean
</TT>
359 (and, for the extra credit problem,
<TT>sumsq
</TT> and
<TT>stdev
</TT>),
360 adding code in the main dice-rolling loop to update
<TT>sum
</TT> and
<TT>n
</TT>
361 (and maybe also
<TT>sumsq
</TT>),
362 and finally adding code at the end to compute the mean
363 (and standard deviation)
366 #include
<stdio.h
>
367 #include
<stdlib.h
>
368 #include
<math.h
>
374 int a[
13]; /* uses [
2.
.12] */
381 for(i =
2; i
<=
12; i = i +
1)
384 for(i =
0; i
< 100; i = i +
1)
388 a[d1 + d2] = a[d1 + d2] +
1;
390 sumsq = sumsq + (d1 + d2) * (d1 + d2);
394 for(i =
2; i
<=
12; i = i +
1)
395 printf(
"%d: %d\n", i, a[i]);
399 stdev = sqrt((sumsq - sum * sum / n) / (n -
1));
400 printf(
"average: %f\n", mean);
401 printf(
"std. dev.: %f\n", stdev);
407 <I>Write a
<TT>randrange
</TT> function.
408 </I><p>Here is a straightforward implementation
409 of
<TT>randrange2
</TT>:
411 #include
<stdlib.h
>
413 int randrange2(int m, int n)
415 return rand() % (n - m +
1) + m;
418 Here is one using the suggested ``better way of reducing the
419 range of the
<TT>rand
</TT> function'':
421 #include
<stdlib.h
>
423 int randrange2(int m, int n)
425 return rand() / (RAND_MAX / (n - m +
1) +
1) + m;
428 Notice that I've replaced N in the suggested general form
429 with the expression
<TT>n - m +
1</TT>.
430 <p>You could implement the simpler
<TT>randrange
</TT> function either as
434 return rand() % n +
1;
437 or, using the improvement,
441 return rand() / (RAND_MAX / n +
1) +
1;
445 by writing it ``on top of''
446 the more general
<TT>randrange2
</TT>
451 return randrange2(
1, n);
454 <p>The various ``fudge factors'' in these expressions
455 deserve some explanation.
457 one is straightforward:
458 The
<TT>+
1</TT> in
<TT>(n - m +
1)
</TT>
459 simply gives us the number of numbers in the range
<TT>m
</TT> to
460 <TT>n
</TT>,
<em>including
</em> <TT>m
</TT> and
<TT>n
</TT>.
461 (Leaving out the
<TT>+
1</TT> in this case is the classic
462 example of a
<dfn>fencepost error
</dfn>,
463 named after the old puzzle,
465 ``How many pickets are there in
466 a picket fence ten feet long, with the pickets one foot apart?'')
467 <p>The other
<TT>+
1</TT> is a bit trickier.
468 First let's consider the second implementation of
<TT>randrange
</TT>.
469 We want to divide
<TT>rand
</TT>'s output by some number
470 so that the results will come out in the range
0 to
<TT>n -
</TT>1.
471 (Then we'll add in
1 to get numbers in the range
1
473 Left to its own devices,
474 <TT>rand
</TT> will return numbers in the range
0 to
<TT>RAND_MAX
</TT>
475 (where
<TT>RAND_MAX
</TT> is a
477 constant defined for us in
<TT><stdlib.h
></TT>).
478 The division, remember, is going to be integer division,
480 So numbers which would have come out in the range
481 0.0 to
0.99999... (if the division were exact) will all truncate to
0,
482 numbers which would have come out in the range
483 1.0 to
1.99999... will all truncate to
1,
484 2.0 to
2.99999... will all truncate to
2,
486 If we were to divide
<TT>rand
</TT>'s output
491 that is, if we were to write
493 rand() / (RAND_MAX / n)
495 then when
<TT>rand
</TT> returned
<TT>RAND_MAX
</TT>,
500 which is one too many.
501 (This wouldn't happen too often--only when
<TT>rand
</TT>
502 returned that one value, its maximum value--but it would be a
503 bug, and a hard one to find, because it wouldn't show up very
505 So if we add one to the denominator,
507 divide by the quantity
511 then when
<TT>rand
</TT> returns
<TT>RAND_MAX
</TT>,
512 the division will yield a number just shy of
514 which will then be truncated to
516 which is just what we want.
517 We add in
1, and we're done.
518 <p>In the case of the more general
<TT>randrange2
</TT>,
519 everything we've said applies,
520 with
<TT>n
</TT> replaced by
<TT>n - m +
1</TT>.
523 RAND_MAX / (n - m +
1)
525 would occasionally give us a number one too big
526 (
<TT>n +
1</TT>, after adding in
<TT>m
</TT>),
529 RAND_MAX / (n - m +
1) +
1
532 <p>Finally, just two lines in the dice-rolling program would need
534 to make use of the new function:
541 d1 = randrange2(
1,
6);
542 d2 = randrange2(
1,
6);
544 <p>The answer to the extra-credit portion of the exercise
545 is that under some compilers,
546 the output of the
<TT>rand
</TT> function
547 is not quite as random as you might wish.
548 In particular, it's not uncommon for the
<TT>rand
</TT> funciton
549 to produce alternately even and odd numbers,
550 such that if you repeatedly compute
<TT>rand %
2</TT>,
551 you'll get the decidedly non-random sequence
0,
1,
0,
1,
0,
1,
0,
1... .
552 It's for this reason that
553 the slightly more elaborate range-reduction techniques
554 involving the constant
<TT>RAND_MAX
</TT>
557 <I>Rewrite the dice-rolling program to also print a histogram.
559 #include
<stdio.h
>
560 #include
<stdlib.h
>
566 int a[
13]; /* uses [
2.
.12] */
568 for(i =
2; i
<=
12; i = i +
1)
571 for(i =
0; i
< 100; i = i +
1)
575 a[d1 + d2] = a[d1 + d2] +
1;
578 for(i =
2; i
<=
12; i = i +
1)
580 printf(
"%d: %d\t", i, a[i]);
581 printnchars('*', a[i]);
588 The
<TT>\t
</TT> in the second-to-last call to
<TT>printf
</TT>
589 prints a tab character,
590 so that the histogram bars will all be lined up,
591 regardless of the number of digits
592 in the particular values of
<TT>i
</TT> or
<TT>a[i]
</TT>.
593 Another possibility would be to use
<TT>printf
</TT>'s
595 (which we haven't really covered yet)
596 to keep the digits lined up.
597 That approach might look like this:
599 printf(
"%2d: %3d ", i, a[i])
604 This page by
<a href=
"http://www.eskimo.com/~scs/">Steve Summit
</a>
605 //
<a href=
"copyright.html">Copyright
</a> 1995-
9
606 //
<a href=
"mailto:scs@eskimo.com">mail feedback
</a>