Home > Software engineering >  Unable to correctly allocate memory and failing to free it in my (ft_split) function
Unable to correctly allocate memory and failing to free it in my (ft_split) function

Time:07-07

I am trying to create a ft_split function which should:

Allocates with malloc and returns an array of strings obtained by splitting ’s’ using the character ’c’ as a delimiter. The array must end with a NULL pointer.

I have included all the code with the code sample below and the breakpoint where the debugger is giving me one of the errors.

now am having problems with:

  1. when I input a string and at the end of it i add the delimiter it gives this error

the string:

" To be or not to be that is the question "

the error:

Segmentation fault

  1. when I input this string

the string:

"Hello there"

it will give the right answer and then this error

Hello
there
Segmentation fault

  1. i just cant figure out how i should free the memory allocations created i have included what i think was the correct way commented.

my code:

size_t  ft_strlen(const char *s)
{
    size_t  i;

    i = 0;
    while (s[i] != '\0')
    {
        i  ;
    }
    return (i);
}

char    *ft_strcpy(char *dest, const char *src)
{
        int     i;

        i = 0;
        while (src[i] != '\0')
        {
                dest[i] = src[i];
                i  ;
        }
        dest[i] = '\0';
        return (dest);
}

char    *string_length(char const *str, char c, int i)
{
    int     j;
    char    *string;

    j = 0;
    // when i try the debugger with the first string in the main function it goes
    // directly to this line and break.
    string = (char *)malloc((ft_strlen(str)) * sizeof(*string));
    if(!string)
        return (NULL);
    while (str[i] == c)
        i  ;
    while (str[i])
    {
        *string = str[i];
        if (str[i   1] == c || str[i   1] == '\0')
        {
            string  ;
            j  ;
            *string = '\0';
            return (string - j);
        }
        string  ;
        j  ;
        i  ;
    }
    return (0);
}

int count_strings(char const *str, char c)
{
    int i;
    int count;
    int def;

    i = 0;
    count = 0;
    def = 1;
    while (str[i] == c)
        i  ;
    while (str[i])
    {
        if (str[i] == c && def == 1)
        {
            i  ;
            def = 0;
        }
        if (str[i] != c && def == 0)
        {
            count  ;
            def = 1;
        }
        i  ;
    }
    return (count);
}

int first_del(char const *str, char c, int i)
{
    while (str[i] == c)
        i  ;
    return (i);

}
char    **ft_split(char const *s, char c)
{
    int     count;
    int     i;
    int     len;
    int     num_of_strings;
    char    **split;
    char    *string;
    char    **it;

    i = 0;
    count = 0;
    num_of_strings = count_strings(s, c);
    split = (char **)malloc((num_of_strings   1) * sizeof(char *));
    if (!split)
        return (NULL);
    split[num_of_strings   1] = NULL;
    while (i <= num_of_strings)
    {
        count = first_del(s, c, count);
        string = string_length(s, c, count);
        len = ft_strlen(string);
        split[i] = (char *)malloc(len   1);
        ft_strcpy(split[i], string);
        count  = len;
        i  ;
        free(string);
        string = NULL;
    }
    return (split);
}
int main(void)
{
    char s[] = "   To    be    or    not    to    be    that     is   the question ";
    char **split_strings = ft_split(s, ' ');
    for (int i = 0; i < 10; i  )
        printf("%s\n", split_strings[i]);

    char s2[] = "Hello there";
    char **split_strings2 = ft_split(s2, ' ');
    for (int i = 0; i < 2; i  )
        printf("%s\n", split_strings2[i]);
} 

CodePudding user response:

string = (char *)malloc((ft_strlen(str)   1) * sizeof(*string));

split = (char **)malloc((num_of_strings   2) * sizeof(char *));

to free the memory allocation in the main function:

int i = 0;
while (split_strings && split_strings[i])
{
    free (split_strings[i]);
    i  ;
} 
free (split_strings); 

credits to xing

CodePudding user response:

First, define a function that splits a given string into multiple tokens, separated by a given separator:

bool split(const char *str, const char sep, char **tokens, const size_t maxtokens, size_t *ntokens)
{
    *ntokens = 0;
    const char *start = str;
    const char *p = str;
    
    for (;;) {
        if (*ntokens >= maxtokens) return false;
        
        while (*p && *p == sep)   p;
        if (!*p) return true;
        
        start = p;
        
        while (*p && *p != sep)   p;
        
        size_t len = p - start;
        char *tmp = malloc(sizeof(char) * (len   1));
        strncpy(tmp, start, len);
        tmp[len] = '\0';
        tokens[(*ntokens)  ] = tmp;
        
        if (!*p) return true;
    }
    
    return true;
}
  • str is the string to be splitted;
  • sep is the separator/delimiter;
  • tokens is the array that will hold your tokens;
  • maxtokens is the maximum number of tokens your array can hold (i.e. its capacity);
  • ntokens is the actual number of tokens in str.

Returns:

  • true if the string has been tokenized totally,
  • false if the maximum number of tokens limit (maxtokens) is reached and the end of string is not reached.

Then, define a function that computes the number of tokens in a given string:

size_t count_tokens(const char *str, const char sep)
{
    size_t counter = 0;
    for (const char *p = str; ; ) {
        while (*p && *p == sep)   p;
        if (!*p) return counter;
        
        while (*p && *p != sep)   p;
          counter;
        
        if (!*p) return counter;
    }
    return counter;
}

Putting the two together:

int main(void)
{
    const char *str = "   To    be    or    not    to    be    that     is   the question ";
    
    const size_t maxtokens = count_tokens(str, ' ');
    size_t ntokens = 0;
    char *tokens[maxtokens 1]; //  1 for the last NULL entry.
    
    split(str, ' ', tokens, maxtokens, &ntokens);
    tokens[maxtokens] = NULL; // Last entry is NULL

    for (size_t i = 0; tokens[i];   i) {
        printf("%d)\t%s\n", i 1, tokens[i]);
    }
}

Output:

1)  To
2)  be
3)  or
4)  not
5)  to
6)  be
7)  that
8)  is
9)  the
10) question

Notes:

  • If you are not allowed to use <string.h>, you can replace strncpy() with your own version.
  • Don't forget to free the memory allocated with malloc() as soon as you are done with the tokens.
  • Related