陣列與字串


  1. 陣列與指標
    1. 陣列變數設定初始值的語法:
                  int x[5] = { 2, 3, 5, 7, 11 };      或簡寫成:
                  int x[]  = { 2, 3, 5, 7, 11 };
              
      

    2. 陣列的名字單獨寫時, 相當於最前面那個元素的位址. 例: 若有 int dm[13];dm& dm[0] 有相同的意義.
      Q: 有沒有那一個盒子的名字叫做 dm?
    3. 指標變數或陣列名稱與整數相加的意義: dm+5 相當於 & dm[5], 也就是說 dm[5] 相當於 * (dm+5) 同樣地, 若有 int *p; 則 p[k]*(p+k)意義完全相同.
    4. 注意: 因為在 C/C++ 當中, 所有的變數都必須宣告型別, 所以 C compiler 可以自動推算指標變數加一時, 真正的樓層數應該移動多少. 上例中若 dm 在第 0x2f4c 層, 則 dm+1 為第 0x2f50 層; 但若當初宣告為 char dm[13]; 則 dm+1 為第 0x2f4d 層.
    5. Q: 在 a[b] 一式中, a 與 b 各扮演 ?-value 的角色?
    6. 作業: 請做 address.c 當中的作業 3
    7. 作業: 假設有下列宣告及程式片段
                      int tab[10], *p, *q, *r, x;
                      p = tab;
                      q = &x;
                      r = &tab[2];
              
      

      則我們總共要來了幾個盒子可以用? 並解釋以下各程式片段的作用 (圖示?)
                      ++x             ++&x            
                      ++*(tab+3)      ++(tab+3)
                      ++p[1]          ++*p
                      ++(q+2)         ++*(q+2)
                      ++r             ++r[3]
              
      

    8. 作業:
      1. 把 randwalk.c 當中四處走動的遊標改成四處走動的蠶寶寶. 第一個版本先不考慮身體打結的狀況. 再加入測試條件避免身體打結 (但是既不可以打結, 又不可以走回頭路, 還要避免撞牆, 有沒有甚麼情況會卡住呢?)
      2. 修改蠶寶寶程式, 讓螢幕上同時出現 n 隻. 不要管彼此穿越了.
      3. 寫一個簡單的 game of life
    9. 高維陣列: 採 row major 儲存方式. 例如:
                  int x[2][3] = {
                      { 1, 2, 3 },
                      { 4, 5, 6 }
                  };
              
      

              x[0]   == &x[0][0]      x[0]+1 == &x[0][1]      x[0]+2 == &x[0][2]
              x[0]+3 == &x[1][0]      x[0]+4 == &x[1][1]      x[0]+5 == &x[1][2]
              
      

  2. 字串
    1. 字串不過是字元的陣列而已. 約定俗成: 每個字串的最後一個字元必須是 '\0' (ASCII 碼為零的那個字元) 例:
                  char s[8];
                  s[0] = 'h';   s[1] = 'e';   s[2] = 'l';
                  s[3] = 'l';   s[4] = 'o';   s[5] = '\0';
              
      

      Q: 如果當初宣告 s 為 char *s; 會有什麼問題?
    2. 初始值的設定: 上例可簡寫為:
                  char s[8] = { 'h', 'e', 'l', 'l', 'o', '\0' };      又可簡寫為:
                  char s[8] = "hello";
              
      

    3. Q: 仔細研究主程式的 prototype: int main(int argc, char *argv[]); 如果使用者在命令列上輸入: a.out hello world good morning 請問下列各式的型別各是什麼, 值各是多少? (畫圖表示)
                      (argv+1)[2]     argv[1]+2       argv[1][2]
                      *argv+1+2       *(argv+1)+2     *(argv+1+2)
                      *(argv+1)[2]    *(argv[1]+2)    (*argv+1)[2]
              
      

    4. 特殊語法: 字元指標的初始值設定:
                  char * p = "hello";
              
      

      系統會安排一塊可讀不可寫的空間存放 "hello", 並將那塊空間的起始位址存放到 p 裡面. 建議寫成:
                  char const * p = "hello";
              
      

    5. 一般規則: string literal 單獨寫時, 系統會安排一塊可讀不可寫的空間存放該字串, 並傳回那塊空間的起始位址. (例外: 字元陣列的初始值設定)
    6. C 不允許將一個陣列以 "=" 直接拷貝到另一個陣列. 如果要拷貝字串, 必須呼叫系統函數: strcpy(s, "hello");
    7. 傳遞參數時, 副程式期待它的實際參數扮演 r-value 的角色: 假設有
                  char s[8], t[8];
                  char * p, * q;
                  p = s;
                  q = t;
              
      

      strcpy(p, "hello");strcpy(s, "hello"); 的效果相同. Q: strcpy(p+1, q+2) 有何效果?
    8. 作業: 學習使用 string.h 中宣告的 strcpy, strcat, strlen, strcmp, strchr, strrchr, strstr 等函數. 例: strcmp("save earth", "save earth ") == ? 又, 若
                      char s[20] = "hello, ";
                      char t[20] = "world!";
              
      

      則 strcpy(s, t) 之後, printf("%s\n%s\n", s, t) 印出?
      而 strcat(s, t) 之後, printf("%s\n%s\n", s, t) 印出?
    9. 空字元/空指標/空字串的分別:
      1. 空字元: '\0' 這個 ASCII 碼為零的字元. 例: char c = '\0';
      2. 空指標: 0x0000 這個位址. 例: char * p = NULL; 注意: NULL 的定義可在 stdio.h 或 stdlib.h 中找到, 其實只是 0, 但是應該把 NULL 當做指標看, 而不要把 NULL 當做數字來看.
      3. 空字串: 程式可以使用的字元陣列, 但是只包含一個字元 -- 空字元. 例: char s[8] = "";
    10. Q: 假設有上面的宣告, 則以下各式的運算結果各為 True 或是 False? 還是會有 Compile time error 或是 Run time error?
                      p==NULL         p=='\0'         p==""
                      s==NULL         s=='\0'         s==""
                      *p==NULL        *p=='\0'        *p==""
                      *s==NULL        *s=='\0'        *s==""
              
      

    11. 作業: 寫一個函數 my_strcmp 模擬 strcmp, 並且寫主程式從命令列接受兩個字串參數, 印出 strcmp 的比較結果與 my_strcmp 的比較結果. 注意邊界狀況 (boundary conditions), 例如輸入的字串如果是空指標/空字串等等.