2010-02-18 64 views
0

第一个函数读取一个包含'char'的文件并将它们放入链表中。它不工作:(。为什么这个C链接列表程序给出'分段错误'?

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

struct list { 
    char val; 
    struct list* next; 
}; 

typedef struct list element; 

int lcreate(char* fname, element* list); 
int ldelete(element* list); 
int linsert(char a, char b, element* list); 
int lremove(char a, element* list); 
int lsave(char* fname, element* list); 



int lcreate(char* fname, element* list) { 
    element* elem = list; 
    char c = 0; 
    FILE * file = NULL; 

    file = fopen(fname, "r"); 

    while ((c = getc(file)) != EOF) 
    { 
     if(list == NULL) { 
      list = (element*)malloc(sizeof(element)); 
      if(list == NULL) { 
       return 0; 
      } 
      list->val = c; 
     } 
     else { 

      elem->next=(element*)malloc(sizeof(element)); 
      elem = elem->next; 
      elem-> val = c; 
     } 
    } 
    fclose(file); 
    elem->next = NULL; 
    return 1; 
} 



int main(void) { 
    int i = 0; 


    element * list = NULL; 
    lcreate("list.txt", list); 

    for(i = 0; i<4; ++i) { 
     printf("%c", list->val); 
     list = list->next; 
    } 

    return 0; 
} 

固定的问题“文件”是零。

回答

6

一个明显的问题是正确的在这里:

FILE * file = NULL; 

fopen(fname, "r"); 

对于fopen完成了,你需要的结果从fopen分配给您FILE *

file = fopen(fname, "r"); 

编辑:既然你用C的工作,你无法通过引用传递指针。作为替代方案,你可以传递一个指针的指针:

int lcreate(char *fname, element **list) { 

    // ... 
    *list = malloc(sizeof(element)); 
    (*list)->next = null; 
    (*list)->val = c; 
// ... 
} 

基本上,lcreate里面所有的代码将需要参考*list,而不是仅仅list。或者,你可以用一个指针指向现有列表作为输入,并返回一个指针列表,所以在main你会碰到这样的:list = lcreate("list.txt", list);

+0

谢谢我现在解决了这个问题。 – ron 2010-02-18 23:39:06

+0

别忘了'elem = list'分配一个值。如果你希望'list'更新时更新'elem',你需要在Jerry的版本中将'elem'改成原始代码中的'element ** elem =&list'或'element ** elem = list'。 – MSN 2010-02-19 05:42:50

2

fileNULL,你永远文件句柄分配给它。

+0

固定................ – ron 2010-02-18 23:39:33

1

是的 - 什么人说一下FILE指针,通过list按值而不是参考lcreate(),是正确的。

您还没有从lcreate()返回列表的大小 - 您应该通过返回值或指针参数返回该列表的大小。

您试图在main()函数中遍历列表4次,但列表中可能少于4个项目。如果list为NULL,最终printf()将导致分段错误。

如果在进行这些更改后仍然存在问题,我会建议在您的代码中添加跟踪以确定发生分段错误的时间点。

更新:

也请记住释放你遍历列表后,您已分配的内存,否则你会得到一个内存泄漏结束(虽然在实践中这不会真的是一个问题因为程序结束了,但释放内存是一个很好的习惯)。

+0

固定................ – ron 2010-02-18 23:41:48

1

在你main功能,您也传递list按值lcreate。在lcreate()函数中,您将覆盖list的本地副本,而不会更改主函数中list的值。由于list初始化为NULL,因此在拨打list->val时会出现段错误。

+0

好吧,我如何覆盖lcreate列表?谢谢! – ron 2010-02-18 23:40:56

+0

@ron - 传递给'list'的双指针,即'element ** list; lcreate(“list.txt”,列表);'。然后在'lcreate'方法中,像这样分配它:'* list = malloc(...)'。这将确保调用者将看到被调用者所做的更改。 – LeopardSkinPillBoxHat 2010-02-18 23:50:48

0

我还可以看到另外一个问题。在lcreate()的while语句中if语句的真子句malloc的某些内存并将其分配给list,但elem未更新。

while ((c = getc(file)) != EOF) 
{ 
    if(list == NULL) { 
     list = (element*)malloc(sizeof(element)); 
     if(list == NULL) { 
      return 0; 
     } 
     list->val = c; 
    } 
    else { 
通过while循环 list不会非空但 elem仍然是空的,以便elem->下一个试图分配给遵从空指针,因此段故障(其,顺便说一句,装置

下一次您尝试访问尚未分配给你的进程)内存: -

else { 
    elem->next=(element*)malloc(sizeof(element)); 

正如其他人所指出的,你也不会返回list回主所以它仍然将是NULL当你打的printf ()循环。

最后,在查看这些问题时,调试器是您的朋友。你会看到哪一行会触发seg故障,以及变量的状态。

0

通过检查非null pinter可以检查malloc是否成功。 此外,您可能希望在此时间之外分配头部/第一个链接,以避免每次在while循环中对头部进行空值检查。当然,这些都是优化,如果你的链表增长的真的很大!

相关问题