Midterm Practice Solutions ========================== #. Write a program that calculates the percentage score on an exam. It should ask the user how much the exam is out of, and then ask what score the user got on it. Then it prints the percentage score. Here's a sample run:: What is the exam out of? 34 What is your score? 29.5 You scored 86.7647% Your program should do the following error-checking: - If the user enters 0, or less, for what the exam is out of, then use ``cmpt::error`` to throw an exception. - If the user enters less than 0 for their score, then use ``cmpt::error`` to throw an exception. Note that there is no highest possible score, and so, for instance, someone could get a score higher than what the exam is out of (and so they will get a % over 100). **Sample solution**:: #include "cmpt_error.h" #include using namespace std; int main() { cout << "What is the exam out of? "; double out_of = 0.0; cin >> out_of; if (out_of <= 0.0) { cmpt::error("exam must be out of more than 0"); } cout << "What is your score? "; double score = 0.0; cin >> score; if (score < 0.0) { cmpt::error("score must be 0 or higer"); } double pct = 100.0 * score / out_of; cout << "You scored " << pct << "%\n"; } #. Suppose ``a``, ``b``, and ``c`` are all variables of type ``int``. They have been created, but we don't know the exact value any of them contain. Write a fragment of code that prints "yes" if either ``a``, ``b``, and ``c`` are *all* different, or they are *all* the same. Otherwise, print "no". Sample solution:: if ((a == b && b == c) || (a != b && a != c && b != c)) { cout << "yes" } else { cout << "no" } #. Re-write the following loops as equivalent while-loops:: // loop 1 for(int i = 0; i < 100; i++) { cout << i*i; } // loop 2 for(int j = 750; j >= 0; j-=2) { cout << j; } **Sample solution**:: // loop 1 int i = 0; while (i < 100) { cout << i * i; i++; } // loop 2 int j = 750; while (j >= 0) { cout << j; j -= 2; } #. Write a fragment of code that is an infinite loop that prints "hello" forever. Do it in the following ways: a) Using a for-loop b) Using a while-loop c) Without using an explicit loop **Sample solution**: Many different answers are possible. For example:: // a for (;;) { cout << "hello\n"; } // b while (true) { cout << "hello\n"; } // c void hello() { cout << "hello"; hello(); } #. Write a function that prints a fancy title on the screen. For example, if your program has this statement:: title("Geometry Helper"); Then this text should appear on the screen:: --------------- Geometry Helper --------------- The passed-in string should be sandwiched between lines of ``'-'`` characters that are the same length as the string. **Sample solution**:: void title(const string& s) { for(int i = 0; i < s.size(); ++i) { cout << "-"; } cout << "\n"; cout << s; cout << "\n"; for(int i = 0; i < s.size(); ++i) { cout << "-"; } cout << "\n"; } #. Suppose you're a hacker trying to break into a digital safe protected by a 3-digit combination of the form *abc*, where *a*, *b*, and *c* are all between 0 and 9 (inclusive). a) Write a program that prints all 3-digit safe combinations on the screen, in order from smallest to biggest, like this:: 000 001 002 ... 567 568 ... 998 999 **Sample solution**:: void safe_a() { for(int i = 0; i < 1000; ++i) { if (i < 10) { cout << "00" << i << "\n"; } else if (i < 100) { cout << "0" << i << "\n"; } else { cout << i << "\n"; } } } b) It turns out that any combination whose 3rd digit is a 3 will trigger an alarm. So, write a program that prints all 3-digit safe combinations on the screen, in order from smallest to biggest, that **don't** end with a 3:: 000 001 002 004 ... 361 362 364 ... 998 999 **Sample solution**:: void safe_b() { for(int i = 0; i < 1000; ++i) { if (i % 10 != 3) { if (i < 10) { cout << "00" << i << "\n"; } else if (i < 100) { cout << "0" << i << "\n"; } else { cout << i << "\n"; } } } } c) A new version of the safe triggers an alarm if the final digit of the combination is an odd number. Write a program that prints all 3-digit safe combinations on the screen, in order from smallest to biggest, that **don't** end with an odd digit:: 000 002 004 006 ... 362 364 366 ... 994 996 998 **Sample solution**:: void safe_c() { for(int i = 0; i < 1000; ++i) { int last_digit = i % 10; if (last_digit % 2 == 0) { if (i < 10) { cout << "00" << i << "\n"; } else if (i < 100) { cout << "0" << i << "\n"; } else { cout << i << "\n"; } } } } d) An even newer version of the safe triggers an alarm if *one or more* of the digits in the combination are odd. Write a program that prints all 3-digit safe combinations on the screen, in order from smallest to biggest, that **don't** contain an odd digit:: 000 002 004 ... 008 020 022 ... 086 088 200 202 204 ... 884 886 888 **Sample solution**:: void safe_d() { for(int d1 = 0; d1 < 10; ++d1) { for(int d2 = 0; d2 < 10; ++d2) { for(int d3 = 0; d3 < 10; ++d3) { if (d1 % 2 == 1 || d2 % 2 == 1 || d3 % 2 == 1) { // do nothing } else { cout << d1 << d2 << d3 << "\n"; } } } } } e) Due to customer complaints about the previous version of the safe having too many alarm-triggering combinations, the safe was modified with a software update such that any combination with **exactly one** odd digit will trigger an alarm. Write a program that prints all 3-digit safe combinations on the screen, in order from smallest to biggest, that contain either 0, 2, or 3 odd digits:: 000 002 004 006 ... 008 011 013 015 017 ... 097 099 101 103 105 ... 110 111 112 113 114 115 116 ... 997 998 999 **Sample solution**:: void safe_e() { for(int d1 = 0; d1 < 10; ++d1) { for(int d2 = 0; d2 < 10; ++d2) { for(int d3 = 0; d3 < 10; ++d3) { int count = 0; if (d1 % 2 == 1) count++; if (d2 % 2 == 1) count++; if (d3 % 2 == 1) count++; if (count != 1) { cout << d1 << d2 << d3 << "\n"; } } } } } #. Write a function called ``set_to_next_letter`` that works as follows:: char c = 'a'; set_to_next_letter(c); cout << c; // prints 'b' set_to_next_letter(c); cout << c; // prints 'c' set_to_next_letter(c); cout << c; // prints 'd' c = 'z'; set_to_next_letter(c); cout << c; // prints 'a' Notice that if ``c`` is ``'z'``, then ``set_to_next_letter(c)`` sets ``c`` to be ``'a'``, i.e. it "wraps around". You can assume that only lowercase letters in the range ``'a'`` to ``'z'`` will be passed to ``set_to_next_letter``. **Sample solution**:: void set_to_next_letter(char& letter) { if (letter == 'z') { letter = 'a'; } else { letter++; } } #. The following questions are based on this table of hexadecimal and decimal digits: ========= ============= Hex Digit Decimal Digit ========= ============= 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 a, A 10 b, B 11 c, C 12 d, D 13 e, E 14 f, F 15 ========= ============= a) Write a function that returns ``true`` if a character is a hex digit, and false otherwise. It should have this header:: bool is_hex(char c) For example, ``is_hex('2')``, ``is_hex('e')``, and ``is_hex('F')`` all return ``true``, while ``is_hex('$')``, ``is_hex('g')``, and ``is_hex('-')`` all return ``false``. **Sample solution**:: bool is_hex(char c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } b) Write a test driver program that asks the user to enter a character, and then prints whether or not the character is a hex digit. The test driver loop should stop when the user types the ``'!'`` character. For example:: --> a a is a hex digit --> 2 2 is a hex digit --> $ $ is not a hex digit --> ! (done) **Sample solution**:: void test_char(char c) { if (is_hex(c)) { cout << c << " is a hex digit\n"; } else { cout << c << " is not a hex digit\n"; } } int main() { char c = ' '; while (c != '!') { cout << "Please enter a char: "; cin >> c; test_char(c); } } c) Re-write the following function so that it behaves exactly the same, but it does not use a ``switch`` statement:: int hex_to_int(char c) { switch (c) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'a': case 'A': return 10; case 'b': case 'B': return 11; case 'c': case 'C': return 12; case 'd': case 'D': return 13; case 'e': case 'E': return 14; case 'f': case 'F': return 15; default: cmpt::error("unknown hex digit"); return -1; // to satisfy compiler } } **Sample solution**:: int hex_to_int(char c) { if (c == '0') { return 0; } else if (c == '1') { return 1; } else if (c == '2') { return 2; } else if (c == '3') { return 3; } else if (c == '4') { return 4; } else if (c == '5') { return 5; } else if (c == '6') { return 6; } else if (c == '7') { return 7; } else if (c == '8') { return 8; } else if (c == '9') { return 9; } else if (c == 'a' || c == 'A') { return 10; } else if (c == 'b' || c == 'B') { return 11; } else if (c == 'c' || c == 'C') { return 12; } else if (c == 'd' || c == 'D') { return 13; } else if (c == 'e' || c == 'E') { return 14; } else if (c == 'f' || c == 'F') { return 15; } else { cmpt::error("unknown hex digit"); return -1; // to satisfy compiler } } d) Write a function that takes a single ``int`` n as input, and returns the ``char`` that corresponds to the hex digit of n. If n is less than 0 or greater than 16, then use the ``cmpt::error`` function to throw an exception. **Sample solution**:: char int_to_hex(int n) { switch (n) { case 0: return '0'; case 1: return '1'; case 2: return '2'; case 3: return '3'; case 4: return '4'; case 5: return '5'; case 6: return '6'; case 7: return '7'; case 8: return '8'; case 9: return '9'; case 10: return 'a'; case 11: return 'b'; case 12: return 'c'; case 13: return 'd'; case 14: return 'e'; case 15: return 'f'; default: cmpt::error("n out of range"); return ' '; } }