2014-02-19 34 views
1

我正在编写C代码来实现链表。但是,在打印列表内容时,它仅打印最后一个节点的值。我一直在调试long.Please help。代码未打印链表C

#include <stdio.h> 
#include <malloc.h> 

struct list { 
    char *name; 
    char *type; 
    int occurance; 
    struct list *prev; 
    struct list *link; 
}; 

struct list *start=NULL,*ptr,*newnode; 

void main() { 
    int choice = 0; 
    char name1[10], type1[10]; 
    int occ; 

    do { 
     printf("Enter name:"); 
     scanf("%s", name1); 
     printf("Enter type:"); 
     scanf("%s", type1); 
     printf("Enter occurance:"); 
     scanf("%d", &occ); 
     newnode = (struct list *)malloc(sizeof(struct list)); 
     newnode->link = NULL; 
     newnode->prev = NULL; 
     newnode->name = name1; 
     newnode->type = type1; 
     newnode->occurance = occ; 
     if(newnode == NULL) { 
      printf("Memory could not be allocated!"); 
      // exit(0); 
     } 
     if(start == NULL) { 
      start = newnode; 
      ptr = start; 
      printf("start is: %s", start->name); 
     } 
     else if(start->link == NULL) { 
      start->link = newnode; 
      newnode->prev = start; 
      ptr = newnode; 
     } 
     else { 
      ptr->link = newnode; 
      newnode->prev = ptr; 
      ptr = ptr->link; 
     } 
     printf("Enter 1 to continue: "); 
     scanf("%d", &choice); 
    } while(choice == 1); 

    // display 
    ptr = start; 
    while(ptr != NULL) { 
     printf("%s ", ptr->name); 
     printf("%s ", ptr->type); 
     printf("%d \n", ptr->occurance); 
     ptr = ptr->link; 
    } 
} 

我试图做出开始和newnode局部变量,以及,但它不能正常工作。

+0

Cqnqrd的回答有它。另一点,虽然:1)你检查'newnode == NULL'有点晚,因为你已经解除引用'newnode'来设置它的成员。并且你不需要“else if”作为'start-> link == NULL';您的'else {}'块中的相同代码也适用于这种情况。 – TypeIA

+0

哦,是的,我现在注意到了,谢谢@dvnrrs – user2538255

+0

将'main'的签名更改为'int main(void)'。还要注意'malloc.h'不是标准的。改为使用'stdlib.h'。 – ajay

回答

1

您不能使用相同的运算符来分配char *。相反,您必须使用功能strcpy

不要这样做:

newnode->name=name1; 
newnode->type=type1; 

但做到这一点:

strcpy(newnode->name, name1); 
strcpy(newnode->type, type1); 

目前你的整个char*都指向同一个内存块。

编辑: 由于使用的指针,则必须从一个指针值复制到另一个之前分配存储器(或你会遇到段错误)。所以,你还需要与malloc分配您的节点的名称和类型的记忆:

//allocate memory of node's name attribute with the same amount as name1 (+1 for null terminating character) 
newnode->name = malloc(sizeof(char) * (strlen(name1)+1)); 
newnode->type= malloc(sizeof(char) * (strlen(type1)+1)); 
+1

有一点空间(malloced或数组)也会有用。 :-) – ooga

+0

虽然在'strcpy()'之前,他将不得不为'malloc()'字符串留出一些空间。 – TypeIA

+0

确实如此,但我猜奥普会自己找到它。 ;-) – bagage

0

有几件事情在你的代码以提高所以让我们把它逐个。首先,您看到的行为是因为链表中所有节点的结构成员nametype指向相同的内存位置,即分别为name1type1

struct list { 
    char *name; 
    char *type; 
    // other members 
}; 

这里,name是一个指向一个字符,所以是type。在maindo while循环中,您将每个节点的名称和类型分别读入到每个迭代中的阵列name1type1。因此,之前的值name1type1被覆盖并因此丢失。现在您将name1type1分配给每个新创建节点的相应成员。

// after allocating memory for a new node 

newnode->name = name1; // name1 evaluates to a pointer to name1[0] 
newnode->type = type1; // type1 evaluates to a pointer to type1[0] 

因此,所有节点的name构件都指向name1其中仅保留最后一个字符串的读,并且类似地所有节点的type构件指向type1其还具有读出的最后一个字符串。

既然我们已经讨论过您的程序的行为,那么解决方案是什么?您保持每个节点的名称和类型不会被输入的下一个值覆盖。您每次为新节点读取内容时都要为它们分配内存。

newnode->name = strdup(name1); // make a copy of name1 before it's overwritten 
newnode->type = strdup(type1); // make a copy of type1 before it's overwritten 

strdup分配足够的内存来复制传递给它的字符串。它基本上和mallocstrcpy一样。详细了解它here

现在让我们来看看从程序顶部开始的其他事情。

  • malloc.h已弃用,不是标准品。改为使用stdlib.h。更多here
  • C标准为main函数设置了两个签名:int main(void);另一个是int main(int argc, char *argv[]);更多here
  • 在使用scanf读取字符串时,应防止缓冲区溢出。如果用户输入长度超过9个字符的名称和类型,则会导致未定义的行为甚至崩溃。您应该用scanf("%9s", name1)替换scanf("%s", name1)。格式字符串中的9表示scanf最多可以读取9个非空白字符。一个字符空间留给自动添加的终止空字节。
  • 在呼叫后立即检查返回值mallocNULL。如果malloc未能分配内存,那么您的程序只会崩溃。
  • 您不需要do while loop中的else if区块。它将永远不会被输入,除非在循环的第一次迭代中,当它使start->previous = start这不是你想要的。 start->previous应始终为NULL
+0

非常感谢这样一个详尽的和详细的答案......特别是在最后提到的改进:) – user2538255