简体   繁体   English

在另一个函数中的Malloc

[英]Malloc inside another function

I have to allocate a struct from within another function, obviously using pointers. 我必须从另一个函数中分配一个结构,显然是使用指针。 I've been staring at this problem for hours and tried in a million different ways to solve it. 我一直在盯着这个问题几个小时,并尝试以一百万种不同的方式来解决它。

This is some sample code (very simplified): 这是一些示例代码(非常简化):

...
some_struct s;
printf("Before: %d\n", &s);
allocate(&s);
printf("After: %d\n", &s);
...

/* The allocation function */
int allocate(some_struct *arg) {

arg = malloc(sizeof(some_struct));
printf("In function: %d\n", &arg);

return 0;
}

This does give me the same address before and after the allocate-call: 这确实在分配调用之前和之后给了我相同的地址:

Before: -1079752900
In function: -1079752928
After: -1079752900

I know it's probably because it makes a copy in the function, but I don't know how to actually work on the pointer I gave as argument. 我知道这可能是因为它在函数中创建了一个副本,但是我不知道如何实际处理作为参数给出的指针。 I tried defining some_struct *s instead of some_struct s, but no luck. 我尝试定义some_struct * s而不是some_struct s,但是没有运气。 I tried with: 我尝试过:

int allocate(some_struct **arg)

which works just fine (the allocate-function needs to be changed as well), BUT according to the assignment I may NOT change the declaration, and it HAS to be *arg.. And it would be most correct if I just have to declare some_struct s.. Not some_struct *s. 它工作得很好(分配功能也需要更改),但是根据分配,我可能不会更改声明,而必须是* arg。如果我只需要声明,那将是最正确的some_struct s .. not some_struct * s。 The purpose of the allocation function is to initialize a struct (a some_struct), which also includes allocating it. 分配函数的目的是初始化一个结构(some_struct),该结构还包括对其进行分配。

One more thing I forgot to mention. 我忘了提一件事。 The return 0 in the allocate function is reserved for some status messages and therefore I can't return the address using this. 分配函数中的return 0保留用于某些状态消息,因此我无法使用此返回地址。

Typically, I'd return the pointer from allocate : 通常,我会从allocate返回指针:

void * allocate()
{
    void * retval = malloc(sizeof(some_struct));
    /* initialize *retval */
    return retval;
}

If you want to return it in a parameter, you have to pass a pointer to the parameter. 如果要在参数中返回它,则必须传递一个指向该参数的指针。 Since this is a pointer to a some_struct, you have to pass a pointer to a pointer: 由于这是指向some_struct的指针,因此您必须将指针传递给指针:

void allocate (some_struct ** ret)
{
    *ret = malloc(sizeof(some_struct));
    /* initialization of **ret */
    return;
}

to be called as 被称为

some_struct *s;
allocate(&s);
int func(some_struct *arg) {
    arg = malloc(sizeof(some_struct));
    ... 
}

Here you just assign the result of malloc to the local arg variable. 在这里,您只需将malloc的结果分配给本地arg变量。 pointers are passed by value in C, a copy of the pointer gets passed to the function. 指针通过C中的值传递,指针的副本传递给函数。 You cannot change the pointer of the caller this way. 您不能以这种方式更改调用者的指针。 Keep in mind the difference in a pointer and what it points to. 请记住指针的不同之处及其指向的内容。

You have various options: 您有多种选择:

Return the pointer from the function: 从函数返回指针:

 some_struct *func(void) {
    arg = malloc(sizeof(some_struct));
    ...
    return arg;
}
...
some_struct *a = func();

Allocate the structure in the caller: 在调用方中分配结构:

 int func(some_struct *arg) {
    ...
    arg->something = foo;

}
... 
some_struct a;
func(&a);

Or dynamically allocate it 或动态分配

some_struct *a = malloc(sizeof *a);
func(a);

Using a pointer to the callers pointer: 使用指向调用者指针的指针:

 int func(some_struct **arg) {
    *arg = malloc(sizeof **arg);

}
... 
some_struct *a;
func(&a);

Use a global variable (ugly..) 使用全局变量(很丑..)

 some_struct *global;
 int func(void) {
    global = malloc(sizeof *global);

}
 ... 
some_struct *a;
func();
a = global;

I highly doubt this is what your teacher had in mind, but you can cheat using a series of legal type conversions. 我非常怀疑这是您的老师的想法,但是您可以使用一系列合法的类型转换作弊。

   int allocate(some_struct *arg) 
   /* we're actually going to pass in a some_struct ** instead. 
      Our caller knows this, and allocate knows this.  */
   { 
      void *intermediate = arg;  /* strip away type information */
      some_struct **real_deal = intermediate;  /* the real type */
      *real_deal = malloc(sizeof *real_deal); /* store malloc's return in the 
                                                 object pointed to by real_deal */
      return *real_deal != 0;  /* return something more useful than always 0 */
   }

Then your caller does the same: 然后,您的呼叫者执行相同的操作:

   {
      some_struct *s; 
      void *address_of_s = &s; 
      int success = allocate(address_of_s); 
      /* what malloc returned should now be what s points to */
      /* check whether success is non-zero before trying to use it */
   }

This relies on a rule in C that says any pointer to an object can be implicitly converted to a void pointer, and vice-versa, without loss. 这依赖于C语言中的一条规则,即任何指向对象的指针都可以隐式转换为void指针,反之亦然,而不会丢失。

Note that formally this is undefined, but it is all but sure to work. 请注意,这在形式上是未定义的,但是几乎可以保证一切正常。 While any object pointer value is required to be able to convert to a void* and back without loss, there is nothing in the language that guarantees that a some_struct* can store a some_struct** without loss. 尽管要求任何对象指针值都能够转换为void*且无损返回,但该语言中没有任何东西可以保证some_struct*可以存储some_struct**而不会丢失。 But it has a very high likelihood of working just fine. 但是它很有可能正常工作。

Your teacher gave you no option but to write formally illegal code. 您的老师别无选择,只能编写正式的非法代码。 I don't see that you have any other option besides "cheating" like this. 除了这种“作弊”之外,我看不到您还有其他选择。

You can't do it this way. 你不能这样子。 You can't declare a struct by value, and then change it by address. 您不能按值声明结构,然后按地址更改它。

some_struct *s;
printf("Before: %d\n", s");
allocate(&s);
printf("After: %d\n", s");
...

/* The allocation function */
int allocate(some_struct **arg) {

*arg = malloc(sizeof(some_struct));
printf("In function: %d\n", *arg");

return 0;
}

You need to modify the pointed value for the struct. 您需要修改结构的指针值。 So you need another level of indirection, thus you have to send a pointer to the struct pointer. 因此,您需要另一个间接级别,因此必须将指针发送到struct指针。

Well, C uses pass-by-value, which means that functions get copies of their arguments, and any changes made to those copies don`t affect the original in the caller. 嗯,C使用了按值传递,这意味着函数将获取其参数的副本 ,并且对这些副本所做的任何更改都不会影响调用方中的原始参数。

/* The allocation function */
int allocate(some_struct *arg) {

arg = malloc(sizeof(some_struct));
printf("In function: %d\n", &arg");

return 0;
}

Here you pass in the address of your some_struct s. 在这里,您输入some_struct的地址。 Then you discard that address, and replace it with whatever was returned by malloc. 然后,您丢弃该地址,并将其替换为malloc返回的内容。 Then you return, and the return value of malloc is lost forever, and you've leaked memory. 然后您返回,并且malloc的返回值永远丢失,并且您已经泄漏了内存。 And your some_struct s has not been changed. 并且您的some_struct尚未更改。 It still has whatever random number it was initialized to, which you printed out. 它仍然具有初始化后的任何随机数,并将其打印出来。

If you may not change the signature of the allocate function, it can never be useful. 如果您不更改分配函数的签名,那么它将永远无用。 It must either take the address of a pointer, so that it can modify the value of that pointer, or it must return a pointer that your caller can tuck away. 它必须使用指针的地址,以便可以修改该指针的值,或者必须返回一个调用者可以隐藏的指针。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM