如何在函数中动态分配内存?
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()
之前表示堆内存对象,因为该对象尚未分配,其地址已分配给aPtr
槽fPtr
。此后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**)&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 那么最好陈述你的观点(你想表达的东西)而不是问一个问题(听起来你想学习一些东西)以上是关于如何在函数中动态分配内存?的主要内容,如果未能解决你的问题,请参考以下文章