# APCS觀念題2016年3月 > 日期:2023年2月2日 > 作者:王一哲 1. 下列程式正確的輸出應該如下: ``` * *** ***** ******* ********* ``` 在不修改下列程式之第 4 行及第 7 行程式碼的前提下,最少需修改幾行程式碼以得到正確輸出? (A) 1   (B) 2   \(C\) 3   (D) 4 ```c= int k = 4; int m = 1; for (int i=1; i<=5; i=i+1) { for (int j=1; j<=k; j=j+1) { printf (" "); } for (int j=1; j<=m; j=j+1) { printf ("*"); } printf ("\n"); k = k - 1; m = m + 1; } ``` <br /> <span style="font-weight:bold">答案</span>:A <span style="color:blue">詳解</span>:將第12行改成 m = 2\*i + 1 或是 m += 2 即可。以下是測試用的程式碼: ```c= #include <stdio.h> int main() { int k = 4; int m = 1; for (int i=1; i<=5; i=i+1) { for (int j=1; j<=k; j=j+1) { printf (" "); } for (int j=1; j<=m; j=j+1) { printf ("*"); } printf ("\n"); k = k - 1; m = 2*i + 1; // m += 2; } return 0; } ``` <br /><br /> 2. 給定一陣列 a[10]={1, 3, 9, 2, 5, 8, 4, 9, 6, 7}, i.e., a[0]=1, a[1]=3, …,a[8]=6, a[9]=7,以 f(a, 10)呼叫執行下列函式後,回傳值為何? (A) 1   (B) 2   \(C\) 7   (D) 9 ```c int f (int a[], int n) { int index = 0; for (int i=1; i<=n-1; i=i+1) { if (a[i] >= a[index]) { index = i; } } return index; } ``` <br /> <span style="font-weight:bold">答案</span>:C <span style="color:blue">詳解</span>:若陣列中索引值為i的元素大於等於第i個元素,則將i的值指定給index,最後的回傳值就是陣列中最大且位於最後面的元素索引值。以下是測試用的程式碼: ```c= #include <stdio.h> int f (int a[], int n); int main() { int a[10] = {1, 3, 9, 2, 5, 8, 4, 9, 6, 7}; printf("%d\n", f(a, 10)); return 0; } int f (int a[], int n) { int index = 0; for (int i=1; i<=n-1; i=i+1) { if (a[i] >= a[index]) { index = i; } } return index; } ``` <br /><br /> 3. 給定一整數陣列 a[0]、a[1]、…、a[99] 且 a[k]=3k+1,以 value=100 呼叫以下兩函式,假設函式 f1 及 f2 之 while 迴圈主體分別執行 n1 與 n2 次 (i.e, 計算 if 敘述執行次數,不包含 else if 敘述),請問 n1 與 n2 之值為何? 註: (low + high)/2 只取整數部分。 (A) n1=33, n2=4   (B) n1=33, n2=5   \(C\) n1=34, n2=4   (D) n1=34, n2=5 ```c int f1(int a[], int value) { int r_value = -1; int i = 0; while (i < 100) { if (a[i] == value) { r_value = i; break; } i = i + 1; } return r_value; } ``` ```c int f2(int a[], int value) { int r_value = -1; int low = 0, high = 99; int mid; while (low <= high) { mid = (low + high)/2; if (a[mid] == value) { r_value = mid; break; } else if (a[mid] < value) { low = mid + 1; } else { high = mid - 1; } } return r_value; } ``` <br /> <span style="font-weight:bold">答案</span>:D <span style="color:blue">詳解</span>:依照題目敘述,陣列 a[100] = {1, 4, 7, ..., 298},呼叫 f1(a, 100) 及 f2(a, 100) 會回傳元素100於陣列中的索引值33。f1 為循序搜尋,依照索引值由小到大一個一個搜尋,因此要運作34次。f2 為二分搜尋法,可以依照程式碼,用紙筆列出運作過程中變數 low、high、mid、a[mid] 分別對應的數值,我在以下的程式碼加上一些輸出變數值的部分,應該會比較容易理解程式的運作流程。 ```c= #include <stdio.h> int f1(int a[], int n); int f2(int a[], int n); int main() { int a[100], val1, val2; for(int k = 0; k < 100; k++) { a[k] = 3*k + 1; } val1 = f1(a, 100); val2 = f2(a, 100); printf("f1(a, 100) = %d\tf2(a, 100) = %d\n", val1, val2); return 0; } int f1(int a[], int value) { int r_value = -1; int i = 0; while (i < 100) { if (a[i] == value) { r_value = i; break; } i = i + 1; } return r_value; } int f2(int a[], int value) { int r_value = -1; int low = 0, high = 99; int mid; int tmp, count = 0; while (low <= high) { count++; mid = (low + high)/2; printf("執行前:count = %d, low = %d, high = %d, mid = %d\n", count, low, high, mid); tmp = a[mid]; if (a[mid] == value) { r_value = mid; break; } else if (a[mid] < value) { low = mid + 1; } else { high = mid - 1; } printf("執行後:a[mid] = %d, low = %d, high = %d\n", tmp, low, high); } return r_value; } ``` 輸出結果 ```c 執行前:count = 1, low = 0, high = 99, mid = 49 執行後:a[mid] = 148, low = 0, high = 48 執行前:count = 2, low = 0, high = 48, mid = 24 執行後:a[mid] = 73, low = 25, high = 48 執行前:count = 3, low = 25, high = 48, mid = 36 執行後:a[mid] = 109, low = 25, high = 35 執行前:count = 4, low = 25, high = 35, mid = 30 執行後:a[mid] = 91, low = 31, high = 35 執行前:count = 5, low = 31, high = 35, mid = 33 f1(a, 100) = 33 f2(a, 100) = 33 ``` <br /><br /> 4. 經過運算後,下列程式的輸出為何? (A) 1275   (B) 20   \(C\) 1000   (D) 810 ```c for (i=1; i<=100; i=i+1) { b[i] = i; } a[0] = 0; for (i=1; i<=100; i=i+1) { a[i] = b[i] + a[i-1]; } printf ("%d\n", a[50]-a[30]); ``` <br /> <span style="font-weight:bold">答案</span>:D <span style="color:blue">詳解</span>:從前3行程式碼可以看出陣列 b[0] 沒有被指定值,不過預設值通常會是0,其它的值則是依序填入1、2、3、...、100。從第4到7行程式碼可以看出,a[i] 為 0 + 1 + 2 + ... + i,或是將前幾個值列出來就可以看出規律,a[0] = 0,a[1] = 0 + 1,a[2] = 0 + 1 + 2,a[3] = 0 + 1 + 2 + 3,因此 $$ a[50] = 0 + 1 + 2 + \dots + 50 = \frac{(1+50) \times 50}{2} = 1275 $$ $$ a[30] = 0 + 1 + 2 + \dots + 30 = \frac{(1+30) \times 30}{2} = 465 $$ $$ a[50] - a[30] = 1275 - 465 = 810 $$ 以下是測試用的程式碼 ```c= #include <stdio.h> int main() { int a[101], b[101]; for (int i=1; i<=100; i=i+1) { b[i] = i; printf("b[%d] = %d\n", i, b[i]); } a[0] = 0; for (int i=1; i<=100; i=i+1) { a[i] = b[i] + a[i-1]; printf("a[%d] = %d\n", i, a[i]); } printf ("%d\n", a[50]-a[30]); return 0; } ``` <br /><br /> 5. 函式 f 定義如下,如果呼叫 f(1000),指令sum=sum+i 被執行的次數最接近下列何者? (A) 1000   (B) 3000   \(C\) 5000   (D) 10000 ```c int f (int n) { int sum=0; if (n<2) { return 0; } for (int i=1; i<=n; i=i+1) { sum = sum + i; } sum = sum + f(2*n/3); return sum; } ``` <br /> <span style="font-weight:bold">答案</span>:B <span style="color:blue">詳解</span>:本題需要用到函式的遞迴 (recursion),這裡是在函式 f 當中呼叫函式 f,這是 APCS 觀念題中特別愛考的內容,解題時最好先找出函式的出口,也就是停止運作的條件,通常是回傳某個常數值,再用紙筆列出幾次運算過程,應該可以找出運作規律。以本題的而言,函式出口為 n < 2 時,回傳值為 0;當 n > 2 時,sum = sum + 1 會被運作 n 次;呼叫 f(1000) 時,會接著依序呼叫f(666)、f(444)、f(296)、f(197)、f(131)、f(87)、f(58)、f(38)、f(25)、f(16)、f(10)、f(6)、f(4)、f(2),因此 sum = sum + 1 會被運作 2980 次。以下是測試用的程式碼 ```c= #include <stdio.h> int f (int n); int sum = 0, count = 0; int main() { sum, count = f(1000); printf("sum = %d count = %d\n", sum, count); return 0; } int f (int n) { if (n < 2) { return 0; } printf("n = %d\n", n); for (int i=1; i<=n; i=i+1) { sum = sum + i; count++; } sum = sum + f(2*n/3); return sum, count; } ``` <br /><br /> 6. List 是一個陣列,裡面的元素是 element,它的定義如右。List 中的每一個 element 利用 next 這個整數變數來記錄下一個 element 在陣列中的位置,如果沒有下一個 element,next 就會記錄-1。所有的 element 串成了一個串列 (linked list)。例如在 list 中有三筆資料 <img height="50%" width="50%" src="https://imgur.com/GJ6CCJj.png" style="display: block; margin-left: auto; margin-right: auto;"/> <br /> 它所代表的串列如下圖 <img height="30%" width="30%" src="https://imgur.com/VbJxxAg.png" style="display: block; margin-left: auto; margin-right: auto;"/> <br /> RemoveNextElement 是一個程序,用來移除串列中 current 所指向的下一個元素,但是必須 保持原始串列的順序。例如,若 current 為 3 (對應到 list[3]),呼叫 RemoveNextElement 後,串列應為 <img height="20%" width="20%" src="https://imgur.com/SnzckZq.png" style="display: block; margin-left: auto; margin-right: auto;"/> <br /> 請問在空格中應該填入的程式碼為何? ```c struct element { char data; int next; } void RemoveNextElement (elementlist[], int current) { if (list[current].next != -1) { /*移除 current 的下一個 element*/ /*此行為要填入的程式碼*/ } } ``` (A) list[current].next = current; (B) list[current].next = list[list[current].next].next; \(C\) current = list[list[current].next].next; (D) list[list[current].next].next = list[current].next; <br /> <span style="font-weight:bold">答案</span>:B <span style="color:blue">詳解</span>:本題考的是鏈結串列 (linked list),不是指 Python 資料格式之一的串列 (list)。如果 current 為 3,代表 RemoveNextElement 要跳過4號元素,連結到5號元素,因此答案為B。 <br /><br /> 7. 請問以 a(13,15)呼叫下列 a()函式,函式執行完後其回傳值為何? (A) 90   (B) 103   \(C\) 93   (D) 60 ```c int a(int n, int m) { if (n < 10) { if (m < 10) { return n + m ; } else { return a(n, m-2) + m ; } } else { return a(n-1, m) + n ; } } ``` <br /> <span style="font-weight:bold">答案</span>:B <span style="color:blue">詳解</span>:本題考函式的遞迴 (recursion),直接列出運作過程 $$ \begin{align*} a(13, 15) &= a(12, 15) + 13\\ &= a(11, 15) + 12 + 13\\ &= a(10, 15) + 11 + 12 + 13\\ &= a(9, 15) + 10 + 11 + 12 + 13\\ &= a(9, 13) + 46 + 15\\ &= a(9, 11) + 46 + 13 + 15\\ &= a(9, 9) + 46 + 11+ 13 + 15\\ &= 9 + 9 + 46 + 39\\ &= 103 \end{align*} $$ <br /><br /> 8. 一個費式數列定義第一個數為 0 第二個數為 1 之後的每個數都等於前兩個數相加,如下所示:0、 1、 1、 2、 3、 5、 8、 13、 21、 34、 55、 89…。右列的程式用以計算第 N 個(N ≥ 2)費式數列的數值,請問 (a) 與 (b) 兩個空格的敘述(statement)應該為何? (A) (a) f[i]=f[i-1]+f[i-2]   (b) f[N] (B) (a) a = a + b      (b) a \(C\) (a) b = a + b      (b) b (D) (a) f[i]=f[i-1]+f[i-2]   (b) f[i] ```c int a=0; int b=1; int i, temp, N; … for (i=2; i<=N; i=i+1) { temp = b; ____(a)____ ; a = temp; printf ("%d\n", ____(b)____ ); } ``` <br /> <span style="font-weight:bold">答案</span>:C <span style="color:blue">詳解</span>:於 for 迴圈中,先將 b 的值指定給 temp,再將 b 更新為 b + a,最後將 temp 的值指定給 a,也就是把 b 原來的值指定給 a,由此可知當迴圈運作時,b 的值依序為 1、1 + 1 = 2、2 + 1 = 3、3 + 2 = 5、5 + 3 = 8、8 + 5 = 13、...,答案為C。 <br /><br /> 9. 請問下列程式輸出為何? (A) 1   (B) 4   \(C\) 3   (D) 33 ```c int A[5], B[5], i, c; … for (i=1; i<=4; i=i+1) { A[i] = 2 + i*4; B[i] = i*5; } c = 0; for (i=1; i<=4; i=i+1) { if (B[i] > A[i]) { c = c + (B[i] % A[i]); } else { c = 1; } } printf ("%d\n", c); ``` <br /> <span style="font-weight:bold">答案</span>:B <span style="color:blue">詳解</span>:由程式碼第3到6行可以看出陣列 A = {0, 6, 10, 14, 18}、B = {0, 5, 10, 15, 20}。程式碼第8到15行回迴圈運作時,第1次為 A[1] > B[1]、6 > 5,輸出 c = 1;第2次為 A[2] = B[2]、10 = 10,輸出 c = 1;第3次為 A[3] < B[3]、14 < 15,輸出 c = 1 + (15%14) = 2;第4次為 A[4] < B[4]、18 < 20,輸出 c = 2 + (20%18) = 4,答案為B。 <br /><br /> 10. 給定下列 g() 函式, g(13) 回傳值為何? (A) 16   (B) 18   \(C\) 19   (D) 22 ```c int g(int a) { if (a > 1) { return g(a - 2) + 3; } return a; } ``` <br /> <span style="font-weight:bold">答案</span>:C <span style="color:blue">詳解</span>:本題考函式的遞迴 (recursion),直接列出運作流程 $$ \begin{align*} g(13) &= g(11) + 3\\ &= g(9) + 3 + 3\\ &= g(7) + 3 + 3 + 3\\ &= g(5) + 3 + 3 + 3 + 3\\ &= g(3) + 3 + 3 + 3 + 3 + 3\\ &= g(1) + 3 + 3 + 3 + 3 + 3 + 3\\ &= 1 + 3 + 3 + 3 + 3 + 3 + 3\\ &= 19 \end{align*} $$ <br /><br /> 11. 定義 a[n] 為一陣列(array), 陣列元素的指標為 0 至 n-1。 若要將陣列中 a[0]的元素移到 a[n-1],下列程式片段空白處該填入何運算式? (A) n+1   (B) n   \(C\) n-1   (D) n-2 ```c int i, hold, n; … for (i=0; i<=_____ ; i=i+1) { hold = a[i]; a[i] = a[i+1]; a[i+1] = hold; } ``` <br /> <span style="font-weight:bold">答案</span>:D <span style="color:blue">詳解</span>:for 迴圈中的程式碼會將 a[i] 與 a[i+1] 的元素交換,若要使 a[0] 最後被換到 a[n-1],最後一次運作時 i = n-2,因此答案為D。 <br /><br /> 12. 給定下列函式 f1() 及 f2()。 f1(1)運算過程中,以下敘述何者為錯? (A) 印出的數字最大的是 4   (B) f1 一共被呼叫二次   \(C\) f2 一共被呼叫三次   (D) 數字 2 被印出兩次 ```c void f1 (int m) { if (m > 3) { printf ("%d\n", m); return; } else { printf ("%d\n", m); f2(m+2); printf ("%d\n", m); } } void f2 (int n) { if (n > 3) { printf ("%d\n", n); return; } else { printf ("%d\n", n); f1(n-1); printf ("%d\n", n); } } ``` <br /> <span style="font-weight:bold">答案</span>:C <span style="color:blue">詳解</span>:本題考函式的遞迴 (recursion),呼叫f1(1)之後運作流程如下: 1. 第1層:印出1,呼叫 f2(3) 2. 第2層:印出3,呼叫 f1(2) 3. 第3層:印出2,呼叫 f2(4) 4. 第4層:印出4,遇到 return,結束遞迴,往上層移動 5. 回到第3層:印出2 6. 回到第2層:印出3 7. 回到第1層:印出1,結束程式 C錯誤,f2 被呼叫2次。 <br /><br /> 13. 下列程式片段擬以輾轉相除法求 i 與 j 的最大公因數。請問 while 迴圈內容何者正確? (A) k = i % j; i = j; j = k;     (B) i = j; j = k; k = i % j; \(C\) i = j; j = i % k; k = i;     (D) k = i; i = j; j = i % k; ```c i = 76; j = 48; while ((i % j) != 0) { ________________ ________________ ________________ } printf ("%d\n", j); ``` <br /> <span style="font-weight:bold">答案</span>:A <span style="color:blue">詳解</span>:輾轉相除法是以這次計算時的除數作為下次計算時的被除數,這次計算時得到的餘數作為下次計算時的除數,重複這個過程直到餘數為0時,此時的除數就是最大公因數,因此答案為A。 <br /><br /> 14. 下列程式輸出為何? (A) bar: 6 bar: 1 bar: 8   (B) bar: 6 foo: 1 bar: 3 \(C\) bar: 1 foo: 1 bar: 8   (D) bar: 6 foo: 1 foo: 3 ```c void foo (int i) { if (i <= 5) { printf ("foo: %d\n", i); } else { bar(i - 10); } } void bar (int i) { if (i <= 10) { printf ("bar: %d\n", i); } else { foo(i - 5); } } void main() { foo(15106); bar(3091); foo(6693); } ``` <br /> <span style="font-weight:bold">答案</span>:A <span style="color:blue">詳解</span>:本題考函式的遞迴 (recursion)。由於代入的數值很大,要先找出運作規律,例如foo(100) = bar(90) = foo(85) 或是 bar(100) = foo(95) = bar(85),如果經過 foo 及 bar 各1次,代入的數值減15,當代入的數值小於、等於20可能會結束遞迴。 1. 由於 15106 % 15 = 1,因此 foo(15106) = foo(16) = bar(6),6 <= 10,印出 bar: 6,結束遞迴。 2. 由於 3091 % 15 = 1,因此 bar(3091) = bar(16) = foo(11) = bar(1),1 <= 10,印出 bar: 1,結束遞迴。 3. 由於 6693 % 15 = 3,因此 foo(6693) = foo(18) = bar(8),8 <= 10,印出 bar: 8,結束遞迴。 答案為A。 <br /><br /> 15. 若以 f(22)呼叫下列 f()函式,總共會印出多少數字? (A) 16   (B) 22   \(C\) 11   (D) 15 ```c void f(int n) { printf ("%d\n", n); while (n != 1) { if ((n%2)==1) { n = 3*n + 1; } else { n = n / 2; } printf ("%d\n", n); } } ``` <br /> <span style="font-weight:bold">答案</span>:A <span style="color:blue">詳解</span>:直接列出運作過程,一開始先印出輸入的參數值22,接下來在 n != 1 的條件不成立之前不會離開 while 迴圈,印出的 n 值依序為 11、34、17、52、26、13、40、20、10、5、16、8、4、2、1,共16個數字。 <br /><br /> 16. 下列程式執行過後所輸出數值為何? (A) 11   (B) 13   \(C\) 15   (D) 16 ```c void main () { int count = 10; if (count > 0) { count = 11; } if (count > 10) { count = 12; if (count % 3 == 4) { count = 1; } else { count = 0; } } else if (count > 11) { count = 13; } else { count = 14; } if (count) { count = 15; } else { count = 16; } printf ("%d\n", count); } ``` <br /> <span style="font-weight:bold">答案</span>:D <span style="color:blue">詳解</span>:程式分為以下5個步驟 1. count 初始值為10,符合第1個 if 的條件 count > 0,count 被重設為11。 2. 進到第2個 if,符合條件 count > 10,count 被重設為12。 3. 進到內層的 if,由於 12%3 = 0,不符合條件 count % 3 == 4,進到內層的 else,count 被重設為0。 4. 進到第3個 if,if(count) 代表 count 大於1時成立,由於 count = 0,進到 else,count 被重設為16。 5. 印出16。 <br /><br /> 17. 下列程式片段主要功能為:輸入六個整數,檢測並印出最後一個數字是否為六個數字中最小的值。然而,這個程式是錯誤的。請問以下哪一組測試資料可以測試出程式有誤? (A) 11 12 13 14 15 3    (B) 11 12 13 14 25 20    \(C\) 23 15 18 20 11 12    (D) 18 17 19 24 15 16 ```c #define TRUE 1 #define FALSE 0 int d[6], val, allBig; … for (int i=1; i<=5; i=i+1) { scanf ("%d", &d[i]); } scanf ("%d", &val); allBig = TRUE; for (int i=1; i<=5; i=i+1) { if (d[i] > val) { allBig = TRUE; } else { allBig = FALSE; } } if (allBig == TRUE) { printf ("%d is the smallest.\n", val); } else { printf ("%d is not the smallest.\n", val); } ``` <br /> <span style="font-weight:bold">答案</span>:B <span style="color:blue">詳解</span>:第10到17行的程式碼,只能夠依序檢測第1到5個數值是否大於第6個數值,而且只會留下最後一次的檢測結果,若執行程式時依序輸入 11 12 13 14 25 20,最後 allBig 為 TRUE,但是20並不是這6個數字中最小的值。 <br /><br /> 18. 程式編譯器可以發現下列哪種錯誤? (A) 語法錯誤   (B) 語意錯誤   \(C\) 邏輯錯誤   (D) 以上皆是 <span style="font-weight:bold">答案</span>:A <span style="color:blue">詳解</span>:編譯器只能發現語法錯誤,例如少了逗號、分號、括號之類的錯誤,通常還會提示出錯處的行號。編譯式或直譯式語言皆有可能發生語意錯誤(邏輯錯誤, logic error),編譯或直譯時無法被發現,可能會回傳預料之外的執行結果。 <br /><br /> 19. 大部分程式語言都是以列為主的方式儲存陣列。在一個8x4的陣列(array) A裡,若每個元素需要兩單位的記憶體大小,且若A[0][0]的記憶體位址為 108 (十進制表示),則 A[1][2]的記憶體位址為何? (A) 120   (B) 124   \(C\) 128   (D) 以上皆非 <br /> <span style="font-weight:bold">答案</span>:A <span style="color:blue">詳解</span>:A[0][0] 之後依序為 A[0][1]、A[0][2]、A[0][3]、A[1][0]、A[1][1]、A[1][2],A[1][2] 為 A[0][0] 之後第6個元素,因此記憶體位址為 $$ 108 + 6 \times 2 = 120 $$ 若二維陣列 A 為 $m$ 列、$n$ 欄($m \times n$),每個元素使用 $d$ 個位元的記憶體,A[0][0] 的記憶體位址為 $loc_0$,則 A[i][j] 的記憶體位址為 $$ loc = loc_0 + (i \times n + j) \times d $$ <br /><br /> 20. 下列為一個計算 n 階乘 (factorial) 的函式,請問該如何修改才會得到正確的結果? (A) 第 2 行,改為 int fac = n; (B) 第 3 行,改為 if (n > 0) { \(C\) 第 4 行,改為 fac = n * fun(n+1); (D) 第 4 行,改為 fac = fac * fun(n-1); ```c= int fun (int n) { int fac = 1; if (n >= 0) { fac = n * fun(n - 1); } return fac; } ``` <br /> <span style="font-weight:bold">答案</span>:B <span style="color:blue">詳解</span>:本題考函式的遞迴 (recursion),重點在於第4行執行的規律,按照階乘的定義 $n! = 1 \times 2 \times 3 \times \dots \times (n-1) \times n$,列出幾次運算過程應該就能看出答案,例如 1. fun(0) = 1 2. fun(1) = 1 * fun(0) = 1 3. fun(2) = 2 * fun(1) = 1 * 2 = 2 4. fun(3) = 3 * fun(2) = 1 * 2 * 3 = 6 5. fun(4) = 4 * fun(3) = 1 * 2 * 3 * 4 = 24 6. fun(n) = n * fun(n-1) = n! 因此答案為B。 <br /><br /> 21. 下列程式碼,執行時的輸出為何? (A) 0 2 4 6 8 10        (B) 0 1 2 3 4 5 6 7 8 9 10 \(C\) 0 1 3 5 7 9         (D) 0 1 3 5 7 9 11 ```c void main() { for (int i=0; i<=10; i=i+1) { printf ("%d ", i); i = i + 1; } printf ("\n"); } ``` <br /> <span style="font-weight:bold">答案</span>:A <span style="color:blue">詳解</span>:for 迴圈每次運作時,會先印出i的值再將i加1,但是 for 迴圈的增量又會再將i加1,因此印出的值依序為0、2、4、6、8、10。 <br /><br /> 22. 下列 f()函式執行後所回傳的值為何? (A) 1023   (B) 1024   \(C\) 2047   (D) 2048 ```c int f() { int p = 2; while (p < 2000) { p = 2 * p; } return p; } ``` <br /> <span style="font-weight:bold">答案</span>:D <span style="color:blue">詳解</span>:f() 當中的 while 迴圈每次運作時會將p的值變為2倍,最後一次運作時,p的輸入值為1024,輸出值為2048,因此答案為D。 <br /><br /> 23. 下列 f()函式 (a), (b), \(c\) 處需分別填入哪些數字,方能使得 f(4) 輸出 2468 的結果? (A) 1, 2, 1   (B) 0, 1, 2   \(C\) 0, 2, 1   (D) 1, 1, 1 ```c int f(int n) { int p = 0; int i = n; while (i >= ____(a)____ ) { p = 10 – ____(b)____ * i; printf ("%d", p); i = i - ____(c)____ ; } } ``` <br /> <span style="font-weight:bold">答案</span>:A <span style="color:blue">詳解</span>:將選項代入對應的位置,看輸出值是否符合題目的要求,選項A對應的p值分別為2、4、6、8,為正確答案;選項B對應的p值分別為6、8、10,選項C對應的p值分別為2、4、6、8、10,選項D對應的p值分別為6、7、8、9。 <br /><br /> 24. 下列 g(4)函式呼叫執行後,回傳值為何? (A) 6   (B) 11   \(C\) 13   (D) 14 ```c int f (int n) { if (n > 3) { return 1; } else if (n == 2) { return (3 + f(n+1)); } else { return (1 + f(n+1)); } } int g(int n) { int j = 0; for (int i=1; i<=n-1; i=i+1) { j = j + f(i); } return j; } ``` <br /> <span style="font-weight:bold">答案</span>:C <span style="color:blue">詳解</span>:本題考函式的遞迴 (recursion)。由於呼叫 g(4) 回傳值為 j = 0 + f(1) + f(2) + f(3),因此先列出 f(1)、f(2)、f(3) 的運作流程會比較簡單。 $$ \begin{align*} f(1) &= 1 + f(2) = 1 + 3 + f(3) = 1 + 3 + 1 + f(4) = 1 + 3 + 1 + 1 = 6 \\ f(2) &= 3 + f(3) = 3 + 1 + f(4) = 3 + 1 + 1 = 5\\ f(3) &= 1 + f(4) = 1 + 1 = 2\\ g(4) &= 0 + f(1) + f(2) + f(3) = 0 + 6 + 5 + 2 = 13 \end{align*} $$ <br /><br /> 25. 下列 Mystery()函式 else 部分運算式應為何,才能使得 Mystery(9) 的回傳值為 34。 (A) x + Mystery(x-1)        (B) x * Mystery(x-1) \(C\) Mystery(x-2) + Mystery(x+2)   (D) Mystery(x-2) + Mystery(x-1) ```c int Mystery (int x) { if (x <= 1) { return x; } else { return ____________ ; } } ``` <br /> <span style="font-weight:bold">答案</span>:D <span style="color:blue">詳解</span>:最方便的作法是將選項代入程式碼中看輸出結果,為了簡化算式,以下將 Mystery() 簡寫為 M(),選項A計算公差為1的等差級數 $$ M(9) = 9 + M(8) = 9 + 8 + M(7) = \dots = 9 + 8 + 7 + \dots + 1 = 45 $$ 選項B計算階乘 $$ M(9) = 9 \times M(8) = 9 \times 8 \times M(7) = \dots = 9 \times 8 \times 7 \times \dots \times 1 = 9! = 362880 $$ 選項C不會收斂 $$ M(9) = M(7) + M(11) = [M(5) + M(9)] + [M(9) + M(13)] = \dots $$ 選項D計算費氏數列(費波那契數列, Fibonacci numbers),依序列出 M(0) 到 M(9) $$ \begin{align*} M(0) &= 0\\ M(1) &= 1 \\ M(2) &= M(0) + M(1) = 1\\ M(3) &= M(1) + M(2) = 1 + 1 = 2\\ M(4) &= M(2) + M(3) = 1 + 2 = 3\\ M(5) &= M(3) + M(4) = 2 + 3 = 5\\ M(6) &= M(4) + M(5) = 3 + 5 = 8\\ M(7) &= M(5) + M(6) = 5 + 8 = 13\\ M(8) &= M(6) + M(7) = 8 + 13 = 21\\ M(9) &= M(7) + M(8) = 13 + 21 = 34 \end{align*} $$ 因此答案為D。 <br /><br /> --- ###### tags:`APCS`、`C`、`C++`