.. highlight:: c++ :linenothreshold: 5 ****************************************** Type, Variable, Assignment, and Expression ****************************************** Types ===== + For each type, understand: * is a class type? * is numeric? * is ordered? * is signed? * is exact? * range * related types .. list-table:: Common C++ Types :header-rows: 1 :widths: 15 30 * - Name - Tags * - int - non-class, numeric, signed, ordered, exact * - unsigned int - non-class, numeric, unsigned, ordered, exact * - float - non-class, numeric, signed, ordered, not exact * - double - non-class, numeric, signed, ordered, not exact * - char - non-class, numeric, unsigned, ordered, exact * - string - class, not numeric, ordered * - vector - class template, not numeric + Derived types - Types that are derived from other data-types. * :doc:`pointer type ` * :doc:`array type ` * :doc:`reference type ` + Class templates Class templates can be instantiated by specifying the template arguments to generate class types. * The template itself is not a type or class * E.g. ``vector`` is a template while ``vector`` is a type Variables ========= + identifier naming :: // ==== identifiers ==== // ---- correct ---- int _a; int ____; int a10___; int a_1_0; int _1_0; // ---- wrong ---- int a$; int 3x; int mid-var; // ---- Good ---- int myVar1; // var is a good abbreviation for variable int count; double avgAge; // avg is a a good abbreviation for average double gpa; // good abbreviation // ---- Poor ---- int PtAc; // unknown abbreviation int v; // not informative double count = 1.5; // name not matches the purpose int NUMBER; // not following naming convention + variable declaration - must be declared before being referred + initialization * assignment during declaration * not assignment! have different syntax! :: // ==== declarations, initialization ==== // ---- correct ---- int a; int a = 10; int a, b, c; int a, b = 5, c = 10; // ---- wrong ---- int a int a b c; // use before declare a = 10; int a; * constant variable - must be initialized! - can never be changed later! - all uppercase with under score - ``const`` keyword can be before or after the type :: // ---- correct ---- const int CONSTANT1 = 100; int const CONSTANT2 = 200; // --- Wrong ---- const int CONSTANT3; // no initialization CONSTANT1 = 200; // modification not allowed cin >> CONSTANT2; // modification not allowed // ---- bad ---- Literal ======= How values are represented in the source code. + int ``1``, ``100`` + double ``3.0``, ``3e2``, ``3.0e-1`` + char ``'a'`` + string ``"abc"`` * escape sequence ``\n``, ``\t``, ``\"``, ``\'``, ``\\`` etc. in char or string literal + long ``1000l`` + float ``1.0f`` + unsigned int ``100u`` Assignment ========== + ``=`` operator + assignment operation requires an lvalue on the left and an rvalue on the right + lvalue * something that binds to a defined memory address * variables * references + rvalue * anything that does or does not bind to a defined memory address * temporary and short-lived * literals * compound expressions e.g. ``x + y`` * temporary object e.g. ``string(argv[0])`` + short-handed assignment operators * ``+=`` * ``-=`` * ``*=`` * ``/=`` * ``%=`` :: // ==== Assignment ==== // ---- correct ---- int a = 10; int b = a; b = a; a += b; double c = a; b = a * c; // ---- wrong ---- a + b = 20; // non-lvalue on the left a == 10; // wrong operator // use without initial value int a; a = a + 1; a += 1; Conversion and Type casting =========================== + Type conversion (implicit) 1. assignment **forces** any type casting 2. implicit conversion happens in operations between mixed types (the value of the type with smaller range will be converted to the type with lager range, a.k.a. widened) + Type casting (explicit) * explicit type casting ``static_cast(variable)`` * **Avoid C style type conversion** like ``(int) doubleValue`` :: // ==== conversion, type casting ==== // ---- correct ---- int a = 10; double b; char c = 'L'; b = a; // a converted to double a = b; // b converted to int // c converted to int and added to a; // the resulting int converted to double when assigned to b b = a + c; // average without losing precision int total = 7; int count = 3; double average = static_cast(total) / count; // convert to 3.210000 double val = 3.213; double result = static_cast(val * 100) / 100.0; // ---- wrong ---- int total = 7; int count = 3; double average = total / count; // lose precision, get 2.0, expect 2.3333... double average = static_cast(total / count); // cast too late // ---- bad ---- cout << ((int) 3.5) << endl; // C-style type casting Expressions =========== + operators * arithmetic ``+ - * / %`` * increase, decrease: ``++``, ``--`` - requires an lvalue - similar to ``+= 1`` or ``-= 1`` - prefix vs suffix - prefer prefix if possible (run faster, save memory) * relational ``== != < > <= >=`` * logic ``&& || !`` - short circuit evaluation In the evaluation of logical expression with binary logical operators (&& and ||), the operands are evaluated from left to right. If the value of the right operand does not affect the result, it will be skipped in the evaluation. * bit-wise ``& | !`` * assignment ``=`` * other operator: ``::``, ``<<``, ``>>``, ``&``, ``*``, ``.``, ``->`` + Precedence rule (order of evaluation, arithmetic, relational, and logic only) #. ``()`` #. ``!`` logical negation #. ``-`` arithmetic negation #. ``*, /, %`` arithmetic multiplication, division, and modulo #. ``+, -`` arithmetic addition, subtraction #. ``>, <, >=, <=`` relational #. ``==, !=`` relational #. ``&&`` logical and #. ``||`` logical or + Pitfalls * ``=`` vs ``==`` * relational ``&& ||`` vs bit-wise ``& |`` * ``%`` on non-int * lose precision in integer division * chained range check ``1 < a < 10`` * bool vs int, asymmetric interconversion - true -> 1, false -> 0 - non-zero -> true, 0 -> false :: // ==== operators ==== // ---- correct ---- if (age > 1 && age < 10) cout << "Young child\n"; // ---- wrong ---- double a = 10; int b = a % 3; if (grade = 100) cout << "perfect!"; if (age < 10 & age > 1) // this actually works well but is a wrong syntax cout << "Young child\n"; if (1 < age < 10) // will compile but wrong! cout << "Young child\n"; + Step-wise evaluation, in every step consider: * conversion and type casting * precedence rule :: // ==== Expression ==== // ---- step-wise evaluation ---- // given: x = 2 (x + 5) / 4 = (2 + 5) / 4 = 7 / 4 = 1 static_cast(19.5 / 3) + 5.0 = static_cast(6.5) + 5.0 = 6 + 5.0 = 11.0 ((17 / 2 + 19 % 3 - 3 * 2 + 4 * 3) >= (5 + 2 * 4)) && !((((4 * 5) + 1) /2) == (7 / 3 + 2 * 5 - 2) || !(4 >= 3)) = ((8 + 1 - 6 + 12) >= (5 + 8)) && !(((20 + 1) / 2) == (2 + 10 - 2) || !(true)) = (15 >= 13) && !((21 / 2) == 10 || false) = true && !(true || false) = true && !true = true && false = false + evaluation tree Visual aid when evaluating complex expressions e.g. ``3.0 / a + 5 < 8 && c > 'b' || d % 2 == 1`` .. graphviz:: graph eval_tree{ "||" -- { "&&", "=="}; "&&" -- {"<", ">"}; "==" -- {"\%", "1"}; "<" -- {"+", "8"}; "+" -- {"/", "5"}; "/" -- {"3.0", "a"}; ">" -- {"c", "\'b\'"}; "\%" -- {"d", "2"}; } Core Concepts ============= .. glossary:: Identifier User defined names Reserved word (keyword) Names used by the language Variable A named container to store a value Type Storage format supported by the language Variable initialization Providing initial value to a variable when it is declared Literal Textual representation of fixed-values used in source code Lvalue An expression that binds to a defined memory address Rvalue An expression that does not bind to any defined memory address Expression Text representations in source code of something that evaluates to a value Precedence rule The order of evaluation of operators in an expression