Last Updated: 2015-07-08 Wed 10:51

Exam 2 Practice Problems

This document contains some practice problems designed to prepare students for the second exam. Some questions have answers are partial answers available while others do not. Students may visit office hours to discuss full answers to all problems.

Table of Contents

1 Pointers on the Stack

 1: #include <stdio.h>
 2: void mult1(int p1, int p2){
 3:   p1 = p1 * p2;
 4: }
 5: void mult2(int *p1, int *p2){
 6:   *p1 = (*p1) * (*p2);
 7: }
 8: int main(){
 9:   int i=4, j=2, k=7;
10:   mult1(i, j);                  /* Start here */
11:   mult2(&j, &k);
12:   printf("%d %d %d\n",i,j,k);
13:   /* Show state of stack */
14: 
15:   int *p = &i;
16:   mult2(p,p);
17:   printf("%d %d %d %d\n",i,j,k,*p);
18:   /* Show state of stack */
19: 
20:   mult1(k,*p);
21:   *p = 5;
22:   printf("%d %d %d %d\n",i,j,k,*p);
23:   /* Show state of stack */
24: 
25:   p = &k;
26:   *p = 2;
27:   mult2(p, &i);
28:   printf("%d %d %d %d\n",i,j,k,*p);
29:   /* Show state of stack */
30: 
31:   j = *p - i;
32:   mult1(*p,i);
33:   mult2(&i,&j);
34:   printf("%d %d %d %d\n",i,j,k,*p);
35:   /* Show state of stack */
36: 
37:   return 0;
38: }

For the program above, show the contents of the stack frame of main() at each position indicated. This will require you to understand pointer dereferencing and the address-of operator as well as how the functions mult1() and mult2() affect the stack.

Use the following as the initial state of the stack with the addresses of main() local variables as given and line 9 of main() has been executed already.

Method Line Var Value Addr Notes
main() 10 i 4 2048  
    j 2 2052  
    k 2 2056  
    p ? 2060  

2 Memory Errors

Examine the following code written by programmer Sy Zeoff

 1: #include <stdio.h>
 2: #include <string.h>
 3: #include <stdlib.h>
 4: 
 5: typedef struct{
 6:   char name[128];
 7:   double dist;
 8: } planet_t;
 9: 
10: planet_t * copy_planet_array(planet_t *pa){
11:   planet_t *new_pa = malloc(sizeof(pa) * sizeof(planet_t));
12:   int i=0;
13:   for(i=0; i<sizeof(pa); i++){
14:     new_pa[i] = pa[i];
15:   }
16:   return new_pa;
17: }
18: 
19: int main(){
20:   planet_t solarsys[9] = {
21:     {.name="Mercury"  , .dist=0.4},
22:     {.name="Venus"    , .dist=0.7},
23:     {.name="Earth"    , .dist=1.0},
24:     {.name="Mars"     , .dist=1.5},
25:     {.name="Jupiter"  , .dist=5.2},
26:     {.name="Saturn"   , .dist=9.5},
27:     {.name="Uranus"   , .dist=19.6},
28:     {.name="Neptune"  , .dist=30.0},
29:     {.name="PLUTO!!!" , .dist=35.0}
30:   };
31: 
32:   planet_t * copy = copy_planet_array(solarsys);
33: 
34:   int i;
35:   for(i=0; i<9; i++){
36:     printf("%s %lf\n",copy[i].name,copy[i].dist);
37:   }
38: 
39:   free(copy);
40: 
41:   return 0;
42: }

Sy intends for the function copy_planet_array() to create a heap-allocated copy an array of planet_t objects. The program compiles but on running it, Sy sees that something is wrong based on the output of main().

 1: > gcc memory_errors.c 
 2: > a.out
 3: Mercury 0.400000
 4: Venus 0.700000
 5: Earth 1.000000
 6: Mars 1.500000
 7: Jupiter 5.200000
 8: Saturn 9.500000
 9: Uranus 19.600000
10: Neptune 30.000000
11:  0.000000

Sy is inclined to "fix" this error by changing one line of copy_planet_array() from

for(i=0; i<sizeof(pa); i++){

to

for(i=0; i<sizeof(pa)+1; i++){

Answer the following questions.

  1. Explain why Sy's proposed "fix" will not work in every case.
  2. Explain why Sy has a fatal flaw in his understanding of how to solve this problem
  3. Create a working version of copy_planet_array(). This may involve deviating from Sy's current version of the program somewhat such as altering its prototype or re-arranging his code.

3 Heap Memory

The following program involves memory allocation on the heap. Focuse your attention on the main() function. The remaining functions are utilities to print program information as it runs.

 1: #include <stdio.h>
 2: #include <stdlib.h>
 3: 
 4: typedef struct{
 5:   int channel; double frequency, phase;
 6: } channel_params;
 7: 
 8: void print_state(channel_params chan, channel_params *cpp,
 9:                  int *ip, channel_params *cpa, int cpa_len);
10: 
11: int main(){
12:   channel_params chan = {.channel=2, .frequency=2.417e9, .phase=0.5};
13:   channel_params *cpp = &chan;
14:   int *ip = &(chan.channel);
15:   channel_params *cpa = NULL;
16: 
17:   /* Draw the stack and heap here */
18:   print_state(chan, cpp, ip, cpa, 0);
19: 
20:   cpa = malloc(sizeof(channel_params)*3);
21:   cpa[0] = chan;
22:   cpa[1] = *cpp;
23:   cpa[1].phase = 1.0;
24:   cpa[2].channel=3; cpa[2].frequency=2.422e9; cpa[2].phase=0.75;
25: 
26:   cpp = &cpa[1];
27:   
28:   /* Draw the stack and heap here */
29:   print_state(chan, cpp, ip, cpa, 3);
30:   
31:   ip = &cpa[1].channel;
32:   *ip = 4;
33:   cpp->frequency = 2.427e9;
34: 
35:   /* Draw the stack and heap here */
36:   print_state(chan, cpp, ip, cpa, 3);
37: 
38:   free(cpa);
39: 
40:   return 0;
41: }
42: 
43: /* Utility to print a channel */
44: void print_channel(channel_params cp){
45:   printf("{.channel=%2d, .frequency=%8.3e, .phase=%6.2lf}",
46:          cp.channel, cp.frequency, cp.phase);
47: }
48: 
49: /* Utilitity to print an array of channel_params */
50: void print_channels(channel_params *cps, int n_cps){
51:   int i;
52:   for(i=0; i<n_cps; i++){
53:     printf("[%2d]: ",i);
54:     print_channel(cps[i]);
55:     printf("\n");
56:   }
57: }
58: 
59: /* Print state of program */
60: void print_state(channel_params chan, channel_params *cpp,
61:                  int *ip, channel_params *cpa, int cpa_len){
62:   printf("chan : "); print_channel(chan); printf("\n");
63:   printf("*cpp : "); print_channel(*cpp); printf("\n");
64:   printf("*ip  : "); printf("%d\n",*ip);
65:   if(cpa == NULL){
66:     printf("*cpa : NULL\n");
67:   }
68:   else{
69:     printf("cpa[]:\n");print_channels(cpa,cpa_len);
70:   }
71:   printf("\n");
72: }

Draw the state of the stack and the heap at the positions indicated. Make the following assumptions.

  • ints are 32 bits, doubles are 64 bits, pointers are 32 bits
  • The stack frame for main() is laid as indicated below.
  • The heap starts at the position indicated below.
Method Line Var Value Addr Notes
main() 10 chan.channel ? 1024  
    chan.frequency ? 1028  
    chan.phase ? 1036  
    cpp ? 1044  
    ip ? 1048  
    cpa ? 1052  
         
        4048 Heap starts here

4 Input File Processing: Count Word Occurrences

Write a main() function which counts the number times a word appears in a file. Both the file to search and the word to search for are specified on the command line as per the examples below.

 1: > gcc count_word.c
 2: > a.out
 3: usage: a.out word filename
 4: > a.out apple not-there.txt
 5: Could not open file 'not-there.txt'; exiting
 6: 
 7: > cat fruitss.txt 
 8: banana grape apple
 9: apple orange
10: grape apple
11: banana
12: kiwi apple tomato
13: > a.out banana fruitss.txt 
14: banana appears 2 times in file fruitss.txt
15: > a.out apple fruitss.txt 
16: apple appears 4 times in file fruitss.txt
17: > cat veggies.txt 
18: carrot beet carrot 
19: asparagus beet
20: tomato beet carrot
21: beet tomato
22: > a.out carrot veggies.txt 
23: carrot appears 3 times in file veggies.txt
24: > a.out apple veggies.txt 
25: apple appears 0 times in file veggies.txt
26: > a.out beet veggies.txt 
27: beet appears 4 times in file veggies.txt

Notes and hints

  • You may assume that all words in files are shorter than 128 characters long. This is a mildly dangerous assumption but simplifies the code.
  • While it is possible to solve this problem by scanning character by character through a file, it is much easier to read whole words from a file using an appropriate call to fscanf() which should also ignore whitespace.
  • Make sure to check that both command line arguments are specified (search word and file to search) and that the file is opened successfully.
  • You will likely want to do string comparison to check whether a word read from the file matches the search word. Review the header file which allows one to access string functions and how the string comparison function works.

5 Ordered Pair Allocation

The struct int_pair is defined below.

typedef struct {
  int i,j;
} int_pair;

It represents a pair of integers with its i and j fields.

Write a function

int_pair * allocate_pairs(int max_i, int max_j, int *len);

which allocates memory for an array of int_pairs on the heap and fills it with pairs in a specific pattern. All integers 0,1,2,... (max_i-1) are paired with all integers 0,1,2,... (max_j-1) and appear as pairs in the array. The order of pairs should follow this pattern.

(0,0), (0,1), (0,2),... (0,max_j-1), (1,0), (1,1), ... (1,max_j-1),  (2,0), ... (max_i-1, max_j-1)

Note that the j field of the pairs changes faster than the i field.

The argument len to the function allocate_pairs() is a pointer to single integer that should be set to the length of the array.

The following main() function demonstrates the prototype and use of allocate_pairs().

 1: #include <stdio.h>
 2: #include <string.h>
 3: #include <stdlib.h>
 4: 
 5: typedef struct {
 6:   int i,j;
 7: } int_pair;
 8: 
 9: int_pair * allocate_pairs(int max_i, int max_j, int *len);
10: 
11: int main(int argc, char **argv){
12:   int len = -1;
13:   int_pair *arr = NULL;
14:   int k;
15:   
16:   arr = allocate_pairs(1, 9, &len);
17:   for(k=0; k<len; k++){
18:     printf("(%d,%d), ",arr[k].i, arr[k].j);
19:   }
20:   printf("\n");
21:   // (0,0), (0,1), (0,2), (0,3), (0,4), (0,5), (0,6), (0,7), (0,8),  
22:   free(arr);
23: 
24:   arr = allocate_pairs(7, 2, &len);
25:   for(k=0; k<len; k++){
26:     printf("(%d,%d), ",arr[k].i, arr[k].j);
27:   }
28:   printf("\n");
29:   // (0,0), (0,1), (1,0), (1,1), (2,0), (2,1), (3,0), (3,1), (4,0), (4,1), (5,0), (5,1), (6,0), (6,1), 
30:   free(arr);
31: 
32:   arr = allocate_pairs(4, 5, &len);
33:   for(k=0; k<len; k++){
34:     printf("(%d,%d), ",arr[k].i, arr[k].j);
35:   }
36:   printf("\n");
37:   // (0,0), (0,1), (0,2), (0,3), (0,4), (1,0), (1,1), (1,2), (1,3), (1,4), (2,0), (2,1), (2,2), (2,3), (2,4), (3,0), (3,1), (3,2), (3,3), (3,4), 
38:   free(arr);
39: 
40:   return 0;
41: }

Author: Chris Kauffman (kauffman@cs.gmu.edu)
Date: 2015-07-08 Wed 10:51