我如何分配内存并将其返回(通过指针参数)到调用函数?
我有几个不同的function,看起来像这样的代码:
void someFunction (int *data) { data = (int *) malloc (sizeof (data)); } void useData (int *data) { printf ("%p", data); } int main () { int *data = NULL; someFunction (data); useData (data); return 0; }
someFunction ()
和useData ()
在单独的模块(* .c文件)中定义。
问题是,虽然malloc工作正常,并且分配的内存在someFunction
函数中可用,但是一旦函数返回,相同的内存就不可用。
程序的一个例子可以在这里看到,输出显示了不同的内存地址。
有人可以请给我解释我在这里做错了什么,我怎么能得到这个代码工作?
编辑:所以它看起来像我需要使用双指针来做到这一点 – 当我真的需要使用双指针时,我将如何去做同样的事情? 所以例如数据是
int **data = NULL; //used for 2D array
然后我需要在函数调用中使用三重指针吗?
你想要使用指针指针:
void someFunction (int **data) { *data = malloc (sizeof (int)); } void useData (int *data) { printf ("%p", data); } int main () { int *data = NULL; someFunction (&data); useData (data); return 0; }
为什么? 那么,你想在主函数中改变你的指针data
。 在C中,如果你想改变传入的参数(并在调用者的版本中显示该变化),你必须传递一个指针,指向你想改变的任何东西。 在这种情况下,那个“你想改变的东西”是一个指针 – 所以为了能够改变这个指针,你必须使用一个指向指针的指针。
请注意,在主要问题的顶部,代码中存在另一个错误: sizeof(data)
为您提供了存储指针所需的字节数(在32位操作系统上是4个字节,在64位操作系统上是8个字节),而你真的需要存储指针指向的字节数(一个int
,即大多数操作系统的4字节)。 因为通常sizeof(int *)>=sizeof(int)
,这可能不会造成问题,但是有一点要注意。 我已经在上面的代码中纠正了这个问题。
以下是关于指针的一些有用的问题:
C指针指针如何工作?
用于多级指针解引用?
一个常见的陷阱,特别是如果你从Java转移到C / C ++
记住,当你传递一个指针时,它会传递值,即指针的值被复制。 对指针指向的数据进行更改是很好的,但是指针本身的任何更改都只是本地的,因为它是一个副本!
诀窍是通过引用传递指针,因为你想改变它,即malloc等。
**指针 – >会吓到一个noobie C程序员;)
如果要修改指针,必须将指针传递给指针。
即。 :
void someFunction (int **data) { *data = malloc (sizeof (int)*ARRAY_SIZE); }
编辑:添加ARRAY_SIZE,在某些时候你必须知道你想分配多less个整数。
这是因为指针数据通过值传递给someFunction
。
int *data = NULL; //data is passed by value here. someFunction (data); //the memory allocated inside someFunction is not available.
指针指针或返回分配的指针将解决问题。
void someFunction (int **data) { *data = (int *) malloc (sizeof (data)); } int* someFunction (int *data) { data = (int *) malloc (sizeof (data)); return data; }
someFunction()将其参数设置为int *。 所以当你从main()调用它的时候,你创build的值的一个副本。 无论你在函数内部修改的是这个副本,因此这些更改不会反映到外部。 正如其他人所build议的那样,您可以使用int **来获取数据中反映的更改。 这样做的其他方法是从someFunction()返回int *。
除了使用双指针技术,如果只有1个返回参数需要重写,如下所示:
int *someFunction () { return (int *) malloc (sizeof (int *)); }
并使用它:
int *data = someFunction ();
以下是在函数中分配内存的一般模式,并通过参数返回指针:
void myAllocator (T **p, size_t count) { *p = malloc(sizeof **p * count); } ... void foo(void) { T *p = NULL; myAllocator(&p, 100); ... }
另一种方法是使指针的函数的返回值(我的首选方法):
T *myAllocator (size_t count) { T *p = malloc(sizeof *p * count); return p; } ... void foo(void) { T *p = myAllocator(100); ... }
内存pipe理的一些注意事项:
- 避免内存pipe理问题的最好方法是避免内存pipe理; 除非你真的需要,否则不要用dynamic内存。
- 不要使用malloc()的结果,除非您使用的是早于1989 ANSI标准的实现,或者您打算将代码编译为C ++。 如果忘记包含stdlib.h,或者在范围内没有malloc()的原型,那么强制返回值将抑制有价值的编译器诊断。
- 使用被分配的对象的大小,而不是数据types的大小(即
sizeof *p
而不是sizeof (T)
); 如果数据types必须改变(比如从int到long或从float到double),这将为你节省一些烧心。 这也使得代码读得更好一点IMO。 - 隔离更高级别的内存pipe理function分配和释放函数; 这些不仅可以处理分配,还可以处理初始化和错误。
在这里你试图修改指针,即从“data == Null”到“data == 0xabcd”你分配的其他一些内存。 所以要修改你需要传递的数据即数据的地址。
void someFunction (int **data) { *data = (int *) malloc (sizeof (int)); }
回复您在下面编辑的附加问题:
'*'表示一个指向某个东西的指针。 所以'**'是一个指向某个东西的指针,'***'是一个指向某个东西的指针的指针,等等。
'int ** data'(如果数据不是函数参数)的通常解释是指向int数组列表的指针(例如'int a [100] [100]')。
所以你需要首先分配你的int数组(为简单起见,我使用了一个直接调用malloc()):
data = (int**) malloc(arrayCount); //allocate a list of int pointers for (int i = 0; i < arrayCount; i++) //assign a list of ints to each int pointer data [i] = (int*) malloc(arrayElemCount);
而不是使用双指针,我们可以只分配一个新的指针并返回它,不需要传递双指针,因为它不在函数的任何地方使用。
返回void *
因此可以用于任何types的分配。
void *someFunction (size_t size) { return malloc (size); }
并将其用作:
int *data = someFunction (sizeof(int));