Se ha denunciado esta presentación.
Se está descargando tu SlideShare. ×
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Próximo SlideShare
C語言分支流程
C語言分支流程
Cargando en…3
×

Eche un vistazo a continuación

1 de 75 Anuncio

Más Contenido Relacionado

Similares a C語言陣列與字串 (20)

Anuncio

Más de 吳錫修 (ShyiShiou Wu) (20)

Más reciente (20)

Anuncio

C語言陣列與字串

  1. 1. 陣列與字串  陣列特性  ⼀維陣列  資料搜尋  資料排序  二維與多維陣列  字串與字元陣列  字串函數  指標運算  動態配置陣列 Revised on July 25, 2021
  2. 2. Make each day count  陣列資料結構 (array data structure),簡稱陣列 (Array),是由相同類 型資料的集合所組成的資料結構,分配⼀塊連續的記憶體來儲存。陣 列中的每筆資料稱為元素 (element),利用元素的索引 (index) 可以計 算出該元素對應的儲存位址  C 語言陣列的索引值是從 0 開始 陣列是什麼? 2 Element 0 Element 1 Element 2 Element 3 Element 4 索引 0 1 2 3 4 addr addr + datatype × 1 addr + datatype × 2 addr + datatype × 3 addr + datatype × 4
  3. 3. Make each day count  變數的目的是暫時儲存執行時所需的資料,當程式需要儲存大量相同 型別資料時 (5位學生的測驗成績),若個別以變數宣告,必須宣告 5 個 int 整數變數來儲存這5個成績: int quiz1 = 71; int quiz2 = 83; int quiz3 = 67; int quiz4 = 49; int quiz5 = 59;  上述程式碼宣告 5 個變數,5個數量還好,如果是⼀班 50 位學生的成 績,我們需要 50 個變數;如果⼀個公司有 500 位員工時,在程式中就 需要宣告大量變數,如此使得維護程式碼變得十分複雜  觀察上述測驗成績的 5 個變數,其擁有的共同特性:  變數的資料型態相同都是 int  變數有循序性,擁有順序的編號 1~5 陣列適用時機 1/2 3
  4. 4. Make each day count  我們可以將相同資料型別的 5 個 int 變數集合起來,使用⼀個名稱 quizzes 代表:  陣列如同是排成⼀列的箱⼦,每⼀個箱⼦可儲存⼀筆資料,稱為「元 素 (Element)」,以此例有 5 個元素,存取元素是使用「索引 (Index)」 值的順序 陣列適用時機 2/2 4 71 83 67 49 59 int quizzes[5] = {71, 83, 67, 49, 59}; 索引 0 1 2 3 4 5 個資料 初始值
  5. 5. Make each day count  「⼀維陣列 (one-dimensional arrays)」是最基本的陣列結構,只有⼀ 個索引值,類似班上學生的座號,可以使用座號取出學生資料  C 語言的陣列如同變數,在使用前也需要事先宣告;陣列宣告可以分 成三部分:陣列型別、陣列名稱和元素數:  陣列型別 陣列名稱[元素數]; int quizzes[5];  上述程式碼宣告 int 資料型態的陣列,陣列名稱是 quizzes,整數常數 5 表 示陣列有 5 個元素。陣列的元素數必須是整數常數。在宣告 5 個元素的陣 列後,相當於是宣告了以下 5 個變數: quizzes[0] quizzes[1] quizzes[2] quizzes[3] quizzes[4] 一維陣列 1/2 5
  6. 6. Make each day count  陣列索引  []中是索引 (index),因為從 0 開始,所以第 1 個元素是 quizzes[0],第 2 個元素是 quizzes[1],第 3 個元素是 quizzes[2],以此類推,最大索引值 是「元素數 - 1」,即「5 - 1 = 4」 一維陣列 2/2 6 quizzes[0] quizzes[1] quizzes[2] - - - - - quizzes[3] quizzes[4]
  7. 7. Make each day count  C 語言的陣列可以在宣告同時指定陣列初值,其語法如下:  陣列型別 陣列名稱[元素數] = {常數值, 常數值, … };  陣列是使用「=」等號指定陣列元素的初值,陣列值是使用大括號括起 的常數值清單,以「,」逗號分隔,⼀個值對應⼀個元素。例如: int quizzes[5] = {71, 83, 67, 49, 59}; 陣列的初值 7 quizzes[0] quizzes[1] quizzes[2] 71 83 67 49 59 quizzes[3] quizzes[4]
  8. 8. Make each day count  因為「=」等號後大括號中的初值數量就是元素數,所以,我們可以不 用指定陣列的元素數,因為它就是初值個數,如下所示: int quizzes[] = {71, 83, 67, 49, 59};  上述⼀維陣列宣告和之前完全相同,唯⼀差異就是沒有指定「[]」中的元 素數 printf("array elements = %d", sizeof(quizzes) / sizeof(int)); //5 以陣列的初值指定元素數 8
  9. 9. Make each day count  每⼀個陣列元素相當於是⼀個變數,我們可以如同變數⼀樣設定陣列 元素值 int quizzes[5]; quizzes[0] = 71; quizzes[1] = 83; quizzes[2] = 67; quizzes[3] = 49; quizzes[4] = 59; 指定陣列元素值 9
  10. 10. Make each day count  每⼀個陣列元素相當於是⼀個變數,也可如同⼀般變數⼀樣由鍵盤輸 入變數值 int n; printf("輸入小考次數:"); scanf("%d", &n); int i, quizzes[n]; printf("請輸入%d筆小考成績(整數值,數值間以空白鍵區隔):", n); for (i = 0; i < n; i++) scanf("%d", &quizzes[i]); 使用鍵盤輸入陣列元素值 10
  11. 11. Make each day count  陣列在宣告後,使用指定敘述指定陣列元素值,語法如下:  陣列名稱[索引] = 變數、運算式或常數值;  陣列索引值是從 0 開始 int n; printf("輸入小考次數:"); scanf("%d", &n); int i, quizzes[n], sum = 0; float average; printf("請輸入%d筆小考成績(整數值,數值間以空白鍵區隔):", n); for (i = 0; i < n; i++) { scanf("%d", &quizzes[i]); sum += quizzes[i]; //計算小考成績總和 } average = (float)sum / n; //計算小考平均成績 printf("小考平均成績為:%0.1f", average); 讀取陣列元素值 11
  12. 12. Make each day count  C 語言為了執行效率的考量,並不會檢查陣列索引值的範圍  如果存取的陣列元素超過陣列尺寸,即索引值大於陣列最大索引值 (元 素數 - 1),C 程式在編譯時並不會產生錯誤,也不會有任何警告,但 是,可能因為覆蓋或取得其他記憶體空間的值,而造成不可預期的執 行結果 陣列索引的範圍問題 12
  13. 13. Make each day count  搜尋 (Search) 就是在⼀堆資料中找出所要之特定資料。當資料量少時 很容易,當資料量龐大時,如何快速搜尋為⼀重要課題  循序搜尋法 (Sequential Search)  從第⼀個資料開始取出,依序⼀⼀與「目標資料」相互比較,直到找到所 要元素或所有資料均尋找完為止,此方法稱「循序搜尋」  優點  程式容易撰寫  資料不須事先排序 (Sorting)  缺點  搜尋效率比較差,平均次數 = (N + 1) / 2,每次都必須要從頭到尾逐筆 檢查 資料搜尋 1/4 13
  14. 14. Make each day count void sequential_search(){ int data[] = {3, 4, 1, 7, 6, 15, 9, 8, 12}; int i, fnum, n; n = sizeof(data) / sizeof(data[0]); printf("n輸入欲搜尋的整數:"); scanf("%d", &fnum); for (i = 0; i < n; i++) { if (fnum == data[i]) { printf("n%d在陣列元素data[%d]內", fnum, i); break; } } if (i == n) printf("n%d資料不在陣列中", fnum); } 資料搜尋 2/4 14
  15. 15. Make each day count  二分搜尋法 (Binary Search)  如果資料已先排序過,則可使用二分法來進行搜尋  二分法是將資料分成兩部份,再將鍵值與中間值比較,如鍵值相等則找到, 小於再比前半段,大於再比後半段。如此,分段比較至找到或無資料為止  優點:搜尋效率佳,平均次數 = log2 N  缺點  資料必需事先排序  檔案資料必需使是可直接存取或隨機檔 資料搜尋 3/4 15
  16. 16. Make each day count void binary_search(){ int data[] = {1, 3, 4, 6, 7, 8, 9, 12, 15}; int i, n, fnum, high, low, middle; n = sizeof(data) / sizeof(data[0]); low = 0, high = n; middle = (low + high) / 2; //搜尋中間位 printf("n輸入欲搜尋的整數:"); scanf("%d", &fnum); do { if (data[middle] == fnum) { //找到資料 printf("n%d在陣列元素data[%d]內", fnum, middle); break; } else if (fnum < data[middle]) high = middle - 1; //搜尋左半部 else low = middle + 1; //搜尋右半部 middle = (low + high) / 2; //更新中間位置 } while(low <= high); if (low > high) printf("n%d資料不在陣列中", fnum); } 資料搜尋 4/4 16
  17. 17. Make each day count  排序是指將多筆資料以某⼀鍵值,重新排列資料順序,使資料由大到 小遞減方式或由小到大遞增方式排列  排序演算法有很種,以下介紹  泡沫排序法 (Bubble Sorting)  插入排序法 (Insertion Sorting)  選擇排序法 (Select Sorting)  希爾排序法 (Shell Sorting) 資料排序 1/17 17
  18. 18. Make each day count  泡沫排序法 (Bubble Sorting)  由未排序中的第⼀筆開始,與第二筆資料比對。若第⼀筆大於第二筆則資 料交換 (Swap),若還有未排序的資料,則用第二筆和第三筆資料比對,依 此類推  執行時,未排序資料中的最大值會如同氣泡般往右跑  若未排序的資料中,比對時都沒有進行交換,代表資料已排序好,則提早 結束排序 資料排序 2/17 18 26 62 2 12 39 5 26 62 2 12 39 5 26 2 62 12 39 5 26 2 12 62 39 5 26 2 12 39 62 5 第一循環 26 2 12 39 5 62
  19. 19. Make each day count void bubble_sort() { int data[] = {26, 62, 2, 12, 39, 5}; int i, j, k, temp, n, flag; n = sizeof(data) / sizeof(data[0]); printf("未排序資料n"); for (k = 0; k < n; k++) printf("%d ", data[k]); for (i = 0; i < n - 1; i++){ //n個數字排序,只用n-1回合 flag = 0; //每回合開始清除交換旗號 for (j = 0; j < n - i - 1; j++){ if (data[j] > data[j + 1]){ temp = data[j]; data[j] = data[j + 1]; data[j + 1] = temp; flag = 1; //表示發生過交換 } } printf("n第%d回排序結果n", i + 1); for (k = 0; k < n; k++) printf("%d ", data[k]); if (flag == 0) break; //此回合沒有發生交換,表示資料已排序 } 資料排序 3/17 19
  20. 20. Make each day count printf("n排序後資料n"); for (k = 0; k < n; k++) printf("%d ", data[k]); printf("n"); } 資料排序 4/17 20
  21. 21. Make each day count  插入排序法 (Insertion Sorting)  依序由未排序中的第二筆(正處理的值),插入到已排序中的適當位置  插入時由處理值位置開始向左比較,直到遇到第⼀個比處理值小的值, 再插入 (使得所有在處理值左側的數值都小於處理值)  比較時,若遇到的值比正處理的值大或相等,則將值往右移  資料:26, 62, 2, 12, 39, 5 資料排序 5/17 21
  22. 22. Make each day count void insert_sort(){ int data[] = {26, 62, 2, 12, 39, 5}; int i, j, k, temp, n; n = sizeof(data) / sizeof(data[0]); printf("未排序資料n"); for (k = 0; k < n; k++) printf("%d ", data[k]); for (i = 1; i < n; i++) { j = i; while (j > 0 && data[j - 1] > data[j]) { temp = data[j]; data[j] = data[j - 1]; data[j - 1] = temp; j--; } printf("n第%d回排序結果n", i); for (k = 0; k < n; k++) printf("%d ", data[k]); } 資料排序 6/17 22
  23. 23. Make each day count printf("n排序後資料n"); for (k = 0; k < n; k++) printf("%d ", data[i]); printf("n"); } 資料排序 7/17 23
  24. 24. Make each day count  選擇排序法 (Select Sorting)  由未排序中的第⼀筆開始,與第二筆資料比對。若第⼀筆大於第二筆則資 料交換(Swap),以使得較小的資料存放在第⼀個位置上  若還有未排序的資料,第⼀筆資料再與第三筆、第四筆…等資料比對,直 到第⼀循環全部比對完畢  第⼀循環後,第⼀筆資料就是所有資料中的最小值。第二循環則從第2筆 開始,依此類推 資料排序 8/17 24 26 62 2 12 39 5 26 62 2 12 39 5 2 62 26 12 39 5 2 62 26 12 39 5 2 62 26 12 39 5 第一循環
  25. 25. Make each day count void select_sort() { int data[] = {26, 62, 2, 12, 39, 5}; int i, j, k, temp, n; n = sizeof(data) / sizeof(data[0]); printf("未排序資料n"); for (k = 0; k < n; k++) printf("%d ", data[k]); for (i = 0; i < n - 1; i++){ for (j = i + 1; j < n; j++){ if (data[i] > data[j]){ temp = data[i]; data[i] = data[j]; data[j] = temp; } } printf("n第%d回排序結果n", i + 1); for (k = 0; k < n; k++) printf("%d ", data[k]); } 資料排序 9/17 25
  26. 26. Make each day count printf("n排序後資料n"); for (k = 0; k < n; k++) printf("%d ", data[k]); printf("n"); } 資料排序 10/17 26
  27. 27. Make each day count  希爾排序法 (Shell Sorting)  泡沫排序或插入排序,可能要進行多次的比較和交換才能將該數據移至正 確位置。而希爾排序會用較大的步⻑移動數據,所以小數據只需進行少數 比較和交換即可到正確位置  由大到小選定數個比對間距 (gap)  將資料依指定的 gap 分組,比較第 i 筆與第 i + gap 筆資料,若前者大於後 者,則交換前後資料  每⼀回合必須持續做到沒有發生資料交換 (No SWAP) 為止  調小 gap 值,重覆排序作業,直到 gap 為 1 為止 資料排序 11/17 27
  28. 28. Make each day count  Gap的選擇對執行效率有很大的影響  常見的Gap  Shell原本的Gap:N/2、N/4、...1 (反覆除以2)  Hibbard的Gap:1、3、7、...、2k-1  Knuth的Gap:1、4、13、...、(3k - 1) / 2  Sedgewick的Gap:1、5、19、41、109、...  範例:  假設資料為 45, 84, 77, 83, 55, 49, 91, 64, 91, 5, 37, 31, 70, 38, 51  Gap選用 5, 2, 1 資料排序 12/17 28
  29. 29. Make each day count  第⼀回合 Gap = 5  依Gap將資料分組,各組分別進行插入排序 (下⾯顏⾊相同者為同⼀組)  排序後  若將資料依Gap排列 (5個⼀列),可以發現每行(顏⾊相同者)的順序都是已 排好的 資料排序 13/17 29 45 84 77 83 55 49 91 64 91 5 37 31 70 38 51 37 31 64 38 5 45 84 70 83 51 49 91 77 91 55 37 31 64 38 5 45 84 70 83 51 49 91 77 91 55
  30. 30. Make each day count  第二回合 Gap = 2  依 Gap 將資料分組,各組分別進行插入排序 (下⾯顏⾊相同者為同⼀組)  排序後  若將資料依 gap 排列 (2個⼀列),可以發現每行(顏⾊相同者) 都是已排好的 資料排序 14/17 30 37 31 64 38 5 45 84 70 83 51 49 91 77 91 55 5 31 37 38 49 45 55 51 64 70 77 91 83 91 84 5 31 37 38 49 45 55 51 64 70 77 91 83 91 84
  31. 31. Make each day count  第三回合 Gap=1  排序後 資料排序 15/17 31 5 31 37 38 49 45 55 51 64 70 77 91 83 91 84 5 31 37 38 45 49 51 55 64 70 77 83 84 91 91
  32. 32. Make each day count #include <stdio.h> void shell_sort() { int data[] = {26, 62, 2, 12, 39, 5}; int i, j, k, tmp, n, gap, flag; n = sizeof(data) / sizeof(data[0]); printf("未排序資料n"); for (k = 0; k < n; k++) printf("%d ", data[k]); gap = n / 2; for( ; gap > 0; gap = gap / 2){ printf("ngap為%dn", gap); for(i = gap; i < n; i++){ //插入排序法 tmp = data[i]; for(j = i; j >= gap && tmp < data[j-gap]; j-=gap){ data[j] = data[j-gap]; } data[j] = tmp; for (k = 0; k < n; k++) printf("%d ", data[k]); printf("n"); } } 資料排序 16/17 32
  33. 33. Make each day count printf("n排序後資料n"); for (k = 0; k < n; k++) printf("%d ", data[k]); } 資料排序 17/17 33
  34. 34. Make each day count  ⼀維陣列可用來儲存學生⼀⾨課程的考試成績,使用二維陣列 (two- dimensional arrays),則可以同時儲存多⾨課程的考試成績  二維陣列宣告語法:  陣列型別 陣列名稱[列數][欄數];  上述語法宣告二維陣列,所以有 2 個「[]」,第1個「[]」表示二維陣列有 幾個橫列 (row);第 2 個「[]」行數,表示每⼀橫列有幾欄 (column),二 維陣列的元素個數是「列數×欄數」 二維陣列 1/2 34
  35. 35. Make each day count  ⼀班5位學生的考試成績資料,包含每位學生的國文和數學二⾨課程的 成績,可使用二維陣列來儲存 int quizzes[5][2]; //宣告5X2的二維陣列 二維陣列 2/2 35 quizzes[0][0] quizzes[1][0] quizzes[2][0] - - - - quizzes[3][0] quizzes[4][0] - - - - - quizzes[0][1] quizzes[1][1] quizzes[2][1] quizzes[3][1] quizzes[4][1]
  36. 36. Make each day count  宣告二維陣列的初值時也可使用「=」等號指定陣列元素的初值 陣列型別 陣列名稱[列數][行數] = { {第1列的初值}, {第2列的初值}, …, {第n列 的初值} }; int quizzes[5][2] = {{74, 56}, {37, 68}, {65, 83}, {72, 68}, {75, 87}}; 二維陣列的初值 36 quizzes[0][0] quizzes[1][0] quizzes[2][0] 74 37 65 72 75 quizzes[3][0] quizzes[4][0] 56 68 83 68 87 quizzes[0][1] quizzes[1][1] quizzes[2][1] quizzes[3][1] quizzes[4][1]
  37. 37. Make each day count  存取二維陣列要使用 2 個索引值  每個維度索引值從 0 開始  任⼀維度最大索引值為為元素數 - 1  索再使用指定敘述指定二維陣列的每⼀個元素值,如下所示: int i, sum = 0; float average; int quizzes[5][2] = {{74, 56}, {37, 68}, {65, 83}, {72, 68}, {75, 87}}; for (i = 0; i < 5; i++){ sum = sum + quizzes[i][0]; } average = sum / 5.0; 存取二維陣列內容 37
  38. 38. Make each day count  多維陣列是指「二維陣列」以上維度的陣列(含二維)  如果將⼀維陣列想像成⼀度空間的線;二維陣列是二度空間的平⾯; 三維陣列則是三度空間立方體 多維陣列 38
  39. 39. Make each day count  C 語言的字串 (string) 是字元所組成的⼀維陣列,並⾃動在最後加上空 字元 '0',字串⻑度是從索引值 0 計算到null 字元之前 char msg1[12] = "hello";  宣告⻑度12的字元陣列,陣列索引值從 0 開始,我們可以使用 msg1[0]、 msg1[1]~msg1[11] 存取陣列元素  會⾃動加上 C 語言之字串結束字元 ('0') char msg2[] = "hello";  宣告字元陣列並⾃動依初始值配置空間  會⾃動加上 C 語言之字串結束字元 ('0') C語言字串 1/4 39 'h' 'e' 'l' 'l' 'o' '0' msg2[] 'h' 'e' 'l' 'l' 'o' '0' msg1[12] 0 1 2 3 4 5 6 7 8 9 10 11 0 1 2 3 4 5
  40. 40. Make each day count char msg3[12] = {'h', 'e', 'l', 'l, 'o'};  宣告⻑度 12 的字元陣列  並不會⾃動加上 null 字元 ('0') char msg4[] = {'h', 'e', 'l', 'l, 'o', '0'};  宣告⻑度 6的字元陣列,內容為:'h'、'e'、'l'、'l'、'o'、'0'  中文佔2個bytes,陣列空間遇到中文字時,應記得字數 * 2 C語言字串 2/4 40 'h' 'e' 'l' 'l' 'o' '0' msg4[] 'h' 'e' 'l' 'l' 'o' msg3[12] 0 1 2 3 4 5 6 7 8 9 10 11 0 1 2 3 4 5
  41. 41. Make each day count  字元陣列名稱代表陣列的起始位址,所以在程式中不允許使用=指定運算⼦ 來直接設定字串常值,而必須使用strcpy()函式 char msg[20] = "hello"; msg = "welcome"; //[Error] assignment to expression with array type strcpy(msg, "welcome"); C語言字串 3/4 41
  42. 42. Make each day count char msg1[5] = {'h', 'e', 'l', 'l', 'o'}; //配置5bytes空間 char msg2[20] = "hello"; //配置20bytes空間 char msg3[20] = "歡迎光臨"; //配置20bytes空間 printf("%sn", msg1); printf("%sn", msg2); printf("%sn", msg3); printf("%dn", sizeof(msg1)); printf("%dn", sizeof(msg2)); printf("%dn", sizeof(msg3)); printf("%dn", strlen(msg1)); //strlen()是字串⻑度函式 printf("%dn", strlen(msg2)); printf("%dn", strlen(msg3)); C語言字串 4/4 42 hello字串後的亂碼情形視當時記憶體內容而定
  43. 43. Make each day count  我們已知可以使用⼀維字元陣列來表示字串,程式中如果要使用字串 陣列,可以使用二維字元陣列 char books[][40] = {"C Programming", "Practical C", "C Cookbook", "C Tutorial"}; 字串陣列 43 books[0] books[1] books[2] books[3] 'C' 'P' 'r' 'o' 'g' 'r' 'a' 'm' 'm' 'i' 'n' 'g' '0' ... 'P' 'r' 'a' 'c' 't' 'i' 'c' 'a' 'l' 'C' '0' ... 'C' 'C' 'o' 'o' 'k' 'b' 'o' 'o' 'k' '0' ... 'C' 'T' 'u' 't' 'o' 'r' 'i' 'a' 'l' '0' ...
  44. 44. Make each day count  C 語言標準函數庫已經提供現成的字串轉換函數,使用時程式需加上 前置指令 #include <stdlib.h>  double atof(const char*) 將字串轉換為倍精準浮點數並傳回,轉換失敗時回傳0 float f1 = atof("2.35"); // f1 = 2.35  int atoi(const char*) 將字串轉換為整數並傳回,轉換失敗時回傳0 int n1 = atoi("2.35"); // n1 = 2  long atol(const char*) 將字串轉換為⻑整數並傳回,轉換失敗時回傳0 long l1 = atol("2.35"); // l1 = 2 標準函數庫的字串函數 1/9 44
  45. 45. Make each day count  C 語言標準函數庫已經提供現成的字串處理函數,使用時程式需加上 前置指令 #include <string.h>  size_t strlen(char[] s) 傳回字串s的⻑度(字元個數),但不包含'0'字元 char msg[20] = "hello"; strlen(msg); //回傳5  char[] strcat(char[] s1, char[] s2) 將字串 s2 串接到字串 s1 之後,傳回 s1。注意:s1⻑度必須能容納原來的 s1字串加上s2字串 char msg1[20] = "hello"; char msg2[20] = "welcome"; strcat(msg1, msg2); //msg1內容為"hellowelcome" 標準函數庫的字串函數 2/9 45
  46. 46. Make each day count  char[] strncat(char[] s1, char[] s2, int n) 將字串 s2 前⾯ n 個字元串接到字串 s1 之後,傳回 s1。注意:s1⻑度必須 能容納原來的s1字串加上s2字串 char msg1[20] = "hello"; char msg2[20] = "welcome"; strncat(msg1, msg2, 3); //msg1內容為"hellowel" 標準函數庫的字串函數 3/9 46
  47. 47. Make each day count  char *strchr(char[] str, char ch); 回傳 str 字串中第⼀次出現 ch 字元之位置開始字串,搜尋失敗傳回NULL char msg[30] = "make each day count"; char *ptr, ch = 'c'; ptr = strchr(msg, ch); printf("make each day countn"); if (ptr) printf("The character %c is at position: %dn", ch, ptr-msg); else printf("The character was not foundn"); 標準函數庫的字串函數 4/9 47
  48. 48. Make each day count  char *strrchr(char[] str, char ch); 回傳 str 字串中最後出現 ch 字元之位置開始字串,搜尋失敗傳回NULL  char[] strcpy(char[] s1, char[] s2) 重設 s1 內容為 s2 字串,傳回 s1。注意:s1⻑度必須能容納s2字串 char msg1[20] = "hello"; char msg2[20] = "welcome"; strcpy(msg1, msg2); //msg1內容為"welcome"  char[] strncpy(char[] s1, char[] s2, int n) 重設 s1 內容為 s2 的前⾯ n 字串,傳回 s1。注意:s1⻑度必須能容納s2字 串 char msg1[20] = "hello"; char msg2[20] = "welcome"; strcpy(msg1, msg2, 3); //msg1內容為"wel" 標準函數庫的字串函數 5/9 48
  49. 49. Make each day count  int strcmp(const char* s1, char* s2) 比較字串 s1 和 s2,當 s1 比 s2 小時傳回負值;s1 等於 s2 時傳回 0;s1 比 s2 大時傳回正值 char *msg1 = "hi", *msg2 = "hello", *msg3 = "aloha"; if (strcmp(msg2, msg1) > 0) printf("msg2 is greater than msg1n"); else printf("msg2 is less than msg1n"); if (strcmp(msg2, msg3) > 0) printf("msg2 is greater than msg3n"); else printf("msg2 is less than msg3n"); 標準函數庫的字串函數 6/9 49
  50. 50. Make each day count  int strncmp (char* s1, char * s2 , int n ) 比較兩個字串的前 n 個字元是否相等  兩個字串相同時回傳 0,第⼀個字串大於第二個字串回傳正值,第⼀個 字串小於第二個字串回傳負值 printf("%dn", strcmp("AAA", "AAZ")); //-1  char *strrev(char[] str) 將 str 字串內容前後反轉  char *strlwr(char[] str) 將 str 字串內容轉成小寫英文字⺟  char *strupr(char[] str) 將 str 字串內容轉成大寫英文字⺟ 標準函數庫的字串函數 7/9 50
  51. 51. Make each day count  char *strtok(char[] str1, const char *str2); 依據 str2 中的分隔字元,將 str1 分割成字符。str1 中出現 str2 的分隔字元 處,會置換為0字元。 在第⼀次呼叫strtok()時,必需給 str1 字串, 以後 再呼叫時,參數str1設成NULL即可。 每次呼叫成功則傳回下⼀個分割後 的字串指標,無法分割時傳回NULL const char str[80] = "This is - www.gitbook.net - website"; const char *delimit = " -."; char *token; /* get the first token */ token = strtok(str, delimit); /* walk through other tokens */ while (token != NULL) { printf("%sn", token); token = strtok(NULL, delimit); } 標準函數庫的字串函數 8/9 51
  52. 52. Make each day count  int strxfrm (char* s1, char * s2 , int n ) 以 s2 前 n 個字元取代 s1 前 n 個字元  char *strstr(char[] str1, char[] str2); 回傳 str1 字串中第⼀次出現 str2 字串之位置開始字串,搜尋失敗傳回 NULL char s[] = "Self-trust is the first secret of success."; char t[] = "secret"; char *test; test = strstr(s, t); printf("%sn", test); //secret of success. 標準函數庫的字串函數 9/9 52
  53. 53. Make each day count  特別獎號碼(8個數字)1組,號碼相同者獎金1,000萬元  特獎號碼(8個數字) 1組,號碼相同者獎金200萬元  頭獎號碼(8個數字) 3組,號碼相同者獎金20萬元  二獎,末7 位數號碼與頭獎中獎號碼末7 位相同者各得獎金4萬元  三獎,末6 位數號碼與頭獎中獎號碼末6 位相同者各得獎金1萬元  四獎,末5 位數號碼與頭獎中獎號碼末5 位相同者各得獎金4千元  五獎,末4 位數號碼與頭獎中獎號碼末4 位相同者各得獎金1千元  六獎,末3 位數號碼與頭獎中獎號碼末3 位相同者各得獎金2百元  增開六獎(3個數字)1~3組數,末3位數號碼增開六獎相同者各得獎金2 百元 統一發票對獎規則 53
  54. 54. Make each day count  資料變數宣告 int i; char number[9]; char special[9] = "96363025"; //特別獎號碼 char grand[9] = "69095110"; //特獎號碼 char first[3][9] = {"96745865", "98829035", "45984442"}; //頭獎號碼 char additional_sixth[3][4] = {"292", "650", "230"}; //增開六獎號碼 while(1) { printf("請輸入發票號碼:n"); gets(number); if (number[0]=='0') break; ... } Lab 統一發票對獎程式 1/5 54
  55. 55. Make each day count if (strcmp(number, special) == 0) { printf("恭喜你中了特別獎!金額為1000萬元!n"); continue; } if (strcmp(number, grand) == 0) { printf("恭喜你中了特獎!金額為200萬元!n"); continue; } for (i = 0; i < 3; i++) { if (strcmp(number, first[i])==0) { printf("恭喜你中了頭獎!金額為20萬元!n"); break; } } if (i < 3) continue; Lab 統一發票對獎程式 2/5 55
  56. 56. Make each day count for (i = 0; i < 3; i++) { if (strncmp(&number[1], first[i] + 1, 7) == 0) { printf("恭喜你中了二獎!金額為40000元!n"); break; } } if (i < 3) continue; for (i = 0; i < 3; i++) { if (strncmp(&number[2], first[i] + 2, 6) == 0) { printf("恭喜你中了三獎!金額為10000元!n"); break; } } if (i < 3) continue; Lab 統一發票對獎程式 3/5 56 9 6 7 4 5 8 6 5 first[0] first[0]+1 9 6 7 4 5 8 6 5 first[0] first[0]+2 7 6 9 8 7 6 5 8 6 5 number &number[1] 7 9 8 7 6 5 8 6 5 number &number[2] 6
  57. 57. Make each day count for (i = 0; i < 3; i++) { if (strncmp(&number[3], first[i] + 3, 5) == 0) { printf("恭喜你中了四獎!金額為4000元!n"); break; } } if (i < 3) continue; for (i = 0; i < 3; i++) { if (strncmp(&number[4], first[i] + 4, 4) == 0) { printf("恭喜你中了五獎!金額為1000元!n"); break; } } if (i < 3) continue; Lab 統一發票對獎程式 4/5 57 9 6 7 4 5 8 6 5 first[0] first[0]+3 5 9 6 7 4 5 8 6 5 first[0] first[0]+4 4 9 8 7 6 5 8 6 5 number &number[3] 5 9 8 7 6 5 8 6 5 number &number[4] 4
  58. 58. Make each day count  我們在程式中宣告的每⼀個變數,系統都會在記憶體中安排⼀塊適當 大小的區塊,每個記憶體區塊都有獨⼀無二的位址  ⼀般變數告 datatype var_name;  指標變數宣告  指標變數內容是記憶體位址 (其它變數的位址) datatype *var_name; int a = 100; int *ptr_a = &a; printf("%#Xn", a); //0X64 printf("%#Xn", &a); //視系統而定 printf("%#Xn", ptr_a); //同&a值 printf("%#Xn", *ptr_a); //0X64 printf("%#Xn", &ptr_a); //視系統而定 指標運算子* 1/2 59 100 . . . &a a ptr_a &a &ptr_a &a+4
  59. 59. Make each day count  指標的加法與減法與⼀般數值的加減法不同,在指標運算上加 1 ,是 表示前進⼀個資料型態的記憶體⻑度 int a = 100; int *ptr_a = &a; printf("%#Xn", &a); //視系統而定 printf("%#Xn", ptr_a); //同&a printf("%#Xn", ptr_a+1); //同&a+4  指標變數如果沒有指定初始值,則指標變數所指的記憶體位址是未知 的,貿然使用指標變數存取資料的話,可能會造成不可預期的錯誤。 因此,如果在指標變數宣告時不同時設初始值,最好將指標設為 NULL 方便識別 int *ptr_a = NULL; 指標運算子* 2/2 60 100 . . . &a a ptr_a &a &ptr_a &a+4 = ptr_a+1
  60. 60. Make each day count  先前使用使用二維字元陣列來處理字串陣列,當字串資料⻑度不⼀樣 時,會造成記憶體空間浪費,若不想浪費記憶體空間,可改用字元指 標陣列方式 char *books[][40] = {"C Programming", "Practical C", "C Cookbook", "C Tutorial"}; 指標運算子* 3/3 61 books[0] books[1] books[2] books[3] 'C' 'P' 'r' 'o' 'g' 'r' 'a' 'm' 'm' 'i' 'n' 'g' '0' 'P' 'r' 'a' 'c' 't' 'i' 'c' 'a' 'l' 'C' '0' 'C' 'C' 'o' 'o' 'k' 'b' 'o' 'o' 'k' '0' 'C' 'T' 'u' 't' 'o' 'r' 'i' 'a' 'l' '0' char * char * char * char *
  61. 61. Make each day count  先前程式,都是事先宣告好所要使用的變數,當程式開始執行時,這 些變數就會⾃動被配置記憶體空間  然而有時有些變數無法事先知道資料量,若希望在使用到的時候再配 置空間給變數,並在變數不使用的時候,將變數所佔有的空間還給記 憶體,這時候可以使用 malloc()函式動態配置記憶體,使用 free() 函 式釋放記憶體 指標變數名稱 = (資料型別 *) malloc(記憶體空間大小); free(指標變數名稱); 動態配置陣列 1/2 62
  62. 62. Make each day count  ⼀維陣列 dataType *varName = (dataType *)malloc(n * sizeof(dataType)); int player; printf("玩家人數:"); scanf("%d", &player); _Bool *flush = (_Bool *)malloc(player * sizeof(_Bool)); 動態配置陣列 1/2 63 _Bool _Bool . . . _Bool player flush
  63. 63. Make each day count  二維陣列 dataType **varName, *pData; varName = (dataType **)malloc(m * sizeof(datatype *) + m*n*sizeof(dataType)); for (i = 0, pData = (int *)(varName + m); i < m; i++, pData += n) varName[i] = pData; int player; printf("玩家人數:"); scanf("%d", &player); //動態建立card[player][5],用來記錄玩家的撲克牌 card = (int **)malloc(player * sizeof(int *) + player * 5 * sizeof(int)); for (i = 0, pData = (int *)(card + player); i < player; i++, pData += 5) card[i] = pData; 動態配置陣列 2/2 64 int * int * . . . int * player card int int int int int int int int int int int int int int int int int int int int
  64. 64. Make each day count  https://zh.wikipedia.org/wiki/撲克牌型  五張牌的組合  同花順 Straight Flush  鐡支 Four of a Kind  葫蘆 Full house  同花 Flush  順⼦ Straight  三條 Three of a Kind  兩對 Two Pairs  對⼦ One Pair  烏龍 High card Lab 撲克牌梭哈(show hand)遊戲 1/11 65
  65. 65. Make each day count  宣告變數 _Bool *flush; _Bool *straight; int **rank; int **count; void poker_game(){ int pack[52], i, j, k, tmp, rnd; int suit; int player; int *pData; int **card; ... } Lab 撲克牌梭哈(show hand)遊戲 2/11 66
  66. 66. Make each day count  設定玩家入數 printf("玩家人數(2~6):"); scanf("%d", &player);  建立撲克牌組 //0~12表示黑桃,13~25表示紅心,26~38表示方塊,39~51表示梅花 for(i = 0; i < 52; i++) pack[i] = i;  洗牌 srand(time(NULL)); for(i = 0; i < 52; i++) { rnd = rand() % 52; tmp = pack[i]; pack[i] = pack[rnd]; pack[rnd] = tmp; } Lab 撲克牌梭哈(show hand)遊戲 3/11 67 0 1 2 3 ... 50 51 pack[]
  67. 67. Make each day count  show_card() 副程式,用來顯示撲克牌 void show_card(int card){ int number = card % 13; printf("%s", (card < 13)? "黑桃" : (card<26)? "紅心" : (card<39)? "方塊" : "梅花"); switch(number){ case 0: printf("A "); break; case 1 ... 9: printf("%d ", number + 1); break; case 10:printf("J "); break; case 11:printf("Q "); break; case 12:printf("K "); break; } } Lab 撲克牌梭哈(show hand)遊戲 4/11 68
  68. 68. Make each day count  發牌 //建立card[player][5],用來記錄玩家的撲克牌 card = (int **)malloc(player * sizeof(int *) + player * 5 * sizeof(int)); for(i = 0, pData = (int *)(card + player); i < player; i++, pData += 5) card[i] = pData; //每位玩家發5張牌牌 for(i = 0, k = 0; i < 5; i++) for(j = 0; j < player; j++, k++) card[j][i] = pack[k]; Lab 撲克牌梭哈(show hand)遊戲 5/11 69 int * int * . . . int * player card int int int int int int int int int int int int int int int int int int int int
  69. 69. Make each day count  統計玩家手牌 //建立rank[player][14],用來統計玩家各點數撲克牌之張數,ACE牌可算1或14 rank = (int **)malloc(player * sizeof(int *) + player * 14 * sizeof(int)); for(i = 0, pData = (int *)(rank + player); i < player; i++, pData += 14) rank[i] = pData; //設定初始值 for(i = 0; i < player; i++) for (j = 0; j < 5; j++) rank[i][j] = 0; //統計各點數撲克牌之張數 for(i = 0; i < player; i++){ for(j = 0; j < 5; j++) rank[i][card[i][j] % 13]++; rank[i][13] = rank[i][0]; //ACE牌也可當14點 } Lab 撲克牌梭哈(show hand)遊戲 6/11 70 int * int * . . . int * player rank int int ... int int int ... int int int ... int int int ... int 14
  70. 70. Make each day count  檢查同花 //建立flush[player],用來記錄玩家的撲克牌是否為同花 flush=(_Bool *)malloc(player * sizeof(_Bool)); //設定初始值 for(i = 0; i < player; i++) flush[i] = 0; //檢查玩家5張牌是否相同花⾊ for(i = 0; i < player; i++){ suit = card[i][0] / 13; flush[i] = (card[i][1]/13 == suit) && (card[i][2]/13 == suit) && (card[i][3]/13 == suit) && (card[i][4]/13 == suit); } Lab 撲克牌梭哈(show hand)遊戲 7/11 71 int * int * . . . int * player card int int int int int int int int int int int int int int int int int int int int _Bool _Bool ... _Bool player flush
  71. 71. Make each day count  檢查順⼦ //建立straight[player],用來記錄玩家的撲克牌是否為順⼦ straight = (_Bool *)malloc(player * sizeof(_Bool)); //設定初始值 for(i = 0; i < player; i++) straight[i] = 0; //檢查玩家5張牌是否連續 for(i = 0; i < player; i++){ for(j = 0; j < 10; j++){ if(rank[i][j] == 0) continue; for(k = 1; k < 5; k++) if(rank[i][j + k] == 0) break; if(k == 5){ straight[i] = 1; break; } } } Lab 撲克牌梭哈(show hand)遊戲 7/11 72 int * int * . . . int * player rank int int ... int int int ... int int int ... int int int ... int 14 _Bool _Bool ... _Bool player straight
  72. 72. Make each day count  統計玩家牌型組合 //動態建立count[player][5]用來統計玩家撲克牌中之同點數牌情形 count = (int **)malloc(player * sizeof(int *) + player * 5 * sizeof(int)); for(i=0, pData = (int *)(count + player); i < player; i++, pData += 5) count[i] = pData; //設定初始值 for(i = 0; i < player; i++) for (j = 0; j < 5; j++) count[i][j] = 0; //count[2]==1 對⼦;count[2]==2 兩對;count[3]==1 三條;count[4]==1 鐵支 for(i = 0; i < player; i++) { for(j = 0; j < 13; j++) count[i][rank[i][j]]++; } Lab 撲克牌梭哈(show hand)遊戲 8/11 73 int * int * . . . int * player count int int int int int int int int int int int int int int int int int int int int
  73. 73. Make each day count  梭哈 for(i = 0; i < player; i++){ printf("第%d位玩家:", i + 1); for(j = 0; j < 5; j++){ //顯示玩家手牌 show_card(card[i][j]); } printf("n梭哈牌型:"); show_hand(i); printf("nn"); } Lab 撲克牌梭哈(show hand)遊戲 9/11 74
  74. 74. Make each day count  show_hand()副程式,用來顯示梭哈牌型 void show_hand(int player){ if(flush[player] && straight[player]){ printf("同花順n"); return; } if(count[player][4] == 1) printf("鐵支n"); if(count[player][3] == 1 && count[player][2] == 1){ printf("葫蘆n"); return; } if(flush[player]) { printf("同花n"); return; } if(straight[player]) { printf("順⼦n"); return; } Lab 撲克牌梭哈(show hand)遊戲 10/11 75
  75. 75. Make each day count if (count[player][3] == 1) printf("三條n"); if(count[player][2] == 2) printf("兩對n"); if(count[player][2] == 1) printf("對⼦n"); if(count[player][1] == 5) printf("烏龍n"); }  釋放記憶體 free(card); free(flush); free(rank); free(count); Lab 撲克牌梭哈(show hand)遊戲 11/11 76

×