Home > Software design >  Linked list being overwritten instead of attached to another linked list
Linked list being overwritten instead of attached to another linked list

Time:08-27

This is written in C.

I'm trying to take user input and use it to create/add to a linked list, which I point to with struct Node *dict; Everything is accomplished using global memory.

Creating a new linked list works fine, but when the user tries to add to the linked list, it overwrites the extant linked list.

Here's my code for adding to the list (words is an array of nodes to be appended to the list):

if (dict == NULL) { // If previous list does not exist, global dict pointer should point to node array
    dict = words;
} else {  // Else find end of current linked list and point it to the new list
    struct Node *head = dict;
    while (head->next != NULL) {
        head = head->next;
    }
    head->next = words;
}

When I create a list with the words "apple orange peach," for example, when I print the list, I get the output "apple orange peach." But then when I add "pear" to the list, "apple orange peach" is overwritten and I only see the output "pear," instead of "apple orange peach pear."

EDIT:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <ctype.h>

//// GUI Stuff ////
void drawDashedLine() {
    for (int i = 0; i < 30; i  ) {
        printf("-");
    }
    printf("\n");
}
void drawDottedLine() {
    for (int i = 0; i < 30; i  ) {
        printf(".");
    }
    printf("\n");
}
void drawArrowLine() {
    for (int i = 0; i < 30; i  ) {
        printf(">");
    }
    printf("\n");
}
void drawStarLine() {
    for (int i = 0; i < 30; i  ) {
        printf("*");
    }
    printf("\n");
}

struct Node {
    int length;
    char word[5];
    struct Node * next;
};
// Pointer to global linked list dictionary
struct Node *dict;

struct Node *newDict;


void printDict() {
    drawDottedLine();
    struct Node * head = dict;
    while (head != NULL) {
        printf("%s\n", head -> word);
        head = head -> next;
    }
    drawDottedLine();
    return;
}
void alphabetizeDict() { // Bubble sort
    //printf("%p --- %p\n", dict, dict->next);
    struct Node * head = dict;
    if (head == NULL) {
        return;
    }
    struct Node * ptr2 = NULL;

    int swapped = 1;
    while (swapped) {
        swapped = 0;
        head = dict;
        while (head -> next != ptr2) {
            char * temp1 = strdup(head -> word);
            char * temp2 = strdup(head -> next -> word);

            strupr(temp1);
            strupr(temp2);
            if (strcmp(temp1, temp2) > 0) {
                char temp[5];
                strcpy(temp, head -> word);
                strcpy(head -> word, head -> next -> word);
                strcpy(head -> next -> word, temp);
                swapped = 1;
            }
            head = head -> next;
        }
        ptr2 = head;
    }
    return;
}
void createDict() {
    // To hold the string entered by the user
    char str[5000];
    // Holds 1000 words, each up to 5 characters long (4 plus a NULL char)
    char newString[1000][5];
    printf("\n");
    drawArrowLine();
    printf("Enter word(s): \n");
    fgets(str, sizeof str, stdin);

    int i, j, ctr;
    j = 0;
    ctr = 0; // ctr to iterate through words, j to iterate through letters
    for (i = 0; i <= (strlen(str)); i  ) {
        if (str[i] == ' ' || str[i] == '\0') { // This is whitespace. add null character to terminate string. Start next word
            newString[ctr][j] = '\0';
            ctr  ;
            j = 0;
        } else { // Else add letter to string
            newString[ctr][j] = str[i];
            j  ;
        }
    }
    
        for (int i = 0; i < ctr; i  ) {
            struct Node n;
            n.length = strlen(newString[i]);
            int c = 0;
            char sub[5];
            // Only use word's first four letters
            while (c < strlen(newString[i]) && c < 4) {
                sub[c] = newString[i][c];
                c  ;
            }
            sub[c] = '\0';
            strcpy(n.word, sub);
            n.next = NULL;
            
            if (dict == NULL) {
                dict = &n;
            } else {
                n.next = dict;
                dict = &n;
                }
        }
    

        
    // alphabetizeDict();
    printf("Word(s) added succesfully\n");
    drawArrowLine();
    printf("\n");
    return;
}

void destroyDict() {
    printf("Starting new dictionary......\n");
    while (dict != NULL) {
        struct Node * temp = dict;
        dict = dict -> next;
        temp -> next = NULL;
    }
}
void caseInsensSearch(char * searchTerm) {
    for (int i = 0; searchTerm[i]; i  ) {
        searchTerm[i] = tolower(searchTerm[i]);
    }
    struct Node * head = dict;
    int index = 0;
    while (head != NULL) {
        char lowercaseWord[5];
        for (int i = 0; head -> word[i]; i  ) {
            lowercaseWord[i] = tolower(head -> word[i]);
        }
        if (strcmp(lowercaseWord, searchTerm) == 0) {
            printf("Found %s at index %i\n", head -> word, index);
            drawDashedLine();
            return;
        }
        head = head -> next;
        index  ;
    }
    printf("Sorry, I couldn't find %s in your dictionary.\n", searchTerm);
    drawDashedLine();
    return;
}
void caseSensSearch(char * searchTerm) {
    struct Node * head = dict;
    int index = 0;
    while (head != NULL) {
        if (strcmp(head -> word, searchTerm) == 0) {
            printf("Found %s at index %i\n", head -> word, index);
            drawDashedLine();
            return;
        }
        head = head -> next;
        index  ;
    }
    printf("Sorry, I couldn't find %s in your dictionary.\n", searchTerm);
    drawDashedLine();
    return;
}

void search() {
    int isSens;
    drawDashedLine();
    printf("Enter 1 for Case sensitive\n2 for case insensitive\n");
    drawDashedLine();
    scanf("%d", & isSens);
    while (isSens < 1 || isSens > 2) {
        printf("Please enter a number between 1 and 2:\n");
        scanf("%d", & isSens);
    }
    drawDashedLine();
    printf("Enter a word to search for:\n");
    char searchTerm[5];
    scanf("%s", searchTerm);
    searchTerm[4] = '\0';
    if (isSens == 1) {
        caseSensSearch(searchTerm);
    } else {
        caseInsensSearch(searchTerm);
    }
}

int promptUser() {
    drawStarLine();
    printf("1) Search for a word\n2) Add word(s)\n3) Print dictionary\n4) Start new dictionary\n5) Exit\n");
    drawStarLine();
    printf("\nEnter a number between 1 and 5:\n");

    int choice;
    scanf("", & choice);
    while (choice < 1 || choice > 5) {
        printf("Please enter a number between 1 and 5:\n");
        scanf("%d", & choice);
    }
    return choice;
}

int main() {

    for (;;) {
        int choice = promptUser();
        fflush(stdin);
        if (choice == 1) {
            search();
        } else if (choice == 2) {
            createDict();
        } else if (choice == 3) {
            printDict();
        } else if (choice == 4) {
            destroyDict();
        } else if (choice == 5) {
            return 0;
        }
    }

    return 1;
}

CodePudding user response:

I've spent some time diagnosing this problem for you. The problem statement is bizarre... An array of words could be sorted (even with library qsort()) and grow to the fill the array to the brim, but you claim this must use both a linked list and a global "object pool" that is not dynamically allocated...

Here's some code I've compiled BUT NOT TESTED...

It should be simple to follow and expand to accommodate your requirements.

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

typedef struct Node {   // use 'typdef'. Less typing
    char word[5]; // VERY SHORT WORDS guaranteed
    struct Node *next;
} Node_t;

Node_t dict[ 1000 ]; // global data space
int nextNode = 0;

void printDict() { // traverse LL outputting value(s)
    for( Node_t *pn = dict; pn; pn = pn->next )
        puts( pn->word );
}

void addNode( char *data ) {
    if( nextNode   1 >= sizeof dict/sizeof dict[0] )
        return; // Fixed size cannot grow.

    Node_t *pn = &dict[ nextNode ];
    strcpy( pn->word, data ); // "apple" WON'T fit
    nextNode  ;
//EDIT:
// This is not correct.
// See code block below for correction
    if( nextNode  1 >= sizeof dict/sizeof dict[0] )
        pn->next = NULL;
    else
        pn->next = &dict[ nextNode ];
}

void createDict() {
    char str[5000]; // one lo-o-o-ong input string of short words

    printf( "Enter word(s): \n" );
    fgets( str, sizeof str, stdin );

    // chop words on spaces (or tabs) and store to LL
    for( char *cp = str; ( cp = strtok( cp, " \t" ) ) != NULL; cp = NULL )
        addNode( cp );
}

void destroyDict() { // super simple!
    memset( dict, 0, sizeof dict );
    nextNode = 0;
    // return; // Do not need those return(s) before final closing brace.
}

80% of any problem is the clear understanding of what the problem is to begin with.

EDIT: Realising the code must 'straddle' both array and LL, the above was not exactly correct. Below is the necessary fix to conform with a LL having a NULL next pointer at its 'tail' node.

void addNode( char *data ) {
    if( nextNode   1 >= sizeof dict/sizeof dict[0] )
        return; // Fixed size cannot grow.

    strcpy( dict[ nextNode ].word, data ); // "apple" WON'T fit

    if( nextNode ) // at node 1 or greater
        dict[ nextNode - 1 ].next = &dict[ nextNode ];

    nextNode  ;
}

CodePudding user response:

try this

if (dict == NULL) { // If previous list does not exist, global dict pointer should point to node array
    dict = words;
} else {  // Else find end of current linked list and point it to the new list
    struct Node *head = dict;
    while (head->next != NULL) {
        head = head->next;
    }
    struct Node *ptr = NULL;
    ptr->length = strlen(word);
    strcpy(ptr->word, sub);
    ptr->next = NULL;
    head->next = ptr;
}
  • Related