0

I have to split an initial char and create a list of said char which has to end with a NULL so i can iterate over in the main without knowing list size. The problem is that i get a seg fault whenever i try to check if last element is NULL. i am sorry i am still trying to learn both C and english. Thank you all

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

char **split(const char *s) {
    char **split;
    unsigned m_size = 0, c_size, i, j, k;

    // get s size
    for (i = 0; s[i] != '\0'; i++) {
        if (s[i] == ' ') {
            m_size++;
        }
    }
    m_size++;

    split = (char**) malloc(sizeof(char) * (m_size + 1));

    int sizes[m_size];
    c_size = 0;

    // get s words size
    for (i = 0, j = 0; s[i] != '\0'; i++) {
        if (s[i] == ' ') {
            c_size++;
            sizes[j] = c_size;
            c_size = 0;
            j++;
        } else {
            c_size++;
        }
    }
    sizes[j] = c_size;

    for (i = 0; i < m_size; i++) {
        split[i] = (char *) malloc(sizeof(char) * sizes[i]);
    }
    split[i] = NULL;

    for (i = 0, j = 0, k = 0; s[i] != '\0'; i++) {
        if (s[i] != ' ') {
            split[j][k] = s[i];
            k++;
        } else {
            split[j][k] = '\0';
            j++;
            k = 0;
        }
    }

    return split;
}

int main() {
    char s[19] = "hello how are you?";
    char **splitted;
    unsigned i;
    splitted = split(s);
    if (splitted == NULL) {
        return 1;
    }
    for (i = 0; splitted[i]!=NULL; i++) {
        printf("%s\n", splitted[i]);
    }
    return 0;
}

EDIT

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

char **split(const char *s) {
    char **r;
    unsigned word_size = 0;
    unsigned list_size = 0, i, j, k;

    // get s size
    for (i = 0; s[i] != '\0'; i++) {
        if (s[i] != ' ') {
            word_size++;
        } else {
            if (word_size > 0) {
                list_size++;
                word_size = 0;
            }
        }
    }
    list_size++;

    r = malloc(sizeof(*r) * (list_size + 1));

    int char_sizes[list_size];
    for (i = 0; i < list_size; char_sizes[i] = 0, i++);

    // get s words size
    for (i = 0, j = 0; s[i] != '\0'; i++) {
        if (s[i] != ' ') {
            char_sizes[j]++;
        } else {
            if (char_sizes[j] > 0) {
                j++;
            }
        }
    }

    for (i = 0; i < list_size; i++) {
        r[i] = malloc(sizeof(char) * char_sizes[i]);
    }
    r[i] = NULL;

    for (i = 0, j = 0, k = 0; s[i] != '\0'; i++) {
        if (s[i] != ' ') {
            r[j][k] = s[i];
            k++;
        } else {
            if (k > 0) {
                r[j][k] = '\0';
                j++;
                k = 0;
            }
        }
    }

    return r;
}

void destroy(char **list) {
    unsigned i;
    for (i = 0; list[i] != NULL; i++) {
        free(list[i]);
    }
    free(list);
}

int main() {
    char s[100] = " hello    guys how are?   you,d 31 3  ";
    char **splitted;
    unsigned i;
    splitted = split(s);
    if (splitted == NULL) {
        return 1;
    }
    for (i = 0; splitted[i]!=NULL; i++) {
        printf("%s", splitted[i]);
    }
    destroy(splitted);
    return 0;
}

ok guys i followed your tips and i edited my code. leaving this here if someone wants to point out other errors i will appreciate. now it should work even with multiple spaces. thanks to all

3
  • 4
    first malloc must use sizeof pointer: split = malloc(sizeof(char*) * (m_size + 1)); or, maybe better using the object itself: split = malloc(sizeof *split * (m_size + 1)); Commented May 20, 2020 at 10:55
  • In addition to the wrong size when allocating to split, you should allocate sizes[i] + 1 for each string to accommodate the null terminator. You also don't null-terminate the last string properly if the input doesn't end with a space. Commented May 20, 2020 at 11:00
  • How do you expect your code to behave if you have two spaces in between words ? Ex "Hello World". Do you want a split array like ["Hello", "World"] or ["Hello", "", "World"] ? If you want the former the current code is not capable of doing it. Commented May 20, 2020 at 11:36

1 Answer 1

1

Your are requesting an "array" of pointers to char, but you are allocating an "array" of chars:

split = (char**) malloc(sizeof(char) * (m_size + 1));

should become

split = malloc(sizeof(char*) * (m_size + 1));

Note the sizeof(char*). BTW: Note that in C, you should not cast the result of malloc as explained in this SO post.

Sign up to request clarification or add additional context in comments.

1 Comment

The probably best way to do is to use: split = malloc ( sizeof(*split) * (m_size + 1) ); as it ensures the correct allocation size, in the case the type of the object split is pointing to (as well as the type of split itself) changes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.