2012-04-19 113 views
1

我写了一个节点的结构和我正在那里时,我的malloc一个新的节点它具有列表 - >头部的同一地址。因此在写链表头一个问题列表的结构链表使列表错误。为什么malloc会分配一个已被使用的地址?

driver.c

#include "target.h" 



int main(int argc, char * argv[]){ 
    struct target_list * target = target_list_alloc("list"); 
    target_list_print(target); 
    target_list_append(target, "G"); 
    target_list_append(target, "B"); 
    target_list_print(target); 
    target_list_append(target, "S"); 
    target_list_print(target); 
    target_list_remove(target,"B"); 
    target_list_print(target); 
    target_list_remove(target,"Bl"); 
    target_list_remove(target,"Br"); 
    target_list_print(target); 
    target_list_append(target,"Ba"); //Here is the problem node 
    target_list_print(target); 
    return 0; 
} 

target.h

#ifndef TARGET_H 
#define TARGET_H 


#include <stdbool.h> 
#include <stdio.h> 
#include <errno.h> 
#include <stdlib.h> 
#include <string.h> 

/*-----------------------------------------*/ 

extern char * prog; 

/*-----------------------------------------*/ 

struct source_list{ 
    char * name; 
}; 
struct recipe_list{ 
    char * name; 
}; 

struct target_node{ 
    char * name; 
    struct target_node * next; 
    struct source_list * src_list; 
    struct recipe_list * rec_list; 
}; 

struct target_list{ 
    char * name; 
    struct target_node * head; 
    struct target_node * tail; 
}; 

/*-----------------------------------------------------*/ 

void target_list_init(struct target_list * list, const char * targetname); 
struct target_list * target_list_alloc(const char * targetname); 
void target_list_deallocate(struct target_list * list); 
void target_list_print(struct target_list * list); 
void target_list_append(struct target_list * list, const char * nodename); 
bool is_in_target_list(struct target_list * list, const char * nodename); 
void target_list_remove(struct target_list * list, const char * nodename); 

/*-----------------------------------------------------*/ 

#endif 

target.c

#include "target.h" 

/*----------------------------------------------------------*/ 

//This function will initialize a new target_list with name targetname 
//This function will assume that target_list is already allocated 
void target_list_init(struct target_list * list, const char * targetname){ 
    verify(list != NULL, "null arg list"); 
    verify(targetname != NULL, "null arg targetname"); 
    verify(targetname[0] != '\0',"empty arg targetname"); 
    list->name = Strdup(targetname); 
    list->head = list->tail = NULL; 
} 

/*----------------------------------------------------------*/ 

//This function will allocate a new target_list and return a pointer to it 
struct target_list * target_list_alloc(const char * targetname){ 
    verify(targetname != NULL, "null arg targetname"); 
    verify(targetname[0] != '\0',"empty arg targetname"); 
    struct target_list * list = malloc(sizeof(struct target_list)); 
    list->name = Strdup(targetname); 
    list->head = list->tail = NULL; 
    return list; 
}  

/*---------------------------------------------------------*/ 

//This function will deallocate a target_list 
void target_list_deallocate(struct target_list * list){ 
    verify(list != NULL,"null arg list"); 
    free(list->name); 
    struct target_node * prev = NULL; 
    for(struct target_node * p = list->head; p != NULL; p= p->next){ 
    free(prev); 
    free(p->name); 
    prev = p; 
    } 
    free(prev); 
    free(list); 
} 

/*----------------------------------------------------------*/ 

//This function will print a target_list 
void target_list_print(struct target_list * list){ 
    verify(list != NULL, "null arg list"); 
    printf("list of targets: %s\n",safe_string(list->name)); 
    if(list->head == NULL){ 
    printf(" <empty>\n"); 
    } 
    else{ 
    for(struct target_node * p = list->head; p != NULL; p = p->next){ 
     printf(" %s\n",p->name); 
    } 
    } 
} 

/*-----------------------------------------------------------*/ 

//This function will append a new target_node onto target_list at the end of it 
void target_list_append(struct target_list * list, const char * nodename){ 
    verify(list != NULL, "null arg list"); 
    verify(nodename != NULL, "null arg nodename"); 
    verify(nodename[0] != '\0', "empty arg nodename"); 

    struct target_node * new_node = malloc(sizeof(struct target_node)); 
    new_node->next = NULL; 
    new_node->name = Strdup(nodename); 
    new_node->src_list = NULL; 
    new_node->rec_list = NULL; 
    if(list->head == NULL){ 
    list->head = list->tail = new_node; 
    } 
    else{ 
    list->tail->next = new_node; 
    list->tail = new_node; 
    } 
} 

/*--------------------------------------------------------*/ 

//This function returns 1 if the nodename is already in the target_list and 0 if not 
bool is_in_target_list(struct target_list * list, const char * nodename){ 
    verify(list != NULL, "null arg list"); 
    verify(nodename != NULL, "null arg nodename"); 
    verify(nodename[0] != '\0', "empty arg nodename"); 
    for(struct target_node * p = list->head; p != NULL; p = p->next){ 
    if(strcmp(nodename,p->name) == 0){ 
     return 1; 
    } 
    } 
    return 0; 
} 

/*------------------------------------------------------*/ 

//This function removes a node with name nodename from target_list */ 
void target_list_remove(struct target_list * list, const char * nodename){ 
    verify(list != NULL, "null arg list"); 
    verify(nodename != NULL, "null arg nodename"); 
    verify(nodename[0] != '\0', "empty arg nodename"); 
    if(is_in_target_list(list,nodename)){ 
    struct target_node * prev = NULL; 
    struct target_node * cur = list->head; 
    while(cur != NULL){ 
     if(strcmp(cur->name,nodename) == 0){ 
    break; 
     } 
     prev = cur; 
     cur = cur->next; 
    } 
    //case 1: removing head pointer 
    if(cur == list->head){ 
     free(cur->name); 
     free(cur->src_list); 
     free(cur->rec_list); 
     free(cur); 
     list->head = NULL; 
     list->tail = NULL; 
     free(prev); 
     cur = NULL; 
     prev = NULL; 
    } 
    //case 2: removing tail pointer 
    else if(cur == list->tail){ 
     free(cur->name); 
     free(cur->src_list); 
     free(cur->rec_list); 
     free(cur); 
     list->tail = prev; 
     free(prev); 
     prev = NULL; 
     cur = NULL; 
    } 
    //case 3: removing a middle node 
    else{ 
     prev->next = cur->next; 
     free(cur->name); 
     free(cur->src_list); 
     free(cur->rec_list); 
     free(cur); 
     cur = NULL; 
     free(prev); 
     prev = NULL; 
    } 
    } 
    else{ 
    fprintf(stderr,"%s: Error %s is not in %s, cannot remove it from %s\n",prog,nodename,list->name,list->name); 
    } 
} 

/*----------------------------------------------------*/ 

有别的定义几个辅助函数,其中(验证,..)但它们不会影响malloc的

编译:

gcc -Wall -Wextra -std=c99 -g -o test driver.c target.c cmpsc311.c 
driver.c:5: warning: unused parameter ‘argc’ 
driver.c:5: warning: unused parameter ‘argv’ 

输出:

list of targets: list 
    <empty> 
list of targets: list 
    G 
    B 
list of targets: list 
    G 
    B 
    S 
list of targets: list 
    G 
    S 
[no name]: Error Bl is not in list, cannot remove it from list 
[no name]: Error Br is not in list, cannot remove it from list 
list of targets: list 
    G 
    S 
list of targets: list 
    Ba 

运行GDB,看着列表,列表 - >头,列表 - >尾和new_node(BA)之后,我不知道为什么new_node获取列表 - 地址>头时的malloc版

GDB:

78 struct target_node * new_node = malloc(sizeof(struct target_node)); 
4: new_node = (struct target_node *) 0x3a00000000 
3: list->tail = (struct target_node *) 0x100100940 
2: list->head = (struct target_node *) 0x1001008e0 
1: list = (struct target_list *) 0x1001008b0 
(gdb) n 
79 new_node->next = NULL; 
4: new_node = (struct target_node *) 0x1001008e0 
3: list->tail = (struct target_node *) 0x100100940 
2: list->head = (struct target_node *) 0x1001008e0 
1: list = (struct target_list *) 0x1001008b0 
(gdb) n 

谁能告诉我,为什么日是和如何解决它? 谢谢

+1

你正在删除'remove'函数中的两个节点,这个_looks_就像一个bug。 – Mat 2012-04-19 05:09:37

+1

旁注:这是太多的代码来演示你的问题。你可以包括那些并不真正使用的结构('source_list','recipe_list'),表面上什么都不做的调用(去掉'Bl'和'Br'),作为两个文件发布而不是粘在一起,等等。一般来说,你应该从样本中删除每行代码,以便在发布之前仍然显示问题:http://sscce.org/ – HostileFork 2012-04-19 05:17:30

+0

“Strdup”的定义是什么? – 2012-04-19 05:19:51

回答

1

target_list_remove()功能看起来伪造的。遍历完列表后,prev指向要删除的元素(prev = cur;)和cur指向下一个,而prev应该指向元素之前的要删除的元素。

而且,你正在呼吁curprevfree(),但我的猜测是,你只需要删除一个元素。

解决您的指针,并调用free()只有一次。

0

的问题是在你删除功能。您在列表的头部被释放,以及呼叫target_list_remove(target,"B");调用free(prev)左右。然后分配器将重新使用存储器,以便您下次调用malloc。您可以使用诸如valgrind之类的工具来调试像这样的内存问题。

0

当你卸下“B”在target_list_remove它会降低到“case 3: removing a middle node”因为你的表看起来是在这一点上:

G -> B -> S 

在代码段从列表中删除CUR节点(prev->next = cur->next)并继续释放当前节点的资源。此时您的列表看起来是这样的:

G -> S 

...但释放的CUR节点之后你继续释放上一个节点(也就是表头),并将其设置为null。

当它附加“Ba”节点时,它遇到条件list->head == NULL它是真实的,因此将列表的首尾设置为新的“Ba”节点。

相关问题