Variables, Branching, and Loops in C++

1. Variables and their types

Before you can use a variable in your code, you must first declare it and specify what type of data it will store.

In the following code, the variable x is declared as an integer, meaning it can store whole numbers. The variable dogName is declared as a string, which can store text data. In C++, the text data type is denoted as std::string.

#include<iostream>
int main(){
   int x;
   std::string dogName;
   x=27;
   dogName="Darcy";
   std::cout<<"x is an integer. Its content is "<<x<<"\n";
   std::cout<<"dogName is a text. Its content is "<<dogName<<"\n";
   return 0;
}

These are the most common types of variables.

  • int is used to store integers. Integers are also called whole numbers. They can be positive, negative, or 0.
  • long is also used to store integers. The range for long is larger than the range for int. At the time when this document was written (the year was 2023), most of the C++ compilers on 64-bit operating system will offer the range \(\left[-2^{31}, 2^{31}-1\right]\) for int and the range \(\left[-2^{63}, 2^{63}-1\right]\) for long. There are notable exceptions. One of them is 32-bit version of Raspbian operating system. That operating system is common on Raspberry Pi computers. On that operating system, both int and long have the same range: \(\left[-2^{31}, 2^{31}-1\right]\).
  • float is used to store decimal numbers like 2.17, -337.11.
  • double is also used to store decimal numbers. However, double offers bigger precision. Bigger precision means more decimal places and bigger range. The details are covered in the text floating point representation of decimal numbers. When this document was written, on most 64-bit operating systems, the type float is stored using 32 bits, while the type double is stored using 64 bits.
  • std::string is used to store texts.
Problem 1.

In the following code the variable integerFromUser is not properly declared. Write the command that needs to be put instead of the text // ??? // in order to obtain a valid C++ source file.

#include<iostream>
int main(){
   // ??? //
   std::cin>>integerFromUser;
   long squareOfTheNumber;
   squareOfTheNumber=integerFromUser*integerFromUser;
   std::string message;
   message="The square of the inserted number is";
   std::cout<<message<<" "<<squareOfTheNumber<<"\n";
   return 0;
}

Problem 2.

In the following code the variable message was not properly declared. Write the command that needs to be put instead of the text // ??? // in order to obtain a valid C++ source.

#include<iostream>
int main(){
   long integerFromUser;
   std::cin>>integerFromUser;
   long squareOfTheNumber;
   squareOfTheNumber=integerFromUser*integerFromUser;
   // ??? //
   message="The square of the inserted number is";
   std::cout<<message<<" "<<squareOfTheNumber<<"\n";
   return 0;
}

2. Declaration shortcuts

It is possible to declare several variables in the same command. This is useful when we want to make our code shorter. Instead of giving two commands

long a; long b;
we are allowed to give only one command
long a,b;
In addition, we are allowed to put initial value in our variable during declaration. Instead of having two commands
long a; a=7;
we are allowed to write

long a=7;

3. Branching

Our next task is to write programs with branching. We will introduce if statement. We will explain how to use it by looking at one simple example. Assume that the user is asked to provide an integer x through the standard input. The program will check whether x is bigger than 100. If it is, then the program will print

Congratulations! You know about big numbers!

If x is not bigger than 100, then the program will print

Good enough. Try with a bigger number next time.

This is the code:

#include<iostream>
int main(){
   int x;
   std::cout<<"Insert an integer x. ";
   std::cin>>x;
   if(x>100){
      std::cout<<"Congratulations! You know about big numbers!\n";
   }
   else{
      std::cout<<"Good enough. Try with a bigger number next time.\n";
    }
    return 0;
}

Problem 3.

Write a code that calculates max{a,b} and stores the result in the variable m. Note: You are not allowed to use the function std::max.

You should only write the code that replaces the text // ??? //.

#include<iostream>
int main(){
   long a,b,m;
   std::cin>>a>>b;
   // ??? //
   std::cout<<m<<"\n";
   return 0;
}

4. Comparison operator ==

The following code checks whether the value x is equal to 17 and prints seventeen if it is.

if(x==17){
   std::cout<<"seventeen"<<"\n";
}

Warning: If you accidentally write if(x=17) with one symbol = instead of two symbols ==, then the program will compile. The command x=17 is not a bug by itself. It is an assignment operator. The variable x receives the value 17. In addition, the operation x=17 will succeed and the code will evaluate to true. Consider the following program

#include<iostream>
int main(){
   int x;
   std::cin>>x;
   if(x=17){
      std::cout<<"seventeen\n";
   }
   else{
      std::cout<<"not seventeen\n";
   }
   std::cout<<"The variable x is "<<x<<"\n";
   return 0;
}

No matter what user enters for x, the code will print

seventeen
The variable x is 17

Many compilers will actually give you warnings if you try to use single equality sign when a logical operation == is expected. However, the code will compile, and the binary will end up with a nasty bug.

5. Logical operations

The condition inside the if statement can be more complex. We can combine multiple conditions using logical operations and, or, and negation.

Negation is denoted by !. The following code will print Not seventeen.

int x=18;
if(!(x==17)){
   std::cout<<"Not seventeen\n";
}
else{
   std::cout<<"x is seventeen\n";
}

The operation and is also denoted by &&. The operation or is also denoted by ||.

In this website the symbols &&, ||, and ! will be preferred over and, or, and not.

Problem 4.

Write a code that checks whether the real number x belongs to the union of the open intervals \((5,15)\cup(95,202)\). If it does, the program should print yes. If it does not, the program should print no.

You should only write the code that replaces the text // ??? //.

#include<iostream>
int main(){
   double x;
   std::cin>>x;
   // ??? //
   return 0;
}

6. While loops

Loops are used to simplify the writing of repetitive code. Imagine that you have to print all integers in the closed interval \([3,7]\). Those who do not know how to use loops can succeed. They will write the following program:

#include<iostream>
int main(){
   std::cout<<3<<"\n";
   std::cout<<4<<"\n";
   std::cout<<5<<"\n";
   std::cout<<6<<"\n";
   std::cout<<7<<"\n";
   return 0;
}

This code is repetitive, and most of the lines are similar.

The program can be simplified by using a loop. We will introduce the variable called counter that will initially take the value 3. Then we will have only one command std::cout<<counter<<"\n"; instead of five almost identical commands. The variable counter will then increase by 1 and the command std::cout<<counter<<"\n"; can be executed again. We will have the block of code

{
   std::cout<<counter<<"\n";
   counter=counter+1;
}

The block will repeat for as long as counter<8. We use the command
while (counter<8)

before the block of the code to tell the computer to keep the loop going. The loop will repeat for as long as the condition counter<8 is satisfied.

If you are transferring to C++ from some other computer language, you may be asking

Question: Can I omit the brackets and write while counter<8 instead of while (counter<8)?

The answer is No, you can not. You must write while (counter<8) and you must never write while counter<8 in C++.

The code that prints all integers from [3,7] is:

#include<iostream>
int main(){
   int counter=3;
   while (counter<8){
      std::cout<<counter<<"\n";
      counter=counter+1;
   }
   return 0;
}

Problem 5.

Create a program that reads real numbers of type double from the user input until it reads a negative number or zero. The negative number (or zero) means that the input is over. You are allowed to assume that the input from the user will contain at least one positive element. The program should calculate the maximum of the numbers provided by the user. You are not allowed to use the standard functions max and min. Your code should replace the text // ??? //

#include<iostream>
int main(){
   double x; double largestNumber;
   std::cin>>x; largestNumber=x; 
   std::cin>>x;
   while(x>0.0){
      // ??? //
      std::cin>>x;
   }
   std::cout<<largestNumber<<std::endl;
   return 0;
}

7. For loops

The previous section introduced while loops. The while loops are the most powerful loops in the language. In this section we will talk about a less powerful alternative, for loops. Everything that for loop can do, while loop can do as well. In addition, most of the time while loops are simpler and more elegant. And yet somehow for loops are quite popular among programmers and we must have them in these notes. Occasionally, they offer a bit shorter code. The reason for their popularity is that they are similar to summations in mathematics.

This is the basic structure of the for loop:

for(INITIALIZATION; CONDITION; LAST COMMAND OF THE LOOP){
    CODE THAT REPEATS
}

The for loop from above is equivalent to the following code that involves a while loop:

INITIALIZATION
while( CONDITION){
    CODE THAT REPEATS
    LAST COMMAND OF THE LOOP
}

We will look at one example that has a for loop and the equivalent code that involves a while loop.

long sum=0;
for(long i=0;i<11;i=i+1){
  sum=sum+i;
}

The equivalent code is

long sum=0;
long i=0;
while(i<11){
  sum=sum+i;
  i=i+1;
}

8. Addition assignment operators

The command x+=20; is a shortcut for x=x+20;. The addition assignment operator += modifies the quantity on the left-hand side by adding the value from the right-hand side.

The C++ language supports analogous operators such as -=, *=, /=, %=, &=, etc.

9. Increment and decrement operators

There is a shortcut for the command i=i+1;. An equivalent command is ++i;. When we give the command ++i;, then we say that an increment operator is applied to i.

The language also supports a decrement operator. The command --i; is equivalent to i=i-1;

Remark. The language also supports the postfix increment and decrement operators. They are i++; and i--;. These two operators should be avoided. They are often slower than the prefix operators ++i; and --i;. There is a small difference between prefix and postfix operators in situations where they are used as components of longer commands. It is now considered a bad practice to use increment and decrement operators as parts of longer commands. Nevertheless, here is a basic example that shows the difference.

#include<iostream>
int main(){
  long a,b,c;
  a=10; b=20; 
  c=(++a)+b; 
  std::cout<<a<<" "<<b<<" "<<c<<"\n";
  //a=11, b=20, c=31. 
  a=10; b=20;
  c=(a++)+b;
  std::cout<<a<<" "<<b<<" "<<c<<"\n";
  //a=11, b=20, c=30. In this case a is increased only after the evaluation.
  return 0;
}

10. Scopes of variables

Once a variable is declared, it can be used in the code. The variable cannot be used before it is declared. In addition, the variable cannot be used outside of the block of code in which it is declared. The block of code is the set of all commands that are between the brackets { and }. In the example below we will have two sub-blocks.

#include<iostream>
int main(){
   {
      int x; x=27;
      std::cout<<"The content of the variable is "<<x<<"\n";
   }
   {
      int y; y=37;
      std::cout<<"The content of the variable is "<<y<<"\n";
   }
   return 0;
}

The variable x is declared in the first sub-block. It is not declared in the second, hence it cannot be used in the second block. If you tried to use x in the second block, then the compiler would return an error. The compiler would refuse to make a binary.

On the other hand, you could declare the variable x in different blocks. In those blocks, the variable x could be of different types.

#include<iostream>
int main(){
   {
      int x; x=27;
      std::cout<<"The content of the variable is "<<x<<"\n";
   }
   {
      std::string x; x="<<some funny text>>";
      std::cout<<"The content of the variable is "<<x<<"\n";
   }
   return 0;
}

If one block of code is fully within another block, then in this inner block you are allowed to use the variables declared in the outer block. You are also allowed to declare variables in the inner block with the same name. However, if you do this, then the inner block will loose the access to the variable from the outer block. Here is example:

#include<iostream>
int main(){
   int x=55;
   std::cout<<"This is the most outer block of the main function.\n";
   std::cout<<"The value of x is "<<x<<"\n";
   {
      std::cout<<"The inner block. The current value of x is "<<x<<"\n";
      std::cout<<"We will re-declare x now. \n";
      std::string x;
      x="Darcy";
      std::cout<<"The value of x is "<<x<<"\n";
   }
   std::cout<<"We are now back to the outer block.\n";
   std::cout<<"The value of x is "<<x<<"\n";
   return 0;
}

The variants of the code from above are written quite often. They are always written by mistake. They are common cause for bugs in the programs. Nobody should write such code intentionally.

11. Practice

Problem 6.

Create a program that reads \(5\) real numbers \(a\), \(b\), \(c\), \(d\), and \(e\) from the standard input and calculates the value \[\max\{a,b\}+\min\{c,d,e\}+\max\{b,e\}.\] Your code should replace the text // ??? //

#include<iostream>
int main(){
   double a,b,c,d,e;
   double result; 
   std::cin>>a>>b>>c>>d>>e;
   // ??? //
   std::cout<<result<<"\n";
   return 0;
}

Problem 7.

Create the program that reads six real numbers \(a_{11}\), \(a_{12}\), \(a_{21}\), \(a_{22}\), \(b_1\), and \(b_2\) from the standard input and finds two real numbers \(x\) and \(y\) that are the solutions to the system \begin{eqnarray*} a_{11}x+a_{12}y&=&b_1\\ a_{21}x+a_{22}y&=&b_2. \end{eqnarray*} You are allowed to assume that the user will provide such input values that would guarantee that the system has unique solution.

Your code should replace the text // ??? // below

#include<iostream>
int main(){
    double a11, a12, a21, a22, b1, b2, x, y; 
    std::cin>>a11>>a12>>a21>>a22>>b1>>b2;
    // ??? //
    std::cout<< x<<" "<<y<<std::endl;      
    return 0;
}

Problem 8.

The user input consists of four positive integers \(m\), \(a\), \(b\), and \(c\). Determine the smallest non-negative integer \(x\) such that \[ax+b\] gives the remainder \(c\) when divided by \(m\). If such an integer \(x\) does not exist, display the message There is no such x.

Your code should replace the text // ??? // below

#include<iostream>
int main(){
    int m,a,b,c; 
    std::cin>>m>>a>>b>>c;
    // ??? //
    return 0;
}
\begin{eqnarray*} \begin{array}{|c|l|l|}\hline \mbox{Test case}&\mbox{Input}&\mbox{Output}\\ \hline 1& 17 \quad5\quad 3\quad 2 & 10 \\ \hline 2& 18 \quad2\quad 8\quad 1 &\mbox{There is no such x}\\ \hline \end{array} \end{eqnarray*}

Problem 9.

The user input consists of six positive integers \(m\), \(n\), \(a\), \(b\), \(c\), and \(d\). Determine the smallest non-negative integer \(x\) such that \[ax+b\] gives the remainder \(c\) when divided by \(m\) while for this same \(x\) the number \(ax+b\) gives the remainder \(d\) when divided by \(n\). If such an integer \(x\) does not exist, display the message There is no such x.

Your code should replace the text // ??? // below

#include<iostream>
int main(){
    int m,n,a,b,c,d; 
    std::cin >> m >> n >> a >> b >> c >> d;
    // ??? //
    return 0;
}
\begin{eqnarray*} \begin{array}{|c|l|l|}\hline \mbox{Test case}&\mbox{Input}&\mbox{Output}\\ \hline 1& 17 \quad 19 \quad 5 \quad 3 \quad 2 \quad 6 & 316 \\ \hline 2& 18 \quad 19 \quad 2 \quad 8 \quad 1 \quad 5 &\mbox{There is no such x}\\ \hline \end{array} \end{eqnarray*}

Problem 10.

Note: This problem is graded by auto-grader. The execution must produce the correct results on secret test-cases in order to receive credit. You are only allowed to use the header iostream.

The user input consists of two positive integers \(p\) and \(M\) such that \(p > 3\) and \(M > 3\). Create a program that determines the number of integers \(x\) from \(\{0\), \(1\), \(\dots\), \(M-1\}\) that satisfy \[x^5\; \% \; p = p-1.\]

Problem 11.

The user input consists of a positive integer from the interval \((0,2^{63})\). Create a program that prints the sum of digits of the number that the user provided.

Note: You are not allowed to use strings and arrays. In this problem, the auto-grader will reject your code if it contains the word string or the symbols [ and ].

Problem 12.

The user input consists of a list of integers each of which is either \(0\) or \(1\). Once the user provides the number \(2\) the input is over. You are allowed to assume that the user will provide at least two terms before typing number \(2\). The following sequence of operations is performed with the list from the input. Each operation consists of identifying the two leftmost consecutive terms that are equal. If they are both \(0\), then they are replaced with the single term equal to \(1\). If they are both equal to \(1\), then they are replaced with the single term equal to \(0\). Create the program that determines the final sequence that is obtained after repeatedly performing the described operations.

Example: Input: 1 0 1 1 0 0 1 2.

Output: 1 0 1.

Explanation: The first operation replaces the two leftmost terms \(1\) and \(1\) with \(0\). The resulting sequence is 1 0 0 0 0 1. The next operation transforms the sequence into 1 1 0 0 1 . Next the sequence becomes 0 0 0 1 . The final sequence is 1 0 1 .

Problem 13.

The user input consists of a sequence of numbers from the set \(\{1,2,3\}\) followed by the number \(-1\) that signifies the end of the input. Make the program that repeatedly performs the following operation on the entire sequence until the sequence gets transformed into one that has all terms equal:

In each step, starting from the left we identify the first two consecutive terms of the sequence that are different from each other. Then we remove these two terms and replace them by one single term that is equal to neither of the two original terms. For example \((1 2)\) is replaced by \(3\); \((2 1)\) is replaced by \(3\); \((3 2)\) is replaced by \(1\).

Example:

Input: 
1 1 1 2 3 3 1 2 2 1 3 3 -1 
Output: 
3 3 3

Explanation: The terms of the sequence are \(x_0=1\), \(x_1=1\), \(x_2=1\), \(x_3=2\), \(x_4=3\), \(x_5=3\), \(x_6=1\), \(x_7=2\), \(x_8=2\), \(x_9=1\), \(x_{10}=3\), \(x_{11}=3\). In the first step, we identify the terms \(x_2\) and \(x_3\) that are different from each other and replace them by a single term \(2\). We obtain the sequence \(1\; 1\; 3\; 3 \; 3\; 1\; 2\; 2\; 1\; 3\; 3\). This can be summarized in the following way \begin{eqnarray*} &&1\; 1\; \underbrace{1\; 2}_3\; 3\; 3 \;1\; 2\; 2\; 1\; 3\; 3 \\ &&1\; \underbrace{1\; 3}_2\; 3\; 3 \;1\; 2\; 2\; 1\; 3\; 3 \\ &&\underbrace{1\; 2}_3\; 3\; 3 \;1\; 2\; 2\; 1\; 3\; 3 \\ &&3\; 3\; \underbrace{3 \;1}_2\; 2\; 2\; 1\; 3\; 3 \\ &&3\;\underbrace{3\; 2}_1\; 2\; 2\; 1\; 3\; 3 \\ &&\underbrace{3\;1}_2\; 2\; 2\; 1\; 3\; 3 \\ &&2\; 2\;\underbrace{2\; 1}_3\; 3\; 3 \\ &&2\; \underbrace{2\;3}_1\; 3\; 3 \\ &&\underbrace{2\; 1}_3\; 3\; 3 \\ &&3\; 3\; 3 \end{eqnarray*}