Midterm I Review

The following review covers the topics you asked me to review at the end of week 3's discussion, plus some other stuff.

By no means is it meant to serve as a comprehensive review (look through my other notes for greater detail), but will help you get some more practice as you frantically cram on Wednesday at 4:49 pm.


Type Conversions

Will the following code compile? If so, what will it output?

  #include <iostream>
  #include <string>
  using namespace std;
  
  int main () {
      int bass = 5.6,
          c = 6.5;
      double swim = c / bass;
      
      cout << swim << endl;
  }

Click for answer.

swim = 1, which is what will be printed out. Integer division, despite being stored in a double is still an integer result.


Will the following code compile? If so, what will it output?

  #include <iostream>
  #include <string>
  using namespace std;
  
  int main () {
      string test = 'c';
      int i = test;
      
      cout << i << endl;
  }

Click for answer.

Compilation Error; we're attempting to store a character literal into a string variable (note the single quote). Also, we can't convert from string to int, so storing test into i is also illegal.


Assuming the ASCII character coding schema, will the following code compile? If so, what will it output?
NB: Any questions asking for character codes will likely be given on the exam; in this case, the character code for '1' and '2' are 49 and 50, respectively.

  #include <iostream>
  #include <string>
  using namespace std;
  
  int main () {
      char one = '1',
           two = '2';
      int i = one * two;
      
      cout << i << endl;
  }

Click for answer.

Contrary to what you might think, the character codes for '1' and '2' are NOT 1 and 2, but are actually 49 and 50, respectively. Thus, i = 2450.


Assuming the ASCII character coding schema, will the following code compile? If so, what will it output?
NB: Any questions asking for character codes will likely be given on the exam; in this case, the character code for '\0' is 0...

  #include <iostream>
  #include <string>
  using namespace std;
  
  int main () {
      char nada = '\0',
           tab = '\t';
      
      bool ean = nada && tab;
      
      cout << ean << endl;
  }

Click for answer.

nada holds the null character, with integer code = 0. bool ean consists of the logical AND between two chars (which compares their character codes), one of which is 0 (falsy in C++), and so ean = 0.


Assuming the ASCII character coding schema, will the following code compile? If so, what will it output?
Hint: You do NOT need to know what character is represented by 97 to solve this problem.

  #include <iostream>
  #include <string>
  #include <cctype>
  using namespace std;
  
  /*
   * MOTHER OF ALL TYPE QUESTIONS
   */
  int main () {
      string cheese = "Gouda!";
      // ^^^ bad even by my standards
      
      char a = 97,
           excited = cheese[5];
      
      bool ean = isupper(toupper(excited)) && a;
      
      cout << ean << endl;
  }

Click for answer.

excited = cheese[5] = '!', which means that toupper(excited) = '!', which means isupper('!') = 0 (exclamation marks cannot be uppercase, and so also cannot be converted to uppercase). Therefore, ean = 0 && a = 0.



Precedence

Will the following code compile? If so, what will it output?

  #include <iostream>
  #include <string>
  using namespace std;
  
  int main () {
      int x = 5;
      double y = (x * x + x / x) % 2;
      
      cout << y << endl;
  }

Click for answer.

y = (5 * 5 + 5 / 5) % 2, evaluate parens first
y = (25 + 5 / 5) % 2, * and / have equal precedence, and left to right associativity, so evaluate * on left first
y = (25 + 1) % 2
y = (26) % 2
y = 0, because 26 / 2 = 13 remainder 0


Will the following code compile? If so, what will it output?

  #include <iostream>
  #include <string>
  using namespace std;
  
  int main () {
      int x = !(5 / 3 > 2) * 3;
      
      cout << x << endl;
  }

Click for answer.

x = !(5 / 3 > 2) * 3;
x = !(1 > 2) * 3;
x = !(0) * 3;
x = 1 * 3;
x = 3;


Will the following code compile? If so, what will it output?

  #include <iostream>
  #include <string>
  #include <cctype>
  using namespace std;
  
  int main () {
      // 0 = zero, O = oh... the letter
      const string STRINGY = "0OO0O0O"; // lol
      
      int iHateThisTest = isupper(toupper(STRINGY[1])),
          moreHate = isalpha(STRINGY[0]),
          answer = !(moreHate) && (iHateThisTest + moreHate);
      
      cout << answer << endl;
  }

Click for answer.

iHateThisTest = isupper(toupper(O))
iHateThisTest = isupper(O)
iHateThisTest = 1

moreHate = isalpha(0)
moreHate = 0

answer = !(moreHate) && (iHateThisTest + moreHate)
answer = !(0) && (1 + 0), substituting
answer = 1 && 1, simplifying
answer = 1, rules of logical AND


Will the following code compile? If so, what will it output?

  #include <iostream>
  #include <string>
  using namespace std;
  
  int main () {
      string result;
      int i = 5;
      double sadPi = 3.14;
      char c = 'c';
      
      if (i > 5 || 0 || ((sadPi) == c) * 5 < -(-10)) {
          result = ":D";
      } else {
          result = ":(";
      }
      
      cout << result << endl;
  }

Click for answer.

i > 5 || 0 || ((sadPi) == c) * 5 < -(-10)
= i > 5 || 0 || ((sadPi) == c) * 5 < 10
= i > 5 || 0 || (0) * 5 < 10
= i > 5 || 0 || 0 < 10
= 0 || 0 || 0 < 10
= 0 || 0 || 1
= 0 || 1
= 1, so result = ":D", an emotion very different from what you're feeling after this problem.



Simplifying Conditionals

For use with lecture notes from Week 3 on Simplifying Conditionals.

Simplify the following if-ladder such that its behavior is the same as the original but makes as few comparisons as possible. Assume j is an int

  if ((j == 1 || j == 2) && j > 5) {
      cout << ":O" << endl;
  } else if ((j == 5 || j == 6) && j > 5) {
      cout << ":O" << endl;
  } else {
      cout << "0_o" << endl;
  }

Click for answer.

Notice that the first if is a contradiction since both clauses cannot be true simultaneously. Furthermore, in the second if condition, j > 5 is rules out j == 5 since both cannot be true simultaneously, leaving us with:

  if (j == 6) {
      cout << ":O" << endl;
  } else {
      cout << "0_o" << endl;
  }

Simplify the following if-ladder such that its behavior is the same as the original but makes as few comparisons as possible. Assume j is an int

  if ((j == 1 || j == 2) && j < 5) {
      cout << ":O" << endl;
  } else if ((j == 3 || j == 4) && j < 5) {
      cout << ":O" << endl;
  } else {
      cout << "0_o" << endl;
  }

Click for answer.

We have repetition of actions and redundant conditions, so we can condense to:

  if (j >= 1 && j < 5) {
      cout << ":O" << endl;
  } else {
      cout << "0_o" << endl;
  }

How can we simplify this if-ladder (fewer comparisons) such that its behavior is exactly the same as below?

HINT: I can get it down to a single if-else with 3 conditions in the if statement.

Also, probably good to note that this is a challenging problem unlikely to be as hard as those on the midterm.

  #include <iostream>
  #include <string>
  using namespace std;
  
  int main () {
      string s = "test",
             t = "TeSt",
             test = "t";
      
      if (s == "test" && t == "test" || test == "test") {
          cout << test << endl;
      } else if (s != "test") {
          cout << test << endl;
      } else if (test != "test") {
          cout << s << endl;
      } else {
          cout << t << endl;
      }
  }

Click for answer.

Our first observation is that the first two conditionals share a common action, so we can condense them with a logical OR:

  if (s == "test" && t == "test" || test == "test" || s != "test") {
      cout << test << endl;
  } else if (test != "test") {
      cout << s << endl;
  } else {
      cout << t << endl;
  }

Our second observation is that, in the first conditional, if s == "test" and t == "test", we print the condition, but also if s != "test".

Thus, if s == "test", then the if evaluates to true whenever t == "test", but also if s != "test". We know that for two boolean values A and B,
!A || (A && B)
= (!A || A) && (!A || B)
= 1 && (!A || B)
= !A || B (by distributive property).

In our example, A = (s == "test") and B = (t == "test") So, we can condense the first conditional down to:

  if (t == "test" || test == "test" || s != "test") {
      cout << test << endl;
  } else if (test != "test") {
      cout << s << endl;
  } else {
      cout << t << endl;
  }

Next, we notice that the first conditional has test == "test" and the second conditional has test != "test", which are mutually exclusive (and so all possible combinations of s, t, and test will fall into one of the first two conditionals), so the final else would never be able to be reached.

  if (t == "test" || test == "test" || s != "test") {
      cout << test << endl;
  } else if (test != "test") {
      cout << s << endl;
  }

Finally, observe that if our first conditional evaluates to false, then we know that test != "test", so we do not need to check for it again.

  if (t == "test" || test == "test" || s != "test") {
      cout << test << endl;
  } else {
      cout << s << endl;
  }

Muuuch better... and also more complicated than you'll probably have to do on the midterm! Better to practice hard though.



Input / Output

Examine the following program and answer the questions that follow.

  #include <iostream>
  #include <string>
  using namespace std;
    
  int main () {
      int erestingExample;
      string stuff;
  
      cout << "Enter an int: ";
      cin.ignore(2, '\n');
      cin >> erestingExample;
      cout << erestingExample << endl;
      // [?] Answer 1
        
      cout << "Enter a string: ";
      getline(cin, stuff);
      cout << stuff << endl;
      // [?] Answer 2
  
      cout << "Enter another string: ";
      getline(cin, stuff);
      cout << stuff << endl;
      // [?] Answer 3
  }

Ignoring its many flaws, what values will get printed out if a user inputs the following values ([Enter] indicates the user hit enter on the keyboard):

555[Enter]
stuff[Enter]


Answer 1: 5, because we ignored the first 2 characters of 555 before we hit a newline.
Answer 2: Our first cin.ignore(2, '\n') fails to pick up the newline left by the cin, so our first getline(cin, stuff) sees it and assumes the user just hit enter; thus, the empty string is in variable stuff.
Answer 3: The third getline properly picks up the text "stuff" entered by the user, thus printing "stuff" here.


Consider the following code segment and determine what its output will be for the indicated cout statements.

  #include <iostream>
  #include <string>
  using namespace std;
  
  int main () {
      double test = 210.123456789;
      int i = 54321;
  
      cout.precision(3);
      cout << test << endl;
      // [?] Answer 1
      
      cout.setf(ios::fixed);
      cout.precision(3);
      cout << test << endl;
      // [?] Answer 2
  
      cout.precision(2);
      cout << i << endl; // Answer 2?
      // [?] Answer 3
  }

What will get printed out at the two couts indicated above?


Answer 1: 210
Answer 2: 210.123
Answer 3: 54321



Iteration & Nested Loops

If you haven't tried our class examples, you should do them (ignoring the answer at first) by the prompts in this link.


What will the following code output?

  #include <iostream>
  #include <string>
  using namespace std;
  
  int main () {
    string racecar = "racecar";
    int length = racecar.size();
  
    // I affectionately deem this the "echo" loop
    for (int i = 0; i < length; i++) {
        for (int j = i; j < length; j++) {
            cout << racecar[j];
        }
        cout << endl;
    }
  }

Click for answer.


racecar
acecar
cecar
ecar
car
ar
r


What will the following code output?

  #include <iostream>
  #include <string>
  using namespace std;
  
  int main () {
      int i = 1;
  
    // This outer loop is lame
    while (i < 8) {
      do {
        cout << i << endl;
        i *= 2;
      } while (i <= 8);
    }
    cout << "End value for i: " << i << endl;
  }

Click for answer.


1
2
4
8
End value for i: 16


In Week 3's class, we developed a program that used nested for-loops to created a giant N (your solution located here).
Now, your task is to re-write that program (having it output the exact same giant N) using only a single for-loop.

Click here to see a sample solution.

HINT: Think of having to choose a character for each square of an SIZE x SIZE grid and remember the operators at your disposal.


  #include <iostream>
  #include <string>
  using namespace std;
  
  int main () {
      const int SIZE = 5;
      int count = 0;
      
      // Loop that goes through
      // SIZE rows x SIZE columns
      for (int j = 0; j < SIZE * SIZE; j++) {
          // if j % SIZE == SIZE - 1, then we've
          // hit the end of a row and should add an
          // N and a newline
          if (j % SIZE == SIZE - 1) {
              cout << "N" << endl;
  
          // Otherwise, we add an N when we're at the
          // start of a row, or when we're on the diagonal
          } else if (j % SIZE == 0 || (j % (SIZE + 1)) == 0) {
              cout << "N";
  
          // Put spaces in all other cases
          } else {
              cout << " ";
          }
      }
  }


Code Triage

For each of the following code segments, find the syntax or logic errors specified by the questions following each snippet.


  #include <iostream>
  #include <string>
  using namespace std;
    
  int main () {
      int j = 0;
      while (j < 3) {
          for (int j = 0; j < 3; j++) {
              cout << j << endl;
          }
      }
  }

Find the logic error in the above code segment.

Infinite loop! The outer loop's j never gets incremented.


  #include <iostream>
  #include <string>
  using namespace std;
    
  int main () {
      int j = 0;
      do {
          for (int j = 0; j < 3; j++) {
              cout << j << endl;
          }
          j++;
      } while(j < 3)
  }

Find the syntax error in the above code segment.

Missing semi-colon after the while condition of the do-while loop.


  #include <iostream>
  #include <string>
  using namespace std;
    
  int main () {
      int j = 0;
      do {
          for (j = 0; j < 3; j++) {
              cout << j << endl;
          }
      } while(j <= 3);
  }

Find the logic error in the above code segment.

The inner loop does *not* declare a new variable j, it simply sets the current j to 0 for its pre-loop action. As such, we get an infinite loop!


  #include <iostream>
  #include <string>
  using namespace std;
    
  int main () {
      double bill;
      int tip;
      
      cout << "Enter your bill amount: $";
      cin >> bill;
  
      cout << "Enter the tip percentage (e.g., for 15% enter 15): ";
      cin >> tip;
  
      cout << "---" << endl;
      cout.setf(ios::fixed);
      cout.precision(2);
      cout << "Your total is: " << (bill * (1 + tip / 100)) << endl;
  }

Find the logic error in the above code segment, which is meant to print out a user's total bill after a tip.

Integer division in the tip computation! The expression tip / 100 will not provide the correct percentage.

BONUS: Fix it by adding a maximum 2 characters to the above code.

Add a .0 to the 100 giving us: tip / 100.0, which is no longer integer division.


In the following code snippet, the programmer wanted to catch erroneous input whenever the user input anything that wasn't "yes" or "no"; is it correct?

  if (input != "yes" || input != "no") {
      cout << "[X] Answers must be either \"yes\" or \"no\"" << endl;
      return 1;
  }

Click for answer.

No! If the user correctly answers "yes" then they still enter the error-catch since input = "yes" != "no".



Practice

Try coding the following problems by hand!


Design a program that prints out a pyramid with base that is N characters wide comprised of the 'X' character. If N is odd, then each level must have an odd number of tiles, vice versa for even N.

Warning: Tricky problem! Want a hint? (click here if so)

Consider having two loops nested inside an outer one.

  #include <iostream>
  #include <string>
  using namespace std;
  
  /*
   * For N = 5, output:
   *   X
   *  XXX
   * XXXXX
   *
   * For N = 6, output:
   *   XX
   *  XXXX
   * XXXXXX
   *
   * For N = 7, output:
   *    X
   *   XXX
   *  XXXXX
   * XXXXXXX
   */
  int main () {
      const int N = 5;
  
      // [!] Your code here!
  }

Click for solution.

  #include <iostream>
  #include <string>
  using namespace std;
  
  int main () {
      const int N = 2;
      int rows = (N + 1) / 2;
  
      // We'll need to ensure that we have an
      // odd number of blocks when our N is odd
      bool isOdd = (N % 2) == 1;
  
      // Print row-by-row
      for (int i = 0; i < rows; i++) {
          // Begin by printing left-most spaces
          for (int j = 0; j < rows - i - 1; j++) {
              cout << " ";
          }
  
          // Then print out the number of blocks
          for (int k = 0; k < 2 * (i + 1) - isOdd; k++) {
              cout << "X";
          }
          cout << endl;
      }
  }

Create a program that asks a user for a month number (1 - 12), whether or not it is a leapyear, and outputs the number of days in that month.

Thus, the order of operations is:

  • Ask user for a month number.

  • Verify that the number is between 1 - 12, otherwise print an error message.

  • Ask the user whether or not it's a leap year (acceptable answers are "y" or "n", and should be case-insensitive, i.e., capital or lowercase both work)

  • Verify that the leap year answer is either "y" or "n" (case insensitive), otherwise, print an error message.

  • If all input is valid, print the number of days in the given month.

For reference:

  • 31 Days: 1, 3, 5, 7, 8, 10, 12

  • 30 Days: 4, 5, 9, 11

  • 29 Days (in a leap-year): 2

  • 28 Days (not a leap-year): 2

A+ answers will do it without listing every month...

  #include <iostream>
  #include <string>
  #include <cctype>
  using namespace std;
  
  /*
   * Gathers a month number from the user,
   * asks them if it is a leapyear (y / n),
   * and then outputs the number of days in that month.
   */
  int main () {
      int days = 31,
          month;
      string leapYear;
  
      cout << "Enter a month number: ";
      // [!] Your code here:
      ???
      
      
      // [!] Your code here:
      if ( ??? ) {
          cout << "[X] Months must be between 1 - 12!" << endl;
          ???
      }
  
      cout << "Is it a leap year? (y / n): ";
      // [!] Your code here:
      ???
  
      // [!] Your code here:
      if (???) {
          cout << "[X] Answers must be either \"y\" or \"n\"" << endl;
          ???
      }
  
      // [!] Your code here:
      ???
      
      cout << "There are " << days << " in this month." << endl;
  }

Click for solution.

  #include <iostream>
  #include <string>
  #include <cctype>
  using namespace std;
  
  /*
   * Gathers a month number from the user,
   * asks them if it is a leapyear (yes / no),
   * and then outputs the number of days in that month.
   */
  int main () {
      int days = 31,
          month;
      string leapYear;
  
      cout << "Enter a month number: ";
      cin >> month;
      cin.ignore(10000, '\n');
  
      if (month < 1 || month > 12) {
          cout << "[X] Months must be between 1 - 12!" << endl;
          return 1;
      }
  
      cout << "Is it a leap year? (y / n): ";
      getline(cin, leapYear);
  
      if (leapYear.length() != 1 || (tolower(leapYear[0]) != 'y' && tolower(leapYear[0]) != 'n')) {
          cout << "[X] Answers must be either \"y\" or \"n\"" << endl;
          return 1;
      }
  
      switch (month) {
          case 2:
              days = (tolower(leapYear[0]) == 'y') ? 29 : 28;
              break;
          case 4:
          case 5:
          case 9:
          case 11:
              days = 30;
              break;
      }
  
      cout << "There are " << days << " in this month." << endl;
  }