【问题标题】:C - Bit Fields not modified when initC - 初始化时未修改位字段
【发布时间】:2017-09-30 21:09:59
【问题描述】:

我想知道为什么在我的 malloc 之后所有修改都不起作用。 这是我用来说明这一点的代码:

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

struct Age {
   unsigned int age : 16;
   unsigned int two : 2;
   unsigned int notToBeInitialed: 2;
};

int init(struct Age * p){
 p = (struct Age *) malloc( sizeof(struct Age) );
 p->age = 5;
 return 0;
}

int change(struct Age * p){
   p->age = 99; 
}

int getValue(struct Age * p){
  return p->age;    
}

int main(void) {
    struct Age test;
    init(&test);
    printf( "Age.age : %d\n", getValue(&test) ); // gives me 0 , expected 5
    change(&test);
    printf( "Age.age : %d\n", getValue(&test) ); // gives me 99 
    return 0;
}

我做错了什么?

感谢您的帮助。

来源:http://www.tutorialspoint.com/cprogramming/c_bit_fields.htm 爱迪生:https://ideone.com/O59tqZ

【问题讨论】:

  • 谢谢大家:你们都得到了+1,因为你们所有的答案都是真实的。我认为丹尼尔·特鲁格曼的回答更清楚。我可能把这个概念和另一种语言混为一谈了^^

标签: c field bit bit-fields


【解决方案1】:

您显然误解了自动存储和动态内存分配之间的区别。

局部变量

struct Age test

使用自动存储定义Age 对象。 你不需要做任何其他事情,这个对象已经存在并且现在可以使用了。声明此类对象的唯一缺点是它们存在于整个声明范围内。 你不应该在这个对象上调用 init(至少不是 malloc 部分),因为它已经被初始化了,只需使用 test.age 设置它的值。

以下将按预期工作:

int main(void) {
    struct Age test;
    test.age = 5;
    printf( "Age.age : %d\n", getValue(&test) );
    change(&test);
    printf( "Age.age : %d\n", getValue(&test) );
    return 0;
}

动态内存分配

另一方面,如下:

p = (struct Age *) malloc( sizeof(struct Age) );

使用动态内存分配。 分配新内存,然后将指针返回给您。 在这种情况下,您决定使用此内存来保存 Age 对象。

int init(struct Age ** p){
    *p = (struct Age *) malloc( sizeof(struct Age) );
    (*p)->age = 5;
}

int main(void) {
    struct Age * test;
    init(&test)
    printf( "Age.age : %d\n", getValue(test) );
    change(test);
    printf( "Age.age : %d\n", getValue(test) );
    return 0;
}

总结

这两种方法是互斥的。当您创建一个局部变量时,没有必要为它分配额外的内存。

【讨论】:

  • 谢谢!我真的不需要这种代码的编译器......但另一方面,我确实错过了:)
  • 我学会了小心谨慎。我有时会在编译之前发布答案。无论如何,我通常会尽快编译它,但我对我不得不返回并修改答案的频率感到失望。
【解决方案2】:

您对malloc 的调用会覆盖收到的参数。所以初始化转到那个新对象,然后在函数返回时泄漏。

看来你在混淆初始化和分配。

从您的 init 函数中删除 malloc

那么你可以简单地分两步分配 init。一个好的成语是

struct Age* init(struct Age * p){
 if (p) {
   p->age = 5;
 }
 return p;
}

....

struct Age* testp = init(malloc(sizeof *testp));

顺便说一句,malloc 的返回不能也不应该在 C 中强制转换。

【讨论】:

  • 感谢您的回答:我怎样才能做我的 malloc 然后设置一个字段?
  • 感谢您的编辑。问题是我必须在一个函数中做到这一点:(
  • 所以您真的不知道如何将其放入单个函数中?那应该不会太难,但我不会为你做你作业的最后一步。而且,执行分配的函数永远不应该被称为init
【解决方案3】:

您正在将指针按值传递给函数init。这意味着该函数对该指针的副本进行操作。在这种情况下,您正在为其分配一个新地址,但原始指针不会改变。如果要为指针分配一个新值,该值将在函数返回后保留,则必须将指针的地址(指向指针的指针)传递给函数。

但在您的示例中,在main 中,您正在堆栈上实例化struct Age。您不能通过在堆上分配内存(使用malloc)来更改其地址(位置)。您所能做的就是在堆上完全创建一个新对象(这就是您在init 中所做的)。但是您在该函数中存在内存泄漏,因为malloc-ed 内存永远不会是freed。

【讨论】:

    【解决方案4】:

    这段代码似乎有一些误解。首先,您在 main 函数内的堆栈上分配一个 Age 结构。然后,您将指向 this 的指针传递给您的 init 函数。到目前为止,一切都很好。但是您随后会在 init 函数中为新的 Age 结构分配内存。您修改了这个新版本的内容,但指向它的指针仅存储在“init”函数内的本地“p”变量中,它不会以任何方式传回。当您打印内容时,您打印的是堆栈分配的 Age 结构,而不是您进行更改的 malloc 分配的结构。

    如果您想将堆栈分配结构的引用传递给 init,并让 init 对其进行修改,那么您应该完全删除 malloc 行。

    如果你想让你的 init 函数分配一个新的 Age 结构体,那么它需要将 'struct Age** p' 作为它的参数,以允许它传递一个 'struct Age* p',在方式如下:

    
    
        void init(struct Age** p){
            *p = (struct Age *)malloc( sizeof(struct Age) );
            (*p)->age = 5;
        }
    
        int main(void) {
            struct Age* test;
            init(&test);
            printf( "Age.age : %d\n", test->age );
        }
    
    

    我还将 init 函数的返回类型更改为 void,因为返回值似乎没有任何作用。您可能还应该将“更改”函数的返回类型更改为 void,因为它似乎没有返回任何值。

    【讨论】:

    • 原例子中test对象的分配并没有在堆上分配Age结构(在main函数中),它是一个局部变量...
    • 对不起,我的意思是说堆栈而不是堆
    • 这也不准确。它使用自动存储定义变量,这可能使用堆栈类型的内存来实现,但它是实现定义的。请参阅我的answer here 以查看确切的解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-07-27
    • 2019-10-05
    • 2021-07-26
    • 1970-01-01
    • 2021-09-25
    • 2021-10-27
    • 2021-12-29
    相关资源
    最近更新 更多