C语言中带分隔符的拆分字符串

C语言中带分隔符的拆分字符串,c,string,split,C,String,Split,在C编程语言中,如何编写函数来拆分并返回带分隔符的字符串的数组 char* str = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC"; str_split(str,','); 可以使用该函数拆分字符串(并指定要使用的分隔符)。请注意,strtok()将修改传递给它的字符串。如果其他地方需要原始字符串,请复制它并将副本传递给strtok() 编辑: 示例(请注意,它不处理连续分隔符,例如“JAN、、FEB、MAR”): 字符串标记器此代码应该

在C编程语言中,如何编写函数来拆分并返回带分隔符的字符串的数组

char* str = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC";
str_split(str,',');
可以使用该函数拆分字符串(并指定要使用的分隔符)。请注意,
strtok()
将修改传递给它的字符串。如果其他地方需要原始字符串,请复制它并将副本传递给
strtok()

编辑:

示例(请注意,它不处理连续分隔符,例如“JAN、、FEB、MAR”):


字符串标记器此代码应该为您提供正确的方向

int main(void) {
  char st[] ="Where there is will, there is a way.";
  char *ch;
  ch = strtok(st, " ");
  while (ch != NULL) {
  printf("%s\n", ch);
  ch = strtok(NULL, " ,");
  }
  getch();
  return 0;
}

在上面的示例中,有一种方法可以返回字符串中以null结尾的字符串数组(如您所希望的)。但是,它不可能传递文本字符串,因为它必须由函数修改:

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

char** str_split( char* str, char delim, int* numSplits )
{
    char** ret;
    int retLen;
    char* c;

    if ( ( str == NULL ) ||
        ( delim == '\0' ) )
    {
        /* Either of those will cause problems */
        ret = NULL;
        retLen = -1;
    }
    else
    {
        retLen = 0;
        c = str;

        /* Pre-calculate number of elements */
        do
        {
            if ( *c == delim )
            {
                retLen++;
            }

            c++;
        } while ( *c != '\0' );

        ret = malloc( ( retLen + 1 ) * sizeof( *ret ) );
        ret[retLen] = NULL;

        c = str;
        retLen = 1;
        ret[0] = str;

        do
        {
            if ( *c == delim )
            {
                ret[retLen++] = &c[1];
                *c = '\0';
            }

            c++;
        } while ( *c != '\0' );
    }

    if ( numSplits != NULL )
    {
        *numSplits = retLen;
    }

    return ret;
}

int main( int argc, char* argv[] )
{
    const char* str = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC";

    char* strCpy;
    char** split;
    int num;
    int i;

    strCpy = malloc( strlen( str ) * sizeof( *strCpy ) );
    strcpy( strCpy, str );

    split = str_split( strCpy, ',', &num );

    if ( split == NULL )
    {
        puts( "str_split returned NULL" );
    }
    else
    {
        printf( "%i Results: \n", num );

        for ( i = 0; i < num; i++ )
        {
            puts( split[i] );
        }
    }

    free( split );
    free( strCpy );

    return 0;
}
#包括
#包括
#包括
字符**str_分割(字符*str,字符delim,int*numSplits)
{
字符**ret;
内特雷特伦;
char*c;
如果((str==NULL)||
(delim=='\0'))
{
/*这两种情况都会造成问题*/
ret=NULL;
retLen=-1;
}
其他的
{
retLen=0;
c=str;
/*预先计算元素的数量*/
做
{
如果(*c==delim)
{
retLen++;
}
C++;
}而(*c!='\0');
ret=malloc((retLen+1)*sizeof(*ret));
ret[retLen]=NULL;
c=str;
retLen=1;
ret[0]=str;
做
{
如果(*c==delim)
{
ret[retLen++]=&c[1];
*c='\0';
}
C++;
}而(*c!='\0');
}
if(numSplits!=NULL)
{
*numSplits=retLen;
}
返回ret;
}
int main(int argc,char*argv[])
{
const char*str=“一月、二月、三月、四月、五月、六月、七月、八月、九月、十月、十一月、十二月”;
字符*strCpy;
字符**拆分;
int-num;
int i;
strCpy=malloc(strlen(str)*sizeof(*strCpy));
strcpy(strcpy,str);
split=str_split(strCpy,,,&num);
if(split==NULL)
{
看跌期权(“str_split返回空”);
}
其他的
{
printf(“%i结果:\n”,num);
对于(i=0;i

也许有一种更简洁的方法可以做到这一点,但你已经明白了。

此函数获取一个char*字符串,并通过除数器将其拆分。一排可以有多个除沫器。请注意,该函数修改原始字符串。如果需要原始字符串保持不变,则必须首先复制原始字符串。此函数不使用任何cstring函数调用,因此它可能比其他函数快一点。如果不关心内存分配,可以在函数顶部分配子字符串,使用大小SrLLN(SRCYSTR)/ 2,并且(如C++所提到的)版本跳过函数的下半部分。如果这样做,函数将减少到O(N),但下面显示的内存优化方式是O(2N)

功能:

char** str_split(char *src_str, const char deliminator, size_t &num_sub_str){
  //replace deliminator's with zeros and count how many
  //sub strings with length >= 1 exist
  num_sub_str = 0;
  char *src_str_tmp = src_str;
  bool found_delim = true;
  while(*src_str_tmp){
    if(*src_str_tmp == deliminator){
      *src_str_tmp = 0;
      found_delim = true;
    }
    else if(found_delim){ //found first character of a new string
      num_sub_str++;
      found_delim = false;
      //sub_str_vec.push_back(src_str_tmp); //for c++
    }
    src_str_tmp++;
  }
  printf("Start - found %d sub strings\n", num_sub_str);
  if(num_sub_str <= 0){
    printf("str_split() - no substrings were found\n");
    return(0);
  }

  //if you want to use a c++ vector and push onto it, the rest of this function
  //can be omitted (obviously modifying input parameters to take a vector, etc)

  char **sub_strings = (char **)malloc( (sizeof(char*) * num_sub_str) + 1);
  const char *src_str_terminator = src_str_tmp;
  src_str_tmp = src_str;
  bool found_null = true;
  size_t idx = 0;
  while(src_str_tmp < src_str_terminator){
    if(!*src_str_tmp) //found a NULL
      found_null = true;
    else if(found_null){
      sub_strings[idx++] = src_str_tmp;
      //printf("sub_string_%d: [%s]\n", idx-1, sub_strings[idx-1]);
      found_null = false;
    }
    src_str_tmp++;
  }
  sub_strings[num_sub_str] = NULL;

  return(sub_strings);
}
  char months[] = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC";
  char *str = strdup(months);
  size_t num_sub_str;
  char **sub_strings = str_split(str, ',', num_sub_str);
  char *endptr;
  if(sub_strings){
    for(int i = 0; sub_strings[i]; i++)
      printf("[%s]\n", sub_strings[i]);
  }
  free(sub_strings);
  free(str);
char **tokens;
int count, i;
const char *str = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC";

count = split (str, ',', &tokens);
for (i = 0; i < count; i++) printf ("%s\n", tokens[i]);

/* freeing tokens */
for (i = 0; i < count; i++) free (tokens[i]);
free (tokens);
const char *src = ";b,test,Tèst,;;cd;ελληνικά,nørmälize,;string to";
const char *delim = ";,";
bool keepnulls = true;
size_t ntoks = 0;
// destructive (use copy of src)

char *scopy = strdup( src );
if (!scopy) { ... };          // handle strdup failure

printf( "%s\n", src );
char **arrtoks = str_toksarray_alloc( &scopy, delim, &ntoks, keepnulls );
printf( "%lu tokens read\n", ntoks );
if ( arrtoks ) {
    for (int i=0; arrtoks[i]; i++) {
        printf( "%d: %s\n", i, arrtoks[i] );
    }
}
free( scopy );
free( arrtoks );

/* OUTPUT
;b,test,Tèst,;;cd;ελληνικά,nørmälize,;string to
11 tokens read
0:
1: b
2: test
3: Tèst
4:
5:
6: cd
7: ελληνικά
8: nørmälize
9:
10: string to
 */
// non-destructive

keepnulls = false;    // reject empty tokens

printf( "%s\n", src );
arrtoks = str_toksarray_alloc2( src, delim, &ntoks, keepnulls );
printf( "%lu tokens read\n", ntoks );
if ( arrtoks ) {
    for (int i=0; arrtoks[i]; i++) {
        printf( "%d: %s\n", i, arrtoks[i] );
    }
}
toksarray_free2( arrtoks );                     // dangling arrtoks
// or: arrtoks = toksarray_free2( arrtoks );    // non-dangling artoks

/* OUTPUT
;b,test,Tèst,;;cd;ελληνικά,nørmälize,;string to
7 tokens read
0: b
1: test
2: Tèst
3: cd
4: ελληνικά
5: nørmälize
6: string to
*/
// ----------------------------------------
// Tokenize destructively a nul-terminated source-string.
// Return a dynamically allocated, NULL terminated array of char-pointers
// each pointing to each token found in the source-string, or NULL on error.
//
char **str_toksarray_alloc(char **strp, const char *delim, size_t *ntoks, bool keepnulls)
{
    // sanity checks
    if ( !strp || !*strp || !**strp || !delim ) {
        goto failed;
    }

    char *strpSaved = *strp;                    // save initial *strp pointer
    bool ntoksOk = (ntoks && *ntoks);           // false when ntoks is muted
    size_t _ntoks = (ntoksOk ? *ntoks : 16);    // # of tokens to alloc-ahead

    // alloc array of char-pointers (+1 for NULL sentinel)
    char **toksarr = malloc( (_ntoks+1) * sizeof(*toksarr) );
    if ( !toksarr ) {
        goto failed;
    }

    // Parse *strp tokens into the array
    size_t i = 0;           // # of actually parsed tokens
    char *tok;
    while ( (tok = strsep(strp, delim)) ) {
        // if requested, ignore empty tokens
        if ( *tok == '\0' && !keepnulls ) {
            continue;
        }
        // non-muted ntoks reached? we are done
        if ( ntoksOk && i == _ntoks ) {
            *ntoks = i;
            break;
        }
        // muted ntoks & ran out of space? double toksarr and keep parsing
        if ( !ntoksOk && i == _ntoks ) {
            _ntoks *= 2;
            char **tmparr = realloc( toksarr, (_ntoks+1) * sizeof(*tmparr) );
            if ( !tmparr ) {
                *strp = strpSaved;
                free( toksarr );
                goto failed;
            }
            toksarr = tmparr;
        }
        toksarr[i++] = tok; // get token address
    }
    toksarr[i] = NULL;      // NULL sentinel

    *strp = strpSaved;      // restore initial *strp pointer
    if (ntoks) *ntoks = i;  // pass to caller # of parsed tokens
    return toksarr;

failed:
    if (ntoks) *ntoks = 0;
    return NULL;
}
// ----------------------------------------
// Tokenize non-destructively a nul-terminated source-string.
// Return a dynamically allocated, NULL terminated array of dynamically
// allocated and nul-terminated string copies of each token found in the
// source-string. Return NULL on error.
// The 2 at the end of the name means 2-levels of allocation.
//
char **str_toksarray_alloc2( const char *str, const char *delim, size_t *ntoks, bool keepnulls )
{
    // sanity checks
    if ( !str || !*str || !delim ) {
        if (ntoks) *ntoks = 0;
        return NULL;
    }

    // make a copy of str to work with
    char *_str = strdup( str ); 
    if ( !_str ) {
        if (ntoks) *ntoks = 0;
        return NULL;
    }

    // if ntoks is muted we'll allocate str_tokscount() tokens, else *ntoks
    size_t _ntoks = (ntoks && *ntoks) ? *ntoks : str_tokscount(_str, delim, keepnulls);
    if ( _ntoks == 0 ) {        // str_tokscount() failed
        goto fail_free_str;
    }
    
    // alloc the array of strings (+1 for an extra NULL sentinel)
    char **toksarr = malloc( (_ntoks+1) * sizeof(*toksarr) );
    if ( !toksarr ) {
        goto fail_free_str;
    }

    // Parse str tokens and duplicate them into the array
    size_t i = 0;           // # of actually parsed tokens
    char *tok;
    while ( i < _ntoks && (tok = strsep(&_str, delim)) ) {
        // if requested, skip empty tokens
        if ( *tok == '\0' && !keepnulls ) {
            continue;
        }
        // duplicate current token into the array
        char *tmptok = strdup( tok );
        if ( !tmptok ) {
            goto fail_free_arr;
        }
        toksarr[i++] = tmptok;
    }
    toksarr[i] = NULL;      // NULL sentinel

    free( _str );           // release the local copy of the source-string
    if (ntoks) *ntoks = i;  // pass to caller the # of parsed tokens
    return toksarr;

// cleanup before failing
fail_free_arr:
    for (size_t idx=0; idx < i; idx++) {
        free( toksarr[idx] );
    }
    free( toksarr );

fail_free_str:
    free( _str );
    if (ntoks) *ntoks = 0;
    return NULL;
}

下面的方法将为您完成所有工作(内存分配、计算长度)。更多信息和说明可在此处找到-

如何使用它:

int main (int argc, char ** argv)
{
    int i;
    char *s = "Hello, this is a test module for the string splitting.";
    int c = 0;
    char **arr = NULL;

    c = split(s, ' ', &arr);

    printf("found %d tokens.\n", c);

    for (i = 0; i < c; i++)
        printf("string #%d: %s\n", i, arr[i]);

    return 0;
}
int main(int argc,char**argv)
{
int i;
char*s=“您好,这是用于字符串拆分的测试模块。”;
int c=0;
字符**arr=NULL;
c=拆分、、&arr;
printf(“找到%d个令牌。\n”,c);
对于(i=0;i
#包括
#包括
#包括
#包括
/**
*在delim上拆分str并动态分配指针数组。
*
*返回错误-1时,请检查errno
*成功时返回数组的大小,在空字符串中可能为0
*如果没有发现熟食,则为1。
*
*您可以重写它以返回char**数组,如果为空
*我知道这是一个分配问题,但我在这里做了三重数组。注意
*当击中一行“foo,,bar”中的两个delim时,数组将为:
*{“foo”,NULL,bar}
* 
*您需要定义像“foo”这样的尾部delim的语义,这是
*2计数数组还是1的数组?我选择第二个条目的两个计数
*设置为NULL,因为它没有值。
*修改str,以便在出现问题时复制
*/
整型拆分(字符*str,字符delim,字符***数组,整型*length){
char*p;
字符**res;
整数计数=0;
int k=0;
p=str;
//计算字符串中delim的出现次数
while((p=strchr(p,delim))!=NULL){
*p=0;//Null终止除沫器。
p++;//跳过我们的新null
计数++;
}
//分配动态数组
res=calloc(1,count*sizeof(char*);
如果(!res)返回-1;
p=str;

对于(k=0;k我认为
strep
仍然是最好的工具:

while ((token = strsep(&str, ","))) my_fn(token);
这实际上是一条分割字符串的线

额外的括号是一种风格元素,表示我们有意测试赋值结果,而不是等式运算符
==

要使该模式正常工作,
token
str
都具有类型
char*
。如果您以字符串文字开头,则首先要复制它:

// More general pattern:
const char *my_str_literal = "JAN,FEB,MAR";
char *token, *str, *tofree;

tofree = str = strdup(my_str_literal);  // We own str's memory now.
while ((token = strsep(&str, ","))) my_fn(token);
free(tofree);
如果两个分隔符同时出现在
str
中,您将得到一个
标记
值,该值为空字符串。
str
的值会被修改,因为遇到的每个分隔符都会被零字节覆盖,这是复制首先解析的字符串的另一个很好的理由

在一篇评论中,有人建议
strtok
stresp
好,因为
strtok
更便于携带。Ubuntu和Mac OS X有
stresp
;可以肯定地猜测,其他unixy系统也有类似的功能。Windows缺少
stresp
,但它有
void splitString(const char *original, const char *delimiter, char ** * buffer, int * numStrings, int * * stringLengths){
    const int lo = strlen(original);
    const int ld = strlen(delimiter);
    if(ld > lo){
        *buffer = (void *)0;
        *numStrings = 0;
        *stringLengths = (void *)0;
        return;
    }

    *numStrings = 1;

    for(int i = 0;i < (lo - ld);i++){
        if(strncmp(&original[i], delimiter, ld) == 0) {
            i += (ld - 1);
            (*numStrings)++;
        }
    }

    *stringLengths = (int *) malloc(sizeof(int) * *numStrings);

    int currentStringLength = 0;
    int currentStringNumber = 0;
    int delimiterTokenDecrementCounter = 0;
    for(int i = 0;i < lo;i++){
        if(delimiterTokenDecrementCounter > 0){
            delimiterTokenDecrementCounter--;
        } else if(i < (lo - ld)){
            if(strncmp(&original[i], delimiter, ld) == 0){
                (*stringLengths)[currentStringNumber] = currentStringLength;
                currentStringNumber++;
                currentStringLength = 0;
                delimiterTokenDecrementCounter = ld - 1;
            } else {
                currentStringLength++;
            }
        } else {
            currentStringLength++;
        }

        if(i == (lo - 1)){
            (*stringLengths)[currentStringNumber] = currentStringLength;
        }
    }

    *buffer = (char **) malloc(sizeof(char *) * (*numStrings));
    for(int i = 0;i < *numStrings;i++){
        (*buffer)[i] = (char *) malloc(sizeof(char) * ((*stringLengths)[i] + 1));
    }

    currentStringNumber = 0;
    currentStringLength = 0;
    delimiterTokenDecrementCounter = 0;
    for(int i = 0;i < lo;i++){
        if(delimiterTokenDecrementCounter > 0){
            delimiterTokenDecrementCounter--;
        } else if(currentStringLength >= (*stringLengths)[currentStringNumber]){
            (*buffer)[currentStringNumber][currentStringLength] = 0;
            delimiterTokenDecrementCounter = ld - 1;
            currentStringLength = 0;
            currentStringNumber++;
        } else {
            (*buffer)[currentStringNumber][currentStringLength] = (char)original[i];
            currentStringLength++;
        }
    }
    buffer[currentStringNumber][currentStringLength] = 0;
}
int main(){
    const char *string = "STRING-1 DELIM string-2 DELIM sTrInG-3";
    char **buffer;
    int numStrings;
    int * stringLengths;

    splitString(string, " DELIM ", &buffer, &numStrings, &stringLengths);

    for(int i = 0;i < numStrings;i++){
        printf("String: %s\n", buffer[i]);
    }
}
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
char** split(char* a_str, const char a_delim, int* len){
    char* s = (char*)malloc(sizeof(char) * strlen(a_str));
    strcpy(s, a_str);
    char* tmp = a_str;
    int count = 0;
    while (*tmp != '\0'){
        if (*tmp == a_delim) count += 1;
        tmp += 1;
    }
    *len = count;
    char** results = (char**)malloc(count * sizeof(char*));
    results[0] = s;
    int i = 1;
    while (*s!='\0'){
        if (*s == a_delim){
            *s = '\0';
            s += 1;
            results[i++] = s;
        }
        else s += 1;
    }
    return results;
}
if (str[i]==delim) {
 char *c=delim; while(*c && *c!=str[i]) c++;
 if (*c) {
#include <stdlib.h>
#include <string.h>

char **split(char *str, size_t len, char delim, char ***result, unsigned long *count, unsigned long max) {
  size_t i;
  char **_result;

  // there is at least one string returned
  *count=1;

  _result= *result;

  // when the result array is specified, fill it during the first pass
  if (_result) {
    _result[0]=str;
  }

  // scan the string for delimiter, up to specified length
  for (i=0; i<len; ++i) {

    // to compare against a list of delimiters,
    // define delim as a string and replace 
    // the next line:
    //     if (str[i]==delim) {
    //
    // with the two following lines:
    //     char *c=delim; while(*c && *c!=str[i]) c++;
    //     if (*c) {
    //       
    if (str[i]==delim) {

      // replace delimiter with zero
      str[i]=0;

      // when result array is specified, fill it during the first pass
      if (_result) {
        _result[*count]=str+i+1;
      }

      // increment count for each separator found
      ++(*count);

      // if max is specified, dont go further
      if (max && *count==max)  {
        break;
      }

    }
  }

  // when result array is specified, we are done here
  if (_result) {
    return _result;
  }

  // else allocate memory for result
  // and fill the result array                                                                                    

  *result=malloc((*count)*sizeof(char*));
  if (!*result) {
    return NULL;
  }
  _result=*result;

  // add first string to result
  _result[0]=str;

  // if theres more strings
  for (i=1; i<*count; ++i) {

    // find next string
    while(*str) ++str;
    ++str;

    // add next string to result
    _result[i]=str;

  }

  return _result;
}  
#include <stdio.h>

int main(int argc, char **argv) {
  char *str="JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC";
  char **result=malloc(6*sizeof(char*));
  char **result2=0;
  unsigned long count;
  unsigned long count2;
  unsigned long i;

  split(strdup(str),strlen(str),',',&result,&count,6);
  split(strdup(str),strlen(str),',',&result2,&count2,0);

  if (result)
  for (i=0; i<count; ++i) {
    printf("%s\n",result[i]);
  }

  printf("\n");

  if (result2)
  for (i=0; i<count2; ++i) {
    printf("%s\n", result2[i]);
  }

  return 0;

}
int split (const char *txt, char delim, char ***tokens)
{
    int *tklen, *t, count = 1;
    char **arr, *p = (char *) txt;

    while (*p != '\0') if (*p++ == delim) count += 1;
    t = tklen = calloc (count, sizeof (int));
    for (p = (char *) txt; *p != '\0'; p++) *p == delim ? *t++ : (*t)++;
    *tokens = arr = malloc (count * sizeof (char *));
    t = tklen;
    p = *arr++ = calloc (*(t++) + 1, sizeof (char *));
    while (*txt != '\0')
    {
        if (*txt == delim)
        {
            p = *arr++ = calloc (*(t++) + 1, sizeof (char *));
            txt++;
        }
        else *p++ = *txt++;
    }
    free (tklen);
    return count;
}
char **tokens;
int count, i;
const char *str = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC";

count = split (str, ',', &tokens);
for (i = 0; i < count; i++) printf ("%s\n", tokens[i]);

/* freeing tokens */
for (i = 0; i < count; i++) free (tokens[i]);
free (tokens);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int dtmsplit(char *str, const char *delim, char ***array, int *length ) {
  int i=0;
  char *token;
  char **res = (char **) malloc(0 * sizeof(char *));

  /* get the first token */
   token = strtok(str, delim);
   while( token != NULL ) 
   {
        res = (char **) realloc(res, (i + 1) * sizeof(char *));
        res[i] = token;
        i++;
      token = strtok(NULL, delim);
   }
   *array = res;
   *length = i;
  return 1;
}

int main()
{
    int i;
    int c = 0;
    char **arr = NULL;

    int count =0;

    char str[80] = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC";
    c = dtmsplit(str, ",", &arr, &count);
    printf("Found %d tokens.\n", count);

    for (i = 0; i < count; i++)
        printf("string #%d: %s\n", i, arr[i]);

   return(0);
}
Found 12 tokens.
string #0: JAN
string #1: FEB
string #2: MAR
string #3: APR
string #4: MAY
string #5: JUN
string #6: JUL
string #7: AUG
string #8: SEP
string #9: OCT
string #10: NOV
string #11: DEC
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

typedef struct
{
    uintptr_t   ptr;
    int         size;
} token_t;

int explode(char *str, int slen, const char *delimiter, token_t **tokens)
{
    int i = 0, c1 = 0, c2 = 0;

    for(i = 0; i <= slen; i++)
    {
            if(str[i] == *delimiter)
            {
                c1++;
            }
    }

    if(c1 == 0)
    {
            return -1;
    }

    *tokens = (token_t*)calloc((c1 + 1), sizeof(token_t));
    ((*tokens)[c2]).ptr = (uintptr_t)str;

    i = 0; 
    while(i <= slen)
    {
        if((str[i] == *delimiter) || (i == slen))
        {
                ((*tokens)[c2]).size = (int)((uintptr_t)&(str[i]) - (uintptr_t)(((*tokens)[c2]).ptr));
                if(i < slen)
                {
                    c2++;
                    ((*tokens)[c2]).ptr = (uintptr_t)&(str[i + 1]);
                }
        }
        i++;
    }
    return (c1 + 1);
}

char* implode(token_t *tokens, int size, const char *delimiter)
{
    int     i, len = 0;
    char    *str;

    for(i = 0; i < len; i++)
    {
        len += tokens[i].size + 1;
    }

    str = (char*)calloc(len, sizeof(char));

    len = 0;
    for(i = 0; i < size; i++)
    {
        memcpy((void*)&str[len], (void*)tokens[i].ptr, tokens[i].size);
        len += tokens[i].size;
        str[(len++)] = *delimiter;
    }

    str[len - 1] = '\0';

    return str;
}
int main(int argc, char **argv)
{
    int         i, c;
    char        *exp = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC";
    token_t     *tokens;
    char        *imp;

    printf("%s\n", exp);

    if((c = explode(exp, strlen(exp), ",", &tokens)) > 0)
    {
        imp = implode(tokens, c, ",");
        printf("%s\n", imp);

        for(i = 0; i < c; i++)
        {
            printf("%.*s, %d\n", tokens[i].size, (char*)tokens[i].ptr, tokens[i].size);
        }
    }

    free((void*)tokens);
    free((void*)imp);
    return 0;
}
char *zstring_strtok(char *str, const char *delim) {
    static char *static_str=0;      /* var to store last address */
    int index=0, strlength=0;       /* integers for indexes */
    int found = 0;                  /* check if delim is found */

    /* delimiter cannot be NULL
    * if no more char left, return NULL as well
    */
    if (delim==0 || (str == 0 && static_str == 0))
        return 0;

    if (str == 0)
        str = static_str;

    /* get length of string */
    while(str[strlength])
        strlength++;

    /* find the first occurance of delim */
    for (index=0;index<strlength;index++)
        if (str[index]==delim[0]) {
            found=1;
            break;
        }

    /* if delim is not contained in str, return str */
    if (!found) {
        static_str = 0;
        return str;
    }

    /* check for consecutive delimiters
    *if first char is delim, return delim
    */
    if (str[0]==delim[0]) {
        static_str = (str + 1);
        return (char *)delim;
    }

    /* terminate the string
    * this assignmetn requires char[], so str has to
    * be char[] rather than *char
    */
    str[index] = '\0';

    /* save the rest of the string */
    if ((str + index + 1)!=0)
        static_str = (str + index + 1);
    else
        static_str = 0;

        return str;
}
  Example Usage
      char str[] = "A,B,,,C";
      printf("1 %s\n",zstring_strtok(s,","));
      printf("2 %s\n",zstring_strtok(NULL,","));
      printf("3 %s\n",zstring_strtok(NULL,","));
      printf("4 %s\n",zstring_strtok(NULL,","));
      printf("5 %s\n",zstring_strtok(NULL,","));
      printf("6 %s\n",zstring_strtok(NULL,","));

  Example Output
      1 A
      2 B
      3 ,
      4 ,
      5 C
      6 (null)
#include "bstrlib.h"
#include <stdio.h>
int main() {
  int i;
  char *tmp = "Hello,World,sak";
  bstring bstr = bfromcstr(tmp);
  struct bstrList *blist = bsplit(bstr, ',');
  printf("num %d\n", blist->qty);
  for(i=0;i<blist->qty;i++) {
    printf("%d: %s\n", i, bstr2cstr(blist->entry[i], '_'));
  }

}
typedef struct {
    const char *start;
    size_t len;
} token;

char **split(const char *str, char sep)
{
    char **array;
    unsigned int start = 0, stop, toks = 0, t;
    token *tokens = malloc((strlen(str) + 1) * sizeof(token));
    for (stop = 0; str[stop]; stop++) {
        if (str[stop] == sep) {
            tokens[toks].start = str + start;
            tokens[toks].len = stop - start;
            toks++;
            start = stop + 1;
        }
    }
    /* Mop up the last token */
    tokens[toks].start = str + start;
    tokens[toks].len = stop - start;
    toks++;
    array = malloc((toks + 1) * sizeof(char*));
    for (t = 0; t < toks; t++) {
        /* Calloc makes it nul-terminated */
        char *token = calloc(tokens[t].len + 1, 1);
        memcpy(token, tokens[t].start, tokens[t].len);
        array[t] = token;
    }
    /* Add a sentinel */
    array[t] = NULL; 
    free(tokens);
    return array;
}
int split(char* str, const char delimeter, char*** args) {
    int cnt = 1;
    char* t = str;

    while (*t == delimeter) t++;

    char* t2 = t;
    while (*(t2++))
        if (*t2 == delimeter && *(t2 + 1) != delimeter && *(t2 + 1) != 0) cnt++;

    (*args) = malloc(sizeof(char*) * cnt);

    for(int i = 0; i < cnt; i++) {
        char* ts = t;
        while (*t != delimeter && *t != 0) t++;

        int len = (t - ts + 1);
        (*args)[i] = malloc(sizeof(char) * len);
        memcpy((*args)[i], ts, sizeof(char) * (len - 1));
        (*args)[i][len - 1] = 0;

        while (*t == delimeter) t++;
    }

    return cnt;
}
#include <stdio.h>
#include <string.h>

struct splitFieldType {
    char *field;
    int   maxLength;
};

typedef struct splitFieldType splitField;

int strsplit(splitField *fields, int expected, const char *input, const char *fieldSeparator, void (*softError)(int fieldNumber,int expected,int actual))  {
    int i;
    int fieldSeparatorLen=strlen(fieldSeparator);
    const char *tNext, *tLast=input;

    for (i=0; i<expected && (tNext=strstr(tLast, fieldSeparator))!=NULL; ++i) {
        int len=tNext-tLast;
        if (len>=fields[i].maxLength) {
            softError(i,fields[i].maxLength-1,len);
            len=fields[i].maxLength-1;
        }
        fields[i].field[len]=0;
        strncpy(fields[i].field,tLast,len);
        tLast=tNext+fieldSeparatorLen;
    }
    if (i<expected) {
        if (strlen(tLast)>fields[i].maxLength) {
            softError(i,fields[i].maxLength,strlen(tLast));
        } else {
            strcpy(fields[i].field,tLast);
        }
        return i+1;
    } else {
        return i;
    }
}


void monthSplitSoftError(int fieldNumber, int expected, int actual) {
    fprintf(stderr,"monthSplit: input field #%d is %d bytes, expected %d bytes\n",fieldNumber+1,actual,expected);
}


int main() {
  const char *fieldSeparator=",";
  const char *input="JAN,FEB,MAR,APRI,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC,FOO,BAR";

  struct monthFieldsType {
    char field1[4];
    char field2[4];
    char field3[4];
    char field4[4];
    char field5[4];
    char field6[4];
    char field7[4];
    char field8[4];
    char field9[4];
    char field10[4];
    char field11[4];
    char field12[4];
  } monthFields;

  splitField inputFields[12] = {
    {monthFields.field1,  sizeof(monthFields.field1)},
    {monthFields.field2,  sizeof(monthFields.field2)},
    {monthFields.field3,  sizeof(monthFields.field3)},
    {monthFields.field4,  sizeof(monthFields.field4)},
    {monthFields.field5,  sizeof(monthFields.field5)},
    {monthFields.field6,  sizeof(monthFields.field6)},
    {monthFields.field7,  sizeof(monthFields.field7)},
    {monthFields.field8,  sizeof(monthFields.field8)},
    {monthFields.field9,  sizeof(monthFields.field9)},
    {monthFields.field10, sizeof(monthFields.field10)},
    {monthFields.field11, sizeof(monthFields.field11)},
    {monthFields.field12, sizeof(monthFields.field12)}
  };

  int expected=sizeof(inputFields)/sizeof(splitField);

  printf("input data: %s\n", input);
  printf("expecting %d fields\n",expected);

  int ct=strsplit(inputFields, expected, input, fieldSeparator, monthSplitSoftError);

  if (ct!=expected) {
    printf("string split %d fields, expected %d\n", ct,expected);
  }

  for (int i=0;i<expected;++i) {
    printf("field %d: %s\n",i+1,inputFields[i].field);
  }

  printf("\n");
  printf("Direct structure access, field 10: %s", monthFields.field10);
}
$ gcc strsplitExample.c && ./a.out
input data: JAN,FEB,MAR,APRIL,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC,FOO,BAR
expecting 12 fields
monthSplit: input field #4 is 5 bytes, expected 3 bytes
field 1: JAN
field 2: FEB
field 3: MAR
field 4: APR
field 5: MAY
field 6: JUN
field 7: JUL
field 8: AUG
field 9: SEP
field 10: OCT
field 11: NOV
field 12: DEC

Direct structure access, field 10: OCT
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NPTRS 2     /* initial number of pointers to allocate (must be > 0) */

/* split src into tokens with sentinel NULL after last token.
 * return allocated pointer-to-pointer with sentinel NULL on success,
 * or NULL on failure to allocate initial block of pointers. The number
 * of allocated pointers are doubled each time reallocation required.
 */
char **strsplit (const char *src, const char *delim)
{
    int i = 0, in = 0, nptrs = NPTRS;       /* index, in/out flag, ptr count */
    char **dest = NULL;                     /* ptr-to-ptr to allocate/fill */
    const char *p = src, *ep = p;           /* pointer and end-pointer */

    /* allocate/validate nptrs pointers for dest */
    if (!(dest = malloc (nptrs * sizeof *dest))) {
        perror ("malloc-dest");
        return NULL;
    }
    *dest = NULL;   /* set first pointer as sentinel NULL */

    for (;;) {  /* loop continually until end of src reached */
        if (!*ep || strchr (delim, *ep)) {  /* if at nul-char or delimiter char */
            size_t len = ep - p;            /* get length of token */
            if (in && len) {                /* in-word and chars in token */
                if (i == nptrs - 1) {       /* used pointer == allocated - 1? */
                    /* realloc dest to temporary pointer/validate */
                    void *tmp = realloc (dest, 2 * nptrs * sizeof *dest);
                    if (!tmp) {
                        perror ("realloc-dest");
                        break;  /* don't exit, original dest still valid */
                    }
                    dest = tmp;             /* assign reallocated block to dest */
                    nptrs *= 2;             /* increment allocated pointer count */
                }
                /* allocate/validate storage for token */
                if (!(dest[i] = malloc (len + 1))) {
                    perror ("malloc-dest[i]");
                    break;
                }
                memcpy (dest[i], p, len);   /* copy len chars to storage */
                dest[i++][len] = 0;         /* nul-terminate, advance index */
                dest[i] = NULL;             /* set next pointer NULL */
            }
            if (!*ep)                       /* if at end, break */
                break;
            in = 0;                         /* set in-word flag 0 (false) */
        }
        else {  /* normal word char */
            if (!in)                        /* if not in-word */
                p = ep;                     /* update start to end-pointer */
            in = 1;                         /* set in-word flag 1 (true) */
        }
        ep++;   /* advance to next character */
    }

    return dest;
}

int main (void) {

    char *str = "JAN,FEB,MAR,APR,MAY,,,JUN,JUL,AUG,SEP,OCT,NOV,DEC",
        **tokens;                           /* pointer to pointer to char */

    if ((tokens = strsplit (str, ","))) {   /* split string into tokens */
        for (char **p = tokens; *p; p++) {  /* loop over filled pointers */
            puts (*p);
            free (*p);      /* don't forget to free allocated strings */
        }
        free (tokens);      /* and pointers */
    }
}
$ ./bin/splitinput
JAN
FEB
MAR
APR
MAY
JUN
JUL
AUG
SEP
OCT
NOV
DEC
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>  // C99

// tokenize destructively
char **str_toksarray_alloc(
    char **strp,       /* InOut: pointer to the source non-constant c-string */
    const char *delim, /* c-string containing the delimiting chars */
    size_t *ntoks,     /* InOut: # of tokens to parse/parsed (NULL or *ntoks==0 for all tokens) */
    bool keepnulls     /* false ignores empty tokens, true includes them */
    );

// tokenize non-destructively
char **str_toksarray_alloc2(
   const char *str,    /* the source c-string */
   const char *delim,
   size_t *ntoks,
   bool keepnulls
   );
const char *src = ";b,test,Tèst,;;cd;ελληνικά,nørmälize,;string to";
const char *delim = ";,";
bool keepnulls = true;
size_t ntoks = 0;
// destructive (use copy of src)

char *scopy = strdup( src );
if (!scopy) { ... };          // handle strdup failure

printf( "%s\n", src );
char **arrtoks = str_toksarray_alloc( &scopy, delim, &ntoks, keepnulls );
printf( "%lu tokens read\n", ntoks );
if ( arrtoks ) {
    for (int i=0; arrtoks[i]; i++) {
        printf( "%d: %s\n", i, arrtoks[i] );
    }
}
free( scopy );
free( arrtoks );

/* OUTPUT
;b,test,Tèst,;;cd;ελληνικά,nørmälize,;string to
11 tokens read
0:
1: b
2: test
3: Tèst
4:
5:
6: cd
7: ελληνικά
8: nørmälize
9:
10: string to
 */
// non-destructive

keepnulls = false;    // reject empty tokens

printf( "%s\n", src );
arrtoks = str_toksarray_alloc2( src, delim, &ntoks, keepnulls );
printf( "%lu tokens read\n", ntoks );
if ( arrtoks ) {
    for (int i=0; arrtoks[i]; i++) {
        printf( "%d: %s\n", i, arrtoks[i] );
    }
}
toksarray_free2( arrtoks );                     // dangling arrtoks
// or: arrtoks = toksarray_free2( arrtoks );    // non-dangling artoks

/* OUTPUT
;b,test,Tèst,;;cd;ελληνικά,nørmälize,;string to
7 tokens read
0: b
1: test
2: Tèst
3: cd
4: ελληνικά
5: nørmälize
6: string to
*/
// ----------------------------------------
// Tokenize destructively a nul-terminated source-string.
// Return a dynamically allocated, NULL terminated array of char-pointers
// each pointing to each token found in the source-string, or NULL on error.
//
char **str_toksarray_alloc(char **strp, const char *delim, size_t *ntoks, bool keepnulls)
{
    // sanity checks
    if ( !strp || !*strp || !**strp || !delim ) {
        goto failed;
    }

    char *strpSaved = *strp;                    // save initial *strp pointer
    bool ntoksOk = (ntoks && *ntoks);           // false when ntoks is muted
    size_t _ntoks = (ntoksOk ? *ntoks : 16);    // # of tokens to alloc-ahead

    // alloc array of char-pointers (+1 for NULL sentinel)
    char **toksarr = malloc( (_ntoks+1) * sizeof(*toksarr) );
    if ( !toksarr ) {
        goto failed;
    }

    // Parse *strp tokens into the array
    size_t i = 0;           // # of actually parsed tokens
    char *tok;
    while ( (tok = strsep(strp, delim)) ) {
        // if requested, ignore empty tokens
        if ( *tok == '\0' && !keepnulls ) {
            continue;
        }
        // non-muted ntoks reached? we are done
        if ( ntoksOk && i == _ntoks ) {
            *ntoks = i;
            break;
        }
        // muted ntoks & ran out of space? double toksarr and keep parsing
        if ( !ntoksOk && i == _ntoks ) {
            _ntoks *= 2;
            char **tmparr = realloc( toksarr, (_ntoks+1) * sizeof(*tmparr) );
            if ( !tmparr ) {
                *strp = strpSaved;
                free( toksarr );
                goto failed;
            }
            toksarr = tmparr;
        }
        toksarr[i++] = tok; // get token address
    }
    toksarr[i] = NULL;      // NULL sentinel

    *strp = strpSaved;      // restore initial *strp pointer
    if (ntoks) *ntoks = i;  // pass to caller # of parsed tokens
    return toksarr;

failed:
    if (ntoks) *ntoks = 0;
    return NULL;
}
// ----------------------------------------
// Tokenize non-destructively a nul-terminated source-string.
// Return a dynamically allocated, NULL terminated array of dynamically
// allocated and nul-terminated string copies of each token found in the
// source-string. Return NULL on error.
// The 2 at the end of the name means 2-levels of allocation.
//
char **str_toksarray_alloc2( const char *str, const char *delim, size_t *ntoks, bool keepnulls )
{
    // sanity checks
    if ( !str || !*str || !delim ) {
        if (ntoks) *ntoks = 0;
        return NULL;
    }

    // make a copy of str to work with
    char *_str = strdup( str ); 
    if ( !_str ) {
        if (ntoks) *ntoks = 0;
        return NULL;
    }

    // if ntoks is muted we'll allocate str_tokscount() tokens, else *ntoks
    size_t _ntoks = (ntoks && *ntoks) ? *ntoks : str_tokscount(_str, delim, keepnulls);
    if ( _ntoks == 0 ) {        // str_tokscount() failed
        goto fail_free_str;
    }
    
    // alloc the array of strings (+1 for an extra NULL sentinel)
    char **toksarr = malloc( (_ntoks+1) * sizeof(*toksarr) );
    if ( !toksarr ) {
        goto fail_free_str;
    }

    // Parse str tokens and duplicate them into the array
    size_t i = 0;           // # of actually parsed tokens
    char *tok;
    while ( i < _ntoks && (tok = strsep(&_str, delim)) ) {
        // if requested, skip empty tokens
        if ( *tok == '\0' && !keepnulls ) {
            continue;
        }
        // duplicate current token into the array
        char *tmptok = strdup( tok );
        if ( !tmptok ) {
            goto fail_free_arr;
        }
        toksarr[i++] = tmptok;
    }
    toksarr[i] = NULL;      // NULL sentinel

    free( _str );           // release the local copy of the source-string
    if (ntoks) *ntoks = i;  // pass to caller the # of parsed tokens
    return toksarr;

// cleanup before failing
fail_free_arr:
    for (size_t idx=0; idx < i; idx++) {
        free( toksarr[idx] );
    }
    free( toksarr );

fail_free_str:
    free( _str );
    if (ntoks) *ntoks = 0;
    return NULL;
}
// ----------------------------------------
// Return the count of tokens present in a nul-terminated source-string (str),
// based on the delimiting chars contained in a 2nd nul-terminated string (delim).
// If the boolean argument is false, empty tokens are excluded.
//
// To stay consistent with the behavior of strsep(), the function returns 1 if
// delim is an empty string or none of its delimiters is found in str (in those
// cases the source-string is considered a single token).
// 0 is returned when str or delim are passed as NULL pointers, or when str is
// passed as an empty string.
//
size_t str_tokscount( const char *str, const char *delim, bool keepnulls )
{
    // sanity checks
    if ( !str || !*str || !delim ) {
        return 0;
    }

    const char *tok = str;
    size_t nnulls = strchr(delim, *str) ? 1 : 0;
    size_t ntoks = 1;   // even when no delims in str, str counts as 1 token 
    for (; (str = strpbrk(tok, delim)); ntoks++ ) {
        tok = ++str;
        if ( strchr(delim, *str) ) {
            nnulls++;
        }
    }

    return keepnulls ? ntoks : (ntoks - nnulls);
}
// ----------------------------------------
// Free a dynamically allocated, NULL terminated, array of char-pointers
// with each such pointer pointing to its own dynamically allocated data.
// Return NULL, so the caller has the choice of assigning it back to the
// dangling pointer. The 2 at the end of the name means 2-levels of deallocation.
//
// NULL terminated array means ending with a NULL sentinel.
//      e.g.: toksarr[0] = tok1, ..., toksarr[len] = NULL
//
char **toksarray_free2( char **toksarr )
{
    if ( toksarr ) {
        char **toks = toksarr;
        while ( *toks ) {   // walk until NULL sentinel
            free( *toks++ );
        }
        free( toksarr );
    }

    return NULL;
}