Home > Articles > Programming > C/C++

  • Print
  • + Share This
This chapter is from the book

3.10 Exercises

  1. Write itoh() (Listing 3.3 on page 91) without recursion, and use the same main() program from the chapter. What are the advantages and disadvantages of each version?

    The recursive version of itoh() (Listing 3.3 on page 91) and Exercise 1 both have void return values because each routine displays the result. Modify the recursive version of itoh() to return a character string pointer to the caller. Use the following program to test your solution.

    Listing 3.21 Program with integer-to-hexadecimal conversion

     // itoh2.C - recursive integer-to-hex conversion, returns buffer
     #include <iostream.h>
     #include <stdlib.h>
    
     int main(int argc, const char *argv[])
     {
      unsigned int num;
      char *itoh(unsigned int);      // returns character pointer
    
      if (argc == 1) {
        cerr << "Usage: " << argv[0] << " number" << endl;
        return 1;
      }
    
      num = atoi(argv[1]);
      cout << itoh(num) << endl;     // conversion routine
      return 0;
     }
    
     $ itoh2 23456
     5ba0
  2. Write a function called nextday(), using function prototypes, const declarations, and references where applicable. Here's a program to test nextday().

    Listing 3.22 Tomorrow's date

     // nextday.C - determine tomorrow's date
     #include <iostream.h>
    
     struct data {
      int month, day, year;
     };
    
     int main()
     {
      static date d1 = { 7, 30, 1992 };
      static date d2 = { 12, 31, 1989 };
      static date d3 = { 2, 28, 1992 };
      date next;
    
      next = nextday(d1);
      cout << next.month << ',' << next.day << ',' << next.year << endl;
      next = nextday(d2);
      cout << next.month << ',' << next.day << ',' << next.year << endl;
      next = nextday(d3);
      cout << next.month << ',' << next.day << ',' << next.year << endl;
     }
    
     $ nextday
     7,31,1992
     1,1,1990
     2,29,1992
  3. Should nextday() modify its date argument or not? What effect does this have on your design?

  4. Write functions rol() (rotate left) and ror() (rotate right) that rotate 32-bit integers. The first argument to both functions is an integer to rotate, and the second argument is the number of bits to rotate. Provide a way to embed (cascade) rol()and ror() calls and handle illegal shift counts.

  5. Examine the following C++ program.

    Listing 3.23 Join strings

     // joins.C - joins strings with new/delete operators
     #include <iostream.h>
     #include <string.h>
    
     int main()
     {
      try {
        char *join(const char*, const char*);
        char *joinb(const char*, const char*);
    
        cout << join("alpha","bet") << ' ';
        cout << joinb("duck","soup") << endl;
      }
    
      catch (char *msg) {       // catch handler
        cerr << msg << endl;
        return 1;
      }
      return 0;
     }
     $ joins
     alphabet duck soup

    Write the join() and joinb() routines to concatenate character strings. Function joinb() inserts a blank between its two arguments. Have both routines allocate memory dynamically with operator new and return free store pointers back to the caller.

    Who is responsible for deleting the free store memory here? Is there a memory leak? How would you fix this problem?

  6. Examine the following namespace definitions.

    namespace Black {       // define namespace Black
      void print(int k);
     }
    
     namespace White {       // define namespace White
      void print(int k);
     }
    
     using Black::print;      // global using declaration - OK?
    
     void sub1() {
      using White::print;    // local using declaration
      print(5);         // which print()?
     }
    
     void print(int k) {
      if (k > 0)
        print(k-1);      // which print()?
     }

    Can you identify which print() functions are called? What do you think the scope rules are here? Why is the global using declaration a problem?

  7. Examine the following C++ statements.

    char *ps1 = "hello";
     char **ps2 = new char *("hello");

    In terms of storage classes, describe the differences between these two statements. What are the advantages and disadvantages of these statements in a program?

  8. In Listing 3.19 on page 161, why can't the bsize tunable parameter be a default argument in bmove()?

  9. Write functions called ndim() and nfree() that allocate and free multidimensional arrays of any dimension and any built-in data type. Here are the function prototypes you need for ndim() and nfree().

    void ndim(void *, ...);       // allocate the array
    
     void nfree(void *, int);       // deallocate the array

    Use Standard Args, since ndim() takes a variable number of arguments (see "Functions with a Variable Number of Arguments" on page 104). Here are examples of how you call ndim() and nfree().

    double **a;         // a[i][j] is a double
     ndim(&a, 2, 3, 4, sizeof(double)));
    
     int ***b;          // b[i][j][k] is an int
     ndim(&b, 3, 4, 5, 6, sizeof(int)));
    
     nfree(a, 2);        // deallocate 2D array of doubles
     nfree(b, 3);        // deallocate 3D array of integers

    The prototypes for ndim() and nfree() specify void * for their first argument. This allows calls with generic pointers having any number of indirections (**, ***, etc.). Note that you call ndim() with the address of a generic pointer, making it possible for ndim() to modify the pointer with the address of memory that it allocates dynamically. The second argument of ndim() is the number of dimensions that follow, and its last argument is the size of each array element in bytes.

    Hint: Use a recursive approach for the design of ndim() and nfree().

  • + Share This
  • 🔖 Save To Your Account