6-3 二 維 陣 列 二 維 陣 列 (two dimension array) 表 示 法 與 一 維 陣 列 類 似, 是 由 兩 個 中 括 號 所 組 成 的, 如 下 一 敘 述 : int j[2][3]; 表 示 j 是 陣 列 名 稱, 且 是 由 2 列 (rows) 與 3 行 (columns) 所 組 成 的 二 維 陣 列 二 維 陣 列 可 視 為 是 一 平 面 的 圖 形, 其 示 意 圖 如 下 所 示 : 行 列 j[0][0] j[0][1] j[0][2] j[1][0] j[1][1] j[1][2] 當 然, 也 可 以 設 定 初 值, 如 : int j[2][3] = 0, 1, 2, 3, 4, 5; 與 上 圖 陣 列 元 素 對 應 如 下 : 0 1 2 3 4 5 在 二 維 陣 列 的 初 值 設 定 上, 除 了 上 述 的 表 示 法 之 外, 也 可 以 使 用 大 括 號 來 限 制 每 一 列 的 初 值, 如 下 所 示 : int j[2][3] = 0, 1, 2, 3, 4, 5 ; 6-12
第 6 章 陣 列 因 此, 若 有 一 敘 述 如 下 : int j[2][3] = 0, 1, 2, 3, 4; 其 示 意 圖 表 示 如 下 : 0 1 2 3 4? 表 示 j[1][2] 未 設 定 其 初 值, 但 下 一 敘 述 int j[2][3] = 0, 1, 3, 4, 5 ; 表 示 j[0][2] 未 設 定 其 初 值, 其 示 意 圖 如 下 所 示 : 0 1? 3 4 5 以 此 類 推 若 有 一 敘 述 如 下 : int j[2][3] = 0, 1, 3, 4 ; 則 表 示 j[0][2] 和 j[1][2] 皆 未 設 定 其 初 值 0 1? 3 4? 二 維 陣 列 若 有 設 定 初 值 時, 則 可 省 略 列 的 註 標, 但 行 的 註 標 不 可 省 略, 因 為 它 須 依 據 每 一 列 有 多 少 行, 以 便 用 來 計 算 列 的 個 數 因 此, 下 一 敘 述 是 正 確 的 int j[ ][3] = 0, 1, 2, 3, 4, 5; 6-13
而 下 一 個 敘 述 int j[ ][ ] = 0, 1, 2, 3, 4, 5; 則 是 錯 誤 的, 因 為 沒 有 設 定 行 的 註 標 在 二 維 陣 列 中, 若 有 設 定 初 始 值, 其 中 列 的 註 標 可 省 略, 但 行 的 註 標 不 可 省 略 利 用 巢 狀 的 for 迴 圈 處 理 二 維 陣 列 是 最 方 便 的, 以 外 迴 圈 的 for 控 制 二 維 陣 列 中 列 的 註 標, 而 以 內 迴 圈 的 for 控 制 行 的 註 標, 即 可 存 取 二 維 陣 列 中 所 有 元 素 我 們 來 看 幾 個 範 例, 並 加 以 說 明 之 先 從 範 例 6-3a 看 起 範 例 6-3a /* ex6-3a.c */ int num[2][3] = 0, 1, 2, 3, 4, 5; int i, j; for(i = 0; i < 2; i++) for(j = 0; j < 3; j++) printf("num[%d][%d] = %d\n", i, j, num[i][j]); system("pause"); 6-14
第 6 章 陣 列 輸 出 結 果 num[0][0] = 0 num[0][1] = 1 num[0][2] = 2 num[1][0] = 3 num[1][1] = 4 num[1][2] = 5 範 例 6-3a 定 義 一 個 二 維 陣 列, 並 設 定 其 初 值, 之 後 利 用 巢 狀 的 for 迴 圈, 將 陣 列 每 個 元 素 的 值 印 出 也 可 以 使 用 另 一 種 方 式 定 義 之, 如 範 例 6-3b 所 示 : 範 例 6-3b /* ex6-3b.c */ int num[2][3] = 10, 11, 13, 14; int i, j; for(i = 0; i < 2; i++) for(j = 0; j < 3; j++) printf("num[%d][%d] = %d\n", i, j, num[i][j]); system("pause"); 輸 出 結 果 num[0][0] = 10 num[0][1] = 11 num[0][2] = 0 num[1][0] = 13 num[1][1] = 14 num[1][2] = 0 6-15
範 例 6-3b 使 用 另 一 種 方 式 設 定 二 維 陣 列 初 值, 從 輸 出 結 果 可 以 發 現, 若 陣 列 中 有 設 定 初 值, 但 某 些 元 素 沒 有 被 設 定, 則 其 初 值 將 被 設 為 0, 如 程 式 中 的 num[0][2] 及 num[1][2] 若 沒 有 初 始 陣 列 的 話, 陣 列 的 元 素 值 將 是 垃 圾 值 請 參 閱 範 例 6-3c 範 例 6-3c /* ex6-3c.c */ int num[2][3]; int i, j; for(i = 0; i < 2; i++) for(j = 0; j < 3; j++) printf("num[%d][%d] = %d\n", i, j, num[i][j]); system("pause"); 輸 出 結 果 num[0][0] = 2009118740 num[0][1] = 4007040 num[0][2] = 4006960 num[1][0] = 8 num[1][1] = 2009116333 num[1][2] = 62716964 此 範 例 所 得 到 的 輸 出 結 果, 您 是 否 嚇 了 一 大 跳, 因 為 這 些 全 是 記 憶 體 中 的 殘 餘 值 這 也 給 我 們 一 個 警 示, 要 將 陣 列 的 元 素 初 始 化 二 維 陣 列 的 記 憶 體 位 址 計 算, 與 一 維 陣 列 類 似, 假 設 有 一 陣 列 為 int j[2][3]; 6-16
第 6 章 陣 列 假 設 陣 列 初 始 的 位 址 為 1010, 則 &j[0][0] 的 位 址 為 1010 由 於 陣 列 的 資 料 型 態 是 int, 所 以 &j[0][1] 為 1014 &j[0][2] 為 1018 &j[1][0] 為 1022, 依 此 類 推 由 此 可 知, 二 維 陣 列 的 記 憶 體 空 間 分 配, 是 將 一 列 中 的 各 行 皆 分 配 位 址 完 畢, 再 分 配 下 一 列 二 維 陣 列 每 一 元 素 所 在 的 記 憶 體 位 址 之 計 算 公 式 如 下 : 陣 列 初 始 位 址 + ( 此 元 素 的 列 註 標 )*( 陣 列 行 數 )*( 資 料 型 態 所 佔 的 bytes 數 )+ ( 此 元 素 的 行 註 標 )*( 資 料 型 態 所 佔 的 bytes 數 ) 以 計 算 j[1][2] 元 素 的 位 址 為 例, 陣 列 初 始 位 址 為 1010 此 元 素 的 列 註 標 為 1 此 元 素 的 行 註 標 為 2 陣 列 行 數 為 3 sizeof(int) 為 4, 故 其 所 在 位 址 計 算 如 下 : 1010 + 1 * 3 * 4 + 2 * 4 = 1030 除 了 &j[0][0] 表 示 j[0][0] 元 素 的 記 憶 體 位 址 外, 還 可 以 利 用 j( 此 為 陣 列 名 稱 ) 表 示 j[0][0] 的 元 素 位 址, 而 j+1 是 第 二 列 第 一 個 元 素 的 位 址, 即 &j[1][0] j j[0][0] j[0][1] j[0][2] j + 1 j[1][0] j[1][1] j[1][2] 當 然 二 維 陣 列 的 記 憶 體 和 一 維 陣 列 的 記 憶 體 配 置 一 樣, 是 以 直 線 的 方 式 排 列 的, 二 維 陣 列 將 第 一 列 的 每 一 行 元 素 皆 安 頓 好 之 後, 再 排 第 二 列, 以 此 類 推, 所 以 int j[2][3] = 0, 1, 2, 3, 4, 5; 6-17
其 中 j 是 陣 列 名 稱, 表 示 此 陣 列 第 一 列 第 一 行 元 素 之 位 址, 而 j+1 是 第 二 列 第 一 行 元 素 的 位 址, 如 下 圖 所 示 : j 0 1 2 j+1 3 4 5 除 此 之 外,j[0] 和 j[1] 所 代 表 的 意 思, 如 同 j 和 j+1, 表 示 第 一 列 第 一 行 元 素 和 第 二 列 第 一 行 元 素 的 位 址 如 下 圖 所 示 : j[0] 0 1 2 j[1] 3 4 5 大 家 可 以 想 像, 陣 列 的 第 一 列 都 是 以 j[0] 為 首, 如 :j[0][0],j[0][1],j[0][2], 而 第 二 列 都 是 以 j[1] 為 首, 如 :j[1][0],j[1][1],j[1][2] 雖 然 如 此, 但 其 間 有 一 差 異 在 於,j 和 j[0] 雖 然 表 示 同 一 元 素 的 位 址, 但 兩 者 加 1, 則 有 所 不 同 其 示 意 圖, 如 下 圖 所 示 : j 0 1 2 j+1 3 4 5 j+1 表 示 第 二 列 第 一 行 的 位 址, 而 j[0]+1 則 是 第 一 列 第 二 行 的 位 址, 也 就 是 j 和 j[0] 各 加 1 後, 所 處 理 的 單 位 數 不 一 樣 其 示 意 圖 如 下 所 示 : j[0]+1 j[0] 0 1 2 j[1] 3 4 5 6-18
第 6 章 陣 列 許 多 初 學 者 常 將 j+1 誤 認 為 是 j 的 下 一 個 元 素, 為 j[0][1], 這 在 二 維 陣 列 是 錯 誤 的 觀 念, 而 在 一 維 陣 列 中 是 對 的 如 何 得 知 二 維 陣 列 元 素 的 位 址, 請 參 閱 範 例 6-3d 範 例 6-3d /* ex6-3d.c */ int j[2][3] = 100, 200, 300, 400, 500, 600; printf("j[0][0] = %d\n", j[0][0]); printf("&j[0][0] = %x\n\n", &j[0][0]); printf("j = %x\n", j); printf("j[0] = %x\n\n", j[0]); printf("j+1 = %x\n", j+1); printf("&j[1][0] = %x\n\n", &j[1][0]); printf("j[0]+1 = %x\n", j[0]+1); printf("&j[0][1] = %x\n", &j[0][1]); system("pause"); 輸 出 結 果 j[0][0] = 100 &j[0][0] = 22ff50 j = 22ff50 j[0] = 22ff50 j+1 = 22ff5c &j[1][0] = 22ff5c 6-19
j[0]+1 = 22ff54 &j[0][1] = 22ff54 從 輸 出 結 果 得 知,&j[0][0] j 和 j[0] 是 一 樣 的, 皆 表 示 j[0][0] 元 素 的 位 址 j+1 是 第 二 列 第 一 個 元 素 (j[1][0]) 的 位 址 (&j[1][0]), 其 為 22ff5c, 而 j[0]+1 是 第 一 列 第 二 行 元 素 (j[0][1]) 的 位 址 (&j[0][1]), 其 為 22ff54 你 所 得 到 的 輸 出 結 果 也 許 和 我 不 相 同, 因 為 我 們 所 使 用 的 電 腦 不 是 同 一 台 若 要 計 算 二 維 陣 列 每 一 列 的 總 和 及 陣 列 所 有 元 素 的 和, 則 需 藉 助 巢 狀 迴 圈 請 參 閱 範 例 6-3e 範 例 6-3e /* ex6-3e.c */ int x[2][3] = 100, 200, 300, 400, 500, 600; int i, j, totrow[2], total=0; totrow[0]=0; totrow[1]=0; /* 加 總 陣 列 每 一 列 及 陣 列 所 有 元 素 的 總 和 */ for (i=0; i<2; i++) for(j=0; j<3; j++) totrow[i] += x[i][j]; total += x[i][j]; /* 印 出 陣 列 每 一 列 的 總 和 */ for(i=0; i<2; i++) for(j=0; j<3; j++) printf("%5d ", x[i][j]); printf(" %5d\n", totrow[i]); /* 印 出 陣 列 所 有 元 素 的 總 和 */ printf("%23d\n", total); system("pause"); 6-20
第 6 章 陣 列 輸 出 結 果 100 200 300 600 400 500 600 1500 2100 此 程 式 的 重 點 如 下 : /* 加 總 陣 列 每 一 列 及 陣 列 所 有 元 素 的 總 和 */ for (i=0; i<2; i++) for(j=0; j<3; j++) totrow[i] += x[i][j]; total += x[i][j]; 其 中 totrow[i] += x[i][j]; 表 示 將 陣 列 中 的 每 一 列 的 元 素 加 總 起 來 而 total += x[i][j]; 則 表 示 將 陣 列 中 的 所 有 元 素 加 總 1. 試 問 下 列 兩 個 陣 列 所 配 置 的 元 素 個 數 一 樣 嗎? int arr1[2000]; int arr2[20][100]; 2. 試 問 範 例 6-3d,j+2 j[0]+2 及 &j[0][0]+1 各 為 多 少? 6-21
6-4 字 串 陣 列 欲 將 "computer" "printer" "monitor" 三 個 字 串 存 放 到 陣 列 中, 可 利 用 下 列 其 中 一 個 方 法 char str[3][10] = "computer", "printer", "monitor"; - 或 char str[][10] = "computer", "printer", "monitor"; - 方 法 和 皆 是 利 用 字 元 的 二 維 陣 列 構 成 字 串 陣 列, 其 中 char str[][10] 表 示 一 個 字 串 最 多 10 個 字 元 列 的 註 標, 則 因 有 設 定 初 值 字 串 而 省 略, 從 初 始 的 字 串 得 知, 列 的 個 數 是 3 要 如 何 印 出 字 串 呢? 第 一 個 字 串 可 利 用 str[0] 或 str, 以 %s 格 式 輸 出, 第 二 個 字 串 則 使 用 str[1] 或 str+1, 以 %s 格 式 輸 出, 依 此 類 推 請 參 閱 範 例 6-4a 範 例 6-4a /* ex6-4a.c */ char str[][10] = "computer", "printer", "monitor"; printf("str = %s\n", str[0]); printf("str+1 = %s\n", str+1); printf("str+2 = %s\n", str+2); printf("\n"); printf("str[0] = %s\n", str[0]); printf("str[1] = %s\n", str[1]); printf("str[2] = %s\n", str[2]); system("pause"); 6-22
第 6 章 陣 列 輸 出 結 果 str = computer str + 1 = printer str + 2 = monitor str[0] = computer str[1] = printer str[2] = monitor 程 式 以 字 元 的 二 維 陣 列 定 義 字 串 陣 列, 並 利 用 %s 印 出 陣 列 中 的 字 串 其 中 str 陣 列 表 示 如 下 : str[0], str c o m p u t e r \0 \0 str[1], str+1 p r i n t e r \0 \0 \0 str[2], str+2 m o n i t o r \0 \0 \0 1. 試 問 下 列 片 段 程 式 在 做 什 麼? for(i = 0; i <= 15; i++) for(j = 0; j <= 15; j++) z[i][j] = x[i][j] + y[i][j]; 6-5 多 維 陣 列 二 維 以 上 的 陣 列 皆 稱 為 多 維 陣 列 (multi-dimension array) 多 維 陣 列 的 表 示 法 如 同 一 維 二 維 表 示 法, 有 幾 個 [] 即 代 表 它 是 多 少 維, 如 有 三 個 [], 則 表 示 三 維 陣 列, 四 個 [], 則 為 四 維 陣 列, 以 此 類 推, 所 以 下 一 敘 述 int k[2][3][4]; 6-23
是 三 維 陣 列, 可 視 為 它 是 由 二 個 二 維 陣 列 所 組 成 的 一 立 體 圖 形 每 一 個 二 維 陣 列 有 三 列 四 行 因 此, 此 三 維 陣 列 共 有 24 個 元 素 由 於 多 維 的 陣 列 使 用 率 不 高, 因 此, 在 此 不 加 以 贅 述 之 一 般 來 說, 陣 列 最 常 用 的 是 一 維 和 二 維 陣 列, 最 多 用 到 三 維, 表 示 三 度 空 間 三 維 以 上 的 陣 列 就 比 較 少 用 了 1. 有 一 陣 列 如 下 : char arr4[20][8][12][98]; 試 問 arr4 陣 列 共 有 多 少 個 元 素, 如 何 表 示 第 一 個 元 素 和 最 後 一 個 元 素 6-6 摘 要 陣 列 乃 是 由 一 群 相 同 資 料 型 態 的 變 數 所 組 成 的 集 合 陣 列 的 註 標 ( 或 索 引 ) 是 從 0 開 始 算 起, 所 以 陣 列 的 最 後 一 個 元 素 是 註 標 減 1 陣 列 的 名 稱 表 示 此 陣 列 第 一 個 元 素 的 位 址 如 同 變 數 一 般, 只 要 在 每 一 元 素 的 前 面 加 上 &, 就 可 表 示 此 元 素 的 位 址 一 維 陣 列 的 初 始 個 數 不 可 以 大 於 陣 列 所 定 義 的 個 數 若 將 一 維 陣 列 看 成 是 一 線 性 的 圖 形, 則 二 維 陣 列 可 視 為 一 平 面 的 圖 形, 是 由 多 個 一 維 陣 列 所 組 成 的 字 串 可 視 為 是 由 字 元 所 組 成 的 一 維 陣 列, 而 字 串 陣 列 則 可 看 成 是 二 維 陣 列 在 二 維 陣 列 中, 如 int j[2][3] 6-24
第 6 章 陣 列 j 與 j[0] 都 可 以 表 示 為 陣 列 第 一 列 第 一 個 元 素 的 位 址 (&j[0][0]), 但 這 兩 者 各 加 1 是 不 同 的 位 址 j+1 是 第 二 列 第 一 個 元 素 的 位 址 (&j[1][0]), 而 j[0]+1 則 為 陣 列 第 一 列 第 二 行 的 位 址 (&j[0][1]) 三 維 陣 列 可 看 成 是 一 立 體 的 空 間, 它 是 由 三 個 [] 所 組 成 的 四 維 以 上 的 陣 列 就 很 少 用 了 6-7 關 鍵 字 陣 列 (array) 一 維 陣 列 (one dimension array) 字 串 (string) 字 元 (character) 空 字 元 (null character) 二 維 陣 列 (two dimension array) 6-8 問 題 演 練 1. 請 根 據 下 列 的 題 意, 寫 出 其 正 確 的 C 語 言 宣 告 (a) digits 是 一 由 10 個 整 數 型 態 的 元 素 所 組 成 的 陣 列 (b) rates 是 一 由 6 個 double 資 料 型 態 的 元 素 所 組 成 的 陣 列 (c) mat 是 一 個 二 維 陣 列, 其 共 有 3 列 5 行 的 整 數 型 態 的 元 素 2. 有 一 含 有 10 個 元 素 的 一 維 陣 列, 試 問 其 註 標 (subscript) 由 至 3. 試 回 答 下 列 問 題 : (a) 定 義 一 個 一 維 陣 列, 此 陣 列 有 6 個 整 數 型 態 的 元 素, 初 值 分 別 為 1, 2, 4, 8, 16, 32 (b) 如 何 擷 取 此 陣 列 的 第 三 個 元 素 (c) 如 何 擷 取 陣 列 第 三 個 元 素 的 位 址 6-25
6-26 4. 請 寫 出 下 一 程 式 的 輸 出 結 果 int arr[] = 4, 5, 6; int j; for(j = 0; j < 3; j++) printf("%d ", arr[j]); system("pause"); 5. 有 一 陣 列 宣 告 如 下 : int arr[2][3] = 10, 11, 12, 13, 14, 15 ; 試 問 如 何 擷 取 14 6. 有 一 陣 列 如 下 : int k[] = 100, 200, 300, 400, 500; 假 設 &k[0] 等 於 1010, 試 回 答 下 列 問 題 (a) k =? (b) k + 2 =? (c) &k[2] =? (d) k[2] =? (e) k + 2 和 &k[0] + 2 意 義 一 樣 嗎? (f) k[6] =? 7. 有 一 個 二 維 陣 列 如 下 : float k[][3] = 111.1, 222.2, 333.3, 444.4, 555.5, 666.6; 假 設 &k[0][0] = 1010, 試 回 答 下 列 問 題 ( 若 為 位 址, 請 以 十 進 位 方 式 表 示 之 )
第 6 章 陣 列 (a) k + 1 =? (b) &k[0][0] + 1 =? (c) k[0] + 1 =? (d) k[0][0] + 1 =? (e) k 和 k[0] 所 代 表 的 意 義 一 樣, 那 k+1 和 k[0]+1 所 代 表 的 意 義 也 一 樣 嗎? 6-9 大 家 一 起 來 找 碴 1. // arrdebug1.c // int arr[] = 10, 20, 30, 40, 50, 60; int i, total; for (i=1; i<=6; i++) total += arr[i]; printf("total=%d\n", total); system( PAUSE ); 2. // arrdebug2.c // int arr[5] = 210, 120, 30, 40, 50; int i, pos, max; 6-27
for (i=1; i<5; i++) if (arr[i] > max) max = arr[i]; ; printf(" 陣 列 中 第 %d 個 元 素 是 最 大 值 為 %d\n", pos, max); system( PAUSE ); 3. // arrdebug3.c // int arr[5]; int i, pos, max; for (i=0; i<5; i++) printf(" 請 輸 入 arr[%d]: "); scanf("%d", arr[i]); max=arr[0]; for (i=0; i<5; i++) if (arr[i] > max) max = arr[i]; pos = i; ; printf(" 陣 列 中 第 %d 個 元 素 是 最 大 值 為 %d\n", pos+1, max); system( PAUSE ); 4. // arrdebug4.c // 6-28
第 6 章 陣 列 int arr2[3][2]=10, 202, 301, 140, 505, 260; int i, j, row, col, max; max=arr[0][0]; for (i=0; i<3; i++) for (j=0; j<=2; j++) if (arr[i][j] > max) max = arr[i][j]; row = i; printf(" 陣 列 中 第 %d 列 第 %d 行 的 值 是 最 大 為 %d\n", row+1, col+1, max); system( PAUSE ); 5. // arrdebug5.c // int arr2[3][2]; int i, j, row, col, max; for (i=0; i<3; i++) for (j=0; j<2; j++) printf(" 請 輸 入 arr2[%d][%d]: ", i, j); scanf("%d", arr2[i][j]); max=arr2[0][0]; for (i=0; i<3; i++) for (j=0; j<2; j++) if (arr2[i][j] > max) max = arr2[i][j]; 6-29
printf(" 陣 列 中 第 %d 列 第 %d 行 的 值 是 最 大 為 %d\n", row+1, col+1, max); system( PAUSE ); 6-10 程 式 實 作 1. 輸 入 20 個 整 數 存 放 於 一 陣 列, 然 後 輸 出 此 20 個 整 數 中 最 大 者, 並 且 將 此 數 在 陣 列 中 的 位 置 印 出 2. 試 利 用 二 維 陣 列 記 錄 4 個 禮 拜 中 每 天 的 平 均 氣 溫, 並 印 出 哪 幾 天 的 平 均 氣 溫 高 於 30 度 以 上 請 參 考 範 例 6-3b 3. 輸 入 一 整 數, 並 將 它 轉 換 為 二 進 位 的 數 字 後 印 出 4. 修 改 程 式 實 作 第 3 題, 讓 使 用 者 決 定 是 否 要 繼 續 執 行 6-30