The midterm will cover:

Basic C++ Syntax

What are the two forms of comments in C++?

Is the following a valid comment?

/*
   Commented out
   /*
      Also commented out

    */
    Still commented out
*/

What kind of declaration is this:

using namespace std;

How many statements are there in main, below?

int main() {
    cout << "Hello "; cout << "World!";
    cout << endl;

    int i;
    cout << "Enter your age: ";
    cin >> i;
    cout << "Next year you'll be " << i+1 << " years old.";
    cout << endl;
}

How many declarations?

Write out the skeleton program that we always start with. Add single-line comments to each line, explaining what it’s purpose is.

/*
   comment
 */
#include <iostream>
using namespace std;

int main() 
{
  ...
}

Re-write the following program into a easier format:

     #include<iostream>
using namespace std;int main(
     ){cout<<"Hello\n"
        ;int i = 
   1;cin>>i;cout<< i<<
     endl;}

Statement flow

What will the following print out?

int main() {
    cout << "H";
    cout << "e";
    cout << "l";
    cout << "l";
    cout << "o";
    cout << endl;
}

Can you rewrite this program to be shorter?

What will this program do?

int main() {
    int i;
    cout << "Enter your age: ";
    cin >> i;
    return 0;
    cout << "Wow, that's old.";
}

What will this program do?

int main() {
    cout << "One ";
    {
        cout << "potato, ";
        cout << "two ";
        {
            cout << "potato ";
            cout << "three potato, "
        }
    }
    cout << "four!" << endl;
}

Describe, in English, what effect the following program will have on a and b as input by the user:

#include <iostream>
using namespace std;

int main()
{
    int a,b;
    cin >> a >> b;

    int x = a < b ? a : b;
    int y = a > b ? a : b;

    cout << x << ", " << y << endl;
}

Basic IO

Assuming that the following is a complete program, what’s wrong with it?

/*
   myprogram.cpp
*/
using namespace std;

int main() 
{
    cout << "Hello, world!" << endl;
}

Complete the following program so that it reads a single character from the user and then prints out its value:

#include <iostream>
using namespace std;

int main() {
    cout << "Enter a character: ";

    char c;
    // Your code goes here


    int code = c;
    cout << "Its code is " << code << endl;
}

Strings

String methods:

Name Description
s1 + s2 String concatenation
s.length() Length of the string
s.at(n) The character at position n
s.substr(n,l) Substring starting at n of length l
s.append(s2) Append s2 to the end of s
s.find(p) Position where p first occurs
s.rfind(p) Position where p last occurs
s.insert(pos,s2); Insert s2 into the string at p
string(x,'c') String of character c repeated x times

Assume we have an input string that consists of three names, separated by commas. E.g.,

string data = "matt,scott,mark";
  1. Write code using the string methods to add the name “ethan” to the list.

     data.append(",ethan"); 
     data += ",ethan"; // Equivalent
    
  2. Write code using the string methods to remove the last name (now “ethan”)
    from the list.

     data.erase(data.rfind(","), (data.length() - 1) - data.rfind(",") + 1);
     data.erase(data.rfind(","), data.length() - data.rfind(",")); // equiv
     data.erase(data.rfind(","), data.length()); // also equivalent
    
  3. Write code using the string methods to extract the middle name.

     data.substr(data.find(",") + 1, (data.rfind(",") - 1) - 
                                     (data.find(",") + 1) + 1)
    
  4. Write code using the string methods to replace the last name with “david”.

     data.replace(data.find(",") + 1, 
                  (data.rfind(",") - 1) - (data.find(",") + 1) + 1),
                  "david");
    
  5. Write code using the string methods to get the length of the middle name.

     (data.rfind(",") - 1) - (data.find(",") + 1) + 1
    

Expressions and variables

Add comments to the following program to show where each variable’s scope begins and ends (either // v's scope begins or // v's scope ends for a variable v).

#include <iostream>
using namespace std;

int main() {
    int a;
    cout << "Hello";
    int b;
    {
        int a;
        cout << "Good bye";
        int c;
        cin >> c;
    }
    int c = 12;
    cout << a << endl;
    cout << (a + c) << endl;
}

Write out the values of each of these variables, after the program completes:

int a = 5;
int b = a * 3 + 1;
int c = a % (b / 2);

Explain, in English, what the result of this expression will be, in terms of the variable a:

a < 0 ? -a : a

What is the result of the following expression?

(1 < 2 ? 2.0 : -2.0) + (3 >= 4 && 2 < 3 ? -3.0 : 0.0)

What is the type (not value) of each of the following expressions:

1 + 2 * 3.0           // float or double
3 * 5 - 6 < 8 * 3     // bool
1 < 2 ? 3 < 4 : 6 < 7 // bool
1 + 2 * 3 / 4 % 5     // int

For each of the following statements, write out the equivalent using only the plain = assignment operator (note that some may expand into more than one assignment!)

a += b;
b *= 4 - a * 4;
++a;
--c;
d %= ++a;

What does the following condition test for?

a % 5 == 0

Conditionals

I might give you a nested if and ask you to “flatten” it by combining the conditions; you’ll need to think about what conditions will cause each branch to be triggered.

I might ask you to write an if-else chain to handle some set of conditions, possibly involving multiple variables. E.g., write an if-else chain that will compare the two variables i and j and print “Less than” if i is less than j, “Greater than” if i is greater than j, or “Equal” if they are equal. (Question: if we had three variables, how many ways can they be arranged?)

I might give you an if-else chain of the form

if(x == 0)
  cout << "OK";
else if(x == 1 || x == 2)
  cout << "Getting warm";
else if(x == 3)
  cout << "Hot";
else
  cout << "Extreme conditions detected";

and ask you to translate it into a switch-case statement. Conversely, I might ask you to take a switch-case statement and convert it to an if-else chain. E.g.,

switch(x) {
  case 0:
    cout << "OK";
    break;
  case 1:
  case 2:
    cout << "Getting warm";
    break;
  case 3:
    cout << "Hot";
    break;
  default:
    cout << "Extreme conditions detected";
    break;
}

I might give you a switch statement that lacks all (or some of) the breaks and ask you what will happen for a given value.

Conditionals may also occur elsewhere (e.g., as part of loops, functions, etc.)

Loops

while-loops, run until the condition is false, the condition is tested at the beginning of the loop. Examples

do-while loops run until a condition is false, but always at least once.

do-while is good for situations where we have to do some setup before testing the condition for the first time, or where we want the loop to run at least once.

Any kind of loop can be transformed into any other type of loop. while loops translate into for loops fairly simply. Moving between while and do-while may require the use of break. E.g.,

int i = 0;
while(i < n) {
  // Do stuff
  i++;
}

To convert this to do-while, we have to account for the possibility that n = 0 to start with.

int i == 0;
do {
  if(!(i < n))
    break;

  // Do stuff
  i++;
} while(i < n);

Note that now, the condition at the end is redundant. It’s going to be tested by the if at the beginning, so we can set the condition to true and it will still work correctly.

Sometimes, a loop won’t have a nice tidy condition that can be tested at the beginning or the end. In these cases, a break or continue in the middle can be useful. For example, consider finding the product of a user’s input. We could write this as

int x, product = 1;
while(cin >> x)
  product *= x; 

But this ignores a potential optimization: if the product is ever 0, then we can quit early. We can encode this using break:

int x, product = 1;
while(cin >> x) {
  product *= x; 
  if(product == 0)
    break;
}

If we wanted to, we could optimize the situation where the element x == 1. In this case, the product will be unchanged. (This isn’t really an optimization, because multiplication is easy. But we might be doing some bigger calculation and we could detect early what the results would be, and skip it.)

int x, product = 1;
while(cin >> x) {
    if(x == 1)
        continue;
    product *= x; 
    if(product == 0)
        break;
}

for loops group together the variable initialization, condition, and update steps which many loops have. You should know the order in which these happen:

for(initialization; condition; update)
  body;

becomes

initialization;
while(condition) {
  body;
  update;
}

You should be able to take a for loop and translate it into a while loop, and vice versa (assuming a while loop that depends on a variable). Remember that for loops can be about more than one variable!

for(int i = 0, j = 10; i < j; i++, j--) 
  cout << i << " " << j << endl;

Here, the initialization declares two variables, and the update modifies both of them. What will this print out?

The initialization, condition, or update of a for loop can be empty. If the condition is empty, it’s the same as if you wrote true. You still need the semicolons. The shortest for loop is thus

for(;;)
  // Runs forever

while is the same as

while(true)
  // Runs forever

I might give you a loop and ask you what output it will produce.

Loops and strings: You should know how to use a loop to process the characters in a string:

string s;
for(int i = 0; i < s.length(); i++)
    ... s.at(i) ...

Note that you can combine “fancy” loops (reverse order, loop over every other element, etc.) with accumulating loops. E.g., to sum up all the powers of 2 that are less than 1000:

int sum = 0;
for(int i = 1; i < 1000; i *= 2)
  sum += i;

Pay attention to the common

while(condition); 
  body;

error. I might ask you to find it.

Nested loops: I might give you a nested loop like

for(int i = 0; i < 5; i++)
  for(int j = 0; j <= i; j++)
    cout << i << " " << j << endl;

and ask what this will output. This one is a bit more tricky, because the inner loop depends on the outer loop. Note that you could write an accumulating loop over a nested loop. E.g., suppose we want to find the products of all the pairs of numbers from 0 to 10. (E.g., 0x0, 0x1, … all the way up to 10x10) and then we want to count how many are odd:

int count = 0;
for(int i = 0; i <= 10; i++)
  for(int j = 0; j <= 10; j++)
    if(i*j % 2 == 1)
      count++;

Question: what is the difference between this loop

for(int i = 0; i < 5; i++)
  for(int j = 0; j < 5; j++)
    cout << i << "," << j << endl;

and this loop

for(int i = 0, j = 0; i < 5 && j < 5; i++, j++)
  cout << i << "," << j << endl;

The first will print out all 25 pairs

0,0 0,1 0,2 ... 1,0 1,1, 1,2 ... 4,3 4,4

whereas the second will print out

0,0 1,1 2,2, 3,3 4,4

I.e., in the second loop, the updates happen simultaneously.