C语言printf列填充问题:自定义ls程序的列对齐与空格分隔需求
解决ls定制程序的列对齐问题
你的问题核心在于没有利用printf的宽度格式化功能来固定字段的显示宽度,导致不同长度的内容无法对齐。另外你遇到的段错误大概率不是%-1s本身的问题,而是没有处理getpwuid/getgrgid返回空指针的情况,直接访问pwd->pw_name或grp->gr_name导致的。
正确的解决方案:固定字段宽度+安全空指针检查
我们可以通过给每个printf格式说明符指定固定宽度(默认右对齐,不足补空格),让每个字段占据固定的字符数,自然实现对齐。同时要先检查用户/组信息是否能正常获取,避免空指针访问。
修改后的代码如下:
#include <stdio.h> #include <dirent.h> #include <sys/stat.h> #include <pwd.h> #include <grp.h> #include <time.h> #define MY_TIME_SIZE 20 int main() { DIR *dir = opendir("."); if (!dir) { perror("opendir failed"); return 1; } struct dirent *sd; struct stat sfile; struct passwd *pwd; struct group *grp; time_t t; struct tm *tmp; char MY_TIME[MY_TIME_SIZE]; while ((sd = readdir(dir)) != NULL) { // 跳过.和..,和ls默认行为一致,可选 if (sd->d_name[0] == '.') continue; if (lstat(sd->d_name, &sfile) == -1) { perror("lstat failed"); continue; } pwd = getpwuid(sfile.st_uid); grp = getgrgid(sfile.st_gid); t = sfile.st_mtime; tmp = localtime(&t); strftime(MY_TIME, MY_TIME_SIZE, "%Y-%m-%d %H:%M", tmp); // 用单条printf统一控制格式,每个字段指定固定宽度 printf("%5hu %2d %-12s %-8s %4lld %s %s\n", sfile.st_mode, sfile.st_nlink, pwd ? pwd->pw_name : "(unknown)", // 空指针安全处理 grp ? grp->gr_name : "(unknown)", sfile.st_size, MY_TIME, sd->d_name); } closedir(dir); return 0; }
格式说明符详解:
%5hu:权限数值占5位(右对齐,不足补空格),匹配你示例中的16877这类5位数值%2d:链接数占2位,一位数会自动补前导空格(比如5变成5),两位数刚好填满(比如23变成23)%-12s:用户名左对齐,占12位,避免过长的用户名挤压后续列(你可以根据实际需求调整宽度)%-8s:组名左对齐,占8位,同理可按需调整宽度%4lld:文件大小占4位,三位数自动补前导空格(比如160变成160),四位数刚好填满
额外注意点:
- 空指针检查:
getpwuid和getgrgid可能返回NULL(比如系统中不存在对应用户ID的情况),直接访问成员会触发段错误,所以用三目运算符做安全处理。 - 跳过隐藏文件:示例中加入了跳过
.和..的逻辑,和ls默认行为一致,如果你不需要可以去掉。 - 动态宽度优化:如果想要更接近ls的自适应对齐效果,可以先遍历一遍所有文件,记录每个字段的最大长度,再用
sprintf动态生成格式字符串,这样能完美适配各种长度的内容。
内容的提问来源于stack exchange,提问作者hbrown
相关产品推荐
相关产品推荐

