split関数: 文字列を分割して配列に格納する

英文の単語切り出しをしようと他言語でよくある split 関数を作ってみた。
切り出す単語数が可変バージョンと、最大個数が決まっているバージョンの2パターンを作り、それぞれの長所と短所は以下の通り。

可変バージョン
 長所:配列数は動的に決まるため、読む込む単語数を気にしなくて良い。
 短所:呼出し側で malloc や free が必要。


固定バージョン
 長所:malloc を使っていないので、free のし忘れの心配がない。
 短所:配列数を静的に決める必要があるため、読み込む単語数に制限がある。引数が多い。

あと、strtok も評判悪そうなので、固定バージョンでは地道に走査させてみた。
こういう動く動かないの問題ではなくて、どちらが良いかという問題は非常に悩ましい。

// 可変バージョン
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ALLOCATE_SIZE  64
int split(char ***ary, const char *s, const char *delimiter)
{
  char *tmp = strdup(s);
  
  int i, n;
  for (i = n = 0; (tmp = strtok(tmp, delimiter)) != NULL; i++) {
    if (i >= n) {
      n += ALLOCATE_SIZE;
      *ary = (char **)realloc(*ary, sizeof(char *) * n);
    }
    (*ary)[i] = strdup(tmp);
    tmp = NULL;
  }
  
  return i;
}


int main(void)
{
  char str[] = "I stand here today humbled by the task before us, "
               "grateful for the trust you have bestowed, "
               "mindful of the sacrifices borne by our ancestors.";
  char delimiter[] = " ";
  
  int len, i;
  char **ary;
  ary = (char **)malloc(sizeof(char *));
  
  len = split(&ary, str, delimiter);
  
  for (i = 0; i < len; i++)
    printf("%2d : [%s]\n", i, ary[i]);
  
  free(ary);
  
  return 0;
}
// 固定バージョン
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUF_SIZE 100
#define NELEMS(a) (sizeof(a) / sizeof(a[0]))

static int in(const char *s, const char c);

int split(char *ary[], int len, const char *s, const char *delimiter)
{
  char buf[BUF_SIZE];
  
  int i, j;
  for (i = 0; i < len && *s != '\0'; i++) {
    while (in(delimiter, *s))
      s++;
    for (j = 0; j < BUF_SIZE && *s != '\0' && !in(delimiter, *s); j++, s++)
      buf[j] = *s;
    buf[j] = '\0';
    if (j == 0) break;
    ary[i] = strdup(buf);
  }
  
  return i;
}

static int in(const char *s, const char c)
{
  int i;
  for (i = 0; s[i] != '\0'; i++)
    if (s[i] == c) return 1;
  return 0;
}

int main(void)
{
  char str[] = "I stand here today humbled by the task before us, "
               "grateful for the trust you have bestowed, "
               "mindful of the sacrifices borne by our ancestors.";
  char delimiter[] = " ";
  
  int len, i;
  char *ary[100];
  
  len = split(ary, NELEMS(ary), str, delimiter);
  
  for (i = 0; i < len; i++)
    printf("%2d : [%s]\n", i, ary[i]);
  
  return 0;
}