スニぺったん

無料のコードスニペットを掲載しています。言語ごとにコードスニペットを検索し、利用することが可能です。コードのライセンスはトップページをご覧ください。

  • C言語
  • 文字列を区切り文字で分割しポインタ配列を返す関数 (split)

文字列を区切り文字で分割しポインタ配列を返す関数 (split)

総合評価: - 作成日: 2025-10-05

コメント:
Linuxでメモリリークテスト済み。
Windows/Linuxで動作確認済み。

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

void
split_free_array(char **array) {
    for (char **p = array; *p; p++) {
        free(*p);
    }
    free(array);
}

static void
split_show_array(char **array) {
    for (char **p = array; *p; p++) {
        printf("[%s]\n", *p);
    }
}

size_t
split_count(char **array) {
    size_t n = 0;
    for (char **p = array; *p; p++) {
        n++;
    }
    return n;
}

/**
 * 文字列strをsepで分割する。
 * 返り値は動的確保された文字列のポインタ配列。
 */
char **
split(char sep, const char *str) {
    #undef buf_alloc
    #define buf_alloc() {\
        free(buf);\
        buf = malloc(buf_capa + 1);\
        if (!buf) {\
            goto fail;\
        }\
        buf[0] = 0;\
        buf_len = 0;\
    }\

    #undef buf_resize
    #define buf_resize() {\
        if (buf_len >= buf_capa) {\
            buf_capa *= 2;\
            char *tmp = realloc(buf, buf_capa + 1);\
            if (!tmp) {\
                goto fail;\
            }\
            buf = tmp;\
        }\
    }\

    #undef array_resize
    #define array_resize() {\
        if (array_len >= array_capa) {\
            array_capa *= 2;\
            byte = sizeof(char*);\
            size = byte * array_capa + byte;\
            char **tmp = realloc(array, size);\
            if (!tmp) {\
                goto fail;\
            }\
            array = tmp;\
        }\
    }\

    #undef push_array
    #define push_array() {\
        array_resize();\
        array[array_len++] = buf;\
        array[array_len] = NULL;\
        buf = NULL;\
        buf_alloc();\
    }\

    #undef push_buf
    #define push_buf(c) {\
        buf_resize();\
        buf[buf_len++] = c;\
        buf[buf_len] = 0;\
    }\

    if (!str) {
        return NULL;
    }

    size_t buf_capa = 4;
    size_t buf_len = 0;
    char *buf = NULL;

    buf_alloc();

    size_t array_capa = 4;
    size_t array_len = 0;
    size_t byte = sizeof(char*);
    size_t size = byte * array_capa + byte;
    char **array = malloc(size);
    if (!array) {
        goto fail;\
    }

    array[array_len] = NULL;

    for (const char *p = str; *p; p++) {
        if (*p == sep) {
            push_array();
        } else {
            push_buf(*p);
        }
    }

    push_array();
    free(buf);

    return array;
fail:
    free(buf);
    split_free_array(array);
    return NULL;
}

int
main(void) {
    char **toks;

    assert(split(',', NULL) == NULL);

    toks = split(',', "");
    assert(toks);
    assert(split_count(toks) == 1);
    split_show_array(toks);
    assert(!strcmp(toks[0], ""));
    split_free_array(toks);

    toks = split(',', "123,223,,323");
    assert(toks);
    split_show_array(toks);
    assert(split_count(toks) == 4);
    assert(!strcmp(toks[0], "123"));
    assert(!strcmp(toks[1], "223"));
    assert(!strcmp(toks[2], ""));
    assert(!strcmp(toks[3], "323"));
    split_free_array(toks);

    toks = split(',', ",,,");
    assert(toks);
    split_show_array(toks);
    assert(split_count(toks) == 4);
    assert(!strcmp(toks[0], ""));
    assert(!strcmp(toks[1], ""));
    assert(!strcmp(toks[2], ""));
    assert(!strcmp(toks[3], ""));
    split_free_array(toks);

    return 0;
}