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;
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 malloc
ed 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
|
show 3 more comments
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 malloc
ed 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
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 intobuffer
, which is a local variable, which is destroyed when the surrounding function returns. Also, all elements ofret
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
|
show 3 more comments
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 malloc
ed 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
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 malloc
ed 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
c arrays pointers split malloc
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 intobuffer
, which is a local variable, which is destroyed when the surrounding function returns. Also, all elements ofret
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
|
show 3 more comments
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 intobuffer
, which is a local variable, which is destroyed when the surrounding function returns. Also, all elements ofret
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
|
show 3 more comments
2 Answers
2
active
oldest
votes
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 ofchar 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:
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);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;
When you need to clean up, it's just a single call to
free
, because everything was stored together.
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 usingchar *p
, leavingbuffer
pointed at the beginning of the substring currently being searched. When it finds a delimiter (or end of string), it terminates that substring, appends thebuffer
pointer to your array, and then pointsbuffer
to the start of the next substring, if any. The loop terminates whenbuffer
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
add a comment |
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;
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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 ofchar 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:
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);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;
When you need to clean up, it's just a single call to
free
, because everything was stored together.
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 usingchar *p
, leavingbuffer
pointed at the beginning of the substring currently being searched. When it finds a delimiter (or end of string), it terminates that substring, appends thebuffer
pointer to your array, and then pointsbuffer
to the start of the next substring, if any. The loop terminates whenbuffer
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
add a comment |
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 ofchar 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:
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);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;
When you need to clean up, it's just a single call to
free
, because everything was stored together.
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 usingchar *p
, leavingbuffer
pointed at the beginning of the substring currently being searched. When it finds a delimiter (or end of string), it terminates that substring, appends thebuffer
pointer to your array, and then pointsbuffer
to the start of the next substring, if any. The loop terminates whenbuffer
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
add a comment |
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 ofchar 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:
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);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;
When you need to clean up, it's just a single call to
free
, because everything was stored together.
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 ofchar 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:
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);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;
When you need to clean up, it's just a single call to
free
, because everything was stored together.
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 usingchar *p
, leavingbuffer
pointed at the beginning of the substring currently being searched. When it finds a delimiter (or end of string), it terminates that substring, appends thebuffer
pointer to your array, and then pointsbuffer
to the start of the next substring, if any. The loop terminates whenbuffer
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
add a comment |
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 usingchar *p
, leavingbuffer
pointed at the beginning of the substring currently being searched. When it finds a delimiter (or end of string), it terminates that substring, appends thebuffer
pointer to your array, and then pointsbuffer
to the start of the next substring, if any. The loop terminates whenbuffer
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
add a comment |
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;
add a comment |
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;
add a comment |
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;
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;
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
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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 intobuffer
, which is a local variable, which is destroyed when the surrounding function returns. Also, all elements ofret
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