顯示具有 讀書筆記 標籤的文章。 顯示所有文章
顯示具有 讀書筆記 標籤的文章。 顯示所有文章

2022年9月25日 星期日

Leet code

最近一直寫 Leetcode,部落格也就荒廢許久,想說突破 200 題來分享一下心得。

Distance question

Leetcode 上有很多問題是關於距離,這裡紀錄下一些有用的數學概念。
  • 平均值 (mean)
    平均值的歐幾里得距離最短 (4*4 + 4*4 < 1*1 + 7*7)
    但相乘值最大 (4*4 > 1*7)
  • 中位數 (median)
    中位數的絕對偏差值最低 (跟其物件的距離之總和最短)
  • 眾數 (mode)
    mode minimizes distance for indicator function (理解不能)
    這個我沒寫過類似的,寫過後我再更新。
參考資料 :
1.leetcode/discuss

2021年6月11日 星期五

讀書心得 - C++ Primer (5th Edition) - Chapter 5 (3) - 常用詞彙

常用詞彙

  • block
    Sequence of zero or more statements enclosed in curly braces. A block is a statement, so it can appear anywhere a statement is expected.
  • case label
    Constant expression that follows the keyword case inC++ Primer, Fifth Edition a switch statement. No two case labels in the same switch statement may have the same value.
  • catch clause
    The catch keyword, an exception declaration in parentheses, and a block of statements. The code inside a catch clause does whatever is necessary to handle an exception of the type defined in its exception declaration.
  • compound statement
    Synonym for block.
  • null statement
    An empty statement. Indicated by a single semicolon.
  • raise
    Often used as a synonym for throw. C++ programmers speak of “throwing” or “raising” an exception interchangeably.

讀書心得 - C++ Primer (5th Edition) - Chapter 5 (2) - Exception

Exceptions

Exceptions 是程式在 run-time 遇到的異常,比如與資料庫的連結斷開或遇到其他程式異想不到的 input。Exception handling 基本上就是當程式無法解決問題或者無法繼續執行時發出警告,或者更進一步根據情況處理 exception。
Exception handling 由 detecting, handling parts of a program 所組成
  • throw expressions
    當 detecting part 表示遭遇無法處理的情況
  • try blocks
    handling part 用來處理 exception。程式碼一開始會有一個 try block 隨後跟著一個或以上的 catch clauses。
  • exception classes
    用來傳遞 information about what happened between a throw and an associated catch.

A throw Expression

通常會在 detecting part 發生 exception 時 throw Expression,這麼做原因是有時你不能保證你的程式一定是跟 User 互動的那一個,throw Expression 效果就比你回傳一個錯誤值好用得多。
    // Normal version
    int throwTest(int num1, int num2) {
        if (num1 == num2) {
            cout << "Same." << endl;
            return 0;
        } else {
            cerr << "Not the same." << endl;
            return -1;
        }
    }

    // throw Expression
    void throwTest(int num1, int num2) {
        if (num1 != num2)
            throw runtime_error("Not the same.");
        cout << "Same." << endl;
    }

The try Block

基於 C 風格的錯誤處理,在回傳值代表發生錯誤時予以處理。相比之下 throw 就相對靈活,但也會有終止程式的代價。try catch 的 block 就適合在此情況使用。讓程式有 exception handler。
    try {
        program-statements
    } catch (exception-declaration) {
        handler-statements
    } catch (exception-declaration) {
        handler-statements
    } // . . .

Standard Exceptions

正如上面的 try block 示億程式碼所示,程式必須先宣告 exception 的種類才能近一步去做 handle,這裡紀錄 C++ standard library \ 裡的 exception table。 
    exception         // The most general kind of problem.

    // Runtime errors
    runtime_error     // Problem that can be detected at the run-time.
    range_error       // Result generated outside the range of value that are meaningful.
    overflow_error    // Computation that overflow.
    underflow_error   // Computation that underflow.

    // Logic errors
    logic_error       // Error in the logic of the program.
    domain_error      // Argument for which no result exists.
    invalid_argument  // Inappropriate argument.
    length_error      // Attempt to create an object larger than the maximum size for that type.
    out_of_range      // Use a value outside the valid range.

讀書心得 - C++ Primer (5th Edition) - Chapter 5 (1) - Statement

Statement

  • Simple Statements
    expression 加上 ; 作為結尾視為 statement。
        a + 5  // expression
        a + 5; // statement
        ;      // null statement
    
  • Compound Statements (Blocks)
    在 { } 中間一連串的 statements 或 declarations (也允許是空的),且不用 ; 作為中止符。
        while (val <= 10) {
            sum += val;  // assigns sum + val to sum
            ++val;       // add 1 to val
        }
    
  • Statement Scope
    我們可以在 if else for 等等的 statements 裡宣告參數,但該參數也只有在 statements 裡能存取。
        while (int i = get_num()) // i is created and initialized on each iteration
            cout << i << endl;
        i = 0;  // error: i is not accessible outside the loop
    
  • Conditional Statements
    有 if statement, if else statement 和 switch statement。以下面的 switch code 為示範,"switch (ch)" 的 ch 為 expression,"case 'a':", "case 'e':" ... 為 case label,當 expression match case label,execution 就會從此開始直到 switch 的中止符或 break,所以是有可能橫跨 case labels。合法 case label 為 integral constant expressions,也就是 integral type 的 constant expression
        int vowelCnt = 0
        // any occurrence of a, e, i, o, or u increments vowelCnt
        while (cin >> ch) {
            switch (ch) {
                case 'a':
                case 'e':
                case 'i':
                case 'o':
                case 'u':
                    ++vowelCnt;
                    break;
            }
        }
    
  • Why can't variables be declared in a switch statement?
    首先這是 stackoverflow 裡的一個問題,問題題目應該改成 Why can't variables be initialized in a switch statement?,因為如果只有 declared 是合法的,頂多有 warning。基本上 case 就是 label 的一種,一種常見於有 goto 的程式碼。若你做 variable definition 在 switch statement,等於在這 switch statement scope 裡會有機會因為做了 goto label 的關係而忽略掉該 definition,進而導致程式碼出錯。若要在 switch statement 做 variable definition,你就必須很明確地告訴 compiler 即使有 goto label 忽略該 variable definition 也沒差,因為我只會在那 case 裡使用,也就是加 {} 更近一步明確地縮小 variable definition 的 scope 而非整個 switch statement scope。(Declaration跟Definition間的差異)
        // Ok, 程式碼寫得漂亮,compiler 發現沒有任何 label 會忽略掉 init 的 definition
        switch (num) {
            case 1:
                int init = 0;
                cout << declare << endl;
        }
    
        // Error, case 2 這個 label 會忽略 init 的 definition
        // main.cpp:17:10: error: jump to case label
        // 17 |     case 2:
        //    |          ^
        switch (num) {
            case 1:
                int init = 0;
                cout << init << endl;
            case 2:
                cout << 9999 << endl;
        }
    
        // 加 {},縮小該 variable definition 的 scope
        switch (num) {
            case 1:
                {
                    int init = 0;
                    cout << init << endl;
                }
            case 2:
                cout << 9999 << endl;
        }
    
        // 只是 declaration 不會有事
        // 甚至因為是同 scope 所以 case 2 可以呼叫到
        // declare = 5; 若拿掉會出錯
        // 因為 compiler 發現 declare 從沒被賦予值過
        int num = 2;
        switch (num) {
            case 1:
                int declare;
                declare = 5;
            case 2:
                cout << declare << endl;
        }
        // Output: 21911
    
  • Iterative Statements
    有 while statement, for statement 跟 do while Statement。C++ 的 for statement 除了傳統的還有 range for statement。其中 expression 必須要是 braced initializer list, array, vector 或 string 其中一種。
        for (declaration : expression)
            statement
    
  • Jump Statements
    有 break statement, continue statement 和 goto Statement。
參考資料 :
1.why-cant-variables-be-declared-in-a-switch-statement

2021年5月20日 星期四

讀書心得 - C++ Primer (5th Edition) - Chapter 4 (3) - 常用詞彙

常用詞彙

  • arithmetic conversion
    A conversion from one arithmetic type to another. In the context of the binary arithmetic operators, arithmetic conversions usually attempt to preserve precision by converting a smaller type to a larger type (e.g., integral types are converted to floating point).
  • associativity
    Determines how operators with the same precedence are grouped. Operators can be either right associative (operators are grouped from right to left) or left associative (operators are grouped from left to right).
  • cast
    An explicit conversion.
  • compound expression
    An expression involving more than one operator.
  • expression
    The lowest level of computation in a C++ program. Expressions generally apply an operator to one or more operands. Each expression yields a result. Expressions can be used as operands, so we can write compound expressions requiring the evaluation of multiple operators.

讀書心得 - C++ Primer (5th Edition) - Chapter 4 (2) - Type Conversions

Type Conversions

  • Implicit Conversions
    型別轉換,大部分轉換都是看是否能轉換成 int,例如 char, bool, 和 short。
        bool      flag;   char           cval;
        short     sval;   unsigned short usval;
        int       ival;   unsigned int   uival;
        long      lval;   unsigned long  ulval;
        float     fval;   double         dval;
        3.14159L + 'a'; //  'a' promoted to int, then that int converted to long double
        dval + ival;    //  ival converted to double
        dval + fval;    //  fval converted to double
        ival = dval;    //  dval converted (by truncation) to int
        flag = dval;    //  if dval is 0, then flag is false, otherwise true
        cval + fval;    //  cval promoted to int, then that int converted to float
        sval + cval;    //  sval and cval promoted to int
        cval + lval;    //  cval converted to long
        ival + ulval;   //  ival converted to unsigned long
        usval + ival;   //  promotion depends on the size of unsigned short and int
        uival + lval;   //  conversion depends on the size of unsigned int and long
    
  • Explicit Conversions
    用於我們想明確地強制將 object 轉換為其他類型。cast-name\(expression)。(const相關文章1, const相關文章2)
        // static_cast 最常用的 cast-name
        // cast used to force floating-point division
        double slope = static_cast<double>(j) / i;
    
        // const_cast 用來改變 low-level const (point to const)
        const char *pc;
        char *p = const_cast<char*>(pc); // ok: but writing through p is undefinedc
    
        // reinterpret_cast 對其 operand 進行 low-level bit 的重新解釋
        // 要很理解其型別的 bit 組成才會使用
        int *ip;
        char *pc = reinterpret_cast<char*>(ip);
    
cast 基本上就是擾亂型別,建議能不使用就不使用。

讀書心得 - C++ Primer (5th Edition) - Chapter 4 (1) - Expression & Operator

Expression

運算式 (expression) 由運算元 (operand) 與運算子 (operator) 所組成,最終計算產生一個結果 (result)。
  • Order of Evaluation
    想要計算 expression 的話,就必須知道運算子運作及其先後順序。這裡的 * 號就不是 pointer 而是相乘,然後再來是基本的先乘除後加減。
        cout << 5 + 10 * 20 / 2 << endl;        // 105
        cout << 6 + 3 * 4 / 2 + 2 << endl;      // 14
        cout << (6 + 3) *  (4 / 2 + 2) << endl; // 36
        cout << ((6 + 3) *  4) / 2 + 2 << endl; // 20
        cout << 6 + 3 * 4  / (2 + 2) << endl;   // 9
    
  • Lvalues and Rvalues
    有寫過一篇 Lvalues and Rvalues 也可以參考。這裡紀錄此書寫大概的定義,當我們將一個 object 視為 rvalue 使用,使用的是此 object 的值 (contents)。當我們將一個 object 視為 lvalue 使用,使用的是此 object 的「存在」(記憶體位置)。還有一點也很重要,lvalue 可以代替 rvalue,但反之 rvalue 卻不能代替 lvalue。
        int a = 1;     // a = lvalue, 1 = rvalue
        int b = a + 1; // a = lvalue, a = rvalue (lvalue 代替 rvalue)
        int 1 = a;     // Error, 1 != lvalue (rvalue 不能代替 lvalue)
    

Operators

  • Logical and Relational Operators
    Logical Operators 和 Relational Operators 回傳 bool。Logical Operators AND 跟 OR 永遠都會先計算左側再來計算右側。這裡想特別紀錄的是 && 跟 ||,&& 代表只有左側計算出來是 True 才會計算右側,|| 則是只有左側計算出來是 False 才會計算右側。這可以寫出一些流程控制而不是使用典型的 if else。Relational Operators 則是 >, <, >=, <=, ! 這些。
        // 以下這兩個 val 都會被轉換成 bool
        if (val)  { /*  ...  */ } // true if val is any nonzero value
        if (!val) { /*  ...  */ } // true if val is zero
    
        // 有了上面兩個例子,我們看似可以將其改寫成以下寫法
        if (val == true) { /*  ...  */ }
    
        // 這個會產生問題,只要 val 的型別不是 bool
        // 假設 val 是 int,true 會被轉換成 int 也就是 1 跟原先的任何 nonzero value 相去甚遠
        if (val == 1) { /*  ...  */ } // true if val is 1
    
  • Assignment Operators
    最常見就是等號 (=)。Assignment 是 Right Associative,以下有程式碼示範。另外 Assignment Operators 執行順序較低通常會用括弧輔助。
        int ival, jval;
        ival = jval = 0; // ok: each assigned 0
        // 對於右邊的 assignment,jval = 0
        // 對於左邊的 assignment,ival = (jval = 0)
        // jval assigned 0 後,回傳 jval (ival = jval),ival = 0
    
        // 原先邏輯
        int i = get_value();
        while (i != 42) {
            // do something ...
            i = get_value();
        }
        // 改寫,用括弧輔助
        int i;
        while ((i = get_value()) != 42) {
            // do something ...
        }
    
  • Increment and Decrement Operators
    ++ -- 用來做 Increment 和 Decrement,兩個都有 prefix 跟 postfix 的寫法,效果如下程式碼示範。要注意的是要盡量用 prefix 來做運算,因為你通常不會需要做增減前的 value,而 postfix 會 copy 一份增減前的 value 來做回傳。 
        int i = 0, j;
        j = ++i; // j = 1, i = 1: prefix yields the incremented value
        j = i++; // j = 1, i = 2: postfix yields the unincremented value
    
        // 需要 postfix 的場合
        auto pbeg = v.begin();
        // print elements up to the first negative value
        while (pbeg != v.end() && *beg >= 0)
            cout << *pbeg++ << endl; // print the current value and advance pbeg
    
    Operand 運算順序不是固定的,通常不會造成問題,但如果兩邊有用到同一 variable 且用了 Increment 或 Decrement Operators 問題就會浮現。
        // 原先邏輯是把 s 裡的 char 都改成大寫
        // the behavior of the following loop is undefined!
        auto it = s.begin()
        while (it != s.end() && !isspace(*it))
            *it = toupper(*it++);   // error: this assignment is undefined
    
        // 會有兩種結果
        // 第一種輸出 ABCDEFG
        *beg = toupper(*beg);        // 先執行左邊的 Operand,Output: ABCDEFG
        *(beg + 1) = toupper(*beg);  // 先執行左邊的 Operand,Output: aAAAAAA
    
  • Shift Operators (aka IO Operators) Are Left Associative
        cout << "hi" << " there" << endl;
        ( (cout << "hi") << " there" ) << endl;
    
        cout << 42 + 10;   // ok: + has higher precedence, so the sum is printed
        cout << (10 < 42); // ok: parentheses force intended grouping; prints 1
        cout << 10 < 42;   // error: attempt to compare cout to 42!
    

2021年5月13日 星期四

C++ Primer (5th Edition)

讀書心得 - C++ Primer (5th Edition) - Chapter 3 (4) - 常用詞彙

常用詞彙

  • buffer overflow
    Serious programming bug that results when we use an index that is out-of-range for a container, such as a string, vector, or an array.
  • container
    A type whose objects hold a collection of objects of a given type. vector is a container type.
  • index
    Value used in the subscript operator to denote the element to retrieve from a string, vector, or array.
  • iterator
    A type used to access and navigate among the elements of a container.
  • off-the-end iterator
    The iterator returned by end that refers to a nonexistent element one past the end of a container.

讀書心得 - C++ Primer (5th Edition) - Chapter 3 (3) - Array

Array

Array 為資料結構且跟 Vector 很像,都是裝同一 Type object 的 container。但 Array 為固定大小,所以不能增加 element,但也因為如此有時能提供較好的 run-time performance。
  • Initialize
    在 C++ 裡 Array 的 Size 要為 constant expression,也就是 expression 能在 compile time 就算出來。但因為 C 支援在 Array Size 塞變數,所以 G++ 將此寫法視為一個 extension,只要你不在 compile 時強調要遵循 C++ 的 Rule (-pedantic)。
        unsigned cnt = 42;            // not a constant expression
        constexpr unsigned sz = 42;   // constant expression
    
        int arr[10];                  // array of ten ints
        int *parr[sz];                // array of 42 pointers to int
        string bad[cnt];              // error: cnt is not a constant expression
        string strs[get_size()];      // ok if get_size is constexpr, error otherwise
        int a1[3] = {0, 1, 2};        // [0, 1, 2]
        int a2[]  = {0, 1, 2};        // [0, 1, 2]
        int a3[5] = {0, 1, 2};        // [0, 1, 2, 0, 0]
        string a4[3] = {"hi", "bye"}; // ["hi", "bye", ""]
    
    賦予初始值可用 string 來直接 Initialize。
        char a1[] = {'C', '+', '+'};       // list initialization, no null
        char a2[] = {'C', '+', '+', '\0'}; // list initialization, explicit null
        char a3[] = "C++";                 // null terminator added automatically
        const char a4[6] = "Daniel";       // error: no space for the null!
    
    加入 pointer 和 reference 的宣告
        int *ptrs[10];            // ptrs is an array of ten pointers to int
        int &refs[10] = /* ? */;  // error: no arrays of references
        int (*Parray)[10] = &arr; // Parray points to an array of ten ints
        int (&arrRef)[10] = arr;  // arrRef refers to an array of ten ints
        int *(&arry)[10] = ptrs;  // arry is a reference to an array of ten pointers
    
  • Iterate
    這裡紀錄像 Iterator 的方法。arr[10] 是一個不存在的 index 所以只能取 address,所以當 pointer 指到它時就代表此 Array 已結束,類似 begin 跟 end 的方法。但這是較危險的寫法
        int arr[] = {0,1,2,3,4,5,6,7,8,9};
        int *e = &arr[10];
        for (int *b = arr; b != e; ++b)
            cout << *b << endl; // print the elements in arr
    
    有 function 可以直接用。
        int arr[] = {0,1,2,3,4,5,6,7,8,9}; 
        int *pbeg = begin(arr); // pbeg points to the first
        int *pend = end(arr);   // pend points just past the last element in arr
        for (int* p = pbeg; p != pend; ++p)
            cout << (*p) << endl;
    
  • Using an Array to Initialize a vector
        int int_arr[] = {0, 1, 2, 3, 4, 5};
        // ivec has six elements; each is a copy of the corresponding element in int_arr
        vector<int> ivec(begin(int_arr), end(int_arr));
        // copies three elements: int_arr[1], int_arr[2], int_arr[3]
        vector<int> subVec(int_arr + 1, int_arr + 4);
    
  • Initializing the Elements of a Multidimensional Array
        int ia[3][4] = {    // three elements; each element is an array of size 4
            {0, 1, 2, 3},   // initializers for the row indexed by 0
            {4, 5, 6, 7},   // initializers for the row indexed by 1
            {8, 9, 10, 11}  // initializers for the row indexed by 2
        };
        // equivalent initialization without the optional nested braces for each row
        int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
        // explicitly initialize only element 0 in each row
        int ia[3][4] = {{ 0 }, { 4 }, { 8 }};
        // explicitly initialize row 0; the remaining elements are value initialized
        int ix[3][4] = {0, 3, 6, 9};
    
參考資料 :
1.Initializing array with variable vs real number

2021年5月11日 星期二

讀書心得 - C++ Primer (5th Edition) - Chapter 3 (2) - Vector

Library - vector

  • Intro
    vector 是物件的集合,集合裡的物件都是同一 type,且每個物件都有 index 可以用找到該物件。vector 也是 container 和 class template 的一種。
        vector<int> ivec;             // ivec holds objects of type int
        vector<Sales_item> Sales_vec; // holds Sales_items
        vector<vector<string>> file;  // vector whose elements are vectors
    
  • Initialize
        vector<int> ivec;               // initially empty
        // give ivec some values
        vector<int> ivec2(ivec);        // copy elements of ivec into ivec2   
        vector<int> ivec3 = ivec;       // copy elements of ivec into ivec3   
        vector<string> svec(ivec2);     // error: svec holds strings, not ints
        vector<int> ivec(10, -1);       // ten int elements, each initialized to -1
        vector<string> svec(10, "hi!"); // ten strings; each element is "hi!"
    
  • Add
    push_back 會在 run time 的時候執行,會加 object 到 container 的最後端
        vector<int> v2;        // empty vector
        for (int i = 0; i != 100; ++i)
            v2.push_back(i);    // append sequential integers to v2
        // at end of loop v2 has 100 elements, values 0 . . . 99
    
  • Operations
        v.empty()       // Return true if v is empty; otherwise return false.
        v.size()        // Return the number of elements in v.
        v.push_back(t)  // And an element with value t to end of v.
        v[n]            // Return a reference to the element at position n in v
        v1 = v2         // Replaces the elements in v1 with a copy of the elements in v2
        v1 = {a,b,c...} // Replaces the elements in v1 with a copy of the elements in the comma-separated list
        v1 == v2        // v1 and v2 are equal if they have same number of elements and each
        v1 != v2        // element in v1 is equal to the corresponding element in v2
    

Library - iterators

  • Intro
    雖然使用者可以用 [n] (subscripts) 來取得 string 或 vector 的 element。但有一個更通用的用法也就是 iterator。
  • Using
    不像 pointer 不是用 address-of operator 來獲取 iterator,有些型別本身就有成員回傳 iterator。典型就是行別有成員 begin 和 end。begin 指向第一個 element,而 end 指向的是 container 的"結束",也就是說當 container 的 element 數量為 0 時,begin == end。
        // the compiler determines the type of b and e;
        // b denotes the first element and e denotes one past the last element in v
        auto b = v.begin(), e = v.end(); // b and e have the same type
    
  • Operation
        *iter       // Return a reference to the element denoted by the iterator iter
        iter->mem   // Dereferences iter and fetches the member named mem from the
                    // underlying element. Equivalent to the (*iter).mem
        ++iter      // Refers to the next element in the container
        --iter      // Refers to the previous element in the container
    
    利用 begin() != end() 來確認不是空字串
        string s("some string");
        if (s.begin() != s.end()) { // make sure s is not empty
            auto it = s.begin();    // it denotes the first character in s
            *it = toupper(*it);     // make that character uppercase
        }
    
  • Iterates through the elements in container
    這裡用 string 示範,比較要注意的是常用的迴圈終止條件用的是 != end(),而非用往常的 < 。並不是所有 Iterator 都可以支援 < operator,剛好 vector 還有 string 支援而已。
        // process characters in s until we run out of characters or we hit a whitespace
        for (auto it = s.begin(); it != s.end() && !isspace(*it); ++it)
            *it = toupper(*it); // capitalize the current character
    
  • Type
    如果想要精準宣告 Iterator 的 Type 的話。
        vector<int>::iterator it;        // it can read and write vector<int> elements
        string::iterator it2;            // it2 can read and write characters in a string
        vector<int>::const_iterator it3; // it3 can read but not write elements
        string::const_iterator it4;      // it4 can read but not write characters
    
  • Operations Supported by vector and string Iterators
    上面有提到 vector 跟 string 的 iterator 有支援較多的 operator。
        // The iterators must denote element in, or one past the end of, the same container
    
        iter + n      // Adding (subtracting) an integral value n to (from) an iterator yields an
        iter - n      // iterator that many elements forward (backward) within the container.
    
        iter1 += n    // Compound-assignment for iterator addition. 
        iter1 -= n    // Compound-assignment for iterator subtraction.
    
        iter1 - iter2 // Subtracting two iterators yields the number that when added to the
                      // right-hand iterator yields the left-hand iterator.
    
        >, <=, <, <=  // Relational operators on iterators. One iterator is less than another if it
                      // refers to an element that appears in the container before the referred to 
                      // by the other iterator.
    
    取中間的 iterator
        // compute an iterator to the element closest to the midpoint of vi
        auto mid = vi.begin() + vi.size() / 2;
    
    binary search
        // text must be sorted
        // beg and end will denote the range we're searching
        auto beg = text.begin(), end = text.end();
        auto mid = text.begin() + (end - beg)/2; // original midpoint
        // while there are still elements to look at and we haven't yet found sought
        while (mid != end && *mid != sought) {
            if (sought < *mid)     // is the element we want in the first half?
                end = mid;         // if so, adjust the range to ignore the second half
            else                   // the element we want is in the second half
                beg = mid + 1;     // start looking with the element just after mid
            mid = beg + (end - beg)/2;  // new midpoint
        }
    

2021年5月6日 星期四

讀書心得 - C++ Primer (5th Edition) - Chapter 3 (1) - Namespace

Namespace - using declaration

為了讀取 stdin,程式碼會是 std::cin。 :: 的左邊是告訴 compiler 去哪個 scope 找右邊的 operand。這有時會造成程式碼過於冗長,所以有了 using declaration 讓你更簡單的呼叫 namespace 底下的成員。
    #include <iostream>
    using std::cin;
    int main()
    {
        int i;
        cin >> i;       // ok: cin is a synonym for std::cin
        cout << i;      // error: no using declaration; we must use the full name
        std::cout << i; // ok: explicitly use cout from namepsace std
        return 0;
    }
using declaration 通常不會出現在 header 裡,因為 header 會被複製到各個程式中,會導致所有 include 該 header 的程式用相同的 using declaration 容易造成命名衝突。

Library - string

  • Initialize
        #include <string>
        using std::string;
        string s1;            // default initialization; s1 is the empty string
        string s2 = s1;       // s2 is a copy of  s1
        string s3 = "hiya";   // s3 is a copy of the string literal
        string s4(10, 'c');   // s4 is cccccccccc
    
  • std::cin interaction
    cin 會因為 space 而被分開,以下程式碼若輸入 "Hello World!",則 s1 = "Hello", s2 = "World!"
        string s1, s2;
        cin >> s1 >> s2; // read first input into s1, second into s2
        cout << s1 << s2 << endl; // write both strings
    
    可以用 getline 來讀完整的 "Hello World!"
        string line;
        // read input a line at a time until end-of-file
        while (getline(cin, line))
            cout << line << endl;
        return 0;
    
  • Comparing & Adding Two string
    string 可以使用 ==, != 做比較,也可以用 + 來做字串串接
        string s1 = "hello, ", s2 = "world\n";
        string s3 = s1 + s2;   // s3 is hello, world\n
        s1 += s2;   // equivalent to s1 = s1 + s2
    
  • Iterates through the chars in a string
    可以用 for(auto c : str),也可以用 for(auto &c : str)。&c 是 reference 所以可以改變 str 裡的 char。 
        string str("some string");
        // print the characters in str one character to a line
        for (auto c : str)      // for every char in str
            cout << c << endl;  // print the current character followed by a newline
    

2021年2月19日 星期五

讀書心得 - C++ Primer (5th Edition) - Chapter 2 (4) - 常用詞彙

 常用詞彙

  • bind
    Associating a name with a given entity so that uses of the name are uses of the underlying entity. For example, a reference is a name that is bound to an object.
  • compound type
    A type that is defined in terms of another type.
  • const
    Type qualifier used to define objects that may not be changed. const objects must be initialized, because there is no way to give them a value after they are defined.
  • declaration
    Asserts the existence of a variable, function, or type defined elsewhere. Names may not be used until they are defined or declared.
  • definition
    Allocates storage for a variable of a specified type and optionally initializes the variable. Names may not be used until they are defined or declared.
  • const pointer
    Pointer that is const.
  • pointer to const
    Pointer that can hold the address of a const object. A pointer to const may not be used to change the value of the object to which it points.
  • reference to const
    A reference that may not change the value of the object to which it refers. A reference to const may be bound to a const object, a nonconst object, or the result of an expression.
  • const reference
    因為 reference 本身不是 object 所以不能用 const 修飾,所以口語上跟 reference to const 同義。
  • undefined
    Usage for which the language does not specify a meaning. Knowingly or unknowingly relying on undefined behavior is a great source of hard-to-track runtime errors, security problems, and portability problems.(例如給 unsigned char 賦值 256)
  • word
    The natural unit of integer computation on a given machine. Usually a word is large enough to hold an address. On a 32-bit machine a word is typically 4 bytes.

2020年7月11日 星期六

讀書心得 - C++ Primer (5th Edition) - Chapter 2 (3) - Type Aliases



Type Aliases

    創造資料型態的同義詞,通常是用 typedef 來去實現。
    typedef double wages;   // wages is a synonym for double
    typedef wages base, *p; // base is a synonym for double, p for double*

auto

    寫程式常會有想要一個 variable 去儲存 expression 的運算結果,但要事先知道 expression 的最終資料型態非常困難。所以有 auto 這個特別的資料型態,讓編譯器決定其資料型態,但相對的 variable 一定要 initialize。
    auto item = val1 + val2; // item initialized to the result of val1 + val2
    因為 auto 一次只能當一個資料型態,所以在宣告時如果是用 ", " 分開的複數宣告,資料型態要一致。
    auto i = 0, *p = &i;      // ok: i is int and p is a pointer to int
    auto sz = 0, pi = 3.14;   // error: inconsistent types for sz and pi
    auto 與 const 的互動,基本上 auto 會忽視 top level const ( 物件本身為 const )。
    const int ci = i, &cr = ci;
    auto b = ci;       // b is an int (top-level const in ci is dropped)
    auto c = cr;       // c is an int (cr is an alias for ci whose const is top-level)
    auto d = &i;       // d is an int*(& of an int object is int*)
    auto e = &ci;      // e is const int*(& of a const object is low-level const)
    若想要個 top level auto const,你只能在 auto 前加 const 修飾詞。
    const auto f = ci; // deduced type of ci is int; f has type const int

decltype()

    不同於 auto,decltype() 可以不用去計算 expression,只讓編譯器去分析其資料型態。下面程式碼,編譯器不會呼叫 f(),而是去檢查 f() 的 return 資料型態去給予 sum。
    decltype(f()) sum = x;     // sum has whatever type f returns
    decltype() 也可以與 top level const 互動。
    const int ci = 0, &cj = ci;
    decltype(ci) x = 0;     // x has type const int
    decltype(cj) y = x;     // y has type const int& and is bound to x
    decltype(cj) z;         // error: z is a reference and must be initialized
上一篇 :

2020年7月9日 星期四

讀書心得 - C++ Primer (5th Edition) - Chapter 2 (2) - Const



修飾詞 : Const

    如果我們想要一個不可被改變的參數,這時就會需要這個修飾詞 ( Qualifier ) const。
    const int bufSize = 512;  // input buffer size
    bufSize = 1024;           // error: attempt to write to const object

Const + Reference

    Const + Reference 代表 Reference to const,等於你不能使用這個 Reference 去改變物件。沒有 const 修飾詞 ( plain object ) 的 reference 不可以 bind 有 const 修飾詞的物件,但反之有 const 修飾詞的 reference 可以 bind 無 const 修飾詞的物件。
    int i = 1;
    const int &r = i;  // we can bind a const int& to a plain int object
    i = i + 1;         // "r" will be 2 too.
    r = r + 1;         // error: assignment of read-only reference "r"
    int &j = r;        // error: binding ‘const int’ to reference of type ‘int&’ discards qualifiers

Const + Pointer ( const type * var )

    跟 Reference 一樣 Pointer to const,等於你不能使用這個 Pointer 去改變物件。沒有 const 修飾詞 ( plain object ) 的 Pointer 不可以 bind 有 const 修飾詞的物件,但反之有 const 修飾詞的 Pointer 可以 bind 無 const 修飾詞的物件。
    const double pi = 3.14;     // pi is const; its value may not be changed
    double *ptr = &pi;          // error: ptr is a plain pointer
    const double *cptr = &pi;   // ok: cptr may point to a double that is const
    *cptr = 42;                 // error: cannot assign to *cptr

Const + Pointer ( type * const var )

    但 Pointer 跟 Reference 不一樣,本身也是物件,所以可以 const pointer。const pointer 則必須被 initialized。但因為是 const pointer 而不是 const 指向物件,所以可以用 const pointer 去改變物件。
    int numb = 0;
    int * const cptr1 = &numb;  // cptr1 will always point to numb
    int * const cptr2;          // error: uninitialized const 'cptr2'
    *cptr1 = 5;                 // numb will be 5 too.

top-level/lower-level const

    像 pointer 的 const 就有兩種,所以稱 const pointer object 這種本身為 top-level,稱 point to const 這種為 lower-level。
    int i = 0;
    int *const p1 = &i;       // we can't change the value of p1; const is top-level
    const int ci = 42;        // we cannot change ci; const is top-level
    const int *p2 = &ci;      // we can change p2; const is low-level
    const int *const p3 = p2; // right-most const is top-level, left-most is not
    const int &r = ci;        // const in reference types is always low-level

constexpr ( constant expression )

    constant expression 等於 expression 不能被改變,也就等於這個 expression 必須在編譯時期就可以被計算出來。以下為 constant expression 的例子。
    const int max_files = 20;        // max_files is a constant expression
    const int limit = max_files + 1; // limit is a constant expression
    int staff_size = 27;             // staff_size is not a constant expression
    const int sz = get_size();       // sz is not a constant expression
    int i; 
    const int size1 = i; 
    constexpr int size2 = i;      // error: the value of ‘i’ is not usable in a constant expression
    constexpr int mf = 20;        // 20 is a constant expression
    constexpr int limit = mf + 1; // mf + 1 is a constant expression
    constexpr int sz = size();    // ok only if size is a constexpr function
    constexpr 跟 pointer 的作用
    const int *p = nullptr;       // p is a pointer to a const int
    constexpr int *q = nullptr;   // q is a const pointer to int
相關文章 :
上一篇 :
下一篇 :

2020年7月3日 星期五

讀書心得 - C++ Primer (5th Edition) - Chapter 2 (1) - Primitive Types



C++ 原生內建的資料型態 ( Primitive Types )

    C++ 定義了一些算術用的資料型態 ( Arithmetic Types ) 和一個特殊的資料型態 void。Arithmetic Types : Integer, Character, Boolean, Floating Point, Double Floating Point, Wide Character。

    下面為一些資料型態轉換 :
    bool b = 42;            // b is true
    int i = b;              // i has value 1
    i = 3.14;               // i has value 3
    double pi = i;          // pi has value 3.0
    unsigned char c = -1;   // assuming 8-bit chars, c has value 255
    signed char c2 = 256;   // assuming 8-bit chars, the value of c2 is undefined

Initialization

    各種初始 :
    int units_sold1 = 0;
    int units_sold2 = {0};
    int units_sold3{0};
    int units_sold4(0);
    {} 跟 () 的不同 :
    long double ld = 3.1415926536;
    int a{ld}, b = {ld};    // error: narrowing conversion required
    int c(ld), d = ld;      // ok: but value will be truncated

Declaration 跟 Definition

    為了支援多個檔案的編譯,cpp 區分了 Declaration 跟 Definition。Declaration 代表著跟整個程式宣告一個帶有資料型態的名子,任何檔案都可以去作存取。Definition 則是創造一個物件實體去對應那個帶有資料型態的名子。
    如果想要只宣告名子(代表實際物件會被在其他檔案給實現),則會在宣告時加上 extern,有了 extern 就代表你不能下 Definition。
    extern int i;              // declares but does not define i
    int j;                     // declares and defines j
    extern double pi = 3.1416; // error: ‘pi’ has both ‘extern’ and initializer

Compound Types - References

    Reference 等於創造額外的一個名子給一個物件。所以下面第 refVal2, refVal4 會 error,因為你不能給不存在的物件 ( 或 rvalue ) 取名。References must be initialized.
    int ival = 1024;
    int &refVal = ival;     // refVal refers to (is another name for) ival
    int &refVal2;           // error: a reference must be initialized
    int &refVal3 = refVal;  // ok: refVal3 is bound to the object to which refVal is bound, i.e., to ival
    int &refVal4 = 10;      // error: initializer must be an object

Compound Types - Pointers

    Pointer為一個 "指向" 物件。類似 References 但卻是一個物件,所以可以不用被 initialized,也可以用來複製、分配。下面的 & 是作為 operator,用來取物件的實際位置,與上面提到用來宣告資料型態的的 & 有著不同的意義。
    double dval;
    double *pd = &dval; // ok: initializer is the address of a double
    double *pd2 = pd;   // ok: initializer is a pointer to double
    int *pi = pd;       // error: types of pi and pd differ
    pi = &dval;         // error: assigning the address of a double to a pointer to int
    下面的 * 作為 operator,放在 pointer 前面等於取其指向的該物件
    *p = 0;             // * yields the object; we assign a new value to ival through p
    std::cout << *p;    // prints 0

更多 References & Pointers 範例

    double dval;
    double *pd = &dval;  // ok: initializer is the address of a double
    double *pd2 = pd;    // ok: initializer is a pointer to double
    int *pi = pd;        // error: types of pi and pd differ
    pi = &dval;          // error: assigning the address of a double to a pointer to int

    int i = 42;
    int &r = i;          // & follows a type and is part of a declaration; r is a reference
    int *p;              // * follows a type and is part of a declaration; p is a pointer
    p = &i;              // & is used in an expression as the address-of operator
    *p = i;              // * is used in an expression as the dereference operator
    int &r2 = *p;        // & is part of the declaration; * is the dereference operator
相關文章 :
上一篇 :
下一篇 :

2020年6月14日 星期日

讀書心得 - C++ Primer (5th Edition) - Chapter 1

簡單的 C++ 程式

    要寫一個 C++ 程式跟 C 一樣,寫好 cpp 檔,交給編譯器 ( g++ ) 編成可執行程式。程式至少包含一個名為 main 的 function,用以當作程式的入口 function。
    int main() {
        return 0; // return 0 的原因為 0 通常代表著程式執行成功。
    }

Input/Output

    C++ 本身並沒有定義 I/O,需要額外的標準函式庫,iostream。
    #include <iostream>
    int main()
    {
        // operator << >> 會回傳左邊的 operand
        // 以 std::cin >> v1 >> v2; 為例
        // 執行結果 =
        //     std::cin >> v1;
        //     std::cin >> v2;
        int v1, v2;
        std::cout << "Enter two numbers:" << std::endl;
        std::cin >> v1 >> v2;
        std::cout << "The sum of " << v1 << " and " << v2 << " is " << v1 + v2 << std::endl;
        return 0;
    }

Note

常用詞彙

  • prompt 提示 驅使

    We can extend our main program to prompt the user to give us two numbers and then print their sum

  • expression (數學中的)式,表達式

    The smallest unit of computation. An expression consists of one or more operands and usually one or more operators. Expressions are evaluated to produce a result. For example, assuming i and j are ints, then i + j is an expression and yields the sum of the two int values.

  • angle brackets : <>

  • quotation marks : ""

  • curly braces : {}

  • operator : 運算子

  • operand : 運算元

  • assignment

    Obliterates an object’s current value and replaces that value by a new one.

  • comments : 註解

  • statement : wiki

    The new part of this program is the while statement.A while has the form

    while (condition)
        statement

    A while executes by(alternately) testing the condition and executing the associated
    statement until the condition is false.A condition is an expression that yields a result
    that is either true or false..So long as condition is true, statement is executed.
下一篇 :

2020年1月6日 星期一

讀書心得 - Clean Code - Chapter 5

Chapter 5 - 編排

報紙的啟發


    希望原始檔要跟報紙一樣,從上而下閱讀。上方會有頭條的敘述,讓你理解這段報導在談論些什麼,讓你可以決定如何閱讀。第一段通常會是整篇報導的概要,細節資訊會被隱藏。然後你在持續往下閱讀才會發現所有細節。

    然後報紙本身也不會太長,所以原始檔盡量維持最多 200 ~ 500 行。
    垂直空白區隔
    每一個空白行會對眼睛下一個提示,讓其注意空白行後的第一行。通常用在一個概念接續另新的概念。
    垂直密度
    相依的函式盡量緊靠。
    垂直順序
    跟報紙一樣,應該是高層模組到低層模組。
    水平的空白間隔
    水平空白去強調運算子,下面是用空白強調加減法,以及乘法有較高的優先權所以沒有空白。
     public class Quadratic {
          public static double root1(double a, double b, double c) {
               double determinant = determinant(a, b , c);
               return (-b + Math.sqrt(determinant)) / (2*a);
          }
  
          public static double root2(double a, double b, double c) {
               double determinant = determinant(a, b , c);
               return (-b - Math.sqrt(determinant)) / (2*a);
          }
  
          private static double determinant(double a, double b, double c) {
               return b*b - 4*a*c;
          }
     }

上一篇:
讀書心得 - Clean Code - Chapter 4

2019年12月4日 星期三

讀書心得 - Clean Code - Chapter 4

Chapter 4 - 註解

不要替糟糕的程式碼寫註解 - 重寫它


    註解為必要之惡,用來彌補我們用程式碼表達意圖失敗的狀況。註解在絕大多數的情況無法跟著程式演進,導致過時且偏離當初的程式碼解釋。最後的真相只會存於程式碼。

有益的註解

    法律型的註解
    // Copyright 2011-2019 The Bootstrap Authors
    // Copyright 2011-2019 Twitter, Inc.
    資訊型註解
    資訊型註解提供一些基本資訊,但還是很容易被好的程式碼命名給取代
     // Returns an instance of the Responder being tested.
     protected abstract Responder responderInstance();
    對意圖的解釋
     // This is our best attempt to get a race condition
     // by creating large number of threads.
    對後果的告誡
     // Don't run unless you
     // have some time to kill

     // SimpleDateFormat is not thread safe,
     // so we need to create each instance independently

上一篇:
讀書心得 - Clean Code - Chapter 3 (2)
下一篇:
讀書心得 - Clean Code - Chapter 5

2019年12月3日 星期二

讀書心得 - Clean Code - Chapter 3 (2)

Chapter 3 - 函式 - 2

使用具描述能力的名稱


    不要害怕名字過長,若取了有性質的函式名稱就較能符合「當每個你看到的函式,執行結果都與你想的差不多代表為 Clean Code」

函式的參數


    函式的參數越少越好,因為參數的存在也會影響著你對函式的預期,所以最理想的情況為 0 參數。
    一個參數
  1. 與這個參數有關的問題  - boolean fileExits("Myfile")
  2. 對這個參數做某種操作,然後回傳 - InputStream fileOpen("Myfile")
  3. 事件,利用參數去修改系統狀態 - passwordAttemptFailedNtimes(int attempts)
    第三種命名要特別小心,要明確的表示出此函式為事件。若參數為 flag 那你要知道此為很爛的作法,flag 就代表 True 要做一件事,False 要做一件事,違反了只做一件事的原則。
    兩 ~ 三個參數
    兩個參數影響函式的預期就更多,所以可以轉成一個參數就好好利用。
    物件型態的參數、參數串列
    利用物件型態或陣列去減少參數個數是不錯的方法
    Circle makeCircle(double x, double y, double radius);
    Circle makeCircle(point center, double radius);

指令和查詢的分離


    如果函式除了做某件事情後,還回傳了某個問題的答案,就等於做兩件事
    public boolean set(String attribute, String value);
    if(set("username", "unclebob"))...
    所以讀者看到此段 if 會容易產生誤解且疑惑,所以要將查詢與指令分開
    if(attributeExists("username")){
        setAttribute("username", "unclebob");
        ...
    }
    利用例外處理取代回傳錯誤碼
    錯誤處理本身就是一件事

Don't Repeat Yourself


   n 個重複的程式碼,代表修改要花 n 倍時間。

上一篇:
讀書心得 - Clean Code - Chapter 3 (1)
下一篇:
讀書心得 - Clean Code - Chapter 4

Popular Posts