0

I am trying to implement a split funtion, which receives an array of chars and a delimiter that will decide what chars go to each array in the split array.
I have a problem with strcat and memset, can somone explain my mistakes to me?

        char** split(const char* str, char delimiter)
        {
            int ch=0;
            int word=0;
            const char * zero="\0";
            unsigned int size=num_items(str,delimiter);   

            /* get the size of split[][] */
    
            char** split= calloc(size+1,sizeof(char*));
            for(int i=0; i<strlen(str); i++) 
            {
                if(ch==0)
                { 
                    memset(split[word],'\0',1);

                    /* set the first value to '\0' */

                    ch++;
                }
                if(str[i]!=delimiter)
                {
                    /* adding char by char to the split */
                    strcat(split[word],&str[i]);
                    ch++;
                }else{
                    ch=0;
                    word++;
                }
            }
            return split;
        }
Yunnosch
  • 26,130
  • 9
  • 42
  • 54
  • 1
    What makes you think ",i have problem with strcat and memset"? Please provide a [mre] to demonstrate the symptoms. That includes fixing the comment syntax. – Yunnosch Jun 25 '22 at 14:02
  • 2
    You allocate memory for the array of pointers but not the strings they should point at. The `memset` and `strcat` calls are trying to write to null pointers. – Blastfurnace Jun 25 '22 at 14:26
  • A pointer needs to point to something before you can use it for example as an argument to `memset` or `strcpy`. `char** split= calloc(size+1,sizeof(char*));` allocates memory for an array of pointers, and makes `split` point to the first item of the array. But the pointers in the array do not point anywhere, so `memset` cannot work on them. By the way, `memset(split[word],'\0',1);` is a very roundabout way to say `split[word][0] = 0;` (but the second form won't work for the same reason the first one won't; you need to make `split[word]` to point to something first). – n. m. could be an AI Jun 27 '22 at 18:47

1 Answers1

0

Memory needs to be allocated for the pointers and the strings they point to.
For a single character, it can be assigned directly. No need for strcat and strcat expects pointers to zero terminated strings.

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

char** split(const char* str, char delimiter)
{
    char** split= NULL;
    int ch=0;
    unsigned int size=0;
    size_t len = strlen ( str);

    for(int i=0; i<len; i++)
    {
        if(ch==0)
        {
            char** temp= realloc(split, sizeof *split * (size+2));//allocate pointer
            if ( ! temp) {
                fprintf ( stderr, "problem malloc\n");
                return split;
            }
            split = temp;
            split[size] = calloc ( 1, len + 1);//allocate for string
            if ( ! split[size]) {
                fprintf ( stderr, "problem calloc\n");
                return split;
            }
            split[size + 1] = NULL;//sentinel
        }
        if(str[i]!=delimiter)
        {
            split[size][ch] = str[i];//assign character
            ch++;
        }else{
            size_t length = strlen ( split[size]);
            char *tmp = realloc ( split[size], length + 1);//reallocate to exact size
            if ( ! tmp) {
                fprintf ( stderr, "problem realloc\n");
                return split;
            }
            ch=0;
            size++;
        }
    }
    return split;
}

int main ( void) {
    char **words = NULL;
    char *text = "a bc def ghij klmno pqr st u v  wzyx";
    char space = ' ';

    words = split ( text, space);

    int each = 0;
    while ( words && words[each]) {
        printf ( "%s\n", words[each]);
        ++each;
    }
    each = 0;
    while ( words && words[each]) {
        free ( words[each]);
        ++each;
    }
    free ( words);

    return 0;
}
xing
  • 2,125
  • 2
  • 14
  • 10
  • this: `char *tmp = realloc ( split[size], length + 1)` , etv fails to update the `split[size]` pointer – user3629249 Jun 27 '22 at 18:01
  • @user3629249 How so? When the delimiter is found, that resizes that `split[size]` and advances to the next `size`. It executes once for each `size` – xing Jun 27 '22 at 18:08
  • @user3629249 There was a problem. I changed to `split[size] = calloc ( 1, len + 1);` forgot the `+ 1` – xing Jun 27 '22 at 18:15