2013-05-30 141 views
2

我有兩個相同程序的例子。這個程序有一個函數,它創建一個數組並返回指向數組的指針。C和JAVA程序之間的區別

第一節目(在C):

#include <stdio.h> 
#include <stdlib.h> 

#define N 5 

int* GetValues() 
{ 
    int items[N] = { 1, 2, 3, 4, 5 }; 
    return items; 
} 

int main(int argc, char** argv) { 

    int *array = GetValues();  
    int i;  
    for(i = 0; i < N; i++) 
    { 
     printf("%d\n", array[i]); 
    }  

    return (EXIT_SUCCESS); 
} 

第二程序(在Java中):

package tests; 

public class Tests { 

    public static int[] foo() {   
     int array[] = { 1, 2, 3, 4, 5 }; 
     return array;   
    } 

    public static void main(String[] args) {   
     int[] array = foo();   
     for(int i = 0; i < array.length; i++) { 
      System.out.println(array[i]); 
     }     
    } 
} 

Java程序的結果如下:1,2,3, 4,5

C程序的結果如下:1 -1075386156 -1218492432 1 -1216747208

爲什麼我們會得到不同的結果?我的版本如下。

在GetValues()函數內部的C程序中,將會創建並初始化items [] local array。返回instraction將返回指向數組開始的指針,但該數組將被分配到該函數的LOCAL內存中。當GetValues()函數的最後一條指令被調用時,本地內存將被銷燬。在這種情況下,我們無法預測哪些數據存儲在那裏,我們不知道將打印什麼指令(難怪,內存已被破壞並且值也是如此)。

在java程序中我們有以下情況。 JAVA中的數組是對象。 java中的對象存儲在堆中。因此,執行foo()方法後,將創建對象array並將其放入堆中。執行完方法後,局部變量將被清除,但我們的指針array-object仍然在堆中(垃圾回收器會理解何時該對象必須被刪除),這就是爲什麼我們能夠正常打印它。

我對不對?我是否正確理解這些功能?如果不是,有人可以糾正我? 在此先感謝。

P.S.對不起,我的英語,我希望我解釋我的問題或多或少清楚。

+0

你基本上是對的。這種差異的主要原因是Java沒有工具可以讓你創建一個自動存儲的參考(指針)。所以你不能簡單地在自動存儲中定義一個數組並將其作爲地址,你不得不在堆中創建數組並將其參考存儲在自動存儲中。這是一個相當嚴格的限制,但它巧妙地消除了許多可能的錯誤/暴露。 –

回答

3

是的,你是真正正確的。 Java中的數組存儲在堆中並返回給調用者。 Java程序就如你寫道:

int array[] = new int[5]; 
array[0] = 1; 
...etc. 
return array; 

這是沒有問題的。

C程序中的數組對於函數是本地的,當該函數返回時指向這些本地值的指針無效。

1

在Java數組是對象(從Java Language Specification引號):

一個對象是一個類的實例或陣列。

因此,在您的應用程序的Java版本中,在foo方法中創建的數組實際上存儲在堆中,而不是堆棧中。因此可以在foo方法之外訪問它。

+0

但是C數組也可以存儲在堆中。作爲一個對象,本身與它無關,除了Java不允許「自動」對象。這是Java的限制,而不是「功能」,導致差異。 –

+0

@HotLicks是的,當然。但是,正如你所說的,這種對Java的「限制」導致了OP所要求的行爲差異。 –

2

在C程序int* GetValues()中,您正在返回一個指向局部變量的指針,該變量是未定義的行爲,一旦從函數返回,items將不存在。這將是一次的方式固定代碼:

int *items = malloc(sizeof(int) * 5) ; 
items[0] = 1 ; 
// initialize rest of array 
return items; 

只要記住,你需要freemalloc什麼。

在Java中,arrays are objects和對象圍繞引用傳遞,因此Java中不存在相同的問題,因爲Java將垃圾收集對象,一旦它不再引用它。

1

我不確定您是否在尋求幫助修復代碼或幫助理解爲什麼存在問題。如果您需要後者的幫助,您似乎已經瞭解它:由於C數組存儲在堆棧中(稱爲本地函數存儲器),因此函數返回時,數據不再存在於內存中。相反,您將在釋放後返回指向同一內存的指針。它與返回一個未初始化的指針基本上是一樣的,這會導致一些C代碼真正令人討厭的問題!

int* GetValues() 
{ 
    int items[N] = { 1, 2, 3, 4, 5 }; 
    return items; 
} 

如果您有興趣修復上述代碼,您需要在返回堆之前爲堆上的數組分配空間。堆比堆棧有更多的空間,只要你有指向特定塊的指針,就可以從程序中的任何地方訪問它。

你會看這樣的:

int* GetValues(){ 
    int * items = malloc(sizeof(item) * N) 
    //I used a for loop to populate the array, just for speed 
    int i; 
    for(i = 0; i < 4; i++){ 
    items[i] = i+1 
    } 
    return items 
} 

這可能不是完美的,因爲我有種迅速拼湊一起,同時做別的事情,但希望它橫跨有想法。重要的是你需要初始化一個指向堆的內存中的塊(用malloc完成)。

如果malloc代碼對您沒有意義,您可能需要在C中對內存管理進行一些閱讀。這可能是一種痛苦,但它也是指針能夠如此有用的原因之一。

+0

是的,我知道如何修復以修復代碼。我試圖問我是否理解這種差異的原因是正確的。我似乎理解它是正確的。 –