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

C语言中使用qsort对存储字母数字文件名的动态二维char数组排序问题

Hey there! I feel your pain—being stuck on a sorting issue for two weeks is no fun. Let's break down what's probably going wrong with your qsort crashes and wonky alphanumeric sorting, plus fix it step by step.

First, Why qsort Might Be Crashing

  • NULL pointers in your filename array: If you're not filtering out ./.. or if some file entries failed to be stored properly, you could have NULLs in your array. When qsort tries to compare these, it'll dereference a NULL pointer and crash. Always validate each filename before adding it to your array, and skip the default directory entries.
  • Incorrect comparison function signature: qsort expects a function that takes const void* arguments. If you're casting them incorrectly (e.g., not using const char** when dealing with an array of strings), you'll access invalid memory. Double-check that your compare function matches the required signature.
  • Wrong element count or size: If you miscalculated how many filenames you stored, or passed the wrong size to qsort (e.g., sizeof(char) instead of sizeof(char*)), qsort will read/write outside your array bounds—crash city.

Next, Fixing Alphanumeric Sorting

The default strcmp sorts by ASCII values, which means numbers come before letters, uppercase before lowercase, and file10 will come before file2 (since '1' has a lower ASCII value than '2'). If you want "natural" sorting (where numeric parts are treated as whole numbers), you need a custom compare function.

Working Example Code

Here's a complete implementation that handles directory reading, safe storage, natural sorting, and cleanup:

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

// Natural sort compare function for alphanumeric filenames
int naturalCompare(const void *a, const void *b) {
    const char *str1 = *(const char **)a;
    const char *str2 = *(const char **)b;

    while (*str1 && *str2) {
        if (isdigit((unsigned char)*str1) && isdigit((unsigned char)*str2)) {
            // Parse full numeric sequences instead of single digits
            long num1 = 0, num2 = 0;
            while (isdigit((unsigned char)*str1)) {
                num1 = num1 * 10 + (*str1 - '0');
                str1++;
            }
            while (isdigit((unsigned char)*str2)) {
                num2 = num2 * 10 + (*str2 - '0');
                str2++;
            }
            if (num1 != num2) {
                return (num1 > num2) ? 1 : -1;
            }
        } else {
            // Case-insensitive comparison (remove tolower for case-sensitive)
            int char1 = tolower((unsigned char)*str1);
            int char2 = tolower((unsigned char)*str2);
            if (char1 != char2) {
                return char1 - char2;
            }
            str1++;
            str2++;
        }
    }
    // Handle cases where one string is a prefix of the other
    return strlen(str1) - strlen(str2);
}

// Standard ASCII sort (if that's what you need instead)
int asciiCompare(const void *a, const void *b) {
    const char *str1 = *(const char **)a;
    const char *str2 = *(const char **)b;
    return strcmp(str1, str2);
}

int main() {
    DIR *dir = opendir(".");
    if (!dir) {
        perror("Failed to open directory");
        return 1;
    }

    struct dirent *entry;
    char **filenames = NULL;
    int count = 0;
    int capacity = 4; // Start with small capacity, expand as needed

    // Allocate initial array for filenames
    filenames = malloc(capacity * sizeof(char *));
    if (!filenames) {
        perror("Malloc failed");
        closedir(dir);
        return 1;
    }

    while ((entry = readdir(dir)) != NULL) {
        // Skip the default . and .. directory entries
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        // Expand array if we've hit capacity
        if (count >= capacity) {
            capacity *= 2;
            char **temp = realloc(filenames, capacity * sizeof(char *));
            if (!temp) {
                perror("Realloc failed");
                // Clean up already allocated memory before exiting
                for (int i = 0; i < count; i++) {
                    free(filenames[i]);
                }
                free(filenames);
                closedir(dir);
                return 1;
            }
            filenames = temp;
        }

        // Copy filename to our array (strdup handles allocation)
        filenames[count] = strdup(entry->d_name);
        if (!filenames[count]) {
            perror("Strdup failed");
            // Cleanup
            for (int i = 0; i < count; i++) {
                free(filenames[i]);
            }
            free(filenames);
            closedir(dir);
            return 1;
        }
        count++;
    }
    closedir(dir);

    // Sort using natural compare (swap to asciiCompare if needed)
    qsort(filenames, count, sizeof(char *), naturalCompare);

    // Print sorted results
    printf("Sorted Filenames:\n");
    for (int i = 0; i < count; i++) {
        printf("- %s\n", filenames[i]);
        free(filenames[i]); // Free each filename string
    }
    free(filenames); // Free the array itself

    return 0;
}

Key Checks for Your Own Code

  1. Validate all filenames: Make sure you're not storing NULLs or invalid entries in your array.
  2. Match qsort's compare function rules: Always cast const void* to the correct type (for string arrays, that's const char**).
  3. Choose the right sort logic: Use strcmp for strict ASCII sorting, or the natural compare function for alphanumeric sequences that make human sense.
  4. Memory safety: Always check malloc/realloc/strdup returns, and clean up memory to avoid leaks.

That should fix both the crash and the sorting issues you're seeing. Give it a try and tweak as needed for your specific use case!

内容的提问来源于stack exchange,提问作者N. Adams

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:45:30