Home > Blockchain >  What is wrong with my replace string with another string or character using linked list
What is wrong with my replace string with another string or character using linked list

Time:02-04

I have a linked list with many chars which I input from my input (what is the weather today?), to be replaced with another string (for example what replaced with how, so I get how is the weather today?).

But if the given words are right next to each other for example whatwhat, it will change to howwhat, disregarding the second part.

I think the problem is in the compare function, but I have no clue how to fix it, but the logic of replace should go like this:

If the words from my list and the needed word are the same, then proceed to iterate to the position where the next node of the word that should be changed (unwanted word) should be (pretty much the end of the word), then I create a new linked list with character with the wanted word, and connect temp to the start of the list and the next of the list to the position where the next character of the word that needs to be changed (unwanted word), which I found in the first loop.

Also don't roast my input() function, I know it is unsafe I just want to see what unsafe means with my own eyes, while I still have nothing to lose.

Here is the code:

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

struct node { 
    int value_c;
    struct node *next_c;
    struct node *prev_c;
};

typedef struct node string;

int compare(string *head, char *word) {
    int counter = 0;
    string *temp = head;
    for (int i = 0; i < strlen(word); i  ) {
        if (temp->value_c == word[i]) {
            temp = temp->next_c;
            counter  ;
        }
    }
    if (counter == strlen(word))
        return 1;
    else
        return 0;
}

void print_c(string *head) {
    while (head != NULL) {
        printf("%c", head->value_c);
        head = head->next_c;
    }
}

void append_c(string **head, char thing) {
    string *newNode = (string *)malloc(sizeof(string));

    newNode->value_c = thing;
    newNode->next_c = NULL;
    
    if (*head == NULL) {
        *head = newNode;
        newNode->prev_c = NULL;
        return;
    }
    
    string *temp = *head;

    while (temp->next_c != NULL)
        temp = temp->next_c;

    temp->next_c = newNode;
    newNode->prev_c = temp;
}

string *replace_all1(string *head, char *what, char *with_what) {
    string *temp = head;
    while (temp != NULL) {
        printf("%c ", temp->value_c);
        if (compare(temp, what) == 1) {
            printf("%i ", 1); 
            printf("%c ", temp->value_c);
            string *new = temp;
            for (int i = 0; i < strlen(what) - 1; i  ) {
                new = new->next_c;
            }
            string *word = NULL;
            for (int i = 0; i < strlen(with_what); i  ) {
                append_c(&word, with_what[i]);
            }

            string *word_temp = word;
            while (word_temp->next_c != NULL) {
                word_temp = word_temp->next_c;
            }

            word_temp->next_c = new->next_c;
            if (temp->prev_c != NULL) {
                temp->prev_c->next_c = word;
            } else {
                head = word;
                print_c(head);
                temp = word;
                print_c(temp);
                word->prev_c = NULL;
            }
        }
        temp = temp->next_c;
    }
    printf("\n");
    return head;
}

string *String(char *str) {
    string *st = NULL;
    int i = 0;
    while (str[i] != '\0') {
        append_c(&st, str[i]);
        i  ;
    }
    return st;
}

string *input() {
    char *a = (char *)malloc(sizeof(char));
    scanf("%[^\n]", a); //maximum of 1408
    string *stri = String(a);
    return stri;
    free(a);
}

int main() {
    string *list = NULL;

    string *big_boy_string = input();
    //printf("%c", big_boy_string->value_c);
    //print_c(big_boy_string);
    //printf("\n");
    //printf("%i", compare(big_boy_string, "what"));
    //printf("%i ", len(big_boy_string));

    //printf("\n");
    //print_c(slice(big_boy_string, 1, 10));
    //print_c(replace(big_boy_string, 'h', 'a'));
    //printf("\n");
    //print_c(reverse(big_boy_string));
    print_c(replace_all1(big_boy_string, "a", "b"));
    //getline();
}

CodePudding user response:

char *a = (char*) malloc(sizeof(char)); 
scanf("%[^\n]",a); //maximum of 1408

The first statement allocates memory for just 1 byte. So the maximum is not 1408, but 1. It can store a single char, or the null-terminator if it's a string, but no more.

Next, scanf() will write to out of bounds memory, and invoke undefined behaviour. The subsequent functions all depend on this undefined behaviour, so I'm not going to look at them.

But then, you've a memory leak in the same function.

return stri;
free(a);

You return before freeing the allocated memory. The call to free() is never executed.

The return value of malloc() is also ignored. Code risks undefined behaviour if the subsequent dereferences are on a NULL pointer.

Aside: The cast is meaningless and may hide a bug. malloc() and family returns a void * that is implicitly converted to the right type.


Re: Also don't roast my input() function, I know its unsafe I just want to see what unsafe means with my own eyes.

If you are already aware of this, then you shouldn't be asking why your code doesn't work. You are relying on undefined behaviour (playing with fire).

CodePudding user response:

There is no need to look further than the input function: it has undefined behavior or the worst kind because you attempt to read the input string into a very small array, allocated for a single byte. You must fix this first. Since you know the maximum length of your input string, you can use this:

string *input(void) {
    char a[1409];
    if (scanf("08[^\n]", a) != 1) { //maximum of 1408
        // invalid or missing input
        return NULL;
    }
    scanf(%*[^\n]");  // consume any remaining characters on the input line
    scanf(%*1[\n]");  // consume the newline if present
    return String(a);
}

Here is an alternative using getchar() instead of scanf() which is quite tricky and error prone:

string *input(void) {
    char a[1409];
    int c;
    size_t i = 0;

    while ((c = getchar()) != EOF && c != '\n') {
        if (i   1 < sizeof(a))
            a[i  ] = (char)c;
    }
    if (c == EOF && i == 0) {
        /* end of file without any input */
        return NULL;
    }
    a[i] = '\0';
    return String(a);
}

The compare function is incorrect: it should return false as soon as the comparison fails and it must test for the end of string (temp == NULL):

int compare(const string *head, const char *word) {
    string *temp = head;
    for (int i = 0; word[i] != '\n'; i  ) {
        if (temp == NULL || temp->value_c != word[i])
            return 0;
        temp = temp->next_c;
    }
    return 1;
}
  • Related