我有两个相同程序的例子。该程序有一个函数,它创建一个数组并返回指向数组的指针。
第一个程序(在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。对不起我的英语我希望我或多或少地解释我的问题。
答案 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中的内存管理进行一些阅读。这可能很痛苦,但这也是指针如此有用的部分原因。