スニぺったん

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

  • C言語
  • フォルダ以下のアイテム一覧を取得する関数 (listdir)

フォルダ以下のアイテム一覧を取得する関数 (listdir)

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

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

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

#ifdef _WIN32
#include <windows.h>
#else
#include <dirent.h>
#endif

void
listdir_free_list(char **list) {
    for (char **p = list; *p; p++) {
        free(*p);
    }
    free(list);
}

static char *
listdir_strdup(const char *s) {
    size_t len = strlen(s);
    char *p = malloc(len+1);
    if (!p) {
        return NULL;
    }
    strcpy(p, s);
    return p;
}

/**
 * dir_path以下のアイテムを文字列のポインタ配列として返す。
 */
char **
listdir(const char *dir_path) {
    if (!dir_path) {
        return NULL;
    }

    char **list = NULL;
    size_t list_len = 0;
    size_t list_capa = 4;

    size_t byte = sizeof(char*);
    size_t size = byte * list_capa + byte;
    list = malloc(size);
    if (!list) {
        return NULL;
    }
    list[list_len] = NULL;

    #undef resize
    #define resize() {\
        if (list_len >= list_capa) {\
            list_capa *= 2;\
            size = byte * list_capa + byte;\
            char **tmp = realloc(list, size);\
            if (!tmp) {\
                listdir_free_list(list);\
                return NULL;\
            }\
            list = tmp;\
        }\
    }\

#ifdef _WIN32
    char pattern[MAX_PATH];
    snprintf(pattern, sizeof pattern, "%s\\*", dir_path);

    WIN32_FIND_DATAA fd;
    HANDLE h = FindFirstFileA(pattern, &fd);
    if (h == INVALID_HANDLE_VALUE) {
        listdir_free_list(list);
        return NULL;
    }
    do {
        if (!strcmp(fd.cFileName, ".") ||
            !strcmp(fd.cFileName, "..")) {
            continue;
        }
        resize();
        list[list_len++] = listdir_strdup(fd.cFileName);
        list[list_len] = NULL;
    } while (FindNextFileA(h, &fd));

    FindClose(h);
#else
    DIR *dir = opendir(dir_path);
    if (!dir) {
        listdir_free_list(list);
        return NULL;
    }

    struct dirent *entry;

    while ((entry = readdir(dir)) != NULL) {
        if (!strcmp(entry->d_name, ".") ||
            !strcmp(entry->d_name, "..")) {
            continue;
        }
        resize();
        list[list_len++] = listdir_strdup(entry->d_name);
        list[list_len] = NULL;
    }

    closedir(dir);
#endif

    return list;
}

int
main(int argc, char *argv[]) {
    if (argc < 2) {
        return 1;
    }

    char **list = listdir(argv[1]);
    if (!list) {
        return 1;
    }

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

    listdir_free_list(list);

    assert(listdir("...") == NULL);
    assert(listdir("???") == NULL);

    return 0;
}