2

我无法完全理解 C 中的 malloc() 函数,更准确地说是在需要使用它时。

当我像这样声明一个指向全局结构的指针时,

struct Position* currentPositionPtr;

我是否需要使用 malloc 为其分配动态内存来初始化它?或者稍后在需要时简单地将结构的指针分配给它是一种好习惯,例如

currentPositionPtr = getPosition();

wheregetPosition()返回指向“struct Position”的指针。

4

6 回答 6

8

做什么getPosition()

如果它返回一个指向 的有效指针struct Position,那么您当然不需要为该结构分配内存两次。我希望你的函数看起来不像这样:

struct Position *getPosition()
{
    struct Position p = { x, y };
    return &p;
}

因为这会表现出未定义的行为(通过返回指向块范围自动对象的指针)。通常,您宁愿返回一个已经 malloc()过时的指针:

struct Position *getPosition()
{
    struct Position *p = malloc(sizeof(*p));
    p->x = 42;
    p->y = 1337;
    return p;
}

然后,再次,您不需要额外调用malloc().

但是,如果不是被调用函数负责分配,那么,好吧......调用者是:

void getPosition(struct Position *p)
{
    p->x = 42;
    p->y = 1337;
}

在后一种情况下,您需要这样称呼它:

struct Position *p = malloc(sizeof(*p));
getPosition(p);

如果你需要你的结构来生存函数返回,或者

struct Position p;
getPosition(&p);

如果你不这样做。

于 2013-06-20T16:44:48.583 回答
2

malloc(或其他内存分配功能)在您需要系统为您提供内存时需要。

所以是的,当你这样做时

struct Position* currentPositionPtr;

您将需要致电malloc()

currentPositionPtr = malloc(sizeof(struct Position));

或将指针分配给已分配内存块的地址:

struct Position globalPos;

void func(void) {
    struct Position pos;
    struct Position* currentPositionPtr = &pos; //ok
    struct Position* globalPosPtr = &globalPos; //also ok
    ...
}

因为您所做的只是声明指针,而不是为结构保留空间。

但是,如果您的指针是global,则将其分配给堆栈分配的内存可能很危险。考虑以下:

struct Position *globalPosPtr = NULL;

void foo(void) {
    struct Position pos;
    globalPosPtr = &pos;
    //can dereference globalPosPtr with no problems here
    ...
}

void bar(void) {
    foo();
    //globalPosPtr is invalid here
    ...
}

至于您关于拥有另一个返回指针的函数的问题:

getPosition()将需要使用malloc或其他一些内存分配函数本身。所以这样做非常好,如果您通常希望将结构中的值初始化为某些值,那么这样做是有意义的。但是,请记住,即使您malloc在其他函数内部调用,free当您完成使用它时也需要内存以防止内存泄漏。

要回答标题中的问题,每当您将某个东西声明为指针时,如果您想使用它,就需要给它一些指向的东西。如果你想让它指向一个新的东西,你需要用malloc()或相关的函数动态分配它。

于 2013-06-20T16:43:13.600 回答
1

通常,malloc在以下情况下使用:

  1. 当您想要动态分配内存时:换句话说,当您不知道需要多少内存时。或者当您不知道何时不再需要它时。
  2. 当您要分配大量内存时:堆可以变得非常大,但堆栈受到更多限制。在堆栈上分配非常大的东西可能会导致堆栈溢出(嘿!这就是站点的名称!)。当然,这样的大小是特定于实现的,因此是相当主观的短语“非常大”。
  3. 当您希望分配的内存可以从外部访问时:如果程序的其他线程需要访问一块内存,则将其分配到一个线程的堆栈上将是一个坏主意,因为它可能会随着该线程的移动而被覆盖,然后其他人都会看到损坏的内存。
  4. 可能还有其他几个案例。
于 2013-06-20T16:47:31.963 回答
0

有几件简单的事情要理解:

  1. malloc() 只是从堆中返回内存,用户进程有责任通过调用 FREE 系统调用来释放这块内存。

  2. 当你在编码时知道,你需要处理固定数量的内存,比如一个结构,一个数组,那么你可以用局部变量和全局变量来满足进程的内存需求。

从您的查询来看,当您必须处理 malloc 并作为结果指针时,您似乎感到困惑。

  1. 您需要一个指针来保存 malloc 系统调用分配的内存地址。
  2. 指针不一定指向 malloc 分配的内存,它可以是任何有效的内存,例如:

     int a =2;
     int *ptr; 
     ptr = &a;
    

所以在这里,ptr 指向不是由 malloc 分配的内存位置。

相反,你可以做

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

在您的情况下,指向 struct 的指针 currentPositionPtr 可以指向全局/局部变量的地址,前提是内存地址在整个访问该指针的过程中保持有效。

我希望这可以简化事情。

于 2013-06-20T17:07:38.250 回答
0

如果您使用的是已知大小的结构,则不必使用 malloc 分配内存,因为内存在不同的结构位置之间是不可更改的,但是,

如果在 struct Position 中,您有一个指向未知大小的指针,具体取决于某些用户输入,那么您可以使用 malloc 来分配所需内存块的大小。

如果你正在分配 struct Position 数组,那么

currentPositionPtr = malloc(sizeof(struct Position)*neededSize);

完成后,您将不得不删除内存

free (currentPositionPtr)
于 2013-06-20T16:50:48.083 回答
0

似乎您已经知道 malloc 的工作原理,但我会尝试回答您的问题。

每当您 malloc 时,请确保在其上保留一个指针,以便您可以操纵它(或释放它)。malloc 的优点是它是动态的。您可以声明一个 malloc 结构的链表(例如),而不是声明一个数组,并使用指针来跟踪它们。通过这种方式,您永远不会遇到诸如离开阵列之类的问题。相反,您可以动态地请求更多空间,并在以后需要时释放它。

于 2013-06-20T16:41:46.710 回答