* better
[mascara-docs.git] / lang / C / the.ansi.c.programming.language / c.programming.notes / homework / PS6a.html
blob542813b0d8c9104f6d29eeefb2bdd4a9e4cefbbb
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. -->
5 <html>
6 <head>
7 <link rev="owner" href="mailto:scs@eskimo.com">
8 <link rev="made" href="mailto:scs@eskimo.com">
9 <title>Assignment #6 Answers</title>
10 </head>
11 <body>
12 <H1>Assignment #6 Answers</H1>
18 <B>Introductory C Programming
19 <br>
20 <br>
21 UW Experimental College
22 <br>
23 <br>
24 Assignment #6 ANSWERS
25 </B><br>
26 <br>
27 <p>Question 1.
28 <I>If we say
29 <TT>int i = 5;
30 int *ip = &amp;i;
31 </TT>then what is <TT>ip</TT>?
32 What is its value?
33 </I><p><TT>ip</TT> is a variable which can point to an <TT>int</TT>
34 (that is, its value will be a pointer to an <TT>int</TT>;
35 or informally, we say that <TT>ip</TT> <em>is</em>
36 ``a pointer to an <TT>int</TT>'').
37 Its value is a pointer which points to the variable <TT>i</TT>.
38 <p>Question 2.
39 <I>If ip is a pointer to an int, what does <TT>ip++</TT> mean?
40 What does
41 <TT>*ip++ = 0</TT>
42 do?
43 </I><p><TT>ip++</TT> means about the same as it does for any other variable:
44 increment it by 1,
45 that is,
46 as if we had written <TT>ip = ip + 1</TT>.
48 the case of a pointer,
49 this means to
50 make it point to the object (the <TT>int</TT>)
51 one past the one it used to.
52 <TT>*ip++ = 0</TT> sets the <TT>int</TT> variable pointed to
53 by <TT>ip</TT> to 0,
54 and then increments <TT>ip</TT>
55 to point to the next <TT>int</TT>.
56 <p>Question 3.
57 <I>How much memory does the call <TT>malloc(10)</TT> allocate?
58 What if you want enough memory for 10 <TT>int</TT>s?
59 </I><p><TT>malloc(10)</TT> allocates 10 bytes,
60 which is
61 enough space for 10 <TT>char</TT>s.
62 To allocate space for 10 <TT>int</TT>s,
63 you could call <TT>malloc(10 * sizeof(int))</TT>
65 <p>Question 4.
66 <I>If <TT>char</TT> and <TT>int</TT> pointers are different,
67 how is it possible to write
68 </I><pre>
69 char *cp = malloc(10);
70 int *ip = malloc(sizeof(int));
71 </pre>
72 <I>without error on either line?
73 </I><p><TT>malloc</TT> is declared as returning the special,
74 ``generic'' pointer type <TT>void *</TT>,
75 which can be
76 (and is)
77 automatically converted to different pointer types,
78 as needed.
79 <p>Exercise 1.
80 <I>Write a program to read lines
81 and print only those containing a certain word.
82 </I><br>
83 <br>
84 <pre>
85 #include &lt;stdio.h&gt;
86 #include &lt;string.h&gt;
88 extern int getline(char [], int);
90 int main()
92 char line[100];
93 char *pat = "hello";
95 while(getline(line, 100) != EOF)
97 if(strstr(line, pat) != NULL)
98 printf("%s\n", line);
101 return 0;
102 }</pre>
103 <p>Exercise 2.
104 <I>Rewrite the checkbook-balancing program
105 to use the <TT>getwords</TT> function
106 to make it easy to take the word ``check'' or ``deposit'',
107 and the amount, from a single line.
108 </I><br>
109 <br>
110 <pre>
111 #include &lt;stdio.h&gt;
112 #include &lt;stdlib.h&gt; /* for atof() */
114 #define MAXLINE 100
115 #define MAXWORDS 10
117 extern int getline(char [], int);
118 extern int getwords(char *, char *[], int);
120 int main()
122 double balance = 0.0;
123 char line[MAXLINE];
124 char *words[MAXWORDS];
125 int nwords;
127 while (getline(line, MAXLINE) &gt; 0)
129 nwords = getwords(line, words, MAXWORDS);
131 if(nwords == 0) /* blank line */
132 continue;
134 if(strcmp(words[0], "deposit") == 0)
136 if(nwords &lt; 2)
138 printf("missing amount\n");
139 continue;
141 balance += atof(words[1]);
143 else if(strcmp(words[0], "check") == 0)
145 if(nwords &lt; 2)
147 printf("missing amount\n");
148 continue;
150 balance -= atof(words[1]);
152 else {
153 printf("bad data line: \"%s\"\n", words[0]);
154 continue;
157 printf("balance: %.2f\n", balance);
160 return 0;
161 }</pre>
162 <p>Exercise 3.
163 <I>Rewrite the line-reversing function to use pointers.
164 </I><p>Here is one way:
165 <pre>
166 int reverse(char *string)
168 char *lp = string; /* left pointer */
169 char *rp = &amp;string[strlen(string)-1]; /* right pointer */
170 char tmp;
171 while(lp &lt; rp)
173 tmp = *lp;
174 *lp = *rp;
175 *rp = tmp;
176 lp++;
177 rp--;
179 return 0;
181 </pre>
182 <p>Exercise 4.
183 <I>Rewrite the character-counting function to use pointers.
184 </I><br>
185 <br>
186 <pre>
187 int countnchars(char *string, int ch)
189 char *p;
190 int count = 0;
191 for(p = string; *p != '\0'; p++)
193 if(*p == ch)
194 count++;
196 return count;
198 </pre>
199 <p>Exercise 5.
200 <I>Rewrite the string concatenation program
201 to call <TT>malloc</TT> to allocate memory
202 for the concatenated result.
203 </I><p><pre>
204 #include &lt;stdio.h&gt;
205 #include &lt;stdlib.h&gt; /* for malloc */
206 #include &lt;string.h&gt; /* for strcpy and strcat */
208 #define MAXLINE 100
210 extern int getline(char [], int);
212 int main()
214 char string1[MAXLINE], string2[MAXLINE];
215 int len1, len2;
216 char *newstring;
218 printf("enter first string:\n");
219 len1 = getline(string1, 100);
220 printf("enter second string:\n");
221 len2 = getline(string2, 100);
223 if(len1 == EOF || len2 == EOF)
224 exit(1);
226 newstring = malloc(len1 + len2 + 1); /* +1 for \0 */
228 if(newstring == NULL)
230 printf("out of memory\n");
231 exit(1);
234 strcpy(newstring, string1);
235 strcat(newstring, string2);
237 printf("%s\n", newstring);
239 return 0;
240 }</pre>
241 <p>Exercise 6.
242 <I>Rewrite the string-replacing function to use pointers.
243 </I><p>Here is one way:
244 <pre>
245 void replace(char string[], char *from, char *to)
247 char *start, *p1, *p2;
248 for(start = string; *start != '\0'; start++)
250 p1 = from;
251 p2 = start;
252 while(*p1 != '\0')
254 if(*p1 != *p2)
255 break;
256 p1++;
257 p2++;
259 if(*p1 == '\0')
261 for(p1 = to; *p1 != '\0'; p1++)
262 *start++ = *p1;
263 return;
267 </pre>
268 The bulk of this code is a copy of
269 the <TT>mystrstr</TT>
270 function
271 in the notes, chapter 10, section 10.4, p. 8.
272 (Since <TT>strstr</TT>'s job is to find one string within
273 another, it's a natural for the first half of <TT>replace</TT>.)
274 We could also call <TT>strstr</TT> directly, simplifying <TT>replace</TT>:
275 <pre>
276 #include &lt;string.h&gt;
278 void replace(char string[], char *from, char *to)
280 char *p1;
281 char *start = strstr(string, from);
282 if(start != NULL)
284 for(p1 = to; *p1 != '\0'; p1++)
285 *start++ = *p1;
286 return;
289 </pre>
290 Again,
291 we might wonder about the case when the string to be
292 edited contains multiple occurrences of the <TT>from</TT> string,
293 and ask whether <TT>replace</TT> should replace the first one,
294 or all of them.
295 The problem statement didn't make this detail clear.
296 Our first
297 two implementations have
298 replaced only the first occurrence.
299 It happens, though, that it's trivial to rewrite our first version
300 to make it replace all occurrences--just omit the
301 <TT>return</TT> after the first string has been replaced:
302 <pre>
303 void replace(char string[], char *from, char *to)
305 char *start, *p1, *p2;
306 for(start = string; *start != '\0'; start++)
308 p1 = from;
309 p2 = start;
310 while(*p1 != '\0')
312 if(*p1 != *p2)
313 break;
314 p1++;
315 p2++;
317 if(*p1 == '\0')
319 for(p1 = to; *p1 != '\0'; p1++)
320 *start++ = *p1;
324 </pre>
325 Rewriting the second version wouldn't be much harder.
326 <p>Exercise 7.
327 <I>Write a program to read lines of text up to EOF,
328 and then print them out in reverse order.
329 </I><p>One of the reasons this program is harder
330 is that it uses pointers to pointers.
331 When we used pointers to simulate an array of integers,
332 we used pointers to integers.
333 In this program, we want to simulate an array of strings,
334 or an array of pointers to characters.
335 Therefore, we use <em>pointers</em> to pointers to characters,
336 or <TT>char **</TT>.
337 <pre>
338 #include &lt;stdio.h&gt;
339 #include &lt;stdlib.h&gt;
341 extern int getline(char [], int);
343 #define MAXLINE 100
345 int main()
347 int i;
348 char line[MAXLINE];
349 char **lines;
350 int nalloc, nitems;
352 nalloc = 10;
353 lines = malloc(nalloc * sizeof(char *));
354 if(lines == NULL)
356 printf("out of memory\n");
357 exit(1);
360 nitems = 0;
362 while(getline(line, MAXLINE) != EOF)
364 if(nitems &gt;= nalloc)
366 char **newp;
367 nalloc += 10;
368 newp = realloc(lines, nalloc * sizeof(char *));
369 if(newp == NULL)
371 printf("out of memory\n");
372 exit(1);
374 lines = newp;
377 lines[nitems] = malloc(strlen(line) + 1);
378 strcpy(lines[nitems], line);
379 nitems++;
382 for(i = nitems - 1; i &gt;= 0; i--)
383 printf("%s\n", lines[i]);
385 return 0;
387 </pre>
388 Notice that for each line we read,
389 we call <TT>malloc</TT> to allocate space for a copy of it,
390 and then use <TT>strcpy</TT> to make the copy.
391 We could not simply set
392 <pre>
393 lines[nitems++] = line;
394 </pre>
395 each time,
396 because <TT>line</TT> is a single array,
397 which can only hold one line,
398 and it gets overwritten with the contents of each input line.
399 (In other words,
400 if we didn't call <TT>malloc</TT> and make a copy,
401 we'd end up at the end with only the last line.
402 You might try it to see what happens.)
403 <p><I>Extra credit:
404 remove the restriction imposed by the fixed-size array;
405 allow the program to accept
406 arbitrarily-long lines.
407 </I><p>First we will write another version of <TT>getline</TT>,
408 called <TT>mgetline</TT>.
409 <TT>mgetline</TT> calls <TT>malloc</TT> and <TT>realloc</TT>
410 to get enough memory for the line it's currently reading,
411 regardless of how long that line is.
412 <TT>mgetline</TT> returns a pointer to the allocated memory;
413 therefore,
414 the caller does not have to pass an array for
415 <TT>mgetline</TT> to read into.
416 (It will be the caller's responsibility to <TT>free</TT> the
417 memory when it doesn't need the line of text any more.)
418 <pre>
419 #include &lt;stdio.h&gt;
420 #include &lt;stdlib.h&gt;
422 char *mgetline()
424 char *line;
425 int nalloc = 10;
426 int nch = 0;
427 int c;
429 line = malloc(nalloc + 1);
430 if(line == NULL)
432 printf("out of memory\n");
433 exit(1);
436 while((c = getchar()) != EOF)
438 if(c == '\n')
439 break;
441 if(nch &gt;= nalloc)
443 char *newp;
444 nalloc += 10;
445 newp = realloc(line, nalloc + 1);
446 if(newp == NULL)
448 printf("out of memory\n");
449 exit(1);
451 line = newp;
453 line[nch++] = c;
456 if(c == EOF &amp;&amp; nch == 0)
458 free(line);
459 return NULL;
462 line[nch] = '\0';
464 return line;
466 </pre>
467 Now we can rewrite the line-reversing program to call <TT>mgetline</TT>.
468 Note that we no longer need the local <TT>line</TT> array.
469 Instead, we use a pointer, <TT>linep</TT>,
470 which holds the return value from <TT>mgetline</TT>.
471 Since <TT>mgetline</TT> returns a new pointer to a new block
472 of memory each time we call it,
473 in this program
474 (unlike the previous one)
475 we <em>can</em> set
476 <pre>
477 lines[nitems++] = linep;
478 </pre>
479 without overwriting anything.
480 <pre>
481 #include &lt;stdio.h&gt;
482 #include &lt;stdlib.h&gt;
484 extern char *mgetline();
486 int main()
488 int i;
489 char *linep;
490 char **lines;
491 int nalloc, nitems;
493 nalloc = 10;
494 lines = malloc(nalloc * sizeof(char *));
495 if(lines == NULL)
497 printf("out of memory\n");
498 exit(1);
501 nitems = 0;
503 while((linep = mgetline()) != NULL)
505 if(nitems &gt;= nalloc)
507 char **newp;
508 nalloc += 10;
509 newp = realloc(lines, nalloc * sizeof(char *));
510 if(newp == NULL)
512 printf("out of memory\n");
513 exit(1);
515 lines = newp;
518 lines[nitems++] = linep;
521 for(i = nitems - 1; i &gt;= 0; i--)
522 printf("%s\n", lines[i]);
524 return 0;
526 </pre>
527 <hr>
528 <hr>
530 This page by <a href="http://www.eskimo.com/~scs/">Steve Summit</a>
531 // <a href="copyright.html">Copyright</a> 1995-9
532 // <a href="mailto:scs@eskimo.com">mail feedback</a>
533 </p>
534 </body>
535 </html>