我正在创建自己的 ls 版本,但我被段错误卡住了

I am creating my own version of ls in and I'm stuck with a segfault

提问人:owen.H 提问时间:11/15/2023 最后编辑:UpAndAdamowen.H 更新时间:11/15/2023 访问量:57

问:

这是我制作的代码,我创建了一个时间函数来获取文件的创建日期,然后获取所有权限,然后我将它们全部放在一个名为的函数中,它就在这里段错误ls -lget_permissionmy_ls_l

void get_time(char *str)
{
    str[16] = '\0';
    str = str + 4;
    mini_printf("%s",str);
}

void get_permission(struct stat stat )
{

    my_putchar((S_ISDIR(stat.st_mode)) ? 'd' :
             (S_ISBLK(stat.st_mode) ? 'b' :
             (S_ISCHR(stat.st_mode) ? 'c' : '-')));
    my_putchar((stat.st_mode & S_IRUSR) ? 'r' : '-');
    my_putchar((stat.st_mode & S_IWUSR) ? 'w' : '-');
    my_putchar((stat.st_mode & S_IXUSR) ? 'x' : '-');
    my_putchar((stat.st_mode & S_IRGRP) ? 'r' : '-');
    my_putchar((stat.st_mode & S_IWGRP) ? 'w' : '-');
    my_putchar((stat.st_mode & S_IXGRP) ? 'x' : '-');
    my_putchar((stat.st_mode & S_IROTH) ? 'r' : '-');
    my_putchar((stat.st_mode & S_IWOTH) ? 'w' : '-');
    my_putchar((stat.st_mode & S_IXOTH) ? 'x' :
    (stat.st_mode & S_ISVTX) ? 'T' : '-');
}

int my_ls_l(void)
{
    struct dirent *entry;
    DIR *dir;
    struct stat stat;
    struct passwd *pw = getpwuid(stat.st_uid);
    struct group *grp = getgrgid(stat.st_gid);

    dir = opendir("./");
    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_name[0] != '.') {
            get_permission(stat);
            mini_printf("%s", entry->d_name);
            mini_printf("%s",stat.st_nlink);
            mini_printf("%s",entry->d_name_name);
            mini_printf("%s",grp->gr_name);
            mini_printf("%s",stat.st_size);
            get_time(ctime(&stat.st_mtime));
            mini_printf("\n");
        }
    }
    mini_printf("\n");
    closedir(dir);
}
int main(void) {
    my_ls_l();
    return (0);
}

我试图在这里做ls -l,它得到文件的名称,然后它出现段错误,我不明白为什么

C 分段-故障 LS

评论

1赞 Refugnic Eternium 11/15/2023
根据 , .关键点是“内部”。你不知道这个数组有多大,你肯定不应该写到它。ctimeThe returned value points to an internal array whose validity or value may be altered by any subsequent call to asctime or ctime.
3赞 Some programmer dude 11/15/2023
struct passwd *pw = getpwuid(stat.st_uid);...但是在代码的这一点上,结构是未初始化的。你做事的顺序很重要。stat
3赞 Shawn 11/15/2023
stat在代码中的每个点都未初始化。
0赞 UpAndAdam 11/15/2023
my_putchar和mini_printf的代码在哪里?

答:

2赞 Refugnic Eternium 11/15/2023 #1

您的代码中有多个问题。 最明显的一个是,你既不填充你的结构,也不初始化它,这意味着该结构的每个属性都可以具有任何可能的值。(这使得它毫无用处)。stat

你想要的是函数(https://www.man7.org/linux/man-pages/man2/stat.2.html),如下所示:stat

int my_ls_l(void)
{
    struct dirent *entry;
    DIR *dir;
    struct stat st;


    dir = opendir("./");
    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_name[0] != '.'
            && !stat(entry->d_name, &st)
        ) {
            struct passwd *pw = getpwuid(st.st_uid);
            struct group *grp = getgrgid(st.st_gid);
            get_permission(stat);
            mini_printf("%s", entry->d_name);
            mini_printf("%s",st.st_nlink);
            mini_printf("%s",entry->d_name_name);
            mini_printf("%s",grp->gr_name);
            mini_printf("%s",st.st_size);
            get_time(ctime(&st.st_mtime));
            mini_printf("\n");
        }
    }
    mini_printf("\n");
    closedir(dir);
}

始终检查此类函数的返回值。 此外,最好将绝对路径传递给 ,但对于初学者来说,相对路径应该可以。stat

另一个(潜在)问题是您使用 . 您正在写入未知大小的缓冲区,该缓冲区可以在任何给定时间被覆盖。ctime

使用此类缓冲区时,请将内容复制到您知道其大小的缓冲区中,然后使用该缓冲区。

你的 gettime 函数可以像这样优化:

void get_time(char *str)
{
    mini_printf("%s",str + 4);
}

这是有效的,因为您不是在操作缓冲区,而是将其“复制”到输出流,从第 4 个字符开始。 可以合理地假设 ctime 缓冲区中的字符串已经以 0 结尾。

另一方面:通过调试器运行代码。它将帮助您比我们在 StackOverflow 上更快地发现错误。它将帮助你学会比我们更好地帮助自己。

评论

0赞 owen.H 11/15/2023
好的,谢谢你,我会按照你说的去做