SlideShare una empresa de Scribd logo
1 de 75
Descargar para leer sin conexión
陣列與字串
 陣列特性
 ⼀維陣列
 資料搜尋
 資料排序
 二維與多維陣列
 字串與字元陣列
 字串函數
 指標運算
 動態配置陣列
Revised on July 25, 2021
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
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
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 個資料 初始值
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
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]
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]
Make
each
day
count
 因為「=」等號後大括號中的初值數量就是元素數,所以,我們可以不
用指定陣列的元素數,因為它就是初值個數,如下所示:
int quizzes[] = {71, 83, 67, 49, 59};
 上述⼀維陣列宣告和之前完全相同,唯⼀差異就是沒有指定「[]」中的元
素數
printf("array elements = %d", sizeof(quizzes) / sizeof(int)); //5
以陣列的初值指定元素數
8
Make
each
day
count
 每⼀個陣列元素相當於是⼀個變數,我們可以如同變數⼀樣設定陣列
元素值
int quizzes[5];
quizzes[0] = 71;
quizzes[1] = 83;
quizzes[2] = 67;
quizzes[3] = 49;
quizzes[4] = 59;
指定陣列元素值
9
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
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
Make
each
day
count
 C 語言為了執行效率的考量,並不會檢查陣列索引值的範圍
 如果存取的陣列元素超過陣列尺寸,即索引值大於陣列最大索引值 (元
素數 - 1),C 程式在編譯時並不會產生錯誤,也不會有任何警告,但
是,可能因為覆蓋或取得其他記憶體空間的值,而造成不可預期的執
行結果
陣列索引的範圍問題
12
Make
each
day
count
 搜尋 (Search) 就是在⼀堆資料中找出所要之特定資料。當資料量少時
很容易,當資料量龐大時,如何快速搜尋為⼀重要課題
 循序搜尋法 (Sequential Search)
 從第⼀個資料開始取出,依序⼀⼀與「目標資料」相互比較,直到找到所
要元素或所有資料均尋找完為止,此方法稱「循序搜尋」
 優點
 程式容易撰寫
 資料不須事先排序 (Sorting)
 缺點
 搜尋效率比較差,平均次數 = (N + 1) / 2,每次都必須要從頭到尾逐筆
檢查
資料搜尋 1/4
13
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
Make
each
day
count
 二分搜尋法 (Binary Search)
 如果資料已先排序過,則可使用二分法來進行搜尋
 二分法是將資料分成兩部份,再將鍵值與中間值比較,如鍵值相等則找到,
小於再比前半段,大於再比後半段。如此,分段比較至找到或無資料為止
 優點:搜尋效率佳,平均次數 = log2 N
 缺點
 資料必需事先排序
 檔案資料必需使是可直接存取或隨機檔
資料搜尋 3/4
15
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
Make
each
day
count
 排序是指將多筆資料以某⼀鍵值,重新排列資料順序,使資料由大到
小遞減方式或由小到大遞增方式排列
 排序演算法有很種,以下介紹
 泡沫排序法 (Bubble Sorting)
 插入排序法 (Insertion Sorting)
 選擇排序法 (Select Sorting)
 希爾排序法 (Shell Sorting)
資料排序 1/17
17
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
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
Make
each
day
count
printf("n排序後資料n");
for (k = 0; k < n; k++)
printf("%d ", data[k]);
printf("n");
}
資料排序 4/17
20
Make
each
day
count
 插入排序法 (Insertion Sorting)
 依序由未排序中的第二筆(正處理的值),插入到已排序中的適當位置
 插入時由處理值位置開始向左比較,直到遇到第⼀個比處理值小的值,
再插入 (使得所有在處理值左側的數值都小於處理值)
 比較時,若遇到的值比正處理的值大或相等,則將值往右移
 資料:26, 62, 2, 12, 39, 5
資料排序 5/17
21
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
Make
each
day
count
printf("n排序後資料n");
for (k = 0; k < n; k++)
printf("%d ", data[i]);
printf("n");
}
資料排序 7/17
23
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
第一循環
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
Make
each
day
count
printf("n排序後資料n");
for (k = 0; k < n; k++)
printf("%d ", data[k]);
printf("n");
}
資料排序 10/17
26
Make
each
day
count
 希爾排序法 (Shell Sorting)
 泡沫排序或插入排序,可能要進行多次的比較和交換才能將該數據移至正
確位置。而希爾排序會用較大的步⻑移動數據,所以小數據只需進行少數
比較和交換即可到正確位置
 由大到小選定數個比對間距 (gap)
 將資料依指定的 gap 分組,比較第 i 筆與第 i + gap 筆資料,若前者大於後
者,則交換前後資料
 每⼀回合必須持續做到沒有發生資料交換 (No SWAP) 為止
 調小 gap 值,重覆排序作業,直到 gap 為 1 為止
資料排序 11/17
27
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
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
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
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
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
Make
each
day
count
printf("n排序後資料n");
for (k = 0; k < n; k++)
printf("%d ", data[k]);
}
資料排序 17/17
33
Make
each
day
count
 ⼀維陣列可用來儲存學生⼀⾨課程的考試成績,使用二維陣列 (two-
dimensional arrays),則可以同時儲存多⾨課程的考試成績
 二維陣列宣告語法:
 陣列型別 陣列名稱[列數][欄數];
 上述語法宣告二維陣列,所以有 2 個「[]」,第1個「[]」表示二維陣列有
幾個橫列 (row);第 2 個「[]」行數,表示每⼀橫列有幾欄 (column),二
維陣列的元素個數是「列數×欄數」
二維陣列 1/2
34
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]
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]
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
Make
each
day
count
 多維陣列是指「二維陣列」以上維度的陣列(含二維)
 如果將⼀維陣列想像成⼀度空間的線;二維陣列是二度空間的平⾯;
三維陣列則是三度空間立方體
多維陣列
38
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
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
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
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字串後的亂碼情形視當時記憶體內容而定
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' ...
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
Make
each
day
count
 先前程式,都是事先宣告好所要使用的變數,當程式開始執行時,這
些變數就會⾃動被配置記憶體空間
 然而有時有些變數無法事先知道資料量,若希望在使用到的時候再配
置空間給變數,並在變數不使用的時候,將變數所佔有的空間還給記
憶體,這時候可以使用 malloc()函式動態配置記憶體,使用 free() 函
式釋放記憶體
指標變數名稱 = (資料型別 *) malloc(記憶體空間大小);
free(指標變數名稱);
動態配置陣列 1/2
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
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
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
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
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[]
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
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
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
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
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
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
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
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
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

Más contenido relacionado

La actualidad más candente

жкт, жел. сок
жкт, жел. сокжкт, жел. сок
жкт, жел. сок
fktirf27
 
Презентація "Аліса в країні Див" Захаров В.
Презентація "Аліса в країні Див" Захаров В.Презентація "Аліса в країні Див" Захаров В.
Презентація "Аліса в країні Див" Захаров В.
dtamara123
 
валецький туберкульоз 2014. конф.01.07.
валецький туберкульоз 2014. конф.01.07.валецький туберкульоз 2014. конф.01.07.
валецький туберкульоз 2014. конф.01.07.
Благомед Луцк
 
проект наші друзі птахи
проект наші друзі   птахипроект наші друзі   птахи
проект наші друзі птахи
schoolperem1984
 

La actualidad más candente (20)

Крок 3, база 2014. Загальна лікарська підготовнка
Крок 3, база 2014. Загальна лікарська підготовнкаКрок 3, база 2014. Загальна лікарська підготовнка
Крок 3, база 2014. Загальна лікарська підготовнка
 
техніки вишивання
техніки вишиваннятехніки вишивання
техніки вишивання
 
Urdu Alphabets
Urdu AlphabetsUrdu Alphabets
Urdu Alphabets
 
Олівець
ОлівецьОлівець
Олівець
 
Шарлотта Бронте. Життєвий шлях
Шарлотта Бронте. Життєвий шляхШарлотта Бронте. Життєвий шлях
Шарлотта Бронте. Життєвий шлях
 
жкт, жел. сок
жкт, жел. сокжкт, жел. сок
жкт, жел. сок
 
Ч.Дікенс "Різдвяна пісня в прозі"
Ч.Дікенс "Різдвяна пісня в прозі"Ч.Дікенс "Різдвяна пісня в прозі"
Ч.Дікенс "Різдвяна пісня в прозі"
 
Пригоди Синдбада-мореплавця. Презентація
Пригоди Синдбада-мореплавця. ПрезентаціяПригоди Синдбада-мореплавця. Презентація
Пригоди Синдбада-мореплавця. Презентація
 
Презентація "Аліса в країні Див" Захаров В.
Презентація "Аліса в країні Див" Захаров В.Презентація "Аліса в країні Див" Захаров В.
Презентація "Аліса в країні Див" Захаров В.
 
Тема жіночої долі в творчості Т. Шевченка.
Тема жіночої долі в творчості  Т. Шевченка. Тема жіночої долі в творчості  Т. Шевченка.
Тема жіночої долі в творчості Т. Шевченка.
 
Казкова вікторина
Казкова вікторинаКазкова вікторина
Казкова вікторина
 
Марк Твен
Марк ТвенМарк Твен
Марк Твен
 
валецький туберкульоз 2014. конф.01.07.
валецький туберкульоз 2014. конф.01.07.валецький туберкульоз 2014. конф.01.07.
валецький туберкульоз 2014. конф.01.07.
 
Презентація "Ахейська палацова цивілізація"
Презентація "Ахейська палацова цивілізація"Презентація "Ахейська палацова цивілізація"
Презентація "Ахейська палацова цивілізація"
 
Стівенсон "Балада про вересовий напій"
Стівенсон "Балада про вересовий напій"Стівенсон "Балада про вересовий напій"
Стівенсон "Балада про вересовий напій"
 
Джордж Орвелл Скотоферма.pptx
Джордж Орвелл Скотоферма.pptxДжордж Орвелл Скотоферма.pptx
Джордж Орвелл Скотоферма.pptx
 
Не з дієсловами
Не з дієсловамиНе з дієсловами
Не з дієсловами
 
[Рік] Календарно-тематичне планування - Дизайн та технології для 3 класу за М...
[Рік] Календарно-тематичне планування - Дизайн та технології для 3 класу за М...[Рік] Календарно-тематичне планування - Дизайн та технології для 3 класу за М...
[Рік] Календарно-тематичне планування - Дизайн та технології для 3 класу за М...
 
проект наші друзі птахи
проект наші друзі   птахипроект наші друзі   птахи
проект наші друзі птахи
 
1
11
1
 

Similar a C語言陣列與字串

Rde packagean zhuang_ji_ji_ben_cao_zuo_
Rde packagean zhuang_ji_ji_ben_cao_zuo_Rde packagean zhuang_ji_ji_ben_cao_zuo_
Rde packagean zhuang_ji_ji_ben_cao_zuo_
vinsin27
 
C语言学习100例实例程序
C语言学习100例实例程序C语言学习100例实例程序
C语言学习100例实例程序
yiditushe
 
第01章 绪论(java版)
第01章  绪论(java版)第01章  绪论(java版)
第01章 绪论(java版)
Yan Li
 
Sql Server 高级技巧系列之三整体优化
Sql Server 高级技巧系列之三整体优化Sql Server 高级技巧系列之三整体优化
Sql Server 高级技巧系列之三整体优化
向 翔
 

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

C語言結構與串列
C語言結構與串列 C語言結構與串列
C語言結構與串列
 
Python分支作業
Python分支作業Python分支作業
Python分支作業
 
Arrays的Sort算法分析
Arrays的Sort算法分析Arrays的Sort算法分析
Arrays的Sort算法分析
 
Rde packagean zhuang_ji_ji_ben_cao_zuo_
Rde packagean zhuang_ji_ji_ben_cao_zuo_Rde packagean zhuang_ji_ji_ben_cao_zuo_
Rde packagean zhuang_ji_ji_ben_cao_zuo_
 
Python入門:5大概念初心者必備
Python入門:5大概念初心者必備Python入門:5大概念初心者必備
Python入門:5大概念初心者必備
 
sorting
sortingsorting
sorting
 
Sql培训 (1)
Sql培训 (1)Sql培训 (1)
Sql培训 (1)
 
C语言学习100例实例程序
C语言学习100例实例程序C语言学习100例实例程序
C语言学习100例实例程序
 
Chapter 5 array and struct
Chapter 5 array and structChapter 5 array and struct
Chapter 5 array and struct
 
R 語言教學: 探索性資料分析與文字探勘初探
R 語言教學: 探索性資料分析與文字探勘初探R 語言教學: 探索性資料分析與文字探勘初探
R 語言教學: 探索性資料分析與文字探勘初探
 
Ch10 習題
Ch10 習題Ch10 習題
Ch10 習題
 
DB_Algorithm_and_Data_Structure_About_Sort
DB_Algorithm_and_Data_Structure_About_Sort DB_Algorithm_and_Data_Structure_About_Sort
DB_Algorithm_and_Data_Structure_About_Sort
 
Scilab introduction(Scilab 介紹)
Scilab introduction(Scilab 介紹)Scilab introduction(Scilab 介紹)
Scilab introduction(Scilab 介紹)
 
Ch2
Ch2Ch2
Ch2
 
正課第10週模擬試題_解答.pdf
正課第10週模擬試題_解答.pdf正課第10週模擬試題_解答.pdf
正課第10週模擬試題_解答.pdf
 
Ppt 26-50
Ppt 26-50Ppt 26-50
Ppt 26-50
 
Learning to Rank: An Introduction to LambdaMART
Learning to Rank: An Introduction to LambdaMARTLearning to Rank: An Introduction to LambdaMART
Learning to Rank: An Introduction to LambdaMART
 
Ch2 教學
Ch2 教學Ch2 教學
Ch2 教學
 
第01章 绪论(java版)
第01章  绪论(java版)第01章  绪论(java版)
第01章 绪论(java版)
 
Sql Server 高级技巧系列之三整体优化
Sql Server 高级技巧系列之三整体优化Sql Server 高级技巧系列之三整体优化
Sql Server 高级技巧系列之三整体优化
 

Más de 吳錫修 (ShyiShiou Wu)

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

mbot2.0教學-陀螺儀與三軸加速計應用.pdf
mbot2.0教學-陀螺儀與三軸加速計應用.pdfmbot2.0教學-陀螺儀與三軸加速計應用.pdf
mbot2.0教學-陀螺儀與三軸加速計應用.pdf
 
mbot2.0教學-使用makeblock雲服務.pdf
mbot2.0教學-使用makeblock雲服務.pdfmbot2.0教學-使用makeblock雲服務.pdf
mbot2.0教學-使用makeblock雲服務.pdf
 
mbot2.0教學-局域網路傳輸應用.pdf
mbot2.0教學-局域網路傳輸應用.pdfmbot2.0教學-局域網路傳輸應用.pdf
mbot2.0教學-局域網路傳輸應用.pdf
 
mbot2.0教學-四路顏色感測器應用.pdf
mbot2.0教學-四路顏色感測器應用.pdfmbot2.0教學-四路顏色感測器應用.pdf
mbot2.0教學-四路顏色感測器應用.pdf
 
mbot2.0教學-聲光控制應用.pdf
mbot2.0教學-聲光控制應用.pdfmbot2.0教學-聲光控制應用.pdf
mbot2.0教學-聲光控制應用.pdf
 
mbot2.0教學-光感測器與LED應用.pdf
mbot2.0教學-光感測器與LED應用.pdfmbot2.0教學-光感測器與LED應用.pdf
mbot2.0教學-光感測器與LED應用.pdf
 
mbot2.0教學-超音波感測應用.pdf
mbot2.0教學-超音波感測應用.pdfmbot2.0教學-超音波感測應用.pdf
mbot2.0教學-超音波感測應用.pdf
 
mbot2.0教學-移動控制.pdf
mbot2.0教學-移動控制.pdfmbot2.0教學-移動控制.pdf
mbot2.0教學-移動控制.pdf
 
mbot2.0教學-mblock5開發mBot 2.0應用程式.pdf
mbot2.0教學-mblock5開發mBot 2.0應用程式.pdfmbot2.0教學-mblock5開發mBot 2.0應用程式.pdf
mbot2.0教學-mblock5開發mBot 2.0應用程式.pdf
 
mbot2.0教學-組裝與測試.pdf
mbot2.0教學-組裝與測試.pdfmbot2.0教學-組裝與測試.pdf
mbot2.0教學-組裝與測試.pdf
 
Python元組,字典,集合
Python元組,字典,集合Python元組,字典,集合
Python元組,字典,集合
 
Python函式
Python函式Python函式
Python函式
 
Python串列資料應用
Python串列資料應用Python串列資料應用
Python串列資料應用
 
Python 迴圈作業
Python 迴圈作業Python 迴圈作業
Python 迴圈作業
 
Python基本資料運算
Python基本資料運算Python基本資料運算
Python基本資料運算
 
建置Python開發環境
建置Python開發環境建置Python開發環境
建置Python開發環境
 
micro:bit加速度感測應用
micro:bit加速度感測應用micro:bit加速度感測應用
micro:bit加速度感測應用
 
C語言檔案處理
C語言檔案處理C語言檔案處理
C語言檔案處理
 
C語言列舉與聯合
C語言列舉與聯合C語言列舉與聯合
C語言列舉與聯合
 
C語言應用前置處理
C語言應用前置處理C語言應用前置處理
C語言應用前置處理
 

C語言陣列與字串

  • 1. 陣列與字串  陣列特性  ⼀維陣列  資料搜尋  資料排序  二維與多維陣列  字串與字元陣列  字串函數  指標運算  動態配置陣列 Revised on July 25, 2021
  • 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. 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. 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. 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. 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. 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. Make each day count  因為「=」等號後大括號中的初值數量就是元素數,所以,我們可以不 用指定陣列的元素數,因為它就是初值個數,如下所示: int quizzes[] = {71, 83, 67, 49, 59};  上述⼀維陣列宣告和之前完全相同,唯⼀差異就是沒有指定「[]」中的元 素數 printf("array elements = %d", sizeof(quizzes) / sizeof(int)); //5 以陣列的初值指定元素數 8
  • 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. 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. Make each day count  C 語言為了執行效率的考量,並不會檢查陣列索引值的範圍  如果存取的陣列元素超過陣列尺寸,即索引值大於陣列最大索引值 (元 素數 - 1),C 程式在編譯時並不會產生錯誤,也不會有任何警告,但 是,可能因為覆蓋或取得其他記憶體空間的值,而造成不可預期的執 行結果 陣列索引的範圍問題 12
  • 13. Make each day count  搜尋 (Search) 就是在⼀堆資料中找出所要之特定資料。當資料量少時 很容易,當資料量龐大時,如何快速搜尋為⼀重要課題  循序搜尋法 (Sequential Search)  從第⼀個資料開始取出,依序⼀⼀與「目標資料」相互比較,直到找到所 要元素或所有資料均尋找完為止,此方法稱「循序搜尋」  優點  程式容易撰寫  資料不須事先排序 (Sorting)  缺點  搜尋效率比較差,平均次數 = (N + 1) / 2,每次都必須要從頭到尾逐筆 檢查 資料搜尋 1/4 13
  • 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. Make each day count  二分搜尋法 (Binary Search)  如果資料已先排序過,則可使用二分法來進行搜尋  二分法是將資料分成兩部份,再將鍵值與中間值比較,如鍵值相等則找到, 小於再比前半段,大於再比後半段。如此,分段比較至找到或無資料為止  優點:搜尋效率佳,平均次數 = log2 N  缺點  資料必需事先排序  檔案資料必需使是可直接存取或隨機檔 資料搜尋 3/4 15
  • 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. Make each day count  排序是指將多筆資料以某⼀鍵值,重新排列資料順序,使資料由大到 小遞減方式或由小到大遞增方式排列  排序演算法有很種,以下介紹  泡沫排序法 (Bubble Sorting)  插入排序法 (Insertion Sorting)  選擇排序法 (Select Sorting)  希爾排序法 (Shell Sorting) 資料排序 1/17 17
  • 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. 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. Make each day count printf("n排序後資料n"); for (k = 0; k < n; k++) printf("%d ", data[k]); printf("n"); } 資料排序 4/17 20
  • 21. Make each day count  插入排序法 (Insertion Sorting)  依序由未排序中的第二筆(正處理的值),插入到已排序中的適當位置  插入時由處理值位置開始向左比較,直到遇到第⼀個比處理值小的值, 再插入 (使得所有在處理值左側的數值都小於處理值)  比較時,若遇到的值比正處理的值大或相等,則將值往右移  資料:26, 62, 2, 12, 39, 5 資料排序 5/17 21
  • 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. Make each day count printf("n排序後資料n"); for (k = 0; k < n; k++) printf("%d ", data[i]); printf("n"); } 資料排序 7/17 23
  • 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. 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. Make each day count printf("n排序後資料n"); for (k = 0; k < n; k++) printf("%d ", data[k]); printf("n"); } 資料排序 10/17 26
  • 27. Make each day count  希爾排序法 (Shell Sorting)  泡沫排序或插入排序,可能要進行多次的比較和交換才能將該數據移至正 確位置。而希爾排序會用較大的步⻑移動數據,所以小數據只需進行少數 比較和交換即可到正確位置  由大到小選定數個比對間距 (gap)  將資料依指定的 gap 分組,比較第 i 筆與第 i + gap 筆資料,若前者大於後 者,則交換前後資料  每⼀回合必須持續做到沒有發生資料交換 (No SWAP) 為止  調小 gap 值,重覆排序作業,直到 gap 為 1 為止 資料排序 11/17 27
  • 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. 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. 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. 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. 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. Make each day count printf("n排序後資料n"); for (k = 0; k < n; k++) printf("%d ", data[k]); } 資料排序 17/17 33
  • 34. Make each day count  ⼀維陣列可用來儲存學生⼀⾨課程的考試成績,使用二維陣列 (two- dimensional arrays),則可以同時儲存多⾨課程的考試成績  二維陣列宣告語法:  陣列型別 陣列名稱[列數][欄數];  上述語法宣告二維陣列,所以有 2 個「[]」,第1個「[]」表示二維陣列有 幾個橫列 (row);第 2 個「[]」行數,表示每⼀橫列有幾欄 (column),二 維陣列的元素個數是「列數×欄數」 二維陣列 1/2 34
  • 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. 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. 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
  • 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. 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
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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 *
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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