用C

2015-01-03 43 views
0

恢復到以前的值在存儲區中我打了使用C一點點,寫了下面的代碼:用C

#include<stdio.h> 
#include<stdlib.h> 
int main() { 
    char* value = malloc(5 * sizeof(char)); 
    int vect[3]; 
    printf("%d\n", value[135151]); 
    int i, count = 0; 
    for(i = 0; i < 135152; i++) { 
     if(value[i]) { 
      count++; 
      printf("position is %d, value is %d and i change it with 42\n", i, value[i]); 
      value[i] = 42; 
      vect[count - 1] = i; 
     } 
    } 
    printf("count is %d\n", count); 

    printf("pointer is at location %p\n", value); 
    printf("changed values are %d %d %d\n", value[vect[0]], value[vect[1]], 
                 value[vect[2]]); 

    return 0; 
} 

多次嘗試後,我的筆記本電腦,我發現,如果我打印值[135152]我得到 段錯誤,如果我打印值[135151]我得到0在標準輸出。

之後,我很好奇 發現如果在此區間中有非零值,並顯示3個非零值。然後,我嘗試將它們全部修改爲42(我忘了提及在很多程序執行時,即使向量值顯示在不同的位置,如0xbe7010或0x828010,也是如此在相同的位置保留非零值,這使我明白指針地址是虛擬的(但位置相同))。

之後,我修改了這些值,我最後打印了它們以確保它們,並且它們顯示了它們全部3個。但是,在另一個程序執行中,顯示了以前的值,就像我沒有修改該內存區域一樣。

我會給你我的連續3個輸出:

0 
position is 24, value is -31 and i change it with 42 
position is 25, value is 15 and i change it with 42 
position is 26, value is 2 and i change it with 42 
count is 3 
pointer is at location 0x21bb010 
changed values are 42 42 42 


0 
position is 24, value is -31 and i change it with 42 
position is 25, value is 15 and i change it with 42 
position is 26, value is 2 and i change it with 42 
count is 3 
pointer is at location 0x20d1010 
changed values are 42 42 42 


0 
position is 24, value is -31 and i change it with 42 
position is 25, value is 15 and i change it with 42 
position is 26, value is 2 and i change it with 42 
count is 3 
pointer is at location 0x19d0010 
changed values are 42 42 42 

能否請你告訴我,爲什麼還要改變後的值是否仍然存在?

而且,爲什麼指針地址改變,但內存區域是一樣的? (我懷疑C中的物理和虛擬內存之間存在雙向函數,每次執行程序時都會發生變化)。

感謝您的幫助,併爲此牆文本感到抱歉!

+0

代碼應該總是檢查malloc(和系列)返回的值以確保操作成功 – user3629249

+0

這一行:'printf(「%d \ n」,value [135151]);'正在訪問分配區域之外的內存。這會導致未定義的行爲,導致seg故障事件。 – user3629249

+0

這一行:'if(value [i]){'當'i'大於4時,會導致未定義的行爲,導致seg故障事件。未定義行爲執行時會發生什麼是'未定義'。這可能是任何事情,包括你所看到的行爲。注意:在同一個循環中還有兩個未定義行爲的實例。而不是擔心一些隨機事件是可重複的,更好地修復程序。 – user3629249

回答

3

如果我正確理解你的問題,答案就比你想象的要簡單得多。在每個程序執行時,malloc通過從操作系統請求內存來分配內存,但是每次程序執行時,操作系統和操作系統都不會有任何特別的理由給你內存中的相同空間。據我所知,如果你沒有將你的程序作爲內核級程序運行,那麼真的沒有辦法確保你每次都獲得相同的內存地址,即使在這種情況下你可能也不會有相同的內存地址值,因爲在此期間某些其他程序可能已寫入內存(或由於malloc從易失性存儲器分配內存,所以計算機已關閉)。你正在尋找的是可能將你的數組保存到一個文件並在程序執行時讀取該文件。

幾乎所有你所做的事都是未定義的,所以我不能給你一個足夠的答案來解釋它爲什麼會發生。這裏有一些不同種類的未定義行爲要調用的:

printf("%d\n", value[135151]); 

閱讀你過去的數組的末尾,或者更正式提領,其偏移量是比你的數組的大小(value[5]或更高)放大任何指針是未定義的行爲。我製作了很多程序,甚至是導致段錯誤的解引用,但在這種情況下,它會出現您的操作系統或初始化庫(程序在main之前運行的內容)正在爲您的程序分配一堆內存而無需詢問。

if(value[i]) 

變量或內存空間中尚未被程序賦值的值未定義。對於所有的記憶來說都是零,或者它有任何曾經存在的價值,這是完全合理的。關於閱讀這種內存的問題,很明顯,在操作系統被釋放之後,或者在它被分配給你的程序之前,操作系統會分配一些特定的值。操作系統可能做到這一點的一個重要原因是安全性 - 如果一個程序從它之前的程序中獲得了從程序進入內存的值,它可以讀取其他程序的數據,如果以前的程序將明文密碼轉換爲哈希值,例如。

value[i] = 42; 

這可能不言而喻,但將值分配給未分配給您的內存位置也是未定義的行爲。

編輯:在迴應評論:未定義的行爲意味着標準沒有定義當你這樣做時會發生什麼。顯然,如果程序編譯並運行,它必須表現出一些行爲,但未定義的行爲可能完全不同,具體取決於編譯器,標準庫版本,操作系統以及各種其他因素。在你的情況下,所有的變量聚集在一起導致你所看到的行爲,但是沒有把你編譯器,環境,硬件等的每個細節都分開,我們不能告訴你爲什麼,更重要的是,這種行爲可能(可能會如果我使用不同的操作系統和編譯器編譯並運行這些代碼,那麼它們會完全不同。作爲一個方面說明,我在幾個編譯器上試了這個,在Linux Red Hat上使用clang 3.5.0和gcc使用類似的結果,所以我最好的猜測是這些信息與malloc有關的實現,當釋放內存時可能使用free的元數據。

+0

爲什麼打印的值爲」-31 15 2'每次? – Adrian

+0

在每個執行程序中,我確實喜歡20,我會在相同的位置獲取相同值的值(我的意思是非零值),這讓我想,而且我仍然認爲,在這種情況下,C給了我每次執行時都有相同的內存區域。所以,爲了利用這個,我想覆蓋非零值到其他值(也許它會分配給我另一個內存區域)。但是,驚喜!它爲我分配了相同的內存區域,甚至更多,我覆蓋的值仍然保留在先前的值。 – Emanuel

+3

幾乎你所做的每件事都是未定義的,所以我不能給你一個適當的答案。我會盡力在我的回答中查看每個未定義行爲的實例。 – IllusiveBrian

1

我假設你對「未定義的行爲意味着任何事情都可能發生」並不滿意,並且想知道C本身沒有定義的東西。由於它不是由C定義的,因此以下是部分推測:

地址空間佈局隨機化或ASLR是大多數現代操作系統的一項功能。它隨機化程序中每個主存區的起始地址。其目的是使某些類型的安全漏洞難以被利用。這不在這個問題的範圍內。

此外,代碼在main之前運行。它初始化標準庫中的各種東西。當我說「你的程序」時,我包含了這個代碼。

由於ASLR,堆將從每個進程的不同地址開始。但是,因爲您的程序不使用任何其他隨機性(它除了ASLR外是確定性),它總是以相同的大小和順序分配內存塊。由於malloc在操作系統上不是隨機的 - 除堆的起始地址外 - 它以相同的「模式」分配內存。也許你的內存塊總是在(start_of_heap + 123400),而其他東西總是在(start_of_heap + 123424)處得到一個內存塊 - 在這種情況下,即使確切地址不同,其他內存塊始終爲(your_memory_block + 24)

這個其他的內存塊是什麼?我無法準確猜測 - 但鑑於您的程序不會崩潰,很可能您的程序再也不會使用了。對於某些未使用的功能可能很重要,或者它可能是內存分配程序的簿記信息(從未看到您覆蓋的值,因爲在此之後,您從未調用過mallocfree)。

P.S.覆蓋不屬於你的內存是導致無法預料的崩潰的好方法。你應該認真避免在任何真實程序中這樣做。這也是編寫不可移植程序的好方法 - 也許OSX在那個位置存儲一些更重要的東西,或者它甚至不會分配那個位置(所以當訪問它時會出現段錯誤)。

+0

我已經完成了程序來學習一些關於C的東西,所以這些「錯誤」是爲了對後來發生的事情的好奇心而完成的。所以,基本上,你的意思是那些給予我的值,我嘗試修改而沒有工作,我的意思是內存分配器可以以某種方式使用位置24,25和26上的值。如果是這樣,那麼爲什麼C沒有一些規則說明在訪問時沒有分配的所有東西都應該給出段錯誤?我之前曾經說過,我可以通過計算出vect1 [32] == vect2 [0]來修改char * vect2,使用char * vect1,這是不好的。 – Emanuel

+1

@Emanuel C的設計哲學的一部分不是限制程序員做「壞」的事情,在角落的情況下,他們做了功課,並知道他們在做什麼。例如,在Java中,如果您分配一個數組然後嘗試讀取其最後一個索引,它總是會拋出異常。在這種情況下,編譯器不可能確切知道爲數組分配了多少空間,因爲該信息在運行時存儲在由'malloc'確定的位置,並且可以在運行時確定。 – IllusiveBrian

+0

所以在Java中,分配是在編譯時完成的(這有助於確定我是否讀過它的索引,但會使程序變慢),而在C中它是在運行時完成的,主要是爲了考慮速度?此外,由於有一些元數據可以幫助「免費」功能知道要釋放多少空間,所以不能用這些信息來確定我是否在未分配的索引上讀取或寫入數據? – Emanuel