阿摩線上測驗 登入

申論題資訊

試卷:104年 - 104 關務特種考試_四等_資訊處理:程式語言概要#24070
科目:程式語言
年份:104年
排序:0

申論題內容

四、下列的 C 程式碼有何問題?如果忽略警告而逕行執行程式,在許多系統上,該程式
將顯示重複的行為,列印出 0 1 2 3 4 5 6 7 8 9,為什麼?也請解釋為什麼在其他的
系統上,該程式的執行結果可能會有所不同,甚至結果是無法確定的。(20 分)
void foo() {
int i;
printf("%d ", i++);
}
int main() {
int j;
for (j = 1; j <= 10; j++) foo();
}

詳解 (共 2 筆)

詳解 提供者:AT
問題是i沒有給初始值,系統會自己給他任意數
可以跑出來是因為系統給他0作為初始值,然後不斷加1直到j=10的那圈做完就停止了
在其他系統上執行出來結果不同或是不確定的原因就是因為沒有配置初始值,導致每一次都會隨機分配i的初始值,所以就不能確定會是哪一串數字了

詳解 提供者:hchungw

問題分析

以下是提供的 C 程式碼:

c
複製程式碼

#include <stdio.h>

void foo() { int i; printf("%d ", i++); }

int main() { int j; for (j = 1; j <= 10; j++) foo(); return 0; }

問題

  1. 未初始化的變數 i: 在函數 foo 中,變數 i 被宣告但未初始化。這意味著 i 的值是未定義的,可能是任何值。根據 C 標準,使用未初始化的自動變數是未定義行為。

  2. 未定義行為(Undefined Behavior): 使用未初始化的變數會導致未定義行為。這意味著程式的行為是不可預測的,可能會在不同的執行環境下產生不同的結果。

可能的執行結果

在許多系統上,這段程式碼可能會顯示 0 1 2 3 4 5 6 7 8 9。這是因為:

  1. 堆疊記憶體重用: 在某些系統中,每次呼叫 foo 函數時,堆疊空間可能會重用前一次函數呼叫的記憶體位置。如果變數 i 在第一次使用時是 0,則每次 i++ 都會將其值增加 1,因此會輸出從 0 開始的連續數字。

為什麼在其他系統上結果可能不同

  1. 堆疊初始化: 有些編譯器和運行時環境會初始化堆疊記憶體,以便於偵錯和安全性考量。在這些系統上,未初始化的變數可能會被設置為特定的值(如 0xDEADBEEF 或其他特殊值),這將導致不同的輸出結果。

  2. 堆疊隨機化: 為了增強安全性,某些系統會對堆疊位置進行隨機化處理(堆疊地址空間配置隨機化,ASLR)。這會導致每次執行程式時,未初始化變數的初始值可能會有所不同。

  3. 未定義行為的不可預測性: 未定義行為意味著程式的結果是不可預測的。不同的編譯器、不同的編譯選項或不同的運行時環境都可能影響程式的行為。因此,結果可能在不同系統上完全不同,甚至導致崩潰或其他意外行為。

改正程式碼

為了避免這些問題,我們應該在使用變數 i 之前對其進行初始化:

c
複製程式碼

#include <stdio.h>

void foo() { int i = 0; // 初始化變數 i printf("%d ", i++); }

int main() { int j; for (j = 1; j <= 10; j++) foo(); return 0; }

這樣,程式的行為將會是確定的,每次都會輸出 0 0 0 0 0 0 0 0 0 0。如果我們希望輸出 0 1 2 3 4 5 6 7 8 9,則需要讓 i 在每次呼叫 foo 時累積其值:

c
複製程式碼

#include <stdio.h>

void foo(int *i) { printf("%d ", (*i)++); }

int main() { int j; int i = 0; // 初始化變數 i for (j = 1; j <= 10; j++) foo(&i); return 0; }

這段程式碼將在每次呼叫 foo 時傳遞變數 i 的地址,使得 i 在每次呼叫時遞增,從而輸出 0 1 2 3 4 5 6 7 8 9。