2013-02-19 77 views
2

好的,所以我对c中的结构是全新的,并且我有一个对我来说似乎很陌生的问题。
当使用它的指针将简单的结构传递给函数时,该结构会自动接受该函数的其他参数之一,因为它是新数据。我不知道为什么会发生这种情况.. 在这一刻move_walker()应该什么都不做,对吧?奇怪的问题在c中使用结构指针

typedef struct { 
    int x, 
     y; 
} walker_t; 

walker_t* init_walker(int x, int y) { 
    walker_t walker; 
    walker.x = x; 
    walker.y = y; 
    walker_t *pointer = malloc(sizeof(walker)); 
    pointer = &walker; 
    return pointer; 
} 

int move_walker(walker_t * walker, int direction) { 
    return 0; 
} 

walker_t* walker; 
walker = init_walker(8,2); 

printf("%d %d\n", walker->x, walker->y); //will print '8 2' 
move_walker(walker, 3); 
printf("%d %d\n", walker->x, walker->y); //will print '0 3' 

(我敢肯定,它不事关,但是这个代码实际上扩展到了多个文件。)

+0

您有一个错字;-) change pointer =&walker; * pointer = walker; – qPCR4vir 2013-02-19 12:03:36

+0

你为什么决定为此使用动态内存分配? – Lundin 2013-02-19 12:56:58

回答

2

您在栈上创建结构对象。你会需要它使用

walker_t* init_walker(int x, int y) { 
walker_t* walker = malloc(sizeof(walker_t)); 
... 
return walker; 
} 

分配随着

walker_t *pointer = malloc(sizeof(walker)); 
pointer = &walker; 

要创建一个内存泄漏!将指针分配给指针时,将新内存分配给*指针并丢失指针。

+0

内存泄漏是另一个问题,您的解决方案无法解决它。你正在解决的问题是解引用悬挂引用,而不是内存泄漏! – SomeWittyUsername 2013-02-19 11:55:51

+0

你是对的!这工作。尽管我仍然不完全明白问题是什么,因为第一个printf语句有效,但是只要指针传递给函数,它就不会。 – user1666419 2013-02-19 11:56:47

+0

@icepack对不起,不要让你......我把记忆分配给一个新的对象,超出这个范围,这个功能并不重要。 – 2013-02-19 11:58:03

3

你的init_walker是错误的,因为它返回一个指向栈本地变量的指针walker。一旦init_walker退出,该变量的内存就会被回收。您的第一个printf仍然有效,因为您的walker变量的值在堆栈中尚未触及。但是,只要在此之后进行任何函数调用,原来的init_walker调用的堆栈帧就会被覆盖,并且walker指针现在指向一些随机垃圾。

当您在init_walker的内部malloc中,您已经为您的walker_t堆堆(与堆栈不同,它超出了堆栈帧的生存期)分配内存。所以,你应该这样做,而不是:

walker_t* init_walker(int x, int y) { 
    walker_t *pointer = malloc(sizeof(walker_t)); 
    pointer->x = x; 
    pointer->y = y; 
    return pointer; 
} 
0
walker_t* init_walker(int x, int y) { 
    walker_t walker; 
    walker.x = x; 
    walker.y = y; 
    walker_t *pointer = malloc(sizeof(walker)); 
    *pointer = walker; /* here was the error. Copy the value not the adress */ 
    return pointer; 
} 

但它可以是简单的:

walker_t* init_walker(int x, int y) { 

    walker_t *pointer = malloc(sizeof(*pointer)); 
    pointer->x = x; 
    pointer->y = y;  
    return pointer; 
} 
3

的问题是,你的walker指针变为无效堆栈内存,因为init_walker有一个错误:您在堆栈上创建walker_t结构,然后使用malloc保留内存,并将该内存的地址分配给pointer。到现在为止还挺好。

然而,行pointer = &walker从堆栈复制结构,以新的内存,而不是它使pointer指向栈上你的结构! &walkerwalker的地址,并将其分配给您的指针。你可能想要做的是复制结构。要做到这一点,你必须取消引用指针:

*pointer = walker

这应该使你的程序工作按预期。您也可以跳过堆栈完全靠结构:

walker_t* init_walker(int x, int y) { 
    walker_t *walker = malloc(sizeof(walker_t)); 
    walker->x = x; 
    walker->y = y; 
    return walker; 
} 
0

你的代码是把它政体“很奇怪”。

这将更好地工作......

walker_t *init_walker (int x, int y) 
{ 
    walker_t *p_walker = (walker_t *)malloc (sizeof(walker)); 

    if (p_walker != NULL) 
    { 
     p_walker->x = x; 
     p_walker->y = y; 
    } 
    return (p_walker); 
} 

然后调用free (walker)当您与他们完成

+0

的答案你为什么要使用malloc的结果?我想听听为什么。 – Lundin 2013-02-19 13:02:15

+0

,因为如果你编译的代码中有许多编译器警告启用(这是一个很好的事情),或者编译为C++,你会得到一个有关将void *转换为walker_t *的警告\错误。 编译器警告是你的朋友,启用它们。 – Anonymouse 2013-02-19 14:11:16

+0

在C中,你不会在任何像样的编译器上得到任何编译器警告,无法对void指针进行隐式转换。例如,尝试删除转换并使用'gcc -std = c99 -Wall -Wextra -pedantic'进行编译。相反,您的类型转换_hides_有用的警告是_dangerous_ [在C90编译器上](http://c-faq.com/malloc/mallocnocast.html)。此外[阅读此](http://stackoverflow.com/questions/1565496/specifically-whats-dangerous-about-casting-the-result-of-malloc)。在C++中,你根本不应该使用malloc,它在C++中是危险的(http://www.parashift.com/c++-faq-lite/mixing-malloc-and-delete.html)。 – Lundin 2013-02-19 14:35:26

0

...或者,该代码的完整性检查后,你还可写:

typedef struct 
{ 
    int x, 
    int y; 
} walker_t; 

void init_walker(walker_t* obj, int x, int y) 
{ 
    obj->x = x; 
    obj->y = y; 
} 

walker_t walker; 
init_walker(&walker, 8,2);