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

C语言目录遍历程序中memmove()引发段错误问题求助

解决递归目录遍历中插入排序的段错误及逻辑问题

核心问题分析

  • 参数类型不匹配导致段错误:你的iSort函数定义接受的是struct info *fs_info[](指针数组),但调用时传入的是&fs_info——这里的fs_info是struct info类型的数组,它的地址类型是struct info (*)[N],和函数参数的指针数组类型完全不兼容。这会导致函数内部访问fs_info[j]时,错误地把数组元素当成指针来解引用,进而访问非法内存,触发EXC_BAD_ACCESS。
  • 插入排序逻辑不完整:原代码只保存了size作为key,排序后只恢复了size,完全没处理name字段,会导致文件名和大小不匹配;同时使用memmove的方式不符合插入排序的正确逻辑(插入排序应该是把当前元素暂存,然后把前面比它大的元素后移,最后把暂存的元素插入到正确位置)。
  • 数据类型溢出风险:st.st_size是off_t类型(通常是64位),而你用int存储,对于超过int范围的大文件,大小会被截断,导致数据错误。
  • 错误处理冗余:get_size中错误分支重复调用stat(path, &st),没必要,应该直接用第一次调用的返回值。
  • 后续插入逻辑缺失:当数组填满后,你只调用了排序,但没有判断当前文件是否比数组中最小的文件大,也没有执行替换操作,无法更新最大的N个文件列表。

修正后的代码

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

// number of files to display size information for
const int N = 10;

// 修正size类型为off_t,避免大文件溢出
struct info {
    char name[1024];
    off_t size;
};

/* 修正参数类型:直接接受struct info数组的指针,而非指针数组 */
void iSort(struct info *fs_info, int size)
{
    int i, j;
    struct info key; // 暂存整个结构体,而不是只存size

    for (i = 1; i < size; i++)
    {
        key = fs_info[i]; // 保存当前元素的完整信息
        j = i - 1;

        // 把比key大的元素向后移动
        while (j >= 0 && fs_info[j].size > key.size)
        {
            fs_info[j + 1] = fs_info[j]; // 直接结构体赋值,比memmove更直观
            j = j - 1;
        }
        fs_info[j + 1] = key; // 把暂存的元素插入正确位置
    }
}

void get_size(char *path, struct info fs_info[N])
{
    static int items_added = 0;

    struct stat st;
    int stat_ret = stat(path, &st);
    if (stat_ret == 0)
    {
        // 只处理普通文件,跳过目录(避免把目录大小算进去)
        if (!S_ISREG(st.st_mode)) {
            return;
        }

        if (items_added < N)
        {
            strncpy(fs_info[items_added].name, path, sizeof(fs_info[items_added].name)-1);
            fs_info[items_added].name[sizeof(fs_info[items_added].name)-1] = '\0'; // 确保字符串终止
            fs_info[items_added].size = st.st_size;
            items_added++;
        }
        else
        {
            // 先排序,找到当前最小的文件
            iSort(fs_info, N);
            // 如果当前文件比最小的大,替换它
            if (st.st_size > fs_info[0].size)
            {
                strncpy(fs_info[0].name, path, sizeof(fs_info[0].name)-1);
                fs_info[0].name[sizeof(fs_info[0].name)-1] = '\0';
                fs_info[0].size = st.st_size;
                // 重新排序,保持有序
                iSort(fs_info, N);
            }
        }
    }
    else
    {
        printf("Error getting stat for entry %s: %d\n", path, stat_ret);
    }
}

void walk(const char *currDir, struct info fs_info[N])
{
    DIR *dir = opendir(currDir);
    struct dirent *entry;

    if (dir == NULL)
    {
        perror("opendir failed");
        return;
    }

    while ((entry = readdir(dir)) != NULL)
    {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
        {
            continue;
        }

        char path_to_entry[1024];
        snprintf(path_to_entry, sizeof(path_to_entry), "%s/%s", currDir, entry->d_name);

        get_size(path_to_entry, fs_info);

        if (entry->d_type == DT_DIR)
        {
            walk(path_to_entry, fs_info);
        }
    }
    closedir(dir);
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("Usage: %s <target directory>\n", argv[0]);
        return 1; // 错误退出码
    }

    const char *target_dir = argv[1];

    struct info fs_entries[N] = {0}; // 初始化所有字段为0,无需手动循环

    printf("Finding %d largest files in: %s\n", N, target_dir);

    walk(target_dir, fs_entries);

    // 最后排序一次,从大到小输出
    iSort(fs_entries, N);
    printf("\nTop %d largest files:\n", N);
    for (int i = N-1; i >= 0; i--)
    {
        if (fs_entries[i].size > 0) // 只输出有效条目
            printf("%s : %lld bytes\n", fs_entries[i].name, (long long)fs_entries[i].size);
    }

    return 0;
}

关键修正点说明

  1. 修正iSort参数与逻辑:
    • 把函数参数改为struct info *fs_info(直接指向结构体数组的指针),和调用时传入的数组名(会隐式转为指针)类型匹配。
    • 插入排序时暂存整个struct info结构体,确保文件名和大小一起移动,避免数据不匹配;直接用结构体赋值代替memmove,代码更简洁安全。
  2. 数据类型修正:将struct info中的size改为off_t,并在输出时转为long long打印,避免大文件大小溢出。
  3. 完善文件过滤:在get_size中判断S_ISREG(st.st_mode),只处理普通文件,跳过目录、设备文件等非普通文件。
  4. 完善填满后的逻辑:当数组满了之后,先排序找到最小的文件,若当前文件更大则替换,再重新排序,确保数组始终保存当前找到的最大N个文件。
  5. 优化初始化与错误处理:用struct info fs_entries[N] = {0};直接初始化数组,避免手动循环;错误处理中使用perror打印opendir的错误原因,重复调用stat的问题也被修复。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 06:25:21