Spring 2026 Midterm Answers
CISC-2000-E01 and CISC-2010-E01

  1. What do the underlined a and a + n mean?

    a means &a[0], the address of the first element of the array.
    a+n means &a[n], the address of the (non-existant) element a[n] that would come immediately after the last element a[n-1].
    See, for example, loop.C.

    What (if anything) goes wrong in the following C++ code?
    	const int a[] {
    		 0,
    		10,
    		20,
    		30,
    		40
    	};
    
    	const size_t n {size(a)};   //number of elements in the array
    
    	for (const int *p {a}; p < a + n; ++p) {
    		if (p[0] == p[1]) {
    			cout << "Found 2 consecutive copies of the same value.\n";
    		}
    	}
    

    During the first iteration of the loop, the pointer p points to a[0], so p[0] and p[1] are a[0] and a[1].
    During the fifth and last iteration of the loop, the pointer p points to a[4], so p[0] and p[1] are a[4] and a[5].
    But there is no a[5], so p[1] might be unpredictable garbage. Or p[1] might blow up the program.

  2. The following C++ program creates a new type of structure named player. Then it creates one structure named player1 of this new type. Then it passes the address of this structure down to the two functions moveDown and moveRight. Do the underlined ++p’s increment p? If not, what prevents them from doing so?

    No, the ++ increments p->row. It does not increment p.
    That’s because the -> has higher precedence than the prefix ++. See levels 2 and 3 in this chart.

    Rewrite the program with the following three changes.

    1. Change player from a type of structure to a class of objects. Since the class will have two int data members, it should have a constructor with two int arguments. The class will not need a destructor.
    2. Change player1 from a structure to an object.
    3. Change the functions moveDown and moveRight to member functions of the class. When the program calls these member functions, they should increment the row and col data members of the object.
    #include <cstdlib>   //for the macro EXIT_SUCCESS;
    
    struct player {
    	int row;
    	int col;
    };
    
    void moveDown(player *p);   //function declarations
    void moveRight(player *p);
    
    int main()
    {
    	player player1 {0, 0};
    
    	moveDown(&player1);
    	moveRight(&player1);
    	return EXIT_SUCCESS;
    }
    
    void moveDown(player *p)    //function definitions
    {
    	++p->row;
    }
    
    void moveRight(player *p)
    {
    	++p->col;
    }
    

    The following member functions are short enough to be inline, like the constructor:

    #include <cstdlib>   //for the macro EXIT_SUCCESS;
    
    class player {
    private:
    	int row;
    	int col;
    public:
    	player(int init_row, int init_col): row {init_row}, col {init_col} {}
    	void moveDown();
    	void moveRight();
    };
    
    void player::moveDown()
    {
    	++row;
    }
    
    void player::moveRight()
    {
    	++col;
    }
    
    int main()
    {
    	player player1 {0, 0};
    
    	player1.moveDown();
    	player1.moveRight();
    	return EXIT_SUCCESS;
    }
    
  3. What (if anything) goes wrong in the following C++ code?
    	const int a[] {
    		 0,
    		10,
    		20,
    		30,
    		40
    	};
    
    	const size_t n {size(a)};   //number of elements in the array
    
    	//Output all the elements in the array, but do not change them.
    
    	for (int *const p {a}; p < a + n; ++p) {
    		cout << *p << "\n";
    	}
    

    The const will prevent the ++ from compiling.
    This type of pointer will always point to the same place.

  4. Instead of creating the same two variables, minimum and maximum, over and over in the member functions of this class, please create them in a better way. The two variables should be accessible only to the member functions and friend functions of the class. In other words, the names of the two variables should be mentionable only in the member functions and friends of the class.
    class shoe {
    private:
    	int shoeSize;  //in the range 6 to 16 inclusive
    public:
    	shoe(int init_shoeSize);
    	void changeSize(int newShoeSize);
    };
    
    shoe::shoe(int init_shoeSize)
    	: shoeSize {init_shoeSize}   //Initialize the data member.
    {
    	const int minimum { 6};
    	const int maximum {16};
    	if (shoeSize < minimum || shoeSize > maximum) {
    		cerr << "Can't create shoe with size " << init_shoeSize << "\n";
    		exit(EXIT_FAILURE);
    	}
    }
    
    void shoe::changeSize(int newShoeSize)
    {
    	const int minimum { 6};
    	const int maximum {16};
    	if (newShoeSize < minimum || newShoeSize > maximum) {
    		cerr << "Can't change shoe to size " << newShoeSize << "\n";
    		return;
    	}
    	shoeSize = newShoeSize;   //Update the data member.
    }
    
    class shoe {
    private:
    	int shoeSize;  //in the range 6 to 16 inclusive
    	static const int minimum { 6};
    	static const int maximum {16};
    public:
    	shoe(int init_shoeSize);
    	void changeSize(int newShoeSize);
    };
    
    shoe::shoe(int init_shoeSize)
    	: shoeSize {init_shoeSize}   //Initialize the data member.
    {
    	if (shoeSize < minimum || shoeSize > maximum) {
    		cerr << "Can't create shoe with size " << init_shoeSize << "\n";
    		exit(EXIT_FAILURE);
    	}
    }
    
    void shoe::changeSize(int newShoeSize)
    {
    	if (newShoeSize < minimum || newShoeSize > maximum) {
    		cerr << "Can't change shoe to size " << newShoeSize << "\n";
    		return;
    	}
    	shoeSize = newShoeSize;   //Update the data member.
    }
    
  5. I want to write a function named equals that will take two objects of the same class, and return true or false to tell me if the two objects have the same value. In order to do its work, this function will need to use the private members of the class. Therefore the function will have to be either a member function or a friend function of the class. Should equals be a member function or a friend function, and why? Instead of equals, what would be a better name for this function in C++? (“Better” means the name that everyone would expect the function to have.)

    The function should be a friend function of the class, because it uses two objects of the class.
    (A function that uses only one object should be a member function of the class.)
    The name that everyone expects this function to have is operator==. See, for example, this date.h.

  6. My program opens and closes many files. Is there anything we did in this course that would provide a structure to help me avoid making mistakes of the following kinds?
    1. It would be a ghastly mistake to open a file without later closing it.
    2. It would be a ghastly mistake to close a file without first opening it.
    3. It would be a ghastly mistake to open a file once and then close it twice.
    4. It would be a ghastly mistake to open a file twice and then close it once.

    Make a class of objects whose constructor opens a file and whose destructor closes the file.
    Then create one of these objects and let it live out its life.
    See, for example, the object outfile in constructor.C.

  7. What is the purpose of the #ifndef, #define, and #endif, directives at the start and end of a .h file?

    If a .C file accidentally includes the same .h file more than once, the # directives will make this harmless.
    They will prevent the computer from reading the .h file the second time it is included.

  8. Write the number nineteen in binary and in hexadecimal.

    decimal: 19
    binary: 10011
    hexadecimal: 13

  9. What does the following program output?
    #include <iostream>
    #include <cstdlib>
    using namespace std;
    
    void f(int a);   //function declaration
    
    int main()
    {
    	int i {10};
    	f(i);
    	cout << i << "\n";
    	return EXIT_SUCCESS;
    }
    
    void f(int a)   //function definition
    {
    	++a;
    }
    

    It outputs 10.
    The program makes a copy of i and increments the copy, but this has no effect on i. (The copy is named a.)

  10. What does this output?
    	const int i {1};
    	cout << (i << 4) << "\n";
    

    It outputs 16.
    (By default in C++, an int is output in decimal.)
    Each left-shift gives a result that is twice the original number.
    Four left shifts in a row will give us a result that is 16 times the original number.
    Note that i << 4 has no effect on i, for the same reason that i + 4 has no effect on i.

  11. Here is a 32-bit integer written in binary (base 2). To make it easier to read, I put in spaces.
    1101 1110 1010 1101 1011 1110 1110 1111
    Write this integer in hexadecimal.

    DEADBEEF

  12. Which ones of the following eight statements will compile?
    	int a[] {
    		 0,
    		10,
    		20
    	};
    
    	int *p1 {a};
    	++p1;   //Statement 1
    	++*p1;  //Statement 2
    
    	int *const p2 {a};
    	++p2;   //Statement 3
    	++*p2;  //Statement 4
    
    	const int *p3 {a};
    	++p3;   //Statement 5
    	++*p3;  //Statement 6
    
    	const int *const p4 {a};
    	++p4;   //Statement 7
    	++*p4;  //Statement 8
    

    1, 2, 4, 5
    p2 and p4 always point to the same place.
    p3 and p4 cannot change the value thay are pointing to. They are “needles that can’t scratch the record”.

  13. When would you want to store a series of ints into a vector<int> instead of into a plain old array of ints?
    1. When you don’t know in advance (i.e., when you don’t know when you’re writing the program) how many ints there will be.
    2. If you think you might have to add additional ints as the program is running.
      Unlike a plaiin old array, a vector van expand.
  14. What does the output?
    	int i {0x4 | 0x2};
    	cout << i << "\n";
    

    It outputs 6, because in C++ an int is output in decimal by default.
    In binary, the “bitwise or” calculation is

     100
      10
     110
    
    See Bitwise or.
  15. What goes wrong here?
    	cout << "How many ints do you want to store? ";
    	size_t n {0};
    	cin >> n;
    
    	const int *p {new int[n]}; //Get a block of memory from the operating system.
    
    	//Don't make any other pointers.
    	//Some time later,
    
    	delete[] p;                //Give the block back to the operating system.
    

    The dynamically allocated block of memory is totally useless, because you can’t write any information into it.
    That’s because the only pointer that points to it is a read-only pointer.

  16. Give an operator<< function to the following class, so that the output of the program will be
    (3, 4)
    
    #include <iostream>
    #include <cstdlib>
    using namespace std;
    
    class point {
    private:
    	double x;
    	double y;
    public:
    	point(double init_x, double init_y): x {init_x}, y {init_y} {}
    
    	friend ostream& operator<<(ostream& ost, const point& p) {
    		return ost << "(" << p.x << ", " << p.y << ")";
    	}
    };
    
    int main()
    {
    	const point A {3, 4};
    	cout << A << "\n";   //means operator<<(operator<<(cout, A), "\n");
    	return EXIT_SUCCESS;
    }
    

    See, for example, date.h and date.C.

  17. In base 10, we write an integer using the 10 digits 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9.
    In base 2, we write an integer using only the 2 digits 0 and 1.
    Base 3 is pretty much the same, except that we write an integer using the 3 digits 0, 1, and 2.

    A lot of weird stuff went down in the old Soviet Union. In Red Plenty, a quirky book by Francis Spufford about the Soviet economy, I saw a reference to “glorious eccentricities, like Brusentsov’s trinary processor at the University of Moscow, the only one in the world to explore three-state electronics”. What advantages would a base 3 computer have over a plain old base 10 computer? Any disadvantages?

    The advantages of base 3 over base 10 are the same as the advantages of base 2 over base 10.
    A base 3 component would have simpler electronics than a base 10 component. Therefore

    1. A base 3 component would be cheaper to manufacture than a base 10 component.
    2. A base 3 component would be more reliable than a base 10 component.
    3. A base 3 component would use less electricity than a base 10 component.
    4. A base 3 component would throw off less unwanted heat than a base 10 component.
    5. Etc.

    The disadvantages are the same, too: base 3 need more digits than base 10.
    Consider, for example, the number 2026:
    In base 10, it takes 4 digits (2026).
    In base 3, it takes 7 digits (2210001).
    In base 2, it takes 11 digits (11111101010).

  18. This program has three classes of objects. All of their member functions are short enough to be inline. For simplicity I wrote the entire program in one big .C file, instead of breaking it up realistically into several .h and .C files. Show me the lines of output that the program produces, in the correct order.
    #include <iostream>
    #include <cstdlib>
    using namespace std;
    
    class littleObject {
    private:
    	int i;
    public:
    	littleObject(int init_i): i {init_i} {cout << "littleObject born\n";}
    	~littleObject() {cout << "littleObject dies\n";}
    };
    
    class mediumObject {
    private:
    	littleObject lo;
    public:
    	mediumObject(int init_lo): lo {init_lo} {cout << "mediumObject born\n";}
    	~mediumObject() {cout << "mediumObject dies\n";}
    };
    
    
    class bigObject {
    private:
    	mediumObject mo;
    public:
    	bigObject(int init_mo): mo {init_mo} {cout << "bigObject born\n";}
    	~bigObject() {cout << "bigObject dies\n";}
    };
    
    int main()
    {
    	bigObject bo {10};
    	return EXIT_SUCCESS;
    }
    

    The innermost object is constructed first and destructed last.
    If the outermost object were constructed first and destructed last, we would momentaruly have a hollow object (the outermost one), without any guts.

    littleObject born
    mediumObject born
    bigObject born
    bigObject dies
    mediumObject dies
    littleObject dies