109年關務人員四等程式設計概要
二、請說明下列程式設計重要名詞的差異。(25分) (一)執行期錯誤 (Runtime Error),語意錯誤 (Semantic Error),語法錯誤 (Syntax Error) (二)動態記憶體配置 (Dynamic memory allocation),靜態記憶體配置 (Static memory allocation) |
答:
(一)
1.執行期錯誤(Runtime Error):
(1)定義:
a.執行期錯誤是指在程式成功編譯後,當它被執行時由於某些情況 (如無效的輸入、資源不足或其他未預期的情況) 導致的錯誤。
b.這些錯誤通常不是由編譯器捕獲的,因為它們在語法上是正確的。
c.執行期錯誤可能導致程序異常終止或產生不正確的結果。
(2)範例一:
除以零的錯誤。
#include<stdio.h> int main( ) { int a = 5, b = 0; int result = a / b; // 這將導致執行期錯誤,因為除以零是不允許的 printf("Result: %d\n", result); return 0; } |
(3)範例二:
記憶體配置錯誤。
#include<stdio.h> #include<stdlib.h> int main( ) { int *arr; arr = (int *) malloc(sizeof(int) * 1000000000); // 嘗試分配大量記憶體空間 if (arr == NULL) { printf("Memory allocation failed.\n"); return 1; } // 使用陣列的程式碼 free(arr); return 0; } |
如果系統上沒有足夠的可用記憶體,上述的 malloc 呼叫可能會失敗,導致執行期錯誤。
(4)範例三:
存取超出陣列邊界的錯誤。
#include<stdio.h> int main( ) { int arr[5] = {1, 2, 3, 4, 5}; printf("%d\n", arr[10]); // 存取超出陣列邊界 return 0; } |
嘗試存取 arr[10] 會導致執行期錯誤,因為它超出了陣列的邊界。
2.語意錯誤(Semantic Error):
(1)定義:
是指在程式碼中由於邏輯或概念上的錯誤而產生的問題,這種錯誤不會導致編譯器或解釋器發出錯誤訊息,因為從語法上看,該程式碼是正確的。然而,當執行程式時,它可能不會按照預期的方式運作。
(2)範例:
int average(int a, int b) { return a + b / 2; /* 應該是 (a+ b) / 2 */ } |
程式碼中缺少了一對括號。因此,程式雖然能夠通過編譯並執行,但是由於運算子優先級 (先乘除,後加減) 的緣故,運算結果並不正確。
(3)可能原因:
語句公式寫錯、演算法錯誤、選擇錯誤的演算法、類型轉換錯誤、變數的有效範圍錯誤、遺漏的程式碼區段 (code segment)、對問題或需求的理解有誤等等。
(4)解決方式:將程式中的變數輸出到檔案或列印到螢幕,以定位錯誤所在。
※參考資料:
https://zh.wikipedia.org/wiki/%E9%80%BB%E8%BE%91%E9%94%99%E8%AF%AF_(%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1)
3.語法錯誤(Syntax Error):
(1)定義:
a.是指程式碼中不符合該語言的語法規則的錯誤。當編譯器或解釋器遇到語法錯誤時,它會發出錯誤訊息,並且程式不會執行或編譯。
b.在編譯語言中,語法錯誤一定只在編譯時期出現,編譯器要所有的語法都正確,才能正確編譯。不過在直譯語言中,語法錯誤可能要到執行時期才會出現,而且不一定容易區分語法錯誤及語意錯誤。
(2)範例:
在 Java 語言中,以下的程式是正確的:
System.out.println("Hello World");
以下的程式不正確:
System.out.println(Hello World);
第二個程式理論上要顯示的是叫作 Hello World 的變數,而不是 Hello World這個字,而且 Java 語言的變數名稱中不可有空白。因此,會出現語法錯誤。
※參考資料:
https://zh.wikipedia.org/wiki/%E8%AF%AD%E6%B3%95%E9%94%99%E8%AF%AF
(二)
1.動態記憶體配置(Dynamic memory allocation):
(1)在程式執行時,根據需求動態地分配或釋放記憶體。在 C 語言中,動態記憶體配置主要涉及到使用堆積 (heap) 這部分的記憶體空間。
(2)提供了彈性,允許程式在執行時根據需要分配記憶體。
(3)程式設計師必須確保正確地管理記憶體,包括釋放不再需要的記憶體,以避免記憶體洩漏。
(4)範例:
#include<stdio.h> #include<stdlib.h> int main( ) { int* arr; // 使用 malloc 分配5個整數的記憶體 arr = (int*)malloc(5 * sizeof(int)); if (arr == NULL) { printf("Memory allocation failed.\n"); return 1; } for (int i = 0; i < 5; i++) { arr[i] = i; } // 使用 realloc 改變記憶體大小,增加到10個整數 arr = (int*)realloc(arr, 10 * sizeof(int)); if (arr == NULL) { printf("Memory re-allocation failed.\n"); return 1; } for (int i = 5; i < 10; i++) { arr[i] = i; } for (int i = 0; i < 10; i++) { printf("%d ", arr[i]); } // 釋放記憶體 free(arr); return 0; } |
執行結果:
0 1 2 3 4 5 6 7 8 9
2.靜態記憶體配置(Static memory allocation):
(1)變數的記憶體在程式執行之前就已經配置完成,而且在程式執行過程中,變數的記憶體都固定不變。
(2)它們在程序的整個生命週期中都存在。
(3)缺點為記憶體使用較無彈性,可能會配置過多或過少。
(4)範例:
#include<stdio.h> int globalVar = 100; // 靜態記憶體配置:全域變數 void function( ) { static int staticVar = 50; // 靜態記憶體配置:靜態變數 printf("Static variable: %d\n", staticVar); staticVar += 10; } int main( ) { function( ); // 輸出 Static variable: 50 function( ); // 輸出 Static variable: 60 return 0; } |
globalVar 和 function 中的 staticVar 都是靜態配置的。
註:在編譯時期 (compile-time),編譯器便會配置記憶空間給變數。