C和JAVA程序的区别

时间:2013-05-30 19:02:32

标签: java c programming-languages

我有两个相同程序的例子。该程序有一个函数,它创建一个数组并返回指向数组的指针。

第一个程序(在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数组。返回实例将返回指向数组开始的指针,但此数组将在该函数的LOCAL内存中分配。当调用GetValues()函数的最后一条指令时,本地内存将被销毁。在这种情况下,我们无法预测那里存储了什么数据,我们不知道将打印printf("%d\n", array[i])指令的内容(难怪,内存已经被破坏,值也是如此)。

在java程序中我们有以下情况。 JAVA中的数组是对象。 java中的对象存储在堆中。因此,在执行foo()方法后,将创建对象array并将其归入堆中。在执行方法之后,将清理局部变量,但我们指向array - 对象的指针仍在堆中(垃圾收集器将理解何时必须删除此对象),这就是为什么我们能够正常打印它。

我是对的吗?我能正确理解这个功能吗?如果没有,有人可以纠正我吗? 提前谢谢。

P.S。对不起我的英语我希望我或多或少地解释我的问题。

4 个答案:

答案 0 :(得分:3)

是的,你是正确的。 Java中的数组存储在堆上并返回给调用者。 java程序就像你写的那样:

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

哪个没问题。

C程序中的数组是函数的本地数组,当该函数返回时,指向这些本地值的指针无效。

答案 1 :(得分:2)

int* GetValues()中的C程序中,您返回一个指向未定义行为的局部变量的指针,一旦从函数返回,items将不存在。这将是修复代码的一种方法:

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

请记住,您需要free malloc

在Java arrays are objects中,对象是围绕引用传递的,因此Java中不存在同样的问题,因为Java将Garbage收集对象,一旦它不再引用它。

答案 2 :(得分:1)

在Java数组中是对象(引自Java Language Specification):

  

对象是类实例或数组。

因此,在应用程序的Java版本中,在foo方法中创建的数组实际上存储在堆上,而不是存储在堆栈中。因此,可以在foo方法之外访问它。

答案 3 :(得分: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中的内存管理进行一些阅读。这可能很痛苦,但这也是指针如此有用的部分原因。