Why does my string_split implementation not work?Split string with delimiters in CWith arrays, why is it the case that a[5] == 5[a]?Why is using “for…in” with array iteration a bad idea?How do function pointers in C work?C - Malloc issue (maybe something else)What does the C ??!??! operator do?Why are elementwise additions much faster in separate loops than in a combined loop?strtod with limited string lengthWhy does the C preprocessor interpret the word “linux” as the constant “1”?Unable to access Struct contents properlyWhy should I use a pointer rather than the object itself?

Do injective, yet not bijective, functions have an inverse?

VHDL: is there a way to create an entity into which constants can be passed?

Deck of Cards with Shuffle and Sort functionality

"Distance" between summands in Taylor Series of Cosine

Why do people prefer metropolitan areas, considering monsters and villains?

Is this Cambridge Dictionary example of "felicitate" valid?

Swapping "Good" and "Bad"

Is it okay to use open source code to do an interview task?

What could cause the sea level to massively decrease?

Computer name naming convention for security

What was the profession 芸者 (female entertainer) called in Russia?

Party going through airport security at separate times?

When I press the space bar it deletes the letters in front of it

Category-theoretic treatment of diffs, patches and merging?

Hail hit my roof. Do I need to replace it?

How does Kaya's Ghostform interact with Elenda, the Dusk Rose?

Is it better in terms of durability to remove card+battery or to connect to charger/computer via USB-C?

Moving millions of files to a different directory with specfic name patterns

Is it ok for parents to kiss and romance with each other while their 2- to 8-year-old child watches?

What factors could lead to bishops establishing monastic armies?

No Torah = Revert to Nothingness?

What are the effects of abstaining from eating a certain flavor?

Distinguish the explanations of Galadriel's test in LotR

What is a writing material that persists forever or for a long time?



Why does my string_split implementation not work?


Split string with delimiters in CWith arrays, why is it the case that a[5] == 5[a]?Why is using “for…in” with array iteration a bad idea?How do function pointers in C work?C - Malloc issue (maybe something else)What does the C ??!??! operator do?Why are elementwise additions much faster in separate loops than in a combined loop?strtod with limited string lengthWhy does the C preprocessor interpret the word “linux” as the constant “1”?Unable to access Struct contents properlyWhy should I use a pointer rather than the object itself?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








2















My str_split function returns (or at least I think it does) a char** - so a list of strings essentially. It takes a string parameter, a char delimiter to split the string on, and a pointer to an int to place the number of strings detected.



The way I did it, which may be highly inefficient, is to make a buffer of x length (x = length of string), then copy element of string until we reach delimiter, or '' character. Then it copies the buffer to the char**, which is what we are returning (and has been malloced earlier, and can be freed from main()), then clears the buffer and repeats.



Although the algorithm may be iffy, the logic is definitely sound as my debug code (the _D) shows it's being copied correctly. The part I'm stuck on is when I make a char** in main, set it equal to my function. It doesn't return null, crash the program, or throw any errors, but it doesn't quite seem to work either. I'm assuming this is what is meant be the term Undefined Behavior.



Anyhow, after a lot of thinking (I'm new to all this) I tried something else, which you will see in the code, currently commented out. When I use malloc to copy the buffer to a new string, and pass that copy to aforementioned char**, it seems to work perfectly. HOWEVER, this creates an obvious memory leak as I can't free it later... so I'm lost.



When I did some research I found this post, which follows the idea of my code almost exactly and works, meaning there isn't an inherent problem with the format (return value, parameters, etc) of my str_split function. YET his only has 1 malloc, for the char**, and works just fine.



Below is my code. I've been trying to figure this out and it's scrambling my brain, so I'd really appreciate help!! Sorry in advance for the 'i', 'b', 'c' it's a bit convoluted I know.



Edit: should mention that with the following code,



ret[c] = buffer;
printf("Content of ret[%i] = "%s" n", c, ret[c]);


it does indeed print correctly. It's only when I call the function from main that it gets weird. I'm guessing it's because it's out of scope ?



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

#define DEBUG

#ifdef DEBUG
#define _D if (1)
#else
#define _D if (0)
#endif

char **str_split(char[], char, int*);
int count_char(char[], char);

int main(void)
int num_strings = 0;
char **result = str_split("Helo_World_poopy_pants", '_', &num_strings);

if (result == NULL)
printf("result is NULLn");
return 0;


if (num_strings > 0)
for (int i = 0; i < num_strings; i++)
printf(""%s" n", result[i]);



free(result);

return 0;


char **str_split(char string[], char delim, int *num_strings)

int num_delim = count_char(string, delim);
*num_strings = num_delim + 1;

if (*num_strings < 2)
return NULL;


//return value
char **ret = malloc((*num_strings) * sizeof(char*));

if (ret == NULL)
_D printf("ret is null.n");
return NULL;


int slen = strlen(string);
char buffer[slen];

/* b is the buffer index, c is the index for **ret */
int b = 0, c = 0;
for (int i = 0; i < slen + 1; i++)

char cur = string[i];

if (cur == delim

return ret;


int count_char(char base[], char c)
int count = 0;
int i = 0;

while (base[i] != '')
if (base[i++] == c)
count++;


_D printf("Found %i occurence(s) of '%c'n", count, c);
return count;










share|improve this question



















  • 2





    "Then it copies the buffer to the char**" - no, it doesn't. Where?

    – melpomene
    Mar 25 at 23:15











  • at: ret[c] = buffer; am I missing something really obvious? Sorry! Edit: If you're referring to the usage of copies, I used 'copy' and 'set' interchangeably. As in setting the value of char**[index] equal to the buffer.

    – mysteryuser12345
    Mar 25 at 23:19







  • 2





    That doesn't copy the buffer. ret[c] is just a pointer. You're setting it to point into buffer, which is a local variable, which is destroyed when the surrounding function returns. Also, all elements of ret have the same value (buffer). You're returning an array containing identical garbage pointers.

    – melpomene
    Mar 25 at 23:21











  • You are storing pointers to a buffer that exists on the stack. Using those pointers after returning from the function results in undefined behavior.

    – paddy
    Mar 25 at 23:21











  • @melpomene Ah! I figured it was something like that, but could not for the life of me put it into words. Thanks a lot, sir. So how would you recommend I proceed from here- is there any alternative to malloc'ing each string separately? As of course, I would never be able to free them.

    – mysteryuser12345
    Mar 25 at 23:30

















2















My str_split function returns (or at least I think it does) a char** - so a list of strings essentially. It takes a string parameter, a char delimiter to split the string on, and a pointer to an int to place the number of strings detected.



The way I did it, which may be highly inefficient, is to make a buffer of x length (x = length of string), then copy element of string until we reach delimiter, or '' character. Then it copies the buffer to the char**, which is what we are returning (and has been malloced earlier, and can be freed from main()), then clears the buffer and repeats.



Although the algorithm may be iffy, the logic is definitely sound as my debug code (the _D) shows it's being copied correctly. The part I'm stuck on is when I make a char** in main, set it equal to my function. It doesn't return null, crash the program, or throw any errors, but it doesn't quite seem to work either. I'm assuming this is what is meant be the term Undefined Behavior.



Anyhow, after a lot of thinking (I'm new to all this) I tried something else, which you will see in the code, currently commented out. When I use malloc to copy the buffer to a new string, and pass that copy to aforementioned char**, it seems to work perfectly. HOWEVER, this creates an obvious memory leak as I can't free it later... so I'm lost.



When I did some research I found this post, which follows the idea of my code almost exactly and works, meaning there isn't an inherent problem with the format (return value, parameters, etc) of my str_split function. YET his only has 1 malloc, for the char**, and works just fine.



Below is my code. I've been trying to figure this out and it's scrambling my brain, so I'd really appreciate help!! Sorry in advance for the 'i', 'b', 'c' it's a bit convoluted I know.



Edit: should mention that with the following code,



ret[c] = buffer;
printf("Content of ret[%i] = "%s" n", c, ret[c]);


it does indeed print correctly. It's only when I call the function from main that it gets weird. I'm guessing it's because it's out of scope ?



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

#define DEBUG

#ifdef DEBUG
#define _D if (1)
#else
#define _D if (0)
#endif

char **str_split(char[], char, int*);
int count_char(char[], char);

int main(void)
int num_strings = 0;
char **result = str_split("Helo_World_poopy_pants", '_', &num_strings);

if (result == NULL)
printf("result is NULLn");
return 0;


if (num_strings > 0)
for (int i = 0; i < num_strings; i++)
printf(""%s" n", result[i]);



free(result);

return 0;


char **str_split(char string[], char delim, int *num_strings)

int num_delim = count_char(string, delim);
*num_strings = num_delim + 1;

if (*num_strings < 2)
return NULL;


//return value
char **ret = malloc((*num_strings) * sizeof(char*));

if (ret == NULL)
_D printf("ret is null.n");
return NULL;


int slen = strlen(string);
char buffer[slen];

/* b is the buffer index, c is the index for **ret */
int b = 0, c = 0;
for (int i = 0; i < slen + 1; i++)

char cur = string[i];

if (cur == delim

return ret;


int count_char(char base[], char c)
int count = 0;
int i = 0;

while (base[i] != '')
if (base[i++] == c)
count++;


_D printf("Found %i occurence(s) of '%c'n", count, c);
return count;










share|improve this question



















  • 2





    "Then it copies the buffer to the char**" - no, it doesn't. Where?

    – melpomene
    Mar 25 at 23:15











  • at: ret[c] = buffer; am I missing something really obvious? Sorry! Edit: If you're referring to the usage of copies, I used 'copy' and 'set' interchangeably. As in setting the value of char**[index] equal to the buffer.

    – mysteryuser12345
    Mar 25 at 23:19







  • 2





    That doesn't copy the buffer. ret[c] is just a pointer. You're setting it to point into buffer, which is a local variable, which is destroyed when the surrounding function returns. Also, all elements of ret have the same value (buffer). You're returning an array containing identical garbage pointers.

    – melpomene
    Mar 25 at 23:21











  • You are storing pointers to a buffer that exists on the stack. Using those pointers after returning from the function results in undefined behavior.

    – paddy
    Mar 25 at 23:21











  • @melpomene Ah! I figured it was something like that, but could not for the life of me put it into words. Thanks a lot, sir. So how would you recommend I proceed from here- is there any alternative to malloc'ing each string separately? As of course, I would never be able to free them.

    – mysteryuser12345
    Mar 25 at 23:30













2












2








2


0






My str_split function returns (or at least I think it does) a char** - so a list of strings essentially. It takes a string parameter, a char delimiter to split the string on, and a pointer to an int to place the number of strings detected.



The way I did it, which may be highly inefficient, is to make a buffer of x length (x = length of string), then copy element of string until we reach delimiter, or '' character. Then it copies the buffer to the char**, which is what we are returning (and has been malloced earlier, and can be freed from main()), then clears the buffer and repeats.



Although the algorithm may be iffy, the logic is definitely sound as my debug code (the _D) shows it's being copied correctly. The part I'm stuck on is when I make a char** in main, set it equal to my function. It doesn't return null, crash the program, or throw any errors, but it doesn't quite seem to work either. I'm assuming this is what is meant be the term Undefined Behavior.



Anyhow, after a lot of thinking (I'm new to all this) I tried something else, which you will see in the code, currently commented out. When I use malloc to copy the buffer to a new string, and pass that copy to aforementioned char**, it seems to work perfectly. HOWEVER, this creates an obvious memory leak as I can't free it later... so I'm lost.



When I did some research I found this post, which follows the idea of my code almost exactly and works, meaning there isn't an inherent problem with the format (return value, parameters, etc) of my str_split function. YET his only has 1 malloc, for the char**, and works just fine.



Below is my code. I've been trying to figure this out and it's scrambling my brain, so I'd really appreciate help!! Sorry in advance for the 'i', 'b', 'c' it's a bit convoluted I know.



Edit: should mention that with the following code,



ret[c] = buffer;
printf("Content of ret[%i] = "%s" n", c, ret[c]);


it does indeed print correctly. It's only when I call the function from main that it gets weird. I'm guessing it's because it's out of scope ?



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

#define DEBUG

#ifdef DEBUG
#define _D if (1)
#else
#define _D if (0)
#endif

char **str_split(char[], char, int*);
int count_char(char[], char);

int main(void)
int num_strings = 0;
char **result = str_split("Helo_World_poopy_pants", '_', &num_strings);

if (result == NULL)
printf("result is NULLn");
return 0;


if (num_strings > 0)
for (int i = 0; i < num_strings; i++)
printf(""%s" n", result[i]);



free(result);

return 0;


char **str_split(char string[], char delim, int *num_strings)

int num_delim = count_char(string, delim);
*num_strings = num_delim + 1;

if (*num_strings < 2)
return NULL;


//return value
char **ret = malloc((*num_strings) * sizeof(char*));

if (ret == NULL)
_D printf("ret is null.n");
return NULL;


int slen = strlen(string);
char buffer[slen];

/* b is the buffer index, c is the index for **ret */
int b = 0, c = 0;
for (int i = 0; i < slen + 1; i++)

char cur = string[i];

if (cur == delim

return ret;


int count_char(char base[], char c)
int count = 0;
int i = 0;

while (base[i] != '')
if (base[i++] == c)
count++;


_D printf("Found %i occurence(s) of '%c'n", count, c);
return count;










share|improve this question
















My str_split function returns (or at least I think it does) a char** - so a list of strings essentially. It takes a string parameter, a char delimiter to split the string on, and a pointer to an int to place the number of strings detected.



The way I did it, which may be highly inefficient, is to make a buffer of x length (x = length of string), then copy element of string until we reach delimiter, or '' character. Then it copies the buffer to the char**, which is what we are returning (and has been malloced earlier, and can be freed from main()), then clears the buffer and repeats.



Although the algorithm may be iffy, the logic is definitely sound as my debug code (the _D) shows it's being copied correctly. The part I'm stuck on is when I make a char** in main, set it equal to my function. It doesn't return null, crash the program, or throw any errors, but it doesn't quite seem to work either. I'm assuming this is what is meant be the term Undefined Behavior.



Anyhow, after a lot of thinking (I'm new to all this) I tried something else, which you will see in the code, currently commented out. When I use malloc to copy the buffer to a new string, and pass that copy to aforementioned char**, it seems to work perfectly. HOWEVER, this creates an obvious memory leak as I can't free it later... so I'm lost.



When I did some research I found this post, which follows the idea of my code almost exactly and works, meaning there isn't an inherent problem with the format (return value, parameters, etc) of my str_split function. YET his only has 1 malloc, for the char**, and works just fine.



Below is my code. I've been trying to figure this out and it's scrambling my brain, so I'd really appreciate help!! Sorry in advance for the 'i', 'b', 'c' it's a bit convoluted I know.



Edit: should mention that with the following code,



ret[c] = buffer;
printf("Content of ret[%i] = "%s" n", c, ret[c]);


it does indeed print correctly. It's only when I call the function from main that it gets weird. I'm guessing it's because it's out of scope ?



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

#define DEBUG

#ifdef DEBUG
#define _D if (1)
#else
#define _D if (0)
#endif

char **str_split(char[], char, int*);
int count_char(char[], char);

int main(void)
int num_strings = 0;
char **result = str_split("Helo_World_poopy_pants", '_', &num_strings);

if (result == NULL)
printf("result is NULLn");
return 0;


if (num_strings > 0)
for (int i = 0; i < num_strings; i++)
printf(""%s" n", result[i]);



free(result);

return 0;


char **str_split(char string[], char delim, int *num_strings)

int num_delim = count_char(string, delim);
*num_strings = num_delim + 1;

if (*num_strings < 2)
return NULL;


//return value
char **ret = malloc((*num_strings) * sizeof(char*));

if (ret == NULL)
_D printf("ret is null.n");
return NULL;


int slen = strlen(string);
char buffer[slen];

/* b is the buffer index, c is the index for **ret */
int b = 0, c = 0;
for (int i = 0; i < slen + 1; i++)

char cur = string[i];

if (cur == delim

return ret;


int count_char(char base[], char c)
int count = 0;
int i = 0;

while (base[i] != '')
if (base[i++] == c)
count++;


_D printf("Found %i occurence(s) of '%c'n", count, c);
return count;







c arrays pointers split malloc






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 25 at 23:38









chqrlie

67.4k9 gold badges58 silver badges114 bronze badges




67.4k9 gold badges58 silver badges114 bronze badges










asked Mar 25 at 23:11









mysteryuser12345mysteryuser12345

133 bronze badges




133 bronze badges







  • 2





    "Then it copies the buffer to the char**" - no, it doesn't. Where?

    – melpomene
    Mar 25 at 23:15











  • at: ret[c] = buffer; am I missing something really obvious? Sorry! Edit: If you're referring to the usage of copies, I used 'copy' and 'set' interchangeably. As in setting the value of char**[index] equal to the buffer.

    – mysteryuser12345
    Mar 25 at 23:19







  • 2





    That doesn't copy the buffer. ret[c] is just a pointer. You're setting it to point into buffer, which is a local variable, which is destroyed when the surrounding function returns. Also, all elements of ret have the same value (buffer). You're returning an array containing identical garbage pointers.

    – melpomene
    Mar 25 at 23:21











  • You are storing pointers to a buffer that exists on the stack. Using those pointers after returning from the function results in undefined behavior.

    – paddy
    Mar 25 at 23:21











  • @melpomene Ah! I figured it was something like that, but could not for the life of me put it into words. Thanks a lot, sir. So how would you recommend I proceed from here- is there any alternative to malloc'ing each string separately? As of course, I would never be able to free them.

    – mysteryuser12345
    Mar 25 at 23:30












  • 2





    "Then it copies the buffer to the char**" - no, it doesn't. Where?

    – melpomene
    Mar 25 at 23:15











  • at: ret[c] = buffer; am I missing something really obvious? Sorry! Edit: If you're referring to the usage of copies, I used 'copy' and 'set' interchangeably. As in setting the value of char**[index] equal to the buffer.

    – mysteryuser12345
    Mar 25 at 23:19







  • 2





    That doesn't copy the buffer. ret[c] is just a pointer. You're setting it to point into buffer, which is a local variable, which is destroyed when the surrounding function returns. Also, all elements of ret have the same value (buffer). You're returning an array containing identical garbage pointers.

    – melpomene
    Mar 25 at 23:21











  • You are storing pointers to a buffer that exists on the stack. Using those pointers after returning from the function results in undefined behavior.

    – paddy
    Mar 25 at 23:21











  • @melpomene Ah! I figured it was something like that, but could not for the life of me put it into words. Thanks a lot, sir. So how would you recommend I proceed from here- is there any alternative to malloc'ing each string separately? As of course, I would never be able to free them.

    – mysteryuser12345
    Mar 25 at 23:30







2




2





"Then it copies the buffer to the char**" - no, it doesn't. Where?

– melpomene
Mar 25 at 23:15





"Then it copies the buffer to the char**" - no, it doesn't. Where?

– melpomene
Mar 25 at 23:15













at: ret[c] = buffer; am I missing something really obvious? Sorry! Edit: If you're referring to the usage of copies, I used 'copy' and 'set' interchangeably. As in setting the value of char**[index] equal to the buffer.

– mysteryuser12345
Mar 25 at 23:19






at: ret[c] = buffer; am I missing something really obvious? Sorry! Edit: If you're referring to the usage of copies, I used 'copy' and 'set' interchangeably. As in setting the value of char**[index] equal to the buffer.

– mysteryuser12345
Mar 25 at 23:19





2




2





That doesn't copy the buffer. ret[c] is just a pointer. You're setting it to point into buffer, which is a local variable, which is destroyed when the surrounding function returns. Also, all elements of ret have the same value (buffer). You're returning an array containing identical garbage pointers.

– melpomene
Mar 25 at 23:21





That doesn't copy the buffer. ret[c] is just a pointer. You're setting it to point into buffer, which is a local variable, which is destroyed when the surrounding function returns. Also, all elements of ret have the same value (buffer). You're returning an array containing identical garbage pointers.

– melpomene
Mar 25 at 23:21













You are storing pointers to a buffer that exists on the stack. Using those pointers after returning from the function results in undefined behavior.

– paddy
Mar 25 at 23:21





You are storing pointers to a buffer that exists on the stack. Using those pointers after returning from the function results in undefined behavior.

– paddy
Mar 25 at 23:21













@melpomene Ah! I figured it was something like that, but could not for the life of me put it into words. Thanks a lot, sir. So how would you recommend I proceed from here- is there any alternative to malloc'ing each string separately? As of course, I would never be able to free them.

– mysteryuser12345
Mar 25 at 23:30





@melpomene Ah! I figured it was something like that, but could not for the life of me put it into words. Thanks a lot, sir. So how would you recommend I proceed from here- is there any alternative to malloc'ing each string separately? As of course, I would never be able to free them.

– mysteryuser12345
Mar 25 at 23:30












2 Answers
2






active

oldest

votes


















0














You are storing pointers to a buffer that exists on the stack. Using those pointers after returning from the function results in undefined behavior.



To get around this requires one of the following:




  • Allow the function to modify the input string (i.e. replace delimiters with null-terminator characters) and return pointers into it. The caller must be aware that this can happen. Note that supplying a string literal as you are doing here is illegal in C, so you would instead need to do:



    char my_string[] = "Helo_World_poopy_pants";
    char **result = str_split(my_string, '_', &num_strings);


    In this case, the function should also make it clear that a string literal is not acceptable input, and define its first parameter as const char* string (instead of char string[]).




  • Allow the function to make a copy of the string and then modify the copy. You have expressed concerns about leaking this memory, but that concern is mostly to do with your program's design rather than a necessity.



    It's perfectly valid to duplicate each string individually and then clean them all up later. The main issue is that it's inconvenient, and also slightly pointless.



Let's address the second point. You have several options, but if you insist that the result be easily cleaned-up with a call to free, then try this strategy:




  1. When you allocate the pointer array, also make it large enough to hold a copy of the string:



    // Allocate storage for `num_strings` pointers, plus a copy of the original string,
    // then copy the string into memory immediately following the pointer storage.
    char **ret = malloc((*num_strings) * sizeof(char*) + strlen(string) + 1);
    char *buffer = (char*)&ret[*num_strings];
    strcpy(buffer, string);



  2. Now, do all your string operations on buffer. For example:



    // Extract all delimited substrings. Here, buffer will always point at the
    // current substring, and p will search for the delimiter. Once found,
    // the substring is terminated, its pointer appended to the substring array,
    // and then buffer is pointed at the next substring, if any.
    int c = 0;
    for(char *p = buffer; *buffer; ++p)
    !*p)
    char *next = p;
    if (*p)
    *p = '';
    ++next;

    ret[c++] = buffer;
    buffer = next;




  3. When you need to clean up, it's just a single call to free, because everything was stored together.






share|improve this answer

























  • Thanks so much for the help! I'm still reading through it and trying to understand, but I think this right here is perfect. I'm a little confused by the example you gave in 2. but I'm sure I'll get it eventually.

    – mysteryuser12345
    Mar 25 at 23:54












  • I realized I had a small error, so please see my edit. The loop is pretty basic. It simply walks through each character in the string using char *p, leaving buffer pointed at the beginning of the substring currently being searched. When it finds a delimiter (or end of string), it terminates that substring, appends the buffer pointer to your array, and then points buffer to the start of the next substring, if any. The loop terminates when buffer points to an empty string, which will be the case once all strings (including none, if original was empty) have been extracted.

    – paddy
    Mar 25 at 23:59



















0














The string pointers you store into the res with ret[c] = buffer; array point to an automatic array that goes out of scope when the function returns. The code subsequently has undefined behavior. You should allocate these strings with strdup().



Note also that it might not be appropriate to return NULL when the string does not contain a separator. Why not return an array with a single string?



Here is a simpler implementation:



#include <stdlib.h>

char **str_split(const char *string, char delim, int *num_strings)
int i, n, from, to;
char **res;

for (n = 1, i = 0; string[i]; i++)
n += (string[i] == delim);

*num_strings = 0;
res = malloc(sizeof(*res) * n);
if (res == NULL)
return NULL;

for (i = from = to = 0;; from = to + 1)
for (to = from; string[to] != delim && string[to] != ''; to++)
continue;
res[i] = malloc(to - from + 1);
if (res[i] == NULL)
/* allocation failure: free memory allocated so far */
while (i > 0)
free(res[--i]);
free(res);
return NULL;

memcpy(res[i], string + from, to - from);
res[i][to - from] = '';
i++;
if (string[to] == '')
break;

*num_strings = n;
return res;






share|improve this answer



























    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55347699%2fwhy-does-my-string-split-implementation-not-work%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    You are storing pointers to a buffer that exists on the stack. Using those pointers after returning from the function results in undefined behavior.



    To get around this requires one of the following:




    • Allow the function to modify the input string (i.e. replace delimiters with null-terminator characters) and return pointers into it. The caller must be aware that this can happen. Note that supplying a string literal as you are doing here is illegal in C, so you would instead need to do:



      char my_string[] = "Helo_World_poopy_pants";
      char **result = str_split(my_string, '_', &num_strings);


      In this case, the function should also make it clear that a string literal is not acceptable input, and define its first parameter as const char* string (instead of char string[]).




    • Allow the function to make a copy of the string and then modify the copy. You have expressed concerns about leaking this memory, but that concern is mostly to do with your program's design rather than a necessity.



      It's perfectly valid to duplicate each string individually and then clean them all up later. The main issue is that it's inconvenient, and also slightly pointless.



    Let's address the second point. You have several options, but if you insist that the result be easily cleaned-up with a call to free, then try this strategy:




    1. When you allocate the pointer array, also make it large enough to hold a copy of the string:



      // Allocate storage for `num_strings` pointers, plus a copy of the original string,
      // then copy the string into memory immediately following the pointer storage.
      char **ret = malloc((*num_strings) * sizeof(char*) + strlen(string) + 1);
      char *buffer = (char*)&ret[*num_strings];
      strcpy(buffer, string);



    2. Now, do all your string operations on buffer. For example:



      // Extract all delimited substrings. Here, buffer will always point at the
      // current substring, and p will search for the delimiter. Once found,
      // the substring is terminated, its pointer appended to the substring array,
      // and then buffer is pointed at the next substring, if any.
      int c = 0;
      for(char *p = buffer; *buffer; ++p)
      !*p)
      char *next = p;
      if (*p)
      *p = '';
      ++next;

      ret[c++] = buffer;
      buffer = next;




    3. When you need to clean up, it's just a single call to free, because everything was stored together.






    share|improve this answer

























    • Thanks so much for the help! I'm still reading through it and trying to understand, but I think this right here is perfect. I'm a little confused by the example you gave in 2. but I'm sure I'll get it eventually.

      – mysteryuser12345
      Mar 25 at 23:54












    • I realized I had a small error, so please see my edit. The loop is pretty basic. It simply walks through each character in the string using char *p, leaving buffer pointed at the beginning of the substring currently being searched. When it finds a delimiter (or end of string), it terminates that substring, appends the buffer pointer to your array, and then points buffer to the start of the next substring, if any. The loop terminates when buffer points to an empty string, which will be the case once all strings (including none, if original was empty) have been extracted.

      – paddy
      Mar 25 at 23:59
















    0














    You are storing pointers to a buffer that exists on the stack. Using those pointers after returning from the function results in undefined behavior.



    To get around this requires one of the following:




    • Allow the function to modify the input string (i.e. replace delimiters with null-terminator characters) and return pointers into it. The caller must be aware that this can happen. Note that supplying a string literal as you are doing here is illegal in C, so you would instead need to do:



      char my_string[] = "Helo_World_poopy_pants";
      char **result = str_split(my_string, '_', &num_strings);


      In this case, the function should also make it clear that a string literal is not acceptable input, and define its first parameter as const char* string (instead of char string[]).




    • Allow the function to make a copy of the string and then modify the copy. You have expressed concerns about leaking this memory, but that concern is mostly to do with your program's design rather than a necessity.



      It's perfectly valid to duplicate each string individually and then clean them all up later. The main issue is that it's inconvenient, and also slightly pointless.



    Let's address the second point. You have several options, but if you insist that the result be easily cleaned-up with a call to free, then try this strategy:




    1. When you allocate the pointer array, also make it large enough to hold a copy of the string:



      // Allocate storage for `num_strings` pointers, plus a copy of the original string,
      // then copy the string into memory immediately following the pointer storage.
      char **ret = malloc((*num_strings) * sizeof(char*) + strlen(string) + 1);
      char *buffer = (char*)&ret[*num_strings];
      strcpy(buffer, string);



    2. Now, do all your string operations on buffer. For example:



      // Extract all delimited substrings. Here, buffer will always point at the
      // current substring, and p will search for the delimiter. Once found,
      // the substring is terminated, its pointer appended to the substring array,
      // and then buffer is pointed at the next substring, if any.
      int c = 0;
      for(char *p = buffer; *buffer; ++p)
      !*p)
      char *next = p;
      if (*p)
      *p = '';
      ++next;

      ret[c++] = buffer;
      buffer = next;




    3. When you need to clean up, it's just a single call to free, because everything was stored together.






    share|improve this answer

























    • Thanks so much for the help! I'm still reading through it and trying to understand, but I think this right here is perfect. I'm a little confused by the example you gave in 2. but I'm sure I'll get it eventually.

      – mysteryuser12345
      Mar 25 at 23:54












    • I realized I had a small error, so please see my edit. The loop is pretty basic. It simply walks through each character in the string using char *p, leaving buffer pointed at the beginning of the substring currently being searched. When it finds a delimiter (or end of string), it terminates that substring, appends the buffer pointer to your array, and then points buffer to the start of the next substring, if any. The loop terminates when buffer points to an empty string, which will be the case once all strings (including none, if original was empty) have been extracted.

      – paddy
      Mar 25 at 23:59














    0












    0








    0







    You are storing pointers to a buffer that exists on the stack. Using those pointers after returning from the function results in undefined behavior.



    To get around this requires one of the following:




    • Allow the function to modify the input string (i.e. replace delimiters with null-terminator characters) and return pointers into it. The caller must be aware that this can happen. Note that supplying a string literal as you are doing here is illegal in C, so you would instead need to do:



      char my_string[] = "Helo_World_poopy_pants";
      char **result = str_split(my_string, '_', &num_strings);


      In this case, the function should also make it clear that a string literal is not acceptable input, and define its first parameter as const char* string (instead of char string[]).




    • Allow the function to make a copy of the string and then modify the copy. You have expressed concerns about leaking this memory, but that concern is mostly to do with your program's design rather than a necessity.



      It's perfectly valid to duplicate each string individually and then clean them all up later. The main issue is that it's inconvenient, and also slightly pointless.



    Let's address the second point. You have several options, but if you insist that the result be easily cleaned-up with a call to free, then try this strategy:




    1. When you allocate the pointer array, also make it large enough to hold a copy of the string:



      // Allocate storage for `num_strings` pointers, plus a copy of the original string,
      // then copy the string into memory immediately following the pointer storage.
      char **ret = malloc((*num_strings) * sizeof(char*) + strlen(string) + 1);
      char *buffer = (char*)&ret[*num_strings];
      strcpy(buffer, string);



    2. Now, do all your string operations on buffer. For example:



      // Extract all delimited substrings. Here, buffer will always point at the
      // current substring, and p will search for the delimiter. Once found,
      // the substring is terminated, its pointer appended to the substring array,
      // and then buffer is pointed at the next substring, if any.
      int c = 0;
      for(char *p = buffer; *buffer; ++p)
      !*p)
      char *next = p;
      if (*p)
      *p = '';
      ++next;

      ret[c++] = buffer;
      buffer = next;




    3. When you need to clean up, it's just a single call to free, because everything was stored together.






    share|improve this answer















    You are storing pointers to a buffer that exists on the stack. Using those pointers after returning from the function results in undefined behavior.



    To get around this requires one of the following:




    • Allow the function to modify the input string (i.e. replace delimiters with null-terminator characters) and return pointers into it. The caller must be aware that this can happen. Note that supplying a string literal as you are doing here is illegal in C, so you would instead need to do:



      char my_string[] = "Helo_World_poopy_pants";
      char **result = str_split(my_string, '_', &num_strings);


      In this case, the function should also make it clear that a string literal is not acceptable input, and define its first parameter as const char* string (instead of char string[]).




    • Allow the function to make a copy of the string and then modify the copy. You have expressed concerns about leaking this memory, but that concern is mostly to do with your program's design rather than a necessity.



      It's perfectly valid to duplicate each string individually and then clean them all up later. The main issue is that it's inconvenient, and also slightly pointless.



    Let's address the second point. You have several options, but if you insist that the result be easily cleaned-up with a call to free, then try this strategy:




    1. When you allocate the pointer array, also make it large enough to hold a copy of the string:



      // Allocate storage for `num_strings` pointers, plus a copy of the original string,
      // then copy the string into memory immediately following the pointer storage.
      char **ret = malloc((*num_strings) * sizeof(char*) + strlen(string) + 1);
      char *buffer = (char*)&ret[*num_strings];
      strcpy(buffer, string);



    2. Now, do all your string operations on buffer. For example:



      // Extract all delimited substrings. Here, buffer will always point at the
      // current substring, and p will search for the delimiter. Once found,
      // the substring is terminated, its pointer appended to the substring array,
      // and then buffer is pointed at the next substring, if any.
      int c = 0;
      for(char *p = buffer; *buffer; ++p)
      !*p)
      char *next = p;
      if (*p)
      *p = '';
      ++next;

      ret[c++] = buffer;
      buffer = next;




    3. When you need to clean up, it's just a single call to free, because everything was stored together.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Mar 26 at 0:06

























    answered Mar 25 at 23:42









    paddypaddy

    44.6k5 gold badges39 silver badges79 bronze badges




    44.6k5 gold badges39 silver badges79 bronze badges












    • Thanks so much for the help! I'm still reading through it and trying to understand, but I think this right here is perfect. I'm a little confused by the example you gave in 2. but I'm sure I'll get it eventually.

      – mysteryuser12345
      Mar 25 at 23:54












    • I realized I had a small error, so please see my edit. The loop is pretty basic. It simply walks through each character in the string using char *p, leaving buffer pointed at the beginning of the substring currently being searched. When it finds a delimiter (or end of string), it terminates that substring, appends the buffer pointer to your array, and then points buffer to the start of the next substring, if any. The loop terminates when buffer points to an empty string, which will be the case once all strings (including none, if original was empty) have been extracted.

      – paddy
      Mar 25 at 23:59


















    • Thanks so much for the help! I'm still reading through it and trying to understand, but I think this right here is perfect. I'm a little confused by the example you gave in 2. but I'm sure I'll get it eventually.

      – mysteryuser12345
      Mar 25 at 23:54












    • I realized I had a small error, so please see my edit. The loop is pretty basic. It simply walks through each character in the string using char *p, leaving buffer pointed at the beginning of the substring currently being searched. When it finds a delimiter (or end of string), it terminates that substring, appends the buffer pointer to your array, and then points buffer to the start of the next substring, if any. The loop terminates when buffer points to an empty string, which will be the case once all strings (including none, if original was empty) have been extracted.

      – paddy
      Mar 25 at 23:59

















    Thanks so much for the help! I'm still reading through it and trying to understand, but I think this right here is perfect. I'm a little confused by the example you gave in 2. but I'm sure I'll get it eventually.

    – mysteryuser12345
    Mar 25 at 23:54






    Thanks so much for the help! I'm still reading through it and trying to understand, but I think this right here is perfect. I'm a little confused by the example you gave in 2. but I'm sure I'll get it eventually.

    – mysteryuser12345
    Mar 25 at 23:54














    I realized I had a small error, so please see my edit. The loop is pretty basic. It simply walks through each character in the string using char *p, leaving buffer pointed at the beginning of the substring currently being searched. When it finds a delimiter (or end of string), it terminates that substring, appends the buffer pointer to your array, and then points buffer to the start of the next substring, if any. The loop terminates when buffer points to an empty string, which will be the case once all strings (including none, if original was empty) have been extracted.

    – paddy
    Mar 25 at 23:59






    I realized I had a small error, so please see my edit. The loop is pretty basic. It simply walks through each character in the string using char *p, leaving buffer pointed at the beginning of the substring currently being searched. When it finds a delimiter (or end of string), it terminates that substring, appends the buffer pointer to your array, and then points buffer to the start of the next substring, if any. The loop terminates when buffer points to an empty string, which will be the case once all strings (including none, if original was empty) have been extracted.

    – paddy
    Mar 25 at 23:59














    0














    The string pointers you store into the res with ret[c] = buffer; array point to an automatic array that goes out of scope when the function returns. The code subsequently has undefined behavior. You should allocate these strings with strdup().



    Note also that it might not be appropriate to return NULL when the string does not contain a separator. Why not return an array with a single string?



    Here is a simpler implementation:



    #include <stdlib.h>

    char **str_split(const char *string, char delim, int *num_strings)
    int i, n, from, to;
    char **res;

    for (n = 1, i = 0; string[i]; i++)
    n += (string[i] == delim);

    *num_strings = 0;
    res = malloc(sizeof(*res) * n);
    if (res == NULL)
    return NULL;

    for (i = from = to = 0;; from = to + 1)
    for (to = from; string[to] != delim && string[to] != ''; to++)
    continue;
    res[i] = malloc(to - from + 1);
    if (res[i] == NULL)
    /* allocation failure: free memory allocated so far */
    while (i > 0)
    free(res[--i]);
    free(res);
    return NULL;

    memcpy(res[i], string + from, to - from);
    res[i][to - from] = '';
    i++;
    if (string[to] == '')
    break;

    *num_strings = n;
    return res;






    share|improve this answer





























      0














      The string pointers you store into the res with ret[c] = buffer; array point to an automatic array that goes out of scope when the function returns. The code subsequently has undefined behavior. You should allocate these strings with strdup().



      Note also that it might not be appropriate to return NULL when the string does not contain a separator. Why not return an array with a single string?



      Here is a simpler implementation:



      #include <stdlib.h>

      char **str_split(const char *string, char delim, int *num_strings)
      int i, n, from, to;
      char **res;

      for (n = 1, i = 0; string[i]; i++)
      n += (string[i] == delim);

      *num_strings = 0;
      res = malloc(sizeof(*res) * n);
      if (res == NULL)
      return NULL;

      for (i = from = to = 0;; from = to + 1)
      for (to = from; string[to] != delim && string[to] != ''; to++)
      continue;
      res[i] = malloc(to - from + 1);
      if (res[i] == NULL)
      /* allocation failure: free memory allocated so far */
      while (i > 0)
      free(res[--i]);
      free(res);
      return NULL;

      memcpy(res[i], string + from, to - from);
      res[i][to - from] = '';
      i++;
      if (string[to] == '')
      break;

      *num_strings = n;
      return res;






      share|improve this answer



























        0












        0








        0







        The string pointers you store into the res with ret[c] = buffer; array point to an automatic array that goes out of scope when the function returns. The code subsequently has undefined behavior. You should allocate these strings with strdup().



        Note also that it might not be appropriate to return NULL when the string does not contain a separator. Why not return an array with a single string?



        Here is a simpler implementation:



        #include <stdlib.h>

        char **str_split(const char *string, char delim, int *num_strings)
        int i, n, from, to;
        char **res;

        for (n = 1, i = 0; string[i]; i++)
        n += (string[i] == delim);

        *num_strings = 0;
        res = malloc(sizeof(*res) * n);
        if (res == NULL)
        return NULL;

        for (i = from = to = 0;; from = to + 1)
        for (to = from; string[to] != delim && string[to] != ''; to++)
        continue;
        res[i] = malloc(to - from + 1);
        if (res[i] == NULL)
        /* allocation failure: free memory allocated so far */
        while (i > 0)
        free(res[--i]);
        free(res);
        return NULL;

        memcpy(res[i], string + from, to - from);
        res[i][to - from] = '';
        i++;
        if (string[to] == '')
        break;

        *num_strings = n;
        return res;






        share|improve this answer















        The string pointers you store into the res with ret[c] = buffer; array point to an automatic array that goes out of scope when the function returns. The code subsequently has undefined behavior. You should allocate these strings with strdup().



        Note also that it might not be appropriate to return NULL when the string does not contain a separator. Why not return an array with a single string?



        Here is a simpler implementation:



        #include <stdlib.h>

        char **str_split(const char *string, char delim, int *num_strings)
        int i, n, from, to;
        char **res;

        for (n = 1, i = 0; string[i]; i++)
        n += (string[i] == delim);

        *num_strings = 0;
        res = malloc(sizeof(*res) * n);
        if (res == NULL)
        return NULL;

        for (i = from = to = 0;; from = to + 1)
        for (to = from; string[to] != delim && string[to] != ''; to++)
        continue;
        res[i] = malloc(to - from + 1);
        if (res[i] == NULL)
        /* allocation failure: free memory allocated so far */
        while (i > 0)
        free(res[--i]);
        free(res);
        return NULL;

        memcpy(res[i], string + from, to - from);
        res[i][to - from] = '';
        i++;
        if (string[to] == '')
        break;

        *num_strings = n;
        return res;







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Mar 25 at 23:59

























        answered Mar 25 at 23:41









        chqrliechqrlie

        67.4k9 gold badges58 silver badges114 bronze badges




        67.4k9 gold badges58 silver badges114 bronze badges



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55347699%2fwhy-does-my-string-split-implementation-not-work%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

            Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

            Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript