Question

I'm trying to create a split function using strtok and a dynamic array. However, I have no clue where things are going wrong: No informative error messages. It does say segmentation fault, but I don't understand how the heap is corrupt or whatever causes that happens. Would someone be willing to explain to me what is wrong and how to do it correctly?

Edit 11:16 CST code:

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

char **toArray(char **array, char str[], char sep[], int *count);
char** my_split(const char* str, char delim, int* size);

int main(int argc, char* argv[]) {
    char* test = "Hello there lol";
    int *count = 0;
    char **array = malloc(sizeof(char*) * 5);
    toArray(array, test, " ", count);
    printf("Count: %d\n", *count);

    int array_i;
    for (array_i = 0; array_i < *count; array_i++) {
        printf("array %d: %s\n", array_i, array[array_i]);
        free(array[array_i]);
    }
    free(array);
    return 1;
}

char **toArray(char **array, char str[], char sep[], int *count) {
    char *temp = str;
    temp = strtok(temp, sep);
    array[0] = temp;
    *count = 1;
    while ((temp = strtok(NULL, sep)) != NULL ) {
        array[(*count)++] = temp;
    }
    return array;
}
Was it helpful?

Solution

Compiler messages are our friend. I simpley used them to track down your issues. Try the following, and compare whats been done to what you had. Special attention to decalration and usage of pointer variables... :)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char **toArray(char **array, char str[], char sep[], int *count);

int main(int argc, char* argv[]) {
    char test[] = "Hello there lol";
    int count = 0;
    char **array = malloc((sizeof(char*) * 5) +1); //added "+ 1" here, read why
    toArray(array, test, " ", &count);             //in comment below
    printf("Count: %d\n", count);

    int array_i;
    for (array_i = 0; array_i < count; array_i++) {
        printf("array %d: %s\n", array_i, array[array_i]);
        //free(array[array_i]);
    }
    getchar();
    free(array);
    return 1;
}

char **toArray(char **array, char str[], char sep[], int *count) {
    char *temp = str;
    temp = strtok(temp, sep);
    array[0] = temp;
    *count = 1;
    while ((temp = strtok(NULL, sep)) != NULL) {
        array[(*count)++] = temp;
    }
    return array;
}

[EDIT] Example Output:
enter image description here

Also. The line char **array = malloc(sizeof(char*) * 5);, needed to be char **array = malloc(sizeof(char*) * 5 + 1); because "hello" is actually 5 chars plus a NULL char, '\0'.

Some rules of thumb for C string(s).

1) when using malloc or calloc, don't forget to allow room for '\0'.

     `char *buf1;` //buffer needed to manipulate buf2  
     `char  buf2[]="someString";`  
     `buf1 = malloc(strlen(buf2)+1);` or `buf1 = malloc(sizeof(buf2));`    
                                         (note:, no '+1'.  see '4)' below. ) 

2) clear (initialize) new allocated variable before use. eg:

memset(buf, 0, strlen("someString")+1);  //preferred, all bytes are zeroed

OR

buf[0]=0;  //useful, but use with care (only first byte is zeroed.)  

3) Free all dynamically allocated memory when done with it. Eg:

free(buf);   

4) Using strlen() function or sizeof() macro. (both popular for use in [mc]alloc())
Given:
char *buf1 ="Hello"; //6 characters |H|e|l|l|o|\0|
char buf2[] ="Hello"; //6 characters |H|e|l|l|o|\0|
char buf3[5]="Hello"; //5 characters |H|e|l|l|o|
char buf4[5]="Hel"; //4 characters |H|e|l|\0| |
char buf5[5]="Helloo";//should get compile error, too many initializers

Compare strlen() - sizeof() results:

strlen(buf1); //->5 (requires +1 in malloc for new variable req'd to hold "Hello\0")
sizeof(buf1); //->4 (returns sizof (char *), not # chars in string)

strlen(buf2); //->5 (requires +1 in malloc for new variable req'd yo hold "Hello\0")
sizeof(buf2); //->6 (counts all chars, including '\0')

strlen(buf3); //-> (error: Missing terminating NULL in string argument)
sizeof(buf3); //->5 (counts all chars, but there is no '\0' in this string - wrong!)

strlen(buf4); //->3 (counts chars, but not '\0')
sizeof(buf4); //->5 (counts ALL allocated space, including '\0')

OTHER TIPS

You are passing char *test = "Hello there lol"; to your toArray(). Unfortunately, the string is not modifiable, so when you try to modify it with strtok(), you get a segmentation fault.

The simplest fix is:

char test[] = "Hello there lol";

You also have:

int *count = 0;

and you call the function with:

toArray(array, test, " ", count);

You need an integer, and to pass its address:

int count = 0;
...
toArray(array, test, " ", &count);

You were also trying to free the strings that were pointed at by the elements in array, but those were never allocated (they are parts of the string test). Don't free what was not allocated with malloc() et al.

With those fixes in place, this code works:

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

char **toArray(char **array, char str[], char sep[], int *count);

int main(void)
{
    char test[] = "Hello there lol";
    int count = 0;
    char **array = malloc(sizeof(char *) * 5);

    toArray(array, test, " ", &count);
    printf("Count: %d\n", count);

    for (int i = 0; i < count; i++)
        printf("array %d: %s\n", i, array[i]);
    free(array);
    return 0;
}

char **toArray(char **array, char str[], char sep[], int *count)
{
    char *temp = str;
    temp = strtok(temp, sep);
    array[0] = temp;
    *count = 1;
    while ((temp = strtok(NULL, sep)) != NULL)
        array[(*count)++] = temp;
    return array;
}

Output:

Count: 3
array 0: Hello
array 1: there
array 2: lol
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top