2015-07-10 144 views
-2

我尝试从文本文件中读取数据,然后将每个单词放入列表节点中(然后以相反的顺序将其打印出来)。释放分配的内存会生成分段错误

该程序运行良好,但当试图释放分配的列表节点时,程序崩溃。

#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <ctype.h> 
#include <assert.h> 
#include <math.h> 
typedef struct node{ 
    char* word; 
    struct node* next; 
}; typedef struct node* list; 
void freeall(list lst){ 
    list temp = NULL; 
    while (lst) 
    { 
     temp = lst->next; 
     free(lst); 
     lst = temp; 
    } 
#if 0 
    if (lst == NULL){ return; } 
    freeall(lst->next); 
    free(lst->word); 
    free(lst); 
#endif // 0 

} 
void deleteAllNodes(list start) 
{ 
    while (start != NULL) 
    { 
     list temp = start; 
     free(temp); 
     start = start->next; 
    } 
} 
list createNode(char* buff){ 
    list newnode = (list)malloc(sizeof(list)); 
    assert(newnode); 
    newnode->next = NULL; 
    newnode->word = (char*)calloc(strlen(buff), sizeof(char)); 
    assert(newnode->word); 
    strcpy(newnode->word, buff); 
    return newnode; 
} 
void reverse(const char *str) //you don't need to modify your string 
{ 
    if (*str != '\0'){ //if the first character is not '\O' 
     reverse((str + 1)); // call again the function but with +1 in the pointer addr 
     printf("%c", *str); // then print the character 
    } 
} 
void print_reverse(list lst){ 
    if (lst == NULL) return; 
    print_reverse(lst->next); 
    reverse(lst->word); 
    //free(lst->word); 
} 
list createList(FILE* ifp){ 
    struct node *loop = NULL; 
    list curr = NULL; 
    list lst = NULL; 
    char *word = NULL; 
    size_t size = 2; 
    long fpos = 0; 
    char format[32]; 
    if (ifp == NULL)  // open file 
     perror("Failed to open file \n"); 
    if ((word = malloc(size)) == NULL)     // word memory 
     perror("Failed to allocate memory"); 
    sprintf(format, "%%%us", (unsigned)size - 1);  // format for fscanf 
    while (fscanf(ifp, format, word) == 1) { 
     while (strlen(word) >= size - 1) {    // is buffer full? 
      size *= 2;         // double buff size 
      printf("** doubling to %u **\n", (unsigned)size); 
      if ((word = realloc(word, size)) == NULL) 
       perror("Failed to reallocate memory"); 
      sprintf(format, "%%%us", (unsigned)size - 1);// new format spec 
      fseek(ifp, fpos, SEEK_SET);     // re-read the line 
      if (fscanf(ifp, format, word) == 0) 
       perror("Failed to re-read file"); 
     } 
     curr = createNode(word); 
     if (lst == NULL){lst = curr;} 
     else{ 
      loop = lst; 
      while (loop->next != NULL) {//loop to last structure 
       loop = loop->next;//add structure to end 
      } 
      loop->next = curr; 
     } 
     fpos = ftell(ifp);        // mark file pos 
    } 
    free(word); 
    return lst; 
} 
int main(int argc, char* argv[]){ 
     assert(argc == 2); 
     FILE *ifp = fopen(argv[1], "r"); 
     assert(ifp); 
     list lst = NULL; 
     lst = (list)malloc(sizeof(list)); 
     lst = createList(ifp); 
     print_reverse(lst); 
     fclose(ifp); 
     //freeall(lst); 
     //deleteAllNodes(lst); 
     return 1; 
    } 
+0

任何与该崩溃相关的错误? – Nanhydrin

+0

加上你在'list createNode()'中有一个'newnode'的指针,这个函数返回指针。所以要么你不必在调用函数中释放它,要么找到一种方法在那里做。 – ameyCU

回答

0

的问题,因为我看到它与

list newnode = (list)malloc(sizeof(list)); 

list是一个typedef到struct node*,所以这种说法基本上是

list newnode = (list)malloc(sizeof(struct node*)); 

这是错误。您正在为指向结构变量的指针分配内存,而您应该分配的内存等于结构变量本身的大小。

两件事情在这里

  1. see why not to castmalloc()返回值和家人提C
  2. 从不使用typedef作为指针类型。这不是一个“规则”,但更好地坚持下去。

你分配表,至少,应像

list = malloc(sizeof*list); 

除此之外,在你main()功能,

  • 首先,你分配内存使用lstmalloc() [与上述分配相同的问题]
  • 然后,您指定另一个指针,返回值为createList()lst

这样,你通过malloc()覆盖分配mekory,创造memory leak。根本不需要malloc()

2

在你的deleteAllNodes函数中,你可以释放一个指针然后访问它。您可以尝试以相反的顺序从最后一个开始删除节点,例如使用递归函数。

void deleteAllNodes(list start) 
{ 
    if (start != NULL) 
    { 
     deleteAllNodes(start->next); 
     free(start); 
    } 
} 

或者你可以坚持的东西,如(未经测试)的迭代正缺失:

void deleteAllNodes(list start) 
{ 
    list previous = NULL; 
    while (start != NULL) 
    { 
     if (previous != NULL) 
      free(previous); 
     previous = start; 
     start = start->next; 
    } 
    if (previous != NULL) 
     free(previous); 
} 
+0

它不会释放最后一个节点。在结尾处开始== NULL,但是之前的最后一个节点没有被释放,你必须添加一个if(previous)free(previous);在此之后 –

+0

@GabrieldeGrimouard谢谢,编辑 – mziccard

2

delete all nodes中有一个错误。你释放了一个指针并尝试立即访问它。所以程序崩溃你可以试试这个

void deleteAllNodes(list head) 
{ 
    list ptr = head; 
    while ((ptr = head) != NULL) 
    { 
     head = head->next;   
     free (ptr);    
    } 
} 

将当前ptr指向头部并指向头部到下一个元素。删除当前指针。

+0

我试了你的两个函数,但很不幸,这两个崩溃都给出了与我写的两个原始函数相同的崩溃消息:deleteAllNodes()和freeall()。 –

+0

我得到的所有上述错误(包括我的功能)是调试错误! HEAP CORRUPTION在普通模块(#77)检测到0x00778068后,CRT检测到应用程序在堆缓冲区结束后写入内存。重要的是,如果没有免费的语句,我的程序可以正常工作 –