2014-05-09 37 views
2

我玩弄了C和不同的排序算法。我決定首先嚐試在不初始化的情況下聲明一些大小的自動數組(比如100),而不是生成一個隨機數組進行排序。我預計操作系統(我在Windows XP上)會將零置於其中,否則這可能是某些其他進程留下的數據。但事實證明,這種未初始化的數組中沒有零。所以第一個問題是:它可能是什麼數據,爲什麼不通過操作系統清理?難道它是「cmd」shell的垃圾嗎?我正在運行編譯器和程序?因爲我試過的排序算法沒有分配任何更多的內存,只是將所有內存排序,我認爲會有兩種可能性:(a)爲數組分配的內存區域將變爲在下一次運行中進行排序並保持這種狀態,或者(b)在下一次運行時,操作系統會給程序另外一部分內存,因此會導致另一個垃圾。但事實證明,它既不是。無論我分類多少次,內存都保持不變。所以,第二個問題是:我怎麼可能得到一些隨機的虛擬內存區域,對它進行排序,然後在下一次運行中,我會得到原始形式的相同區域?在Windows中分配的內存的內容

下面是代碼和我的步驟。

#include <stdio.h> 
#define SIZE 100 

void quick_sort(int *a, size_t size) 
{ 
    /* No comments here, everybody knows quicksort 
    and anyone will write it better! :) */ 

    if(size <= 1) return; 

    int tmp, pivot; 
    int small_length, pivot_pos; 

    pivot_pos = size/2; 
    pivot = a[pivot_pos]; 
    tmp = a[0]; 
    a[0] = pivot; 
    a[pivot_pos] = tmp; 

    small_length = 0; 

    for(int i = 1; i < size; i++) 
    { 
     if(a[i] < pivot){ 
      small_length++; 
      tmp = a[small_length]; 
      a[small_length] = a[i]; 
      a[i] = tmp; 
     } 
    } 

    a[0] = a[small_length]; 
    a[small_length] = pivot; 

    quick_sort(a, small_length); 
    quick_sort(a + small_length + 1, size - small_length - 1); 
} 

int main(int argc, char *argv[]) 
{ 
    int a[SIZE]; 
    int i; 

    quick_sort(a, SIZE); 
    for(i = 0; i < SIZE; i++) { 
     printf("%d\n", a[i]); 
    } 
    return 0; 
} 

步驟I中使用:

  1. 編譯quick_sort呼叫評論,看到未排序未初始化數組:cc sort.c -Wall -std=c99 && a > unsorted1(已編譯的可執行是a.exe)。
  2. 取消註釋quick_sort來電查看排序結果:cc ... > sorted
  3. 再次評論該呼叫以再次查看未排序的數組:cc ... > unsorted2
  4. 比較文件unsorted1unsorted2 - 它們是相同的,全部100行。

我也嘗試啓動另一個「cmd」實例,並且數據是相同的。

更新

未排序的數據的

一十六進制轉儲:

0000000 0000 0000 fd7c 0022 fd74 0022 fdd8 0022 
0000020 0170 0000 1448 7c91 ffff ffff 1440 7c91 
0000040 0000 0024 13d2 7c91 301c 0024 3008 0024 
0000060 0010 0000 b988 7c97 0000 003e 0007 0000 
0000100 fd24 0022 0000 0000 fe24 0022 e900 7c90 
0000120 0040 0001 002e 0000 0000 003e eeeb 7c80 
0000140 fe30 0022 e900 7c90 0040 7c91 ffff ffff 
0000160 003d 0001 0002 0000 fd5c 0022 0000 0000 
0000200 fe50 0022 0002 0000 0002 0000 ffff ffff 
0000220 003d 7c91 c2de 77c1 0000 003e 0000 0000 
0000240 c2e3 77c1 a122 0040 0000 0000 2bc4 003e 
0000260 2070 77c0 ffff ffff 0000 003e 2bc0 003e 
0000300 0004 0000 2373 0024 1660 0040 fea0 0022 
0000320 c024 77c1 0000 003e 0000 0000 c02d 77c1 
0000340 1660 0040 2373 0024 1dc0 0040 fec0 0022 
0000360 c024 77c1 0000 003e 0000 0000 c02d 77c1 
0000400 1dc0 0040 2373 0024 0000 0000 5c94 77c2 
0000420 a52e 77c2 1ae8 77c5 fedc 0022 9d60 77c2 
0000440 fe88 0022 4e2f 77c2 feec 0022 5c94 77c2 
0000460 a52e 77c2 1ae8 77c5 fefc 0022 9d60 77c2 
0000500 0008 0000 4e2f 77c2 4e29 77c2 ff3c 0022 
0000520 2373 0024 0000 0000 1dc0 0040 fed4 0022 
0000540 ff08 0022 ffe0 0022 5c94 77c2 2850 77c0 
0000560 ffff ffff 4e29 77c2 4e42 77c2 1dc0 0040 
0000600 ffa0 0022 1e1e 0040 1dc0 0040 0020 0000 

爲了生產轉儲我不得不添加一個文件,的fopen(...),FCLOSE(...)到代碼,並改變了輸出。但是這些調用是在數組聲明之後進行的,所以仍然不確定這會如何影響數組的內容。

二,試圖將SIZE增加到10000,最後看到零。輸出是很多的零,最後是熟悉的垃圾。我不確定內存在哪個方向發展,我預計數據將停留在陣列的開始處......

+0

向我們展示'unsorted1'的十六進制內容 - 最有可能的是分配器填充了類似0xDEADBEEF的東西(儘管我會懷疑更現代的版本......) –

+5

操作系統不會給你的程序留下一塊內存一些其他的流程,這將是一個嚴重的信息泄露安全漏洞。內存只是在你的程序的C運行時庫啓動(全局構造函數,stdio初始化等)之前在調用'main()'之前執行的剩餘堆棧垃圾。 –

回答

4

現代多用戶/多進程操作系統總是將清理內存頁面交給進程請求內存(以便敏感數據不會從一個進程泄漏到另一個進程)。請注意,僅當操作系統最初將內存交給進程時,此「乾淨」合同才適用。如果進程最初爲內存使用內存,然後再使用內存,則內存不會自動重新清理。這就是發生了什麼 - 您的未初始化變量位於堆棧上,並且在運行main之前,堆棧已被C運行時啓動代碼使用。你看到堆棧上剩下的啓動代碼都是垃圾。如果您確切地知道它是什麼,您可以閱讀Microsoft Visual C運行時庫源代碼(它隨Visual Studio提供),或者在反彙編程序中查看反彙編程序的入口點。

這同樣適用於堆。當malloc,VirtualAlloc等首先從操作系統中獲取頁面時,它們將是乾淨的。但是,如果調用freeVirtualFree等,則運行時庫沒有義務將頁面交給操作系統並重新請求它們。它可以抓住它們(不清洗它們)並使用它們來滿足以後的要求。