2017-09-30 112 views
0

我想知道为什么在我的malloc之后所有修改都不起作用。 这里是我用来说明此代码:当初始化时C位字段未被修改

#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 Ideone:https://ideone.com/O59tqZ

+0

谢谢大家:你们都得到了你的+1,因为你的答案都是真的。我认为Daniel Trugman的回答更清楚。我可能混淆了这个概念与另一种语言^^ – jy95

回答

2

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

局部变量

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; 
} 

摘要

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

+0

谢谢!我真的不需要这种代码的编译器......但另一方面,我确实想念:) –

+0

我已经学会了谨慎的方式。我有时会在编译之前发布一个答案。无论如何,我通常会尽快编译它,而且我很多时候不得不回头修改答案而感到失望。 –

+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)); 

BTW,的malloc回不得,不应该在C.

+0

感谢您的答案:我如何做我的malloc,然后建立一个领域? – jy95

+0

请参阅我的编辑 –

+0

感谢您的编辑。问题是我必须在一个函数中完成它:( – jy95

1

投似乎有这个代码的一些误解。首先,您在主函数内的堆栈上分配一个Age结构体。然后你将一个指针传递给你的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,因为返回值似乎没有任何用处。您应该也可以将'change'函数的返回类型更改为void,因为它似乎没有返回任何值。

+1

原始示例中的'test'对象不在堆中分配Age结构(在主函数中),它是一个局部变量... –

+0

对不起,我打算说栈不是堆 –

+0

这不正确它定义了使用自动存储的变量,可以使用堆栈类型的内存来实现,但它是实现定义的。请参阅我的[answer here](https://stackoverflow.com/questions/6159968/declaring-array- of-int/46329105#46329105)来查看e xact解释。 –

1

您正在通过值传递指针到函数init。这意味着该函数在该指针的副本上进行操作。在这种情况下,您正在为其分配新地址,但原始指针未被更改。如果要为指针分配一个新的值,而该值在函数返回后仍然存在,则必须将该指针的地址(指向指针的指针)传递给该函数。

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