如何在函数中动态分配内存?

Posted

技术标签:

【中文标题】如何在函数中动态分配内存?【英文标题】:How to dynamically allocate memory in a function? 【发布时间】:2020-05-11 22:55:01 【问题描述】:

假设我想动态分配内存,但使用函数而不是 main() 函数。

所以我尝试这样做:

dynamAlloc(int *fPtr)

   fPtr=malloc(cols * sizeof(*fPtr) );
   if(fPtr==NULL)
     
      printf("Can't allocate memory");
      exit(1);
    

然后我意识到:即使在堆上分配的内存在程序的整个生命周期内都可以使用,但该内存只能被形式参数 fPtr 引用,而不是实际参数(我们称之为 aPtr)。但是一旦退出函数,该内存就会丢失。

那么我该如何使用函数动态分配内存呢?

【问题讨论】:

formal arument fPtr and not the actual argumen - 什么是“正式论证”?什么是“实际论证”?它们有何不同?您是在问如何从函数的外部范围为变量赋值? 类似How to change a variable in a calling function from a called function?? assign a memory block - 指针不是内存块,它只是内存地址。 所以我所要做的就是将int *fPtr 替换为int **fPtr 以接收&aPtr 作为参数? dynamAlloc(int **fPtr) 然后*fPtr=malloc(cols * sizeof(**fPtr) ); 否则,您将分配的块分配给函数本地指针的 copy ,因此在main() 中永远不会看到分配(本质上是内存泄漏)。在main() 中与dynamAlloc (&pointer) 通话。 @KamiCuk @DavidThe 多个取消引用 * 操作员使它看起来比实际更难,但我意识到这个概念仍然是一样的。非常感谢你给我指路! 【参考方案1】:

内存只能被形式参数fPtr引用,而不是实际参数(我们称之为aPtr)。

aPtr 不能在调用dynamAlloc() 之前表示堆内存对象,因为该对象尚未分配,其地址已分配给aPtrfPtr。此后aPtr引用堆对象。

我们只需要将aPtr的指针地址传递给dynamAlloc()即可。因此,您需要适当的参数(实际参数)和参数(形式参数)在函数之间传递指针 aPtr 的地址,如下所示。

那么我该如何使用函数动态分配内存呢?

您可以像 main() 那样做,不管指针是在 main() 还是其他函数中声明的,您只需将指针 aPtr 的地址传递给其他函数,你想在其中使用堆内存对象,比如fe:

#include <stdio.h>
#include <stdlib.h>

#define cols 5

void dynamAlloc(int** fPtr);

int main()

    int* aPtr;

    dynamAlloc(&aPtr);

    free(aPtr);

    return 0;



void dynamAlloc(int** fPtr)                 

   *fPtr = malloc(sizeof(*fPtr) * cols);
   if(*fPtr == NULL)
     
      printf("Can't allocate memory");
      exit(1);
    


别忘了free()堆内存!

【讨论】:

程序终止后它会在内存中保持不变。操作系统不会将所有分配的内存收回给程序吗?【参考方案2】:

或者直接改成这样:

void dynamAlloc(int **fPtr)

   *fPtr=malloc(cols * sizeof(**fPtr) ); // malloc is returning void* so in that place it would be compiler error, so pointer returned from malloc should be casted to the pointer type of the value.
   if(*fPtr==NULL) // that would be a warning in gcc since NULL is a macro eq to 0, or (void*)0, it compiler version
     
      printf("Can't allocate memory");
      exit(1);
    

及功能用法:

int* ptr = (int*)NULL;
dynamAlloc(&ptr);
*ptr = 1; // assign 1 to the first element, ptr is a valid pointer here

但双指针语法在某些情况下可能会变慢,最后用返回函数回答,该本地指针的副本是更好的做法。

【讨论】:

因为需要 C,所以可以像 int* ptr = (int*)NULL; 你的函数依赖于全局变量。不要在这样的函数中退出程序。 这不是我的功能,这不是修复它的情况,作为嵌入式固件工程师,我会对该代码进行许多其他更改,首先在这种情况下的功能是浪费处理器时间, 除非您对可以稍后检查泄漏字节的 malloc 进行包装,否则总线仍然是,更好的选择是使用宏使该包装在线。 @JohnySiemanoKolano 所以你是说int* dynamAlloc(int * fPtr) 更快(我想这更好?),即堆中的返回地址比双指针语法更好?有什么理由会使用双指针语法而不是其他语法? 另外,我读过 malloc 的强制返回值是不好的做法。见***.com/q/605845/10701114。这就是为什么我没有在malloc() 声明之后发表我的评论,而不是您的评论。虽然有些人说基于链接上的 cmets,铸造不再是坏事。【参考方案3】:

由于您需要更改指针本身 - 需要指向指针的指针

void *allocate(void **tmp, size_t size)

    if(tmp)
    
        *tmp = malloc(size);
    
    return *tmp;



int main()

    int *ptr;

    if(!allocate((void**)&ptr, sizeof(*ptr) * 100))
    
        perror("Error\n");
        exit(1);
    
    /* do something*/
    free(ptr);

【讨论】:

@TruthSeeker 方法极其复杂。指针上的free (void**)&amp;ptr - 通过*(void**) 访问int * 是未定义的行为。【参考方案4】:

使用宏函数更方便,像这样:

#include <stdio.h>
#include <stdlib.h>

#define NEW_ARRAY(ptr, n) \
     \
        (ptr) = malloc((size_t) (n) * sizeof (ptr)[0]); \
        if ((ptr) == NULL)  \
            fputs("Can't allocate memory\n", stderr); \
            exit(EXIT_FAILURE); \
         \
    

#define NEW(ptr) NEW_ARRAY((ptr), 1)

int main(void)

    int *myArray;
    const int myArrayLen = 100;
    int i;

    NEW_ARRAY(myArray, myArrayLen);
    for (i = 0; i < myArrayLen; i++) 
        /*...*/
    
    return 0;

更新:

宏的目的是抽象出细节并使内存分配更不容易出错。对于(非宏)函数,我们必须将元素大小作为参数传递,因为当指针传递给 void 指针类型的形式参数时,该信息会丢失:

void NewArray(void *ptr, int n, int elemSize)

        *ptr = malloc((size_t) n * sizeof elemSize);
        if (*ptr == NULL) 
            fputs("Can't allocate memory\n", stderr);
            exit(EXIT_FAILURE);
        

有了函数NewArray,对应第一个例子的分配调用就变成了

NewArray(&myArray, n, sizeof myArray[0]);

这对我们没什么好处。

【讨论】:

为什么MACRO为什么不用inline函数呢? @TruthSeeker inline 用于函数NEW_ARRAY(ptr, n) 不像函数,更像ptr = foo(n, typeof ptr) @chux-ReinstateMonica:是的,这是真的。我要说的一点是,当我们可以通过常规函数解决为什么要使用 MACRO 时。看完this。我尽量避免使用 MACRO。 @TruthSeeker 那么最好陈述你的观点(你想表达的东西)而不是问一个问题(听起来你想学习一些东西)

以上是关于如何在函数中动态分配内存?的主要内容,如果未能解决你的问题,请参考以下文章

在C语言中,如何给函数分配内存?

c语言中啥是动态分配内存?

构造函数分配内存失败是如何冒出来的?

如何在C中为char**动态分配内存

第十二章 类和动态内存分配

C语言中的动态内存分配的用法举例