-1

I tried reading from text file, and then put every word in list node(and print it afterwards in reverse order).

The program works good, but when trying to free the allocated list nodes, the program crash.

#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;
    }
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • Any errors to go with that crash? – Nanhydrin Jul 10 '15 at 09:37
  • Plus you have a pointer `newnode` in `list createNode()` .This function returns the pointer. So either you have to free it in calling function or find a way to do that there. – ameyCU Jul 10 '15 at 11:39

3 Answers3

3

In your deleteAllNodes function you are free-ing a pointer and then accessing it. You could try deleting nodes in reverse order, starting from the last one, for instance with a recursive function.

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

Or you can stick to the iterative forward deletion with something like (untested):

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);
}
mziccard
  • 2,158
  • 9
  • 17
  • It won t free the last node. at the end start == NULL but previous which is the last node isn't freed you must add an if (previous) free(previous); after the while – Gabrielle de Grimouard Jul 10 '15 at 11:14
3

your delete all nodes has a bug in it. You freed a pointer and tried accessing it immediately. So the program crashes You can try this

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

point the current ptr to the head and point head to next element. Delete the current pointer.

Minions
  • 1,273
  • 1
  • 11
  • 28
  • i tried both your functions, but unfourtenly both crashed give the same crash message as the 2 original function i written: deleteAllNodes() and freeall() . – Liran Siman Tov Jul 10 '15 at 11:49
  • the error i got in all of the above (including my functions) was Debug Error! HEAP CORRUPTION DETECTED after Normal block(#77) at 0x00778068, CRT detected that the application wrote to memory after end of heap buffer .important to mention that without the free statments my program works fine – Liran Siman Tov Jul 10 '15 at 11:49
1

The problem , as I see it is with

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

your list is a typedef to struct node*, so this statement is essentially

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

which is wrong. You're allocating memory for a pointer to structure variable, whereas, you should be allocating memory equal to the size of the structure variable itself.

Two things to mention here

  1. Please see why not to cast the return value of malloc() and family in C.
  2. Never use a typedef for a pointer type. It's not a "rule", but better to stick to it.

Your allocation statement, at least, shall look like

list = malloc(sizeof*list);

Apart from this, in your main() function,

  • First, you're allocating memory to lst using malloc() [Same issue with the allocation as above]
  • Then, you assign another pointer, the return value of createList() to lst.

This way, you're overwriting the allocated mekory through malloc(), creating memory leak. You don't need malloc() there, at all.

Community
  • 1
  • 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261