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

如何打印硬链接数量与文件名?C代码功能异常求助

硬链接检测程序问题解答

用户需求与现有代码

需要实现两个核心功能:

  • 打印当前目录中具有相同inode编号的文件
  • 打印对应硬链接的数量

以下是用户编写的代码:

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

int main() {
    DIR *dp;
    dp = opendir(".");

    struct dirent *dent1, *dent2;
   
    while((dent1 = readdir(dp))) {
        while((dent2 = readdir(dp))) {
            struct stat buf;
            if(stat(dent1->d_name, &buf)) {
                perror("stat");
                exit(1);
            }        
            if((dent1->d_ino == dent2->d_ino) && (dent1->d_name != dent2->d_name) {
                printf("---Same inode files---\n");
                printf("%s\n", dent1->d_name);
                printf("%s\n", dent2->d_name);
                printf("Number of hard links = %o\n", (unsigned int)buf.st_nlink);
                }
            }
        }
    closedir(dp);

    return 0;
}

用户遇到的问题:当前目录存在3个同inode的硬链接,但程序仅打印出其中一组,同时提出三个疑问:

  1. 程序是否存在错误?
  2. 是否需要补充更多代码?
  3. 代码是否低效?

问题解答

1. 程序存在的明确错误

  • 目录流耗尽问题:双层循环共用同一个目录指针dp,内层readdir会一次性读完所有目录项,外层循环后续调用readdir直接返回NULL,导致仅能处理第一个目录项。
  • 文件名比较逻辑错误:dent1->d_name != dent2->d_name是比较指针地址而非字符串内容,正确做法是用strcmp(dent1->d_name, dent2->d_name) != 0。
  • stat调用逻辑缺陷:仅对dent1调用stat,未处理dent2的可能异常;且遇到./..时stat无意义,未做过滤。
  • 格式符错误:硬链接数用八进制%o输出,应该用十进制%u。
  • 语法遗漏:if条件末尾缺少闭合括号,编译时会报错(用户称编译无错误可能是粘贴遗漏)。

2. 需要补充/修正的代码内容

  • 预存目录项:先将所有有效目录项读取到数组中,再进行两两比较,避免目录流被一次性耗尽。
  • 过滤无效项:跳过.和..目录,避免无意义的inode对比。
  • 字符串比较修正:替换指针比较为strcmp字符串内容比较。
  • 去重处理:避免重复打印同一组硬链接(如A&B打印后,不再重复打印B&A)。
  • 完善错误处理:增加opendir失败判断;stat失败时跳过当前文件而非直接退出程序。

3. 代码的低效性分析

当前双层循环的思路本身存在逻辑缺陷,即使修正后,时间复杂度为O(n²),当目录中文件数量较多时,性能会显著下降。更高效的方案是采用哈希分组:遍历一次目录,以inode号为键,将对应文件名存入列表,最后遍历分组结果输出同inode的文件和硬链接数,时间复杂度为O(n),效率远高于双层循环。


修正后的示例代码

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

#define MAX_FILES 1024

// 用于存储同一inode下的所有文件名
typedef struct {
    ino_t inode;
    char **names;
    int count;          // 当前存储的文件名数量
    int capacity;       // 数组容量
} InodeEntry;

int main() {
    DIR *dp = opendir(".");
    if (!dp) {
        perror("opendir failed");
        exit(EXIT_FAILURE);
    }

    struct dirent *dent;
    InodeEntry entries[MAX_FILES] = {0};
    int entry_count = 0;

    // 遍历目录,按inode分组存储文件名
    while ((dent = readdir(dp)) != NULL) {
        // 跳过当前目录和父目录
        if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
            continue;
        }

        struct stat buf;
        if (stat(dent->d_name, &buf) != 0) {
            fprintf(stderr, "stat %s failed: ", dent->d_name);
            perror("");
            continue;
        }

        // 查找当前inode是否已存在分组
        int idx = -1;
        for (int i = 0; i < entry_count; i++) {
            if (entries[i].inode == buf.st_ino) {
                idx = i;
                break;
            }
        }

        if (idx == -1) {
            // 新增inode分组
            if (entry_count >= MAX_FILES) {
                fprintf(stderr, "Reached maximum file limit\n");
                break;
            }
            entries[entry_count].inode = buf.st_ino;
            entries[entry_count].capacity = 4;
            entries[entry_count].names = malloc(sizeof(char*) * entries[entry_count].capacity);
            entries[entry_count].names[0] = strdup(dent->d_name);
            entries[entry_count].count = 1;
            entry_count++;
        } else {
            // 追加文件名到已有分组
            if (entries[idx].count >= entries[idx].capacity) {
                entries[idx].capacity *= 2;
                entries[idx].names = realloc(entries[idx].names, sizeof(char*) * entries[idx].capacity);
            }
            entries[idx].names[entries[idx].count] = strdup(dent->d_name);
            entries[idx].count++;
        }
    }
    closedir(dp);

    // 输出所有同inode的文件及硬链接数
    for (int i = 0; i < entry_count; i++) {
        if (entries[i].count > 1) {
            printf("---Same inode files (inode: %lu)---\n", (unsigned long)entries[i].inode);
            for (int j = 0; j < entries[i].count; j++) {
                printf("%s\n", entries[i].names[j]);
            }
            // 读取硬链接数(同inode文件的st_nlink一致,取第一个即可)
            struct stat buf;
            if (stat(entries[i].names[0], &buf) == 0) {
                printf("Number of hard links = %u\n\n", (unsigned int)buf.st_nlink);
            }
            // 释放内存
            for (int j = 0; j < entries[i].count; j++) {
                free(entries[i].names[j]);
            }
            free(entries[i].names);
        }
    }

    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 01:25:25