1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

C++ Statements, Blocks and Flow Control Statement

Discussion in 'C++' started by BiplabKamal, Jun 15, 2016.

  1. C++ program is a collection of statements. Normal statements are sequential and executed sequentially. These statements can be: Declaration Statements, or Expression statements. Also a group of statement treated as a single statement is called compound statement or block.

    Declaration Statements



    Declaration statements create new identifiers (names) like declaring a variable. Declaration statements are not executable statement. Those statements are basically used by compiler to allocate memory and refer that memory. For example following statement defines two variables i and j but not executable statement.

    int i, j;

    If you combine the initialization of the variables with definition like int i =0; inside a function it is actually a combination of declaration statement and expression statement. It will generate an executable instruction for assigning the value to it’s memory location. If it is done outside function i.e. in global scope the initialization will be at compile time, so no executable instruction. This type of initialization of global variables is called static initialization. There is another type of initialization for global variables called dynamic initialization where compiler allocates the memory but cannot determine the initial value at the compile time, so it defers the initialization at the run time. For example following example shows the run time initialization for global variables. Local variable initialization is always run-time.

    int i = 10, j = 20; // Static initialization
    int k = j*j; // Dynamic initialization

    The initialization value of k depends on the value of j which can not be evaluated at compile time. So compilers generate executable instructions to assign the value at run time. The line of code is equivalent to :

    int k;//Definition
    k = j*j; // Assignment

    Expression Statements



    Expression statements are statements which generate executable instructions after compilation. Expression statements are assignment statements or function calls. For example following assignment statement adds the values of two variables and assign it to another variable.

    i = j + k;

    Compound Statements or Blocks



    A block is a group of statements which are treated by the compiler as if it is a single statement. A block is also called a compound statement. A compound statement can be placed where a single statement is allowed. A compound statement starts with { symbol and ends with } symbol and statements are placed in between. No semicolon(;) is required at the end of the block. When you write a function it’s body has at least one block and all the statements in the function is inside this block. You can have blocks inside a block called nested blocks. Look at the following main function having block inside another block inside another block:

    Code:
    #include <iostream>
    using namespace std;
    int main()
    { // Outer block starts here
        int i = 10;
        int j = 20;
        {//Inner block starts here
            int k = i + j;
            cout << "inner block k =" << k << endl;
            i++;
            j++;
            { // Inner inner block starts here
                k = i + j;
                cout << "inner inner block k =" << k << endl;
                i++;
                j++;
            }//Inner inner block ends here
        }//Inner block ends here
        //k = i + j;// Error: k is undeclared variable
        int k = i + j;
        cout << "Outer block k =" << k << endl;
        return 0;
    }// Outer block ends here
    
    Blocks mainly impact the scope and lifetime of variables defined inside the block. A variable defined inside a block is visible within the block and its inner blocks. Also the lifetime of a variable starts where it is defined and ends at the end of the block in which it is defined. In the above example variable i and j defined in the outer block is available to the inner blocks but variable k defined in the inner block is not available to the outer block. The variable k inside the inner block is released when the inner block ends.

    Flow Control Statement



    So far we discussed about statements, are sequential in nature, which means they are executed sequentially as they are written. But there are scenarios when some statements need to be executed or ignored depending on the value of a variable or expression. There are also scenarios when some statements need to be repeated for a certain number of times or until a condition is met. For these purposes C++ provides special statements called flow control statements. These statements controls the flow of the program. Most of the flow control statements has sub statements which are simple or compound statement (block).

    There are three category of flow control statements: Selection Statement. Iteration Statement and Jump Statement.

    Jump Statements



    Jump statements are used to alter the flow of control by performing a jump to a specific location of the code. The main jump statements are goto statement and throw statement.

    goto statement

    goto statement uses a label placed at any position in the code. Label is a valid identifier followed by colon:)) and the syntax is:

    <identifier>:

    The syntax of goto statement is

    goto <label name>;

    goto statement will take the control of the execution to the next statement after the label. Following code shows the usage of goto statement:

    Code:
    #include <iostream>
    using namespace std;
    int main() {
        int i = 5;
    repeat:
        cout << i << ", ";
        --i;
        if (i>0) goto repeat;
        cout << i <<endl;
    }
    The code will repeat and print: 5, 4, 3, 2, 1, 0
    
    goto statement perform unconditional jump and ignores nested code block and does not do any stack unwinding. So you should be careful using goto statement preferably within the same block. It should not be used to jump to a label outside the block. goto statement is generally considered as low level feature and should be avoided unless there are compelling reasons.

    throw statement

    Another jump statement is throw statement. throw statement is used to signal an exceptional condition. This is required when the program encounter an error which it cannot handle or recover from. In this scenario code can throw an exception object using throw statement to signal an unusual error. When an exception is thrown the execution stops there and the control goes to the exception handler block if available otherwise terminates, The syntax of throw statement is

    throw <value>;

    where value can be any value of any inbuilt type or user defined type. For example following statement will throw an int value;

    throw 10;

    The searching for the handler block has a predefined sequence of steps. Exception handler blocks are implemented with try and catch block. Try block encloses the code which can throw exceptions and the following catch blocks list the handlers of exceptions for the catch block. The exception thrown from the code of a try block is handled by the matching handler block attached to the try block. Try and catch blocks go hand in hand. Here is the syntax of try and catch block:
    Code:
        try
        {
            statement
        }
        catch (<type name> <identifier>(optional))
        {
            statement
        }
        catch (<type name> <identifier>(optional))
        {
            statement
        }
        More catch blocks ...
        catch (...)
        {
            statement
        }
    
    When the code in a try block executes a throw statement the execution stops there, unwind the stack of the try block and the control goes to a matching catch block in the attached catch blocks. Every catch block has a single argument or an ellipsis(…). Catch blocks are matched by the type of value or object thrown. The matching is done in the order catch blocks are placed. If the type of thrown object does not match with any of the catch block type then it goes to the catch (…) block which is also called default handler. Note that all the catch blocks are not mandatory but at least one catch block must be there for a try block. Suppose the throw statement is neither part of a try block in the current block nor does have a matching catch block. In this scenario it look for the next level of try -catch block which is enclosing the current block and so on. If no enclosing try block found in the current function it goes beyond the function and look for try block in the caller code and then callers caller until it finds a matching catch block or terminates the program. While looking for exception handler block in the upper level it unwinds the call stacks of the lower level. Once it find a handler block it executes the block and continue from the next statement after the catch blocks attached to the current try block. We will discuss the exception handling mechanism in detail later in advanced part. Here is a simple example of using throw, try and catch keywords
    Code:
    #include <iostream> 
    using namespace std; 
    
    void ExceptionFunction()
    {
        try
        {
            try
            {
                throw 10;
            }
            catch (char c)
            {
                cout << "Character exception is caught and value is  "<<c << endl;
            }
            catch (double d)
            {
                cout << "Double exception is caught and value is  " << d << endl;
            }
            
        }
        catch(int i)
        {
            cout << "Integer exception caught at outer catch block and value is "<<i << endl;
        }
    }
    int main()
    {
        try {
            ExceptionFunction();
        }
        catch (...)
        {
            cout << "Some exception is caught" << endl;
        }
        return 0;
        
    }
    
    Output:
    Integer exception caught at outer catch block and value is 10

    There are other variety of jump statement like break and continue for specific context of loop or switch statement discussed later in this topic.

    Selection Statements



    Selection statement selects a block of statement depending on the value of an expression. There are two type of selection statement.

    One is conditional statement where either of two code blocks is executed depending on a boolean expression. This is done with if-else statement.

    In the other one any one of some code blocks is executed depending on the value of an expression. This is done with switch case statement.

    if - else statement

    ‘if’ keyword is used to execute a block of statements if a condition is fulfilled. This condition is the result of an boolean expression. If the boolean expression evaluates to true then only the block following if statement is executed and ignored if the expression evaluates to false. Here is the syntax of if statement:

    if(<condition>) <statement>

    where condition is the boolean expression which evaluates either true or false and statement is the sub statement of the if statement which is a block of statements or a simple statement. If the condition is true then statement is executed otherwise ignored. For example following statement will not print anything because the condition is being false.
    Code:
        int j = 20;
        if (j==0) { cout << "The value of j is 0" << endl;}
    
    But the following if statement will execute the print statement:
    Code:
        int i = 10;
        int j = 20;
        if (i > 0 && j > 0)    cout << "Both i and j are positive non zero integers" << endl;
    
    {} is not mandatory for a simple statement. But using brace, indentation and line breaks make the code more readable. Above if statement can be written as shown below which is a good practice.
    Code:
        if (i > 0 && j > 0)
        {
            cout << "Both i and j are positive non zero integers" << endl;
        }
    
    You can specify what to do if the condition is false by using ‘else’ keyword. The syntax is:

    if(<condition>) <statement> else <statement>
    For example :
    Code:
        if (i > 0 && j > 0)
        {
            cout << "Both i and j are positive non zero integers" << endl;
        }
        else
        {
            cout << "Either i or j or both are zero or negative integers" << endl;
        }
    
    There can be multiple if and else statement concatenated like :
    Code:
        int i = 0;
        int j = 20;
        if (i > 0 && j > 0)
        {
            cout << "Both i and j are positive non zero integers" << endl;
        }
        else if(i>0)
        {
            cout << "i is positive non zero integer" << endl;
            cout << "j is zero or negative integer" << endl;
        }
        else
        {
            cout << "i is zero or negative integer" << endl;
            cout << "j is positive non zero integer" << endl;
        }
    
    switch-case statement

    switch-case statement is one form of if-else statement where instead of checking a boolean expression any expression can be checked against a constant value and depending on different values the code block is selected among multiple blocks for execution. Any switch-case statement can be converted to concatenated if-else statement. It has the following syntax:
    Code:
    switch (expression)
    {
        case <constant1> :
        <group of statements1>
        break;
        case <constant2> :
        <group of statements2>
        break;
        …
        default :
        <default group of statements>
    }
    
    If the expression evaluates to <constant1> then <group of statements1> is executed. The break statement is not mandatory but required to jump to the end of the block. If break statement is not there then the execution will continue to the next statement until it reached to a break statement or end of switch statement. See the following example:
    Code:
    #include <iostream>
    using namespace std;
    int GetVal(int val)
    {
        return val*2;
    }
    int main()
    {
        switch (GetVal(1))
        {
            
        case 0:
            cout << "The value is 0" << endl;
            break;
        case 2:
            cout << "The value is 2" << endl;
            break;
        case 4:
            cout << "The value is 4" << endl;
            break;
        default:
            cout << "The value is out of range" << endl;
        }
        return 0
    }
    
    The above program will print "The value is 2". The expression is checked for it’s value against the constant value given in the case label in the order the case labels are placed. In the above example, first the return val of GetVal() is checked for 0 and if matched the execution starts from the statement following label case 0: and continues until a break statement is encountered. Break statement takes the control to the end of the switch-case block. To understand the switch-case statement functioning, think about case statement as a label and switch statement as a concatenated if-else statements with goto statement. Following code is equivalent to the above code:

    Code:
    #include <iostream>
    using namespace std;
    int GetVal(int val)
    {
        return val*2;
    }
    int main()
    {
        int val = GetVal(2);
        if (val == 0)
            goto label0;
        else if (val == 2)
            goto label2;
        else if (val == 4)
            goto label4;
        else
            goto defaultlabel;
        
        label0:
            cout << "The value is 0" << endl;
            goto labelend;
        label2:
            cout << "The value is 2" << endl;
            goto labelend;
        label4:
            cout << "The value is 4" << endl;
            goto labelend;
        defaultlabel:
            cout << "The value is out of range" << endl;
        labelend:
        return 0;
    }
    
    Actually switch-case statement has used the context of label and goto statement which are legacy of C language. This is the reason you need the break statement and no use of braces ({}) to enclose the group of statements under a case label.

    Iteration Statements



    Iteration statements enables a block of code to be executed repeatedly for certain number of times or until a condition is satisfied. This is done with keywords for, while and do which are called for loop, while loop and do-while loop respectively.

    for loop

    for loop enables a block of code to be executed for certain number of times. It has three parts: initialization, condition and increase statement. Initialization code executes only once before the loop starts. The condition expression is checked every time before the sub-block is executed. If the condition results to false the loop ends without executing the loop block. The increase statement is executed after every iteration. The standard is to initialize a counter at the initialize section, counter value is checked in the condition section and the counter is increased in the increase statement section.

    The syntax of for loop is

    for(<initialization>; <condition>; <increase>)

    For example:
    Code:
    #include <iostream>
    using namespace std;
    int main()
    {
        for (int counter = 5;counter > 0;--counter)
            cout << counter << ", ";
        cout << 0 << endl;
        return 0;
    }
    
    You are free to place any statement in those sections of for loop with restriction that 2nd section should be treatable as a boolean expression and the 3rd section should be executable statement. Any variable defined in the initialization section is available in the loop block. Even you can keep all sections empty but the separator semicolons(;) should be there. For example -
    Code:
        #include <iostream>
        using namespace std;
        int counter = 5;
        for (;;)
        {
            cout << counter << ", ";
            --counter;
            if (counter <= 0)
                break;
        }
        cout << 0 << endl;
    
    In the for loop above the exit condition of the loop is missing in the for statement. So the loop will run forever. To come out of the loop the exit condition is checked inside the loop. Also the counter is decremented inside the loop. Whether you use the section of the loop statement to control the number of iteration or not you should ensure the exit of the loop, otherwise it will run infinitely. ‘break’ statement is used to exit the loop i.e. to transfer the control to the statement next to the for loop block. You can also use another keyword ‘continue’ to skip the rest of the statements of the block and start from the beginning of the loop. ‘break’ and ‘continue’ are special jump statement for any kind of loops. Here is an example which uses both break and continue statements in a for loop:
    Code:
    #include <iostream>
    using namespace std;
    int main()
    {
        int counter = 5;
        for (;;)
        {
            cout << counter << ", ";
            --counter;
            if (counter >= 1)
                continue;
            cout << 0 << endl;
            cout << "Exiting loop" << endl;
            break;
        }
        return 0;
    }
    
    Output:
    5, 4, 3, 2, 1, 0
    Exiting loop

    Range-based for loop

    Range based for loop is a special form of for loop which is used to iterate over all the elements of a range of elements sequentially. The syntax is

    for(<declaration > : <range object>) statement

    where declaration defines a variable of type of the element of the range object. Range object can be a collection object like std::string. The defined object in the declaration section is available in the loop block and holds the current element of the range. This loop structure is introduced in C++11 mainly for STL containers which are collection of objects. We will discus them in the chapter related to STL. For the time being let us see some example for std:string class as this class has the property of a container.

    Code:
    #include <iostream>
    using namespace std;
    int main()
    {
        string str{ "Hello World" };
        for (char c : str)
        {
            cout << c << " ";
        }
        cout << endl;
        return 0;
    }
    The optput: H e l l o   W o r l d
    
    You can also use auto keyword instead of type in the declaration section. For example
    Code:
    #include <iostream>
    using namespace std;
    int main()
    {
        string str{ "Hello World" };
        for (auto c : str)
        {
            cout << c << " ";
        }
        cout << endl;
        return 0;
    }
    
    range-based for loop is easier to write when you want to iterate over all the elements sequentially from first element to the last element.

    while loop

    while loop statement is another iterator statement where a block of statement is executed repeatedly till a condition is true. The syntax of while loop is:

    while (<expression>) <statement>

    Where the expression should evaluate to boolean value true or false and the statement can be a simple statement or a compound statement. The loop will first check the value of the expression. If it is true it will execute the statement and repeat the sequence. If the value of the expression is false it will transfer the control to the statement after the loop block. So as long the expression is true the loop will keep on iterate. Some code inside the loop statement should modify something so that the expression becomes false at some point of time when the loop will stop iterating and continue after the loop. Here is an example:

    Code:
    #include <iostream>
    using namespace std;
    int main()
    {
        int counter = 5;
        while (counter>0)
        {
            cout << counter << ", ";
            --counter;
        }
        cout << counter << endl;
        return 0;
    }
    
    Here the expression cannot be blank. If the expression turns to be false in the first place the loop block will not be executed at all and continue after the loop block. Also break statement can be used to exit from the loop without execution the rest of the code of the loop block from where the break statement is placed. Similarly the continue statement can be used to skip the rest of the statement of the loop and start from the beginning of the loop. Following example is the modified version of the above example to use break and continue keywords.
    Code:
    #include <iostream>
    using namespace std;
    int main()
    {
        int counter = 5;
        while (true)
        {
            if (counter <0)
                break;
            if (counter > 0)
            {
                cout << counter << ", ";
                --counter;
                continue;
            }
            cout << counter << endl;
            cout << "Exiting loop" << endl;
            break;
        }
        return 0;
    }
    
    Output:
    5, 4, 3, 2, 1, 0
    Exiting loop

    In the above code expression in the while statement is constant value true. So the loop will run for ever unless it encounters a break statement inside the loop block;

    do-while loop

    do-while loop is similar to while loop with the difference that the checking of the condition is done at the end of the loop. This ensure that the loop will be iterated at least once even it does not meet the condition at the first place. The syntax is:

    do <statement> while (<expression>);

    Here is an example:

    Code:
    #include <iostream>
    using namespace std;
    int main()
    {
        int counter = 0;
        do
        {
            cout << counter << ", ";
            ++counter;
        } while (counter < 5);
        cout << counter << endl;
        return 0;
    }
    
    The output is: 
    0, 1, 2, 3, 4, 5
    
    Similar to any loop you can use break and continue statements to exit or restart the loop.

    Here is an example of sorting and searching of integer numbers which uses control flow statements specifically iteration statements in a great way:
    Code:
    #include <iostream> // Header for input output classes from C++ standard library
    using namespace std; // So that namespace std need not be specified 
    // Will display the integer numbers in an array within a given range
    void DisplayNumbers(int pArr[], int startIndex, int endIndex)
    {
        for (;startIndex <= endIndex;++startIndex)
            cout << pArr[startIndex] << " ";
        cout << endl;
    }
    // Will get the required input from the user
    //User will give the list of numbers and a number to search in the list
    // The function GetInput() will allocate space for the list of numbers and
    //return the memory address or pointer. Also it will return the number of numbers
    //in the list and the number to search in memory locations given by the caller
    void GetInput(int** ppInt, int* pCount,int* pSearch)
    {
        int *pArr{ nullptr }; // Pointer to the list of numbers
        int nCount{ 0 }; // Number of elements in the list
        cout << "Enter the number of nnubers in the list: ";
        cin >> nCount;
        pArr = new int[nCount]; // Allocate the memory for input numbers
        // Store them to the output variables
        *pCount = nCount;
        *ppInt = pArr;
        while (nCount > 0)
        {
            cout << "Enter the next number:";
            cin >>pArr[nCount-1] ; // Storing reverse way, no matter,  0 based index
            --nCount; // Decrementing the count
        }
        if (*pCount > 0)
        {
            cout << "Enter the number to search: ";
            cin >> *pSearch;
    
        }
    }
    
    // Partitin algorithm of the quick sort process
    int Partition(int pArr[], int startPos, int endPos)
    {
        // Swaping the middle elment with the last element to altering the pivor value
        // This will be helpful when numbers are mostly sorted
        /*if (startPos > endPos)
        {
            int pivot = (startPos + endPos) / 2;
            int pval = pArr[pivot];
            pArr[pivot] = pArr[endPos];
            pArr[endPos] = pval;
        }*/
        // Take the pivot val as the last element
        int pivotval = pArr[endPos];
        int left = startPos - 1; // Left pointer before the starting element
        int right = endPos; // Right pointer to the last element
        // Place pivot val in its position in the sorted array
        do
        {
            // Move the left pointer forward and continue it is less than the pivot
            while (pArr[++left] < pivotval); // First increment and then check
            // Move the right pointer backward and continue it is greater than the pivot
            while (right > 0 && pArr[--right] > pivotval); //First decrement and then check
            
            // Swap the elements at left and right position if they have not met each other
            if(left<right)
            {
                if (pArr[left] != pArr[right])
                {
                    int temp = pArr[left];
                    pArr[left] = pArr[right];
                    pArr[right] = temp;
                }
            }
    
        } while (left < right);
        // left position is the final position for the pivot value
        pArr[endPos] = pArr[left];
        pArr[left] = pivotval;
        return left;
    }
    
    // Qucik sort recursive function
    void QuickSort(int pArr[], int startIndex, int endIndex)
    {
        if (endIndex > startIndex)
        {
            cout << "Quick sorting following numbers" << endl;
            DisplayNumbers(pArr, startIndex, endIndex);
            int pivot = Partition(pArr, startIndex, endIndex);
            QuickSort(pArr, startIndex, pivot - 1);
            QuickSort(pArr, pivot + 1, endIndex);
        }
    }
    void Sort(int pArr[], int nCount)
    {
        QuickSort(pArr, 0, nCount - 1);
    }
    
    //Searching a number in a sorted list of numbers
    bool BinarySearch(int list[], int start, int end, int nSearch)
    {
        if (end >= start)
        {
            int middle = (start + end) / 2;
            if (list[middle] == nSearch)
                return true;
            if (list[middle] > nSearch)
                return BinarySearch(list,start,middle-1,nSearch);
            else
                return BinarySearch(list, middle + 1, end, nSearch);
        }
        else
            return false;
    }
    bool Search(int pArr[], int nCount, int nSearch)
    {
        return BinarySearch(pArr, 0, nCount - 1, nSearch);
    }
    
    int main()
    {
        cout << "This program searches a number in a list of numbers" << endl << endl;
        int *pArr{ nullptr };
        int nElementCount{ 0 };
        int nNumberToSearch{ 0 };
        GetInput(&pArr, &nElementCount,&nNumberToSearch);
        Sort(pArr, nElementCount); // Pointer can be treated as an array
        cout << "Sorted numbers are :";
        DisplayNumbers(pArr,0, nElementCount-1);
        if (Search(pArr, nElementCount, nNumberToSearch))
            cout << "The number "<< nNumberToSearch<<" is present" << endl;
        else
            cout << "The number "<< nNumberToSearch<<" is not present" << endl;
        return 0;
    }
    
    Flow control statements are basic building blocks of a function. They are the language constructs to build the function logic. You can almost do everything in a program with those constructs.
     

Share This Page