close
1.    不可以提取不知指向何方的指標(指標變數必需先指向某個可以合法操作的   
    空間,才能進行操作)
    錯誤例子:char *pc1;      /* 未給予初值,不知指向何方 */
                   char *pc2 = 0;  /* pc2 起始化為 null pointer */
                   *pc1 = 'a';     /*  'a' 寫到不知何方,錯誤 */
                   *pc2 = 'b';     /*  'b' 寫到「位址0」,錯誤 */
    正確例子:char c;          
                   char *pc1 = &c;  
                  *pc1 = 'a';      /* c 的內容變為 'a' */
    錯誤例子:char *name;   /* name 尚未指向有效的空間 */
                   printf("Your name, please: ");
                   gets(name);   /* 您確定要寫入的那塊空間合法嗎??? */
                   printf("Hello, %s\n", name);
    正確例子(如果編譯期就能決定字串的最大空間用char[])
    char name[21];  /* 讀入字串最長 20 個字元,保留一格空間放 '\0' */
    printf("Your name, please: ");
    gets(name);
    printf("Hello, %s\n", name);
    (若是在執行時期才能決定字串的最大空間,則需利用動態分配空間) 
    size_t length;
    char *name;
    printf("請輸入字串的最大長度(null字元): ");
    scanf("%u", &length);
    name = (char *)malloc(length);
    printf("Your name, please: ");
    scanf("%s", name);
    printf("Hello, %s\n", name);
    free(name);
2. 不要試圖用 char* 去更改一個"字串常數"
    char* pc = "john";   /* pc 現在指著一個字串常數 */
    *pc = 'J';   /* 但是 pc 沒有權利去更改這個常數! */
    說明:字串常數的內容是"唯讀"的,有使用權但沒有更改的權利,若希望使    
    用可以更改的字串,需將其放在合法空間。
    錯誤例子(strcat()不會另行配置空間,只將資料附加到 s1 所指唯讀字串   
    的後面,會寫入到程式無權碰觸的記憶體空間)
    char *s1 = "Hello, ";
    char *s2 = "world!";
    strcat(s1, s2);
   正確例子:char s1[20] = "Hello, ";
             char *s2 = "world!";
             strcat(s1, s2);
3. 不能在函式中回傳一個指向區域性自動變數的指標(區域變數在離開該區域
   時被消滅,因此呼叫端得到的指標所指的字串內容失效了,但如果指標內容
   是用動態的方式配置,這塊空間是在heap而非stack上,heap空間不會自
   動回收,因此這塊空間在離開函式後依然有效,但要記得free掉記憶體)
   錯誤例子:char *getstr(char *name){
                  char buf[30] = "hello"; 
                  strcat(buf, name);
                  return buf;
                  }
    正確例子:void getstr(char buf[], int buflen, char *name){
                   char s[] = "hello";
                   strcpy(buf, s);
                   strcat(buf, name);
                   }
    正確例子:int* foo(){
                   int* pInteger = (int*) malloc( 10*sizeof(int) );
                   return pInteger;
                   }
4. 在一個運算式中,不能對一個基本型態的變數修改其值超過一次以上(C/C++ 
   並沒有強制規定參數會由哪個方向開始處理(不像Java是由左到右),因此可
   能會造成與預期不符的情況)
    錯誤例子:int i = 7;
                   int j = ++i + i++;
    正確例子:int i = 7;
                   int j = ++i;
                   j += i++;
    錯誤例子:x = x++;
    錯誤例子:int arr[5];
                   int i = 0;
                   arr[i] = i++;
    正確例子:int arr[5];
                   int i = 0;
                   arr[i] = i;
                   i++;
    錯誤例子int Integer=10;
                   printf("%d %d %d", Integer++, Integer++, Integer++);
    錯誤例子void foo(int a, int b) { ... }
                   int main() {
                   int i=0;
                   foo(i++, i++);
                   }
5.  Macro 定義中, 務必為它的參數個別加上括號()
   錯誤例子:#define SQUARE(x)    (x * x)
   正確例子:#define SQUARE(x)    ((x) * (x))
   如果是用 C++,可利用inline function來取代上述的 macro,以免除 macro   
   定義的種種危險性。如:inline int square(int x) { return x * x; }
    macro 定義出的「偽函式」至少缺乏下列幾項函式本有的能力:
    (1) 無法進行參數型別的檢查。
    (2) 無法遞迴呼叫。
    (3) 無法用 & 加在 macro name 之前,取得函式位址。
6. 不可以在 stack 設置過大的變數(編譯器會自行決定 stack 的上限,可能是
    KB 或數十 KB,當變數所需的空間過大時,很容易造成 stack overflow
    程式亦隨之當掉,若真正需要如此大的空間,那麼建議配置在 heap 上,或
    是採用static / globla variabl)
    錯誤例子:int array[10000000];       
    正確例子:int *array = (int*) malloc(10000000*sizeof(int));
7. 不要猜想二維陣列可以用 pointer to pointer 來傳遞:
    void pass1DArray( int array[] );
    int a[10];
    pass1DArray( a );   /* 可以合法編譯,而且執行結果正確!! */
    事實上,編譯器會這麼看待
    void pass1DArray( int *array );
    int a[10];
    pass1DArray( &a[0] );
    二維陣列不能直接改成 int **
    錯誤例子void pass2DArray( int **array );
                   int a[5][10];
                   pass2DArray( a );  /* 這時候編譯器會報錯 */
    在一維陣列中,宣告了一個 a[10],那我可以把 a 當成指標來操作 *a 
    *(a+9),但是多維陣列無法如此使用。
    void pass2DArray(int (*array) [10]); // array 是個指標,指向 int [10]
    int a[5][10];
    pass2DArray( a );
8. 函式內 new 出來的空間記得要讓主程式的指標接住
    錯誤例子:void newArray(int* local, int size) {
                      local = (int*) malloc( size * sizeof(int) );
                  }
                  int main() {
                      int* ptr;
                      newArray(ptr, 10);
                  }
    原因如下:                                          
    1. int* ptr;                      ptr -> |__未知的空間__|
                                              ______________
    2. 呼叫函式 newArray              ptr -> |__未知的空間__| <- local
                                              ______________
    3. malloc 取得合法空間            ptr -> |__未知的空間__| 
                                              ______________
                                             |___合法空間___| <- local
                                              ______________
    4. 離開函式                       ptr -> |__未知的空間__|
    local接到了ptr指向的那個位置,接著函式內local要到了新的位置但是
    ptr指向的位置還是沒變的,因此離開函式後就好像事什麼都沒發生,嚴格
    說起來還發生了 memory leak
    以下是一種解決辦法:int* createNewArray(int size) {
                                      return (int*) malloc( size * sizeof(int) );
                                  }
                                  int main() {
                                      int* ptr;
                                      ptr = createNewArray(10);
                                  }
    如果是 C++可用 Referencevoid newArray(int*& local, int size) {
                                                  local = new int[size];
                                               }
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 阿洲 的頭像
    阿洲

    阿洲程式天地

    阿洲 發表在 痞客邦 留言(0) 人氣()