目前分類:c++基礎 (17)

瀏覽方式: 標題列表 簡短摘要
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];
                                               }

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

C/C++ 上陣列有兩個主要的特性:

1、配置存放陣列元素的記憶體(需要知道陣列『元素個數』還有『元素型態』才能實現)

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

輸出資料至檔案:

#include <stdio.h>

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

<<運算子重載:

#include <iostream>

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

迭代器必有的操作:

operator++:移動到下一個元素

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

  • Jan 24 Fri 2014 15:51
  • 模板

函式模板:

template<class T>

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

複製建構式:

複製建構式是以同型物件作為參數的建構式,對 Grade 類別而言, Grade(const Grade&)就是他的複製建構式:

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

C++援運算子多載 (operator overloading) 允許自定義型態的運算子行為:

class Grade {

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

建構:

1.建構式在類別定義中看起來是個「名稱與類別相同」且「沒有回傳值資料型態」的函式。

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

  • Jan 24 Fri 2014 14:02
  • 函式

函式傳值:

一般呼叫函式時會額外配置函式參數和回傳值的空間,會造成:

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

 

1.參考 (type &):C++ 才有

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

extern:
1.extern聲明變數在其它位置被定義(型式像:extern double someVar),這個位置可能是在同一份文件之中,或是在其它文件之中。
2.extern聲明變數在其它位置被定義,如果使用extern時同時指定其值會造成重覆定義,例如:extern double someVar = 2000;(錯誤),必須先聲明extern找到變數,再指定其值,例如:extern double someVar; someVar = 2000

static
經static修飾的成員變數或成員函式屬於該類別而不是個別物件,所以可以直接使用類別名稱去存取。

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

指標:
1.指標運算上加 1 ,表示前進一個資料型態的記憶體長度,例如在int型態的指標上加1,表示在記憶體位址上前進4個位元組的長度,如果宣告double型態的指標,則每加 1就會前進8個位元組。
2.陣列名稱用來指向陣列第一個元素的記憶體位址,所以陣列arr與&arr[0]所指向的位置是相同的。
3.如果我們將指標ptr指向一個陣列,然後對這個指標作加法,與陣列索引[ ]的意義相同,例如&arr[1]=ptr+1。   
4.如果想要儲存指標的位址,可以使用雙重指標,例如:int **ptr2 = &ptr;

參考:

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

字元陣列操作:
1.字串初始化:
1-1.字串是由字元所組成的陣列,並在最後加上一個空字元'\0',例如:char str[ ] ={'h','e', 'l', 'l', 'o', '\0'}。
1-2.可以用char str[ ] = "hello"的方式來宣告。
1-3.不可以用char str[80]; str = "Just";的方式來宣告,要一個字元一個字元指定至陣列中,並在最後加上空白字元,例如:
    char str[80]; 
    str[0] = 'J';     str[1] = 'u';     str[2] = 's';     str[3] = 't';     str[4] = '\0';
2.可以直接使用字串名來輸出,例如:cout << str << endl;
3.字串是字元陣列,所以可以使用陣列的存取方式取出每一個字元,空字元在作條件判斷時會被視為0。
4.字元陣列可用函式:
4-1.strcpy(str1, str2):str2字串複製給str1字串
4-2.strcat(str1, str2):str2字串串接在str1字串後 
4-3.strlen(str):計算不含空字元的字串長度
4-4.strcmp(str1, str2):比較兩個字串(若相同傳回0,str1較大則傳回大於0的值,較小則傳回小於0的值)
5.字元陣列為陣列一種,所以無法將字串指定給另一個字串,也無法對兩個字串進行串連的動作,例如:
    char str1[] = "text1";
    char str2[] = "text2";
    str1 = str2; (錯誤)
    char str3[] = str1 + str2; (錯誤)

字元指標:
1.字元指標在字串指定操作時較方便,例如字元指標可以(字元陣列不行):
    char *str = "hello";
    str = "world";
2.上述的"hello"與"world"各佔有一塊記憶體空間,兩者指向的記憶體位址不相同。
3.也可以在字元指標中使用陣列,例如char *str[ ]={"Michael","Jeff","Tino"},其中str[1]="Michael"。

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

1.如果有使用動態陣列,必須含入標頭檔 -> #include <vector>
2.vector的建構:
2-1.vector<int> ivector(10),算術相關型態初始為0,指標型態也初始為0(表示不指向任何位址)。
2-2.vector<int> ivector(10, 5),宣告ivector有10個元素,每個元素值初始皆為5。
2-3.可以使用另一個vector來建構,例如:vector<int> ivector2(ivector1)。
2-4.可以使用 operator= 來初始vector,例如:vector<int> ivector2 = ivector1。
2-5.可以使用另一個陣列來建構,要指定的是元素的起始位址與最後一個元素的下一個位址例如:int iarr[]={1,2,3};  vector<int> ivector(iarr,iarr+3);
2-6.可以建構一個元素為空的vector物件,例如:vector<int> ivector。
3.可以使用size()查詢vector的元素長度,或是使用empty()測試長度是否為0。
4.如果打算將元素放入vector中,可以使用push_back(),例如:

for(int i = 0; i < 5; i++) {ivector.push_back(i);}

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

  • Jan 23 Thu 2014 23:50
  • 陣列

1.靜態陣列長度必須事先決定,不可以使用變數來事後決定陣列的長度。
2.宣告陣列時,對於陣列中尚未決定的值,整數陣列的元素會被初始為0,浮點數陣列會被初始為0.0,字元陣列則會被初始為空字元('\0'),而boolean數陣列則會 被初始為false,在宣告陣列時初始陣列元素,可以避免其它的程式存取到非預期的數值。 
3.可以將陣列名稱想成一個指標,指向陣列第一個元素的位址。
4.索引值表示所指陣列元素相對於陣列第一個元素的位移量,位移的量與資料型態長度有關,如果是int整數,則每次位移時是一個int整數的長度,例如iarr[9]就是指相對於第一個元素的位移量為9,C++根據陣列第一個元素的記憶體位置與位移量來得到所指定要存取的陣列元素。
5.不可以將陣列直接指定給另一個陣列,或是直接比較兩個陣列是否相同,例如:

           int arr1[5];

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

1.switch:
    switch (變數名稱或運算式) { 
        case 符合數字或字元: 
            陳述句一; 
            break; 
        case 符合數字或字元: 
            陳述句二; 
            break; 
        default: 
            陳述三; 
    }

2.break:

         break可以離開switch、for、while、do while的區塊,然後前進至下一個陳述句,在switch中用來結束陳述句進行至下一個case的比對,在for、while與do while中,用於停止迴圈執行,並跳至迴圈後的陳述句,如果break出現並不是內含在for、while迴圈中或switch陳述中,則會發生編譯錯誤。ex:
    for(int i = 1; i < 10; i++) { 

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