如何打印硬链接数量与文件名?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. 程序存在的明确错误
- 目录流耗尽问题:双层循环共用同一个目录指针
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
相关产品推荐
相关产品推荐

