在函数内部创建动态内存

6
我希望您能告诉我这段代码为什么无法运行(从内存角度讲),以下是代码内容:
#include <stdio.h>
#include <stdlib.h>

int* fun(int*);
int main()
{
  int a=5;
  int* ptr;
  //  ptr=(int*)malloc(sizeof(int));
  fun(ptr);
  a=*ptr;

  printf("\n the val of a is:%d",a);
  return 0;
}

void fun(int* ptr)
{

  ptr = (int*)malloc(sizeof(int));
  *ptr = 115;


}

为什么这不能工作?我认为堆(更重要的是地址)对栈中所有函数变量都是共用的。
此外,如果我在函数fun内注释掉内存分配并取消在main函数中的注释,则会发生什么问题。它可以正常工作。

顺便说一句,对于一个清晰明确的问题,点赞+1。 - DevSolar
+1 这是一个非常常见的错误,我记得很久以前我也犯过同样的错误(在遥远的星系中 ;))。 - Andreas Brinck
7个回答

15
在C语言中,所有内容都是按值传递
你传递给函数的是在main()中指针的副本
这意味着指向分配的内存的副本指向115。
main()中的ptr仍然指向未定义的位置,因为它从未被赋值。
尝试传递指向指针的指针,这样在fun()中你可以访问指针本身:
#include <stdio.h>
#include <stdlib.h>

int* fun(int**); // <<-- CHANGE
int main()
{
    int a=5;
    int* ptr;
    //  ptr=(int*)malloc(sizeof(int));
    fun(&ptr); // <<-- CHANGE
    a=*ptr;

    printf("\n the val of a is:%d",a);
    return 0;
}

int* fun(int** another_ptr) // <<-- CHANGE
{

    *another_ptr = (int*)malloc(sizeof(int)); // <<-- CHANGE
    **another_ptr = 115; // <<-- CHANGE
    return *another_ptr;
}
另一种选择是让fun()实际返回更新后的指针(如宣传所述),并将其分配给ptr:
#include <stdio.h>
#include <stdlib.h>

int* fun(int*);
int main()
{
    int a=5;
    int* ptr;
    //  ptr=(int*)malloc(sizeof(int));
    ptr = fun(ptr); // <<-- CHANGE
    a=*ptr;

    printf("\n the val of a is:%d",a);
    return 0;
}

int* fun(int* another_ptr)
{
    another_ptr = (int*)malloc(sizeof(int));
    *another_ptr = 115;
    return another_ptr; // <<-- CHANGE
}

编辑:我已经重命名了在fun()中的变量,以使其清楚地与您在main()中使用的变量不同。 在这里,相同的名称并不意味着任何东西。


@Devsolar:如果malloc在fun()内部,那么它将是按值传递。但是,如果malloc在main()中进行,则仍将是按值传递。您能告诉我为什么一个会起作用而另一个不会吗? - tomkaith13
一切都是传值!再读一遍第一行。 - Alex Budovski
在你的代码中:假设你在main()函数中初始化ptr为0x12345678或其他值。你被注释掉的那行调用了malloc()并将其返回值赋给了ptr,使它指向由malloc()分配的内存位置。相反,你的fun()函数收到了ptr副本(指向0x12345678),调用malloc(),将其返回值赋给ptr的副本,然后返回。(错误地没有返回如广告所述的int*)函数返回后,你再次使用的是真实的 ptr - 它仍然指向0x12345678... - DevSolar
@DevSolar:哇,我完全忘记了return语句。对此感到抱歉...非常感谢你。我一直在努力找到不使用双指针的答案。 - tomkaith13
@DevSolar 是否需要 int* fun(int* another_ptr) 这样的函数声明?因为它只是一个副本。 我们可以使用 int* fun(void) 并返回 (int*)malloc(sizeof(int)); 对吗? - undefined
@AlphaGoku 在问题的原始片段中使用了fun(int* ptr)(并将其赋值给ptr),所以我在我的答案中保留了这一点。 - undefined

3

fun()函数的参数是你传递给fun()的变量的一个副本。因此,当你执行以下操作时:

ptr = (int*)malloc(sizeof(int)); 
*ptr = 115;

你只需要更改那份副本。你应该更改函数签名:

int* fun(int** ptr) 
{ 
     *ptr = (int*)malloc(sizeof(int)); 
     **ptr = 115; 
} 

并相应更改你的调用方式。


@sharptooth:如果malloc在fun()内部,那么它将是按值传递。但是,如果malloc在main()中进行,则仍将按值传递。您能告诉我为什么一个会起作用而另一个不会吗? - tomkaith13
因为在第一个情况下,您将指针初始化为指向正确的内存,然后复制该指针,并将副本指向的内容设置为115。而在另一个情况下,您复制未初始化的指针,将副本初始化为指向正确的内存,然后将副本指向的内容设置为115。第二种情况的区别是原始指针仍未初始化 - Anon.

2
你对这里的几件事情感到困惑,但编写该函数的一种简单方法是:

您在这里有几个疑问,但编写此功能的一种简单方法是:

int * fun()
{
  int * ptr = (int*)malloc(sizeof(int));
  * ptr = 115;
  return ptr;
}

现在你需要负责释放内存,所以在main()函数中:

int * ip = fun();
printf( "%d", * ip );
free( ip );

另一种方法是将指向指针的指针(指向指针的指针)的地址传递给函数:

void fun( int ** pp )
{
  * pp = (int*)malloc(sizeof(int));
  ** pp = 115;
}

那么你在 main() 中的代码看起来应该是这样的:
int * ip;
fun( & ip );
printf( "%d", * ip );
free( ip );

我认为你可以看出第一个函数更容易使用。

1

如果你想改变指针的地址,你需要在主函数中传递指针的地址:

fun(&ptr);

(当然要适当地更改fun

目前,它正在更改函数内部的局部变量ptr,而这种更改显然不会神奇地出现在其他任何地方。


0
你正在将 ptr 通过值传递给 funfun 将接收到一个副本并进行修改。你需要将 ptr 作为 int** 传递。
void fun(int** ptr)
{
   *ptr = (int*)malloc(sizeof(int));
   **ptr = 115;
}

并使用以下方式调用:

fun(&ptr);

我还从fun中删除了返回值,因为它没有被使用。


@Andreas:如果malloc在fun()内部,那么它将是按值传递。但是,如果malloc在main()中进行,则仍将按值传递。您能告诉我为什么一个会起作用而另一个不会吗? - tomkaith13

0

请记住,如果您想让一个函数修改参数的值,您必须传递该参数的指针。这也适用于指针值;如果您想让一个函数修改指针值(而不是指针所指向的内容),您必须传递该指针的指针:

void fun (int **ptr)
{
  /**
   * Do not cast the result of malloc() unless you are 
   * working with a *very* old compiler (pre-C89).  
   * Doing so will supress a valuable warning if you 
   * forget to include stdlib.h or otherwise don't have 
   * a prototype for malloc in scope.
   *
   * Also, use the sizeof operator on the item you're
   * allocating, rather than a type expression; if you
   * change the base type of ptr (say from int to long),
   * then you don't have to change all the corresponding
   * malloc() calls as well.
   *
   * type of   ptr = int **
   * type of  *ptr = int *
   * type of **ptr = int
   */  
  *ptr = malloc(sizeof **ptr);
  *ptr = 115;
}

int main(void)
{
  int *p;
  fun(&p);
  printf("Integer value stored at %p is %d\n", (void *) p, *p);
  return 0;
}

顺便提一下,你的示例中存在类型不匹配;你最初声明的fun返回int *,但定义返回void。


0
变量 int* ptr 通过值传递给函数 fun。因此,在函数内部使用 ptr = (int*)malloc(sizeof(int)); 分配的值不会反映在函数外部。所以当你在 main() 中执行 a = *ptr; 时,你正在尝试使用未初始化的指针。如果你想要反映在函数外部对 ptr 所做的更改,则需要将 fun 的签名更改为 fun(int** ptr) 并执行 *ptr = (int*)malloc(sizeof(int));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接