0

The first time addToEnd() is called it works but the second time it crashes the program. I've been trying to debug it and found it happens when head->next happens. I'm a little confused because it's just being read, can that crash the program? If yes how can you possible itterate through the file?

It seems to work on certain values of entry but not others. If two entry's are the same and composed all of one letter it crashes. So if addToEnd(head, "aaaaaaaaa") is called then addToEnd(head, "aaaaaaaaa") is called the program crashes but if addToEnd(head, "aaaaaaaaa") then addToEnd(head, "aaaaaaaab") it is fine.

Here is 100% all of the code

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

typedef struct node
{
  char entry[21];
  struct node* next;
} node;

void readDic();
void reverStr(char *str);
bool isInDic(char *reversed);
void addToEnd(node* head, char entry[21]);
unsigned int searchAndDestroy(node **head, char *entry);
void printList(node* head);
int main()
{
    printf("Hello\n");
    readDic();
    printf("Goodbye!");
    return EXIT_SUCCESS;
}

void readDic()
{
    FILE* words;
    char singleLine[21];
    words = fopen("words.txt", "r");
    node* head = malloc(sizeof(node));
    fscanf(words, "%20s", head->entry);//need to do this initially
    head->next = NULL;
    printf("here 0");

    printf("here 0.1");
    if(words == NULL)
        exit(EXIT_FAILURE);
    printf("here 0.5");
    while(fscanf(words, "%20s", singleLine) == 1)assigned input terms
    {
        printf("\nhere 0.6\n|%s|", singleLine);
        addToEnd(head, singleLine);//problem here
        printf("here 0.7");
        reverStr(singleLine);
        printf("here 1");
        if(isInDic(singleLine)){
            printf("here 2");
            searchAndDestroy(&head, singleLine);
            printf("here 3");
        }
    }
    printf("here 4");
    fclose(words);
    printList(head);
    printf("here 5");
}

//http://stackoverflow.com/questions/198199/how-do-you-reverse-a-string-in-place-in-c-or-c
/* PRE: str must be either NULL or a pointer to a
 * (possibly empty) null-terminated string. */
void reverStr(char *str)
{
    char temp, *end_ptr;

    /* If str is NULL or empty, do nothing */
    if(str == NULL || !(*str))
        return;

    end_ptr = str + strlen(str) - 1;

    /* Swap the chars */
    while( end_ptr > str )
    {
    temp = *str;
    *str = *end_ptr;
    *end_ptr = temp;
    str++;
    end_ptr--;
  }
}

bool isInDic(char* reversed)
{
    FILE* words;
    char singleLine[21];

    words = fopen("words", "r");
    if(words == NULL)
        exit(EXIT_FAILURE);
    while(fscanf(words, "%20s", singleLine) == 1)//the length of the string has to be 1 less than declared size for the newline character
    {
        //printf("singline: %s reversed: %s\n", singleLine, reversed);
        if(strcmp(singleLine, reversed) == 0)//strcmp returns 0 if both cstrings are equal
            return true;
    }
    fclose(words);
    return false;
}

void addToEnd(node* head, char entry[21])
{
    printf("hi");
    //printf("\naddress of next %p\n", (void *)head->next);
    while(head->next != NULL)//just reading head->next screws it up
        head = head->next;
    printf("in addToEnd 2\n");
    node* last = (node*)malloc(sizeof(node));
    printf("in addToEnd 3\n");
    head->next = last;
    printf("in addToEnd 4\n");
    strcpy(last->entry, entry);
    printf("in addToEnd 5\n");
    last->next = NULL;
    printf("in addToEnd 6\n");
}

unsigned int searchAndDestroy(node **head, char *entry)
{
    unsigned int count = 0;

    while(*head)
    {
        node *del;
        if(strcmp((*head)->entry, entry))
        { //this node stays
            head = &(*head)->next;
            continue;
        }
        /* this node goes
        at this point head MUST point to the pointer that points at the node to be deleted
        */
        del = *head;
        *head = (*head)->next;
        free(del);
        count++;
    }
    return count; //number of nodes deleted
}

void printList(node* head)
{
    printf("\nprinting everything\n");
    if(head != NULL)
    {
        while(head->next != NULL)
        {
            printf("%s", head->entry);
            head = head->next;
        }
        printf("%s", head->entry);
    }
}

The answers are correct that head is being set to null but I don't see where?

Celeritas
  • 14,489
  • 36
  • 113
  • 194
  • 1
    UB somewhere. Hard to tell without knowing the struct definition, context, etc. Use a debugger. –  Sep 30 '13 at 17:01
  • How is last->entry defined? If head is null, this will crash. – Charlie Burns Sep 30 '13 at 17:06
  • @Celeritas Undefined behavior. –  Sep 30 '13 at 17:08
  • 2
    please provide complete example. – Karoly Horvath Sep 30 '13 at 17:11
  • @mbratch that's not the issue, all strings are less than 20 – Celeritas Sep 30 '13 at 17:19
  • If this is supposed to create a linked list, then the logic is flawed. If you happen to own or have access to KR, have a look at the structure chapter which had a working example. – gnometorule Sep 30 '13 at 17:19
  • @gnometorule can you say how it's flawed? It's not supposed to be a generic linked list but one customized to a very particular need. – Celeritas Sep 30 '13 at 17:23
  • The KR example seems to do what you want. In terms of flawed, as an answer points out, upon second entry, you hit NULL in while and should stop. I think you need to iterate over head, not head->next, then look at cases (when you hit NULL, malloc and adjust; if not, keep going/descend). Also, I suggest malloc'ing the char * too in your function. That said, didn't read your just posted additional code. – gnometorule Sep 30 '13 at 17:30
  • Shouldn't `head = &(*head)->next;` in `searchAndDestroy` be `*head = (*head)->next;`? – lurker Sep 30 '13 at 17:51

2 Answers2

1

One of three things:

  1. If head is NULL this code will crash at the line you mention.

  2. If last->entry is defined as char* you need to say 'last->entry = strdup(entry)

  3. If the sizeof last->entry is less than 21, your strcpy will overflow it which will result in undefined behavior.

Ok, with your recent edit, I assert that head is null or garbage when you call this function the second time.

Charlie Burns
  • 6,994
  • 20
  • 29
1

When you create head, you don't set head->next to NULL.

Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176