You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言目录树生成程序全局word数组被覆盖问题及排序需求解决咨询

Fixing Your Filename Storage Issue & Implementing Case-Insensitive Tree Sorting

Let's tackle your problems one by one—first the broken filename storage in the word array, then the case-insensitive sorting feature you're aiming for.

1. Why Your word Array Is Overwriting Filenames

The core issue here is how you're storing filenames in the word array:

word[coun] = ("%s", entry->d_name);

This line uses a comma expression, which effectively just assigns the pointer of entry->d_name to word[coun]. The problem? The entry struct returned by readdir() gets reused every loop iteration, and when you recurse into subdirectories, the memory entry->d_name points to gets overwritten with new filenames. By the end of your program, every element in word is pointing to the same memory block, which holds the last filename processed—hence the overwritten entries you're seeing.

Fix for Filename Storage

Instead of storing pointers, you need to copy the actual string data into new memory. Use strdup() (which handles malloc + strcpy for you) to create a duplicate of each filename:

word[coun] = strdup(entry->d_name);
// Always check for allocation failures!
if (word[coun] == NULL) {
    perror("strdup failed");
    exit(EXIT_FAILURE);
}
coun++;

Also, don't forget to free this allocated memory at the end of main() to avoid leaks:

for (int i = 0; i < coun; ++i) {
    free(word[i]);
}
free(word);

2. Better Approach: Case-Insensitive Sorting Per Directory

Storing all filenames in a global array isn't ideal for tree sorting—you want each directory's contents to be sorted independently (which makes the tree structure logical). Here's a cleaner implementation that sorts each directory's entries (directories and files) in case-insensitive order, then builds the tree:

Updated Full Code

#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <ctype.h>

// Struct to hold entry info: name and whether it's a directory
typedef struct {
    char *name;
    int is_dir;
} DirEntry;

// Case-insensitive comparison function for qsort
int compare_entries(const void *a, const void *b) {
    const DirEntry *entry_a = (const DirEntry *)a;
    const DirEntry *entry_b = (const DirEntry *)b;
    // Use strcasecmp for case-insensitive comparison (POSIX standard)
    return strcasecmp(entry_a->name, entry_b->name);
}

void printdir(char *dir, int depth) {
    DIR *dp;
    struct dirent *entry;
    struct stat statbuf;
    DirEntry *entries = NULL;
    int entry_count = 0;

    if ((dp = opendir(dir)) == NULL) {
        fprintf(stderr, "cannot open directory: %s\n", dir);
        return;
    }
    chdir(dir);

    // Step 1: Collect all entries in the current directory
    while ((entry = readdir(dp)) != NULL) {
        lstat(entry->d_name, &statbuf);
        // Skip . and ..
        if (strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0) {
            continue;
        }

        // Allocate space for this entry
        entries = realloc(entries, (entry_count + 1) * sizeof(DirEntry));
        if (entries == NULL) {
            perror("realloc failed");
            exit(EXIT_FAILURE);
        }

        // Store entry details
        entries[entry_count].name = strdup(entry->d_name);
        entries[entry_count].is_dir = S_ISDIR(statbuf.st_mode);
        entry_count++;
    }

    // Step 2: Sort entries case-insensitively
    qsort(entries, entry_count, sizeof(DirEntry), compare_entries);

    // Step 3: Print sorted entries and recurse into directories
    for (int i = 0; i < entry_count; i++) {
        if (entries[i].is_dir) {
            printf("- %*s%s\n", depth, "", entries[i].name);
            printdir(entries[i].name, depth + 1);
        } else {
            printf("%*s - %s\n", depth, "", entries[i].name);
        }
        // Free the duplicated name
        free(entries[i].name);
    }

    // Cleanup
    free(entries);
    chdir("..");
    closedir(dp);
}

int main(int argc, char* argv[]) {
    printdir(".", 0);
    exit(0);
}

Key Improvements Explained

  • Per-directory sorting: We collect all entries in a directory first, sort them with qsort using strcasecmp (for case-insensitive ordering), then print and recurse. This ensures each directory's contents are sorted properly.
  • No global variables: We avoid the global word array entirely, which eliminates the overwriting issue and makes the code more modular.
  • Proper memory management: All allocated strings are freed after use to prevent memory leaks.
  • Clear entry tracking: The DirEntry struct keeps track of whether each entry is a directory, which is needed for both recursion and tree formatting.

Testing the Updated Code

When you run this, you'll get a tree where every directory's contents are sorted alphabetically without case sensitivity—so Tree.c, tree, and TREE will all be grouped together in the order you'd expect.

内容的提问来源于stack exchange,提问作者Vearaa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 17:43:16