2024-07-12    2024-07-12     2306 字  11 分钟
cpp

Preprocessors

  • Preprocessor commands, which begins with #, performs some actions before the complier does the translation.
    • The include command is to include a header file:
      • Files containing definitions of common variables and functions.
      • Written to be included by other programs.
    • #include <iostream>: Before the compilation, the complier looks for the iostream header file and copy the codes therein to replace this line.
    • We may define our own variables and functions into self-defined header files and include them by ourselves:
      • #include "myHeader"
      • Use double quotation marks instead of angle brackets.
      • A path must be specified.

Namespaces

  • Suppose all roads in Taiwan have different names. In this case, we do not need to include the city/county name in our address.

  • This is why we do not need to specify the district for an address in the Taipei city.

  • But we need to specify the district for an address in the New Taipei County.

  • A C++ namespace is a collection (space) of names.

    • For C++ variables, functions, object, etc.
    • The objects cout, cin, and all other items defined in the C++ standard library are defined in the namespace std.
  • By writing using namespace std;, whenever the complier sees a name, it searchs whether it is defined in this program or the namespace std.

  • The scope resolution operator (::)

    • We may specify the namespace of cout each time when we use it with the scope resolution operation ::
#include <iostream>
int main()
{
    std::cout << "Hello World!\n" << std::endl; // \a std::
    return 0;
}

Selection

  • The if statement
if (condition)
{
    statements
}
  • The if-else statement
if (condition)
{
    statements1
}
else
{
    statement2
}
  • Example
int income = 0, tax = 0;

cout << "Please enter your income: ";
cin >> income;

if (income <= 10000)
{
    tax = 0.02 * 10000;
}
else
{
    tax = 0.08 * (income - 10000) + 200;
}
  • An if or an if-else statement can be nested in an if block or/and else block.
#include <iostream>
using namespace std;

int main()
{
    int a = 0, b = 0, c = 0;

    cout << "Enter three numbers: ";
    cin >> a >> b >> c;

    if (a <= b)
    {
        if (a <= c)
        {
            cout << a << " is the smallest\n";
        }
        else
        {
            cout << c << " is the smallest\n";
        }
    }
    else
    {
        if (b <= c)
        {
            cout << b << " is the smallest\n";
        }
        else
        {
            cout << c << " is the smallest\n";
        }
    }
}
  • Revised version:
#include <iostream>
using namespace std;

int main()
{
    int a = 0, b = 0, c = 0;
    
    cout << "Enter three numbers: ";
    cin >> a >> b >> c;
    
    int min = c;

    if (a <= b)
    {
        if (a <= c)
        {
            min = a;
        }
    }
    else
    {
        if (b <= c)
        {
            min = b;
        }
    }
    
    cout << min << " is the smallest";
}
  • The ternary if operator ? :

  • In many cases, what to do after an if-else selection is simple.

  • The ternary if operator ? : can be helpful in this case.

  • condition ? operation A : opertion B;: if condition is true, do operation A; otherwise, operation B.

  • Second revised version:

#include <iostream>
using namespace std;

int main()
{
    int a = 0, b = 0, c = 0;
    
    cout << "Enter three numbers: ";
    cin >> a >> b >> c;

    int min = c;

    if (a <= b)
        a < c ? min = a : min = c;
    else
        min = b <= c ? b : c;

    cout << "The smallest number is " << min << endl;
}
  • Ternary if operators can also be nested (but not suggested)

  • min = a <= b ? a <= c? a : c : b <= c ? b : c;

  • min = (a <= b ? (a <= c? a : c) : (b <= c ? b : c));

  • Dangling if-else

    • What does this mean?
if (a == 10)
    if (b == 10)
        cout << "a and b are both ten. \n";
else
    cout << "a is not ten. \n";
  • In the current C++ standard, it is actually:
if (a == 10)
{
    if (b == 10)
        cout << "a and b are both ten. \n";
    else
        cout << "a is not ten. \n";
}    
  • When we drop {}, our programs may be grammatically ambiguous.

  • In the field of Programming Languages, it is called the dangling program.

  • To handle this, C++ defines that “one else will be paired to the closest if that has not been paired with an else.”

  • Good programming style:

    • Drop { } only when you know what you are doing.
    • Align your { }.
    • Indent your codes properly.
  • Logical operators

    • &&: and.
    • ||: or.
    • !: not.
    • These operators have their aliases (and, or, and not).
  • Each of the two conditions must be complete by itself.

if (a >= 10 && <= 20) // error! \a
    cout << "a is between 10 and 20";
  • Two conditions can be combined only with a logical operator.
if (10 <= a <= 20) // error! \a
    cout << "a is between 10 and 20";
  • Associativity and precedence
    • The && and || operators both associate the two conditions from left to right.
    • It is possible that the second condition is not evaluated at all.
      • If evaluating the first one is enough.
    • There is a precedence rule for operators.
      • Use parentheses.
#include <iostream>
using namespace std;

int main()
{
    int a = 0, b = 0;

    if ((a > 10) && (b = 1))
    ;
    cout << b << endl;  // result: 0 \a

    if ((a > 10) || (b = 5))
    ;
    cout << b << endl; // result: 5 \a
}
  • switch-case
switch (operation)
{
    case value 1:
        statements
        break;
    case value 2:
        statements
        break;
    ...
    default:
        statements
        break;
}
  • it is particularly useful for responding to multiple values of a single operation.
  • For the operatoion:
    • It can contain only a single operand.
    • It must return an integer.
    • After each case, there is a value.
    • If the returned value of the operation equals that value, those statements in the case block will be executed.
    • No curly brackets are needed for blocks.
    • A colon is needed after the value.
    • A break marks the end of a block.
      • The break of the last section is optional.
    • Restriction on those values:
      • Cannot be (non-constant) variables.
      • Must be different integers.
  • What will happen if we enter 10?
int a;
cin >> a;

switch (a)
{
    case 10:
        cout << "ten";
    case 6:
        cout << "six";
        break
}
  • Example:

  • Given a year and a month, how many days is in that month?

  • There are four possibilities:

    • 31 days: January, March, May, July, August, October, December.
    • 30 days: April, June, September, November.
    • 29 days: Februray in a leap year.
    • 28 days: Februray in a ordinary year.
  • A year is a leap year if:

    • It is a multiple of 400, or
    • It is a multiple of 4 but not a multiple of 100.
  • Version 1

#include <iostream>
using namespace std;

int main()
{
    int year = 0, month = 0;
    cout << "Enter year and month: ";
    cin >> year >> month;
    int days = 0;

    if (month ==1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
        days = 31;
    else if (month == 4 || month == 6 || month == 9 || month == 11)
        days = 30;
    else if ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0))
        days = 29;
    else
        days = 28;

    cout << "Number of days: " << days << endl;
}
  • Version 2
#include <iostream>
using namespace std;

int main()
{
    int year = 0, month = 0;
    cout << "Enter year and month: ";
    cin >> year >> month;
    int days = 0;

    switch (month)
    {
        case 1: case 3: case 5: case 7: case 8: case 10: case 12:
            days = 31;
            break;
        case 4: case 6: case 9: case 11:
            days = 30;
            break;
        case 2:
            if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
                days = 29;
            else
                days = 28;
    }

    cout << "Number of days: " << days << endl;
}

Repetition

  • while and do-while
while (operation)
{
    statements
}
do 
{
    statements
} while (operation); // semicolon \a
  • loop counter

  • Using the unary increment/decrement operator ++/-- can be more convenient.(NOTE: postfix/prefix?)

  • Binary self-assigning operators (e.g., +=).

  • For modifying i, i++ has the same effect as i = i + 1.

  • For modifying i, i-- has the same effect as i = i -1.

  • They can be applied on all basic data types.

    • But we should only apply them on integers.
    • Typically, using them is faster than using the corresponding addition/subtraction and assignment operation.
  • Both can be put at the left or the right of the operand.

    • This changes the order of related operations.
    • i++: returns the value of i, and then increment i.
    • ++i: increments i, and then returns the incremented value of i.
    • So is i = i + 1 equivalent to i++ or ++i? (ans: ++i)
  • Self-assigning operations

    • Typically a += b is ** ** than a = a + b, etc.
  • for

for (init; condition; some)
{
    statements
}

picture 0

  • You need those two ; in the ( ).

  • The typical way of using a for statement is:

    • init: Initialize a counter variable.
    • cond: Set up the condition on the counter variable for the loop to continue.
    • some: Modify (mostly increment or decrement) the counter variable.
    • statements: The things that we really want to do.
  • Multi-counter for loops

    • Inside one for statement:
      • You may initialize multiple counters at the same time.
      • You may also check multiple counters at the same time.
      • You may also modify multiple counters at the same time.
    • Use && or || to connect operations on multiple counters.
for (int i = 0, j = 0; i < 10 && j > -5; i++, j--)
    cout << i << " " << j << endl;
  • Good programming style:

    • When you need to execute a loop for a fixed number of iterations, use a for statement with a counter declared only for the loop
      • This also applies if you know the maximum number of iterations.
      • This avoids poetential conflicts on variable names.
    • Use the loop that makes your program the most readable.
    • Typically only the counter variable enters the () of a for statement.
    • You may use fractional numbers for a counters, but this not recommended.
      • Use integer only.
    • Drop {} only when you know what you are doing.
    • Align your {}. Indent your codes properly.
  • Scope of variable

    • variables live only in the block in which they are declared.
    • Two variables declared in the same level cannot have the same name.
int i = 0;
for (; i< 10; i++)
    cout << i << endl;
// ...
int i = 0; // error! \a
for (; i < 10; i++)
     cout << i << endl;
  • This is a good reasons to use for: All loops at the same level may use the same name for loop counters.
for (int i = 0; i< 10; i++)
    cout << i << endl;
// ...
for (int i = 0; i < 10; i++)
     cout << i << endl;
  • However, a variable of an existing name is allowed to be declared in an inner block.
    • In the inner block, after the same variable name is used to declare a new variable, it “replace” the original one.
    • However, its life ends when the inner block ends.
int a = 0;
if (a == 0)
{
    cout << a << endl;
    int a = 10;
    cout << a << endl;
}
cout << a << endl;
  • break and continue
    • When we implement a repetition process, sometimes we need to further change the flow of execution of the loop
    • A break statement brings us to exit the loop immediately.
    • When continue is executed, statements after it in the loop are skipped.
      • The looping condition will be checked immediately.
      • If it is satisfied, the loop starts from the beginning again.
    • How to write a program to print out all integers from 1 to 100 except multiples of 10.
for (int a = 1; a <= 100; a++)
{
    if (a % 10 != 0)
        cout << a << endl;
}
for (int a = 1; a <= 100; a++)
{
    if (a % 10 == 0)
        continue;
    cout << a << endl;
}
  • The effect of break and continue is just on the current level.
    • If a break is used in an inner loop, the execution jumps to the outer loop
    • If a continue is used in an inner loop, the execution jumps to the condition check of the inner loop.
  • What will be printed out at the end of this program
#include <iostream>

int main()
{
    using namespace std;

    int a = 0, b = 0;
    while (a <= 10)
    {
        while (b <= 10)
        {
            if (b == 5)
                break;
            cout << a * b << endl; // result: a = 0, b = 0: 0, 0, 0, 0, 0; a = 1, b = 5: 
            b++;
        }
        a++;
    }
    cout << a << endl; // result: 11
    return 0;
}
  • Using break gives a loop multiple exits
    • It becomes harder to track the flow of a program.
    • It becomes harder to know the state after a loop
  • Using continue highlights the need of getting to the next iteration.
    • Having too many continue still gets people confused.
  • Be careful not to hurt the readability of a program too much.