2014-03-27 58 views
1

我電話採訪了一位技術巨頭的一個問題是這樣的:什麼可能導致變量改變值?

假設你有一個函數,該函數裏面你有

int i = 100; 

你在做一些其他的事情功能沒有接觸變量我和稍後你打印我和你看到的價值是不同的。什麼會導致這種變化?

我回答:某種內存損壞,內存溢出..等等。他們似乎並不滿意答案。現在我想到堆棧指針變得混亂了。有什麼我失蹤的?

+0

科技巨頭通常會問你保持這樣的對話的全部內容保密的,不是嗎? – iavr

+0

我甚至懷疑你是否正確轉錄了問題,因爲它被問及它是否被充分描述。 – Matt

+0

如果您確實無法以任何定義或未定義的方式觸摸'i',我建議觸摸'cout'。 – jingyu9575

回答

2

在if語句中錯誤地使用單個等號(賦值)而不是雙等號(比較)是一種好方法。

+2

,涉及使用OP的單詞「觸摸」變量i。 – carlosdc

+2

有人會認爲他們沒有觸及變量。 ;-)因此是棘手的問題。 –

+0

哈哈我不知道他們是否會接受,但我想這是一個有效的答案 –

1

INT I = 100

如果定義該函數內它,這將是在堆棧變量。因此,如果以任何方式(例如,通過傳遞已溢出的參數或函數內部的某些其他局部變量溢出),它可以更改值「i」。這可能是由於堆棧溢出/損壞而發生的。

但是,這種情況會導致函數的堆棧指針/返回值損壞,最終可能導致程序崩潰/未定義行爲。

2

您使用在不同範圍內其他地方的i變量名稱(例如,在for環,更深的範圍,全局聲明,模塊/功能的靜態,成員變量,...),所以i你以爲你是打印出不是你正在打印的i

另一種可能性 - 引用。另一個引用i的變量。

1

當函數返回時,i的版本完全消失,因爲它是在函數內部聲明的局部變量,所以它的生存期與函數相關。即打印出來外的函數(之後)的所述的i版本是一個完全不同的i,函數

1

這種類型的東西之前定義的(假設你指的是相同的I,這意味着在那裏你打印我的值在同一個函數內)。

#include <stdio.h> 

void f() 
{ 
    char buf[100]; 
    int i = 100; 
    int j; 

    for (j = 0; i <= 100; j++){ 
     buf[j] = 255; 
    } 

    printf("i=%d\n", i); 
} 

int main(int argc, char* argv[]) 
{ 
    f(); 
    return 0; 
} 

猜猜是什麼打印?是的。 I = 255。我想在這裏展示的是,我們可以溢出一個緩衝區並填充隨後的變量內容。

這樣做的一個更微妙的方式是濫用sizeof。

例如

int array[100] 
    sizeof array != 100 

    So you can't do 
    for (i = 0; i < sizeof array; i++) // very bad! 

所以你可以看到一個bug如何導致緩衝區溢出。

但是,隨着現代版本的gcc上述代碼將核心轉儲。包括第一個。我必須使用-fno-stack-protector選項實際編譯它,以便在不轉儲內核的情況下打印結果。如果你做一個大小的話,它會立即轉儲核心。

1

我回答:某種內存損壞,內存溢出..等等。

非常合理的開始。

「沒有觸及變量i」有點含糊不清,因爲我們只是在摸摸i,所以我們只能猜測什麼樣的觸摸不夠明顯可以算作觸摸。也許:

未定義行爲:所有的賭注都關閉....

引用和指針:如果非const引用或指針i創建,i可能已經間接修改。還有可能是一個懸掛在那個堆棧地址上的指針(但不是「你的」i)被賦予了一些異步中斷或其他線程,並且你的i可能通過它的使用被修改)。

中斷處理:不常用的應用程序代碼的一個問題,但如果你編寫自己的中斷處理程序 - 或者嘗試一些α/β的人 - 他們可能會被意外地與你的籌碼擰緊,甚至破壞註冊編譯器預計i可用在

聯彙編語言:如果編譯器的加載i到寄存器中,而你做的寄存器的東西在一些內聯彙編了該編譯器不推/保存並彈出/ r ESTORE值,印刷

i可能似乎已改變的差一錯誤可能導致問題:

char s[3]; 
int i = 100; 
... do something that loads text into c that might not be terminated ... 
s[sizeof s] = '\0'; // "ensure termination"/actually off by one 

誠然,這是由「超限」種覆蓋,儘管它不是「cool」的那種可以隨意遠遠過去s的那種。

其他的想法:

  • 線程是不會受到審查的方式陳述可以用i搞砸可能相關,但每個線程都有一個獨立的堆棧,因此會採取重大腐敗/未定義行爲

  • 「稍後您打印我」 - 我假設這不是他們要找的東西,但有一類方法可能會填滿:以十六進制打印並且思考值64不同從預期的100位小數開始,打印來自其他打印語句(可能在其他線程中)的「干擾」,例如來自另一範圍的)以下爲「0」打印使得i似乎是「1000」