如何分配内存并将其(通过指针参数)返回给调用函数?

时间:2009-09-09 08:28:01

标签: c pointers malloc

我在一些看起来像这样的不同函数中有一些代码:

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中可用,但一旦函数返回,相同的内存就不可用。

可以看到程序的示例运行here,输出显示各种内存地址。

有人可以向我解释一下我在这里做错了什么,以及我如何让这段代码发挥作用?


编辑:所以看起来我需要使用双指针才能做到这一点 - 当我真正需要使用双指针时,我将如何做同样的事情?所以例如数据是

int **data = NULL; //used for 2D array

我是否需要在函数调用中使用三指针?

11 个答案:

答案 0 :(得分:57)

您想使用指针指针:

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个字节,或者为8个字节) 64位OS),而你真的想要存储指针指向(一个int所需的字节数,即大多数操作系统上的4个字节)。因为通常sizeof(int *)>=sizeof(int),这可能不会引起问题,但需要注意的是。我在上面的代码中已经纠正了这一点。

以下是关于指针指针的一些有用的问题:

How do pointer to pointers work in C?

Uses for multiple levels of pointer dereferences?

答案 1 :(得分:8)

一个常见的陷阱,特别是如果你将Java从C / C ++转移到C / C ++

请记住,当您传递指针时,它会传递值,即复制指针的值。对指针指向的数据进行更改是有好处的,但指针本身的任何更改都只是本地的,因为它是一个副本!!

诀窍是使用通过引用传递指针,因为你想要改变它,即malloc等等。

**指针 - >会吓到一个noobie C程序员;)

答案 2 :(得分:4)

如果要修改指针,则必须将指针传递给指针。

即。 :

void someFunction (int **data) {
  *data = malloc (sizeof (int)*ARRAY_SIZE);
}

编辑: 添加了ARRAY_SIZE,在某些时候你必须知道要分配多少个整数。

答案 3 :(得分:2)

这是因为指针数据按值传递给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;
}

答案 4 :(得分:2)

someFunction()将其参数作为int *。因此,当您从main()调用它时,您创建的值的副本。无论您在函数内部修改什么,都是此副本,因此更改不会反映在外部。正如其他人建议的那样,您可以使用int **来获取数据中反映的更改。另外,这样做是从someFunction()返回int *。

答案 5 :(得分:2)

除了使用双指针技术外,如果只需要1个返回参数,则重写如下:

 int *someFunction () {
   return (int *) malloc (sizeof (int *));
 }

并使用它:

 int *data = someFunction ();

答案 6 :(得分:1)

这是在函数中分配内存并通过参数返回指针的一般模式:

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);
  ...
}

关于内存管理的一些注意事项:

  1. 避免内存管理问题的最佳方法是避免内存管理;除非确实需要,否则不要使用动态内存。
  2. 除非您使用的是早于1989 ANSI标准的实现,或者您打算将代码编译为C ++,否则不要强制转换malloc()的结果。如果您忘记包含stdlib.h或者在范围内没有malloc()的原型,则转换返回值将会产生有价值的编译器诊断。
  3. 使用所分配对象的大小而不是数据类型的大小(即sizeof *p而不是sizeof (T));如果数据类型必须改变(例如从int到long或float到double),这将为你节省一些心痛。它还使代码读得更好IMO。
  4. 隔离更高级别的分配和解除分配函数背后的内存管理功能;这些不仅可以处理分配,还可以处理初始化和错误。

答案 7 :(得分:0)

这里你试图修改指针,即从“data == Null”到“data == 0xabcd”你分配的其他一些内存。因此,要修改您需要的数据,请传递数据地址,即& data。

void someFunction (int **data) {
  *data = (int *) malloc (sizeof (int));
}

答案 8 :(得分:0)

回复您编辑的其他问题:

'*'表示指向某事物的指针。因此'**'将指向指向某事物的指针,'***'指向指向某物的指针的指针等。

'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);

答案 9 :(得分:0)

我没有使用双指针,只能分配一个新指针并返回它,不需要传递双指针,因为它不会在函数的任何地方使用。

返回void *,因此可以用于任何类型的分配。

void *someFunction (size_t size) {
    return  malloc (size);
}

并将其用作:

int *data = someFunction (sizeof(int));

答案 10 :(得分:0)

为简单起见,我将上面的单指针参数称为p 和双指针pp(指向p)。

在一个函数中,p所指向的对象可以更改,并且更改不存在 功能。但是,如果p本身已更改,则更改不会 离开功能。

不幸的是,malloc具有其自身的特性,通常 更改p。这就是为什么原始代码不起作用的原因。 校正(58)使用指向p的指针pp。在纠正 功能,p改变了,但是pp没有改变。这样就行了。