0

For homework for my C class, we've been asked to read data from stdin, put the words into a binary tree along with their positions (line and offset), modify the binary tree, and print the binary tree in a file based on positions. I'm halfway there (I hope), but I've run into the problem where my new data keeps overwriting my old data - specifically, the new Insert struct keeps overwriting my old Insert struct when I put it into the Insert array, meaning that I have several identical entries in my array. I'm not quite sure how to stop it from doing that or even why it's happening, though I think it might be because I'm writing the data into the same pointer without clearing it.

Fair warning: we've mostly been left to fend for ourselves this semester, and my code looks so wrong that I'm surprised it works.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define s 5000
#define z 10

struct Position {
    int line; // line number
    int offset; // 1, 2, 3, ...: 1st, 2nd, 3rd, ... word on the line
    struct Position *next;
};

struct TreeNode {
    char *word;
    struct Position *positions; // store positions where the word occurs
    struct TreeNode *parent; 
    struct TreeNode *left;
    struct TreeNode *right;
};

struct Insert {
    char *word;
    struct Position *pos;
};

struct RemoveWord {
    char *word;
};

struct RemovePos {
    struct Position *pos;
};

struct TreeNode *createNode(char *word, struct Position *pos) {
    struct TreeNode *node = (struct TreeNode*) malloc(sizeof(struct TreeNode));
    node->word = malloc(s);

    strcpy(node->word, word);
    node->positions = pos;
    node->parent = node->left = node->right = NULL;

    return node;
}

struct Position *createPos(int line, int offset, struct Position *next) {
    struct Position *node = (struct Position*) malloc(sizeof(struct Position));
    node->line = line;
    node->offset = offset;
    node->next = next;

    return node;
}

struct TreeNode *insertNode(struct TreeNode* tree, char *word, struct Position *pos) {
    struct Position *tpos = (struct Position*) malloc(sizeof(struct Position));


    if (tree == NULL) {
        return createNode(word, pos);
    }
    if (strcmp(word, tree->word) < 0) {
        tree->left = insertNode(tree->left, word, pos);
    } else if (strcmp(word, tree->word) > 0) {
        tree->right = insertNode(tree->right, word, pos);
    } else if (strcmp(word, tree->word) == 0) {
        tpos = tree->positions;
        while(1) {
            if (tpos->next == NULL) {
                tpos->next = pos;
                break;
            }
            tpos = tpos->next;
        }
    }

    return tree;
}

struct TreeNode *min(struct TreeNode* tree) {
    struct TreeNode* c = tree;

    while (c->left != NULL) {
        c = c->left;
    }

    return c;
}

struct TreeNode *removeWord(struct TreeNode* tree, char *word) {
    if (tree == NULL) {
        return tree;
    }

    if (strcmp(word, tree->word) < 0) {
        tree->left = removeWord(tree->left, word);
    } else if (strcmp(word, tree->word) > 0) {
        tree->right = removeWord(tree->right, word);
    } else {
        if (tree->left == NULL) {
            struct TreeNode *temp = tree->right;
            free(tree);
            return temp;
        } else if (tree->right == NULL) {
            struct TreeNode *temp = tree->left;
            free(tree);
            return temp;
        }

        struct TreeNode *temp = min(tree->right);

        strcpy(tree->word, temp->word);

        tree->right = removeWord(tree->right, temp->word);
    }

    return tree;
}

struct TreeNode *removePosition(struct TreeNode *tree, struct Position *pos) {
    if (tree == NULL) {
        return tree;
    }

    removePosition(tree->left, pos);

    if (tree->positions->line == pos->line && tree->positions->offset == pos->offset) {
        tree = removeWord(tree, tree->word);
        return tree;
    }
    while(1) {
        tree->positions = tree->positions->next;
        if (tree->positions == NULL) {
            break;
        }
        if (tree->positions->line == pos->line && tree->positions->offset == pos->offset) {
           tree = removeWord(tree, tree->word);
           return tree;
        }
    }

    removePosition(tree->right, pos);

    return tree;
}

struct TreeNode *removeLine(struct TreeNode *tree, int line) {
    if (tree == NULL) {
        return tree;
    }

    removeLine(tree->left, line);

    if (tree->positions->line == line) {
        tree = removeWord(tree, tree->word);
        return tree;
    }
    while(1) {
        tree->positions = tree->positions->next;
        if (tree->positions == NULL) {
            break;
        }
        if (tree->positions->line == line) {
           tree = removeWord(tree, tree->word);
           return tree;
        }
    }

    removeLine(tree->right, line);

    return tree;
}


//TESTING INORDER -- via sreekar2307 on github
void inorder(struct TreeNode* root) {
    if(root==NULL) return ;
    inorder(root->left);
    printf("word is %s, line is %i, offset is %i\n",root->word, root->positions->line, root->positions->offset);
    while(1) {
        root->positions = root->positions->next;
        if (root->positions == NULL) {
            break;
        }
        printf("---> addition: line is %i, offset is %i\n", root->positions->line, root->positions->offset);
    }
    inorder(root->right);
}

int main() {
    FILE *out;

    char line[s];
    int w = 1;
    int l = 1;
    int b = 1; //switch for before/after END
    int I = 0; //switch for insert
    int R = 0; //switch for remove word
    int RL = 0; //switch for remove line
    int INSERT = 0; // number of insert commands
    int REMOVEWORD = 0; // number of removeword commands
    int REMOVEPOS = 0; // number of removepos commands
    int REMOVELINE = 0; // number of removeline commands
    char *iw = malloc(s); //holds insert word
    int il, io; //holds insert line, offset
    int rwl, rwo; //holds remove word line, offset

    struct Insert* ic[z];
    struct RemoveWord* rwc[z];
    struct RemovePos* rpc[z];

    struct Insert *ic1 = (struct Insert *) malloc(sizeof(struct Insert));
    struct RemoveWord *rwc1 = (struct RemoveWord *) malloc(sizeof(struct RemoveWord));
    struct RemovePos *rpc1 = (struct RemovePos *) malloc(sizeof(struct RemovePos));

    int rlc[z];

    ic1->word = malloc(s);
    rwc1->word = malloc(s);
    rpc1->pos = (struct Position *) malloc(sizeof(struct Position));

    struct Position *pos = (struct Position *) malloc(sizeof(struct Position));
    struct Position *tpos = (struct Position *) malloc(sizeof(struct Position));
    out = fopen("output.txt", "w+");

    pos->next = NULL;
    tpos->next = NULL;

    struct TreeNode *ortree = NULL;

    while (fgets(line, s, stdin)) {
        char *word = malloc(s);
        line[strcspn(line, "\n")] = 0;
        for (word = strtok(line, " "); word; word = strtok(NULL, " ")) {
            pos = createPos(l, w, NULL);
            ortree = insertNode(ortree, word, pos);
            w++;
            if (strcmp(word, "END") == 0) {
                b = 0;
            }
            if (l > 1 && b == 1 && I == 0 && R == 0 && RL == 0) {
                printf("word is %s\n", word);
                if (strcmp(word, "I") == 0) {
                    I = 1;
                    continue;
                } else if (strcmp(word, "R") == 0) {
                    R = 1;
                    continue;
                } else if (strcmp(word, "RL") == 0) {
                    RL = 1;
                    continue;
                }
            }

             if (I == 1) {
                iw = word;
                I++;
                continue;
            }
            if (I == 2) {
                il = atoi(word);
                I++;
                continue;
            }
            if (I == 3) {
                io = atoi(word);
                tpos = createPos(il, io, NULL);
                ic1->pos = tpos;
                strcpy(ic1->word, iw);
                ic[INSERT] = (struct Insert *) malloc(sizeof(struct Insert));
                ic[INSERT] = ic1;
                I = 0;
                INSERT++;
                continue;
            }
            if (R == 1) {
                int r = atoi(word);
                if (r == 0) {
                    strcpy(rwc1->word, word);
                    rwc[REMOVEWORD] = rwc1;
                    REMOVEWORD++;
                    R = 0;
                    continue;
                } else {
                    rwl = r;
                    R++;
                    continue;
                }
            }
            if (R == 2) {
                rwo = atoi(word);
                tpos = createPos(rwl, rwo, NULL);
                rpc1->pos = tpos;
                rpc[REMOVEPOS] = rpc1;
                R = 0;
                REMOVEPOS++;
                continue;
            }
            if (RL == 1) {
                rlc[REMOVELINE] = atoi(word);
                RL = 0;
                REMOVELINE++;
                continue;
            }
        }
        l++;
        w = 1;
        *line = '\0';
    }

    for (int n = 0; n < INSERT; n++) {
        printf("ic[n]->word is %s\n", ic[n]->word);
        ortree = insertNode(ortree, ic[n]->word, ic[n]->pos);
    }

    for (int n = 0; n < REMOVEWORD; n++) {
        printf("rwc[n]->word is %s\n", rwc[n]->word);
        ortree = removeWord(ortree, rwc[n]->word);
    }

    for (int n = 0; n < REMOVEPOS; n++) {
        ortree = removePosition(ortree, rpc[n]->pos);
    }

    for (int n = 0; n < REMOVELINE; n++) {
        ortree = removeLine(ortree, rlc[n]);
    }

    inorder(ortree);

    fclose(out);
    return 0;
}

The input was requested, so here's one of the ten files we were given.

input.1 output.out
RL 1
RL 7
R they
R Center
END
That's a slight uptick from a year ago, when a CNN poll found that 53 percent said they were dreading having to carry on such a conversation, with 43 percent saying they looked forward to such a dialogue.

"There's a sense of dread. It suggests some indigestion may be part of Thanksgiving dinner if politics come up," said Lee Miringoff, director of the Marist Institute for Public Opinion. "People you work with and go out with socially tend to share political views, but when you get to family, if politics is in the recipe, it may not taste very well."

That trepidation about broaching politics isn't coming from just one political party, but almost two-thirds of Democrats said they are, while only about half of Republicans were. (Fifty-six percent of independents also said so.)

President Trump is, unsurprisingly, a polarizing topic of potential dinner conversation. Forty-seven percent of people in the poll said they find it "stressful and frustrating" when talking with people who have a different opinion about the president than they do. (A Pew Research Center poll from June found 59 percent saying the same thing.)

David Z
  • 128,184
  • 27
  • 255
  • 279
greyfiel
  • 11
  • 3
  • 2
    Don't cast the results of malloc – Mad Physicist Dec 18 '17 at 06:13
  • @MadPhysicist , just wondering - why not? It's something that my teacher has had us do in the past, so I figured it was required. (If this is something the internet can easily show me, feel free not to answer; I'll likely look it up on my own once I fix this issue.) – greyfiel Dec 18 '17 at 06:20
  • 2
    [Do I cast the result of malloc?](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) (Perhaps they shouldn't be teaching...) If it doesn't compile, it is because you're using a **C++ compiler**, and if you're using a C++ compiler to compile C code, then you'll just shoot yourself in the foot. – Antti Haapala -- Слава Україні Dec 18 '17 at 06:21
  • @AnttiHaapala , it does compile.. to an extent. I'm getting a segmentation fault caused by removeWord trying to remove the same word twice, which is happening because the array that's holding the words to be removed contains the same word twice. _That's_ because my old data is being overwritten. For the input I have above, 'Center' replaces 'they', meaning that 'Center' is there twice. – greyfiel Dec 18 '17 at 06:27
  • `gcc -fsanitize=undefined; ./a.out`: tree.c:153:24: runtime error: member access within null pointer of type 'struct Position' – Antti Haapala -- Слава Україні Dec 18 '17 at 06:29
  • @AnttiHaapla , I just get a segmentation fault on my end. There's a high chance I'm compiling wrong, but this is what I put in: `gcc -o h5 h5.c` , with h5.c being the name of my file. – greyfiel Dec 18 '17 at 06:31
  • 1
    add `-Wall -Werror -Wextra -fsanitize=undefined` (if they work) – Antti Haapala -- Слава Україні Dec 18 '17 at 06:34
  • There is something wrong in `insertNode` You always call `tpos = malloc ....` but in many cases `tpos` is unused and you have memory leak. Check what happens the first time you call the function. It will do `return createNode(word, pos);` so `tpos` is leaked – Support Ukraine Dec 18 '17 at 06:35
  • `tree->positions->line` on 154, there is a tree node that doesn't have `positions` set or sth. – Antti Haapala -- Слава Україні Dec 18 '17 at 06:35
  • Hi @greyfiel, the etiquette here is _not_ to edit a post to indicate that it's been solved. I've undone that edit for you. It's unfortunate that you have to wait for a while to accept the answer, but that's a system thing to prevent some kind of abuse; just wait and accept it when the time comes. – David Z Dec 18 '17 at 07:17
  • Okay, thanks! I just figured it would be better for people to not waste their time trying to answer something that had been solved, but I get where it's coming from. – greyfiel Dec 18 '17 at 07:32

1 Answers1

1

I was able to fix the above issue by moving my initialization of ic1, rwc1, rpc1, pos, and tpos into the loops in which they were used.

greyfiel
  • 11
  • 3
  • Good you solved but notice that you have memory leaks also in `main`. – Support Ukraine Dec 18 '17 at 06:57
  • 1
    BTW - consider more descriptive variable names. You have a lot of variables with names that tells nothing about their use. Example `l`, `w`, `b`, `R`. That makes the code hard to understand and maintain. – Support Ukraine Dec 18 '17 at 06:59