C 使用静态变量时出现分段错误

C 使用静态变量时出现分段错误,c,unix,C,Unix,操作良好。但是,当我使用一个printf和两个Getpwnam_uu作为参数时,我得到了一个分段错误。我认为我的代码操作没有问题 但是,为什么这会给我一个分段错误??这里的问题很可能与getpwent返回一个指向它所管理的可能是静态内存区域的指针有关。因此,基本上,当您获得返回值时,您必须在再次调用getpwent之前使用它。因为第二次呼叫可能会覆盖甚至释放上一次呼叫返回的区域 从手册页: 返回值可能指向静态区域,并且可能被覆盖 通过对getpwent、getpwnam3或getpwuid3的后

操作良好。但是,当我使用一个printf和两个Getpwnam_uu作为参数时,我得到了一个分段错误。我认为我的代码操作没有问题


但是,为什么这会给我一个分段错误??

这里的问题很可能与getpwent返回一个指向它所管理的可能是静态内存区域的指针有关。因此,基本上,当您获得返回值时,您必须在再次调用getpwent之前使用它。因为第二次呼叫可能会覆盖甚至释放上一次呼叫返回的区域

从手册页:

返回值可能指向静态区域,并且可能被覆盖 通过对getpwent、getpwnam3或getpwuid3的后续调用。做 不将返回的指针传递到free3

所以,两个单独的打印可以工作,因为在第二次呼叫之前使用第一个打印。但是,将两者放在同一打印中意味着第二次调用会使第一次调用返回的指针无效,但是打印会尝试使用两个Ponter。即使没有seg故障,也很可能无法为第一个用户生成正确的输出


相反,您需要更改Getpwnam_uu以将所需的数据复制到新分配的对象中,并返回指向该对象的指针。注意:如果您还需要一些字符串,则复制需要是递归的。

在调用Getpwnam_u2;之间,您需要使用setpwent倒带密码数据库

假设您的应用程序首先调用Getpwnam_cho。如果在数据库中,root位于cho之前,则在搜索中,getpwent将返回root,但您的搜索将放弃它,因为它与cho不同。稍后,getpwent将返回cho,这是有效的结果


如果下一次应用程序调用Getpwnam_root,getpwent将从上次调用时留下的点开始返回条目,该点在数据库中超出root和cho的范围。由于不再返回root,搜索将不会得到结果,您将得到一个空指针,该指针会使程序崩溃。

一个问题是您试图同时保留两个密码条目。对getpwent的后续调用可能会覆盖以前返回的信息。因此,您需要在再次调用getpwent之前完成对返回信息的处理。如有必要,制作所需字段的副本

此外,不需要将指针声明为静态指针,因为您不返回其地址


atturri提到的另一个问题是,您没有在调用之间使用setpwent返回到密码的开头。如果代码在尝试引用密码字段之前检查了NULL返回,这会更清楚。

用户cho是否存在于您的系统中?@fluter:是的,确定您确定Getpwnam_uuu在两次调用中都返回非NULL吗?我认为,如果您以非root用户身份运行程序,那么root密码应该为NULLuser@Michael:Yse,当我使用低于1的命令而不是高于1的命令时,输出为0\n 1000 `并且我使用的是根帐户。从技术上讲,您有一条不返回的函数路径。实际上,if条件包含了跳转循环的唯一原因,因此它总是返回一个值,但是测试是不必要的,删除测试可以避免编译器抱怨。我发现了问题。原因就是阿图里刚才说的。当第一次调用Getpwnam_cho时,请给出正确的值。但不带终端或设置。Getpwnam_uu的第二个调用将返回NULL。因此,用%ld输出NULL会给我一个error@atturri:为什么Getpwnam_uu调用每个printf重置条目搜索行??我的意思是在一个printf中两次调用Getpwnam_uu不是重置条目搜索行。我的意思是当第一次调用Getpwnam_cho时,它将返回值。但是,在调用Getpwnam_root之后,它将返回NULL值,因为在cho下面没有根的条目。但是,为什么每次printf调用都会在第一次搜索不存在分段错误的条目?@A.Cho抱歉,我不确定我是否理解。您需要在每个while循环中从一开始就搜索整个数据库,以确保找到用户。您可以在Getpwnam_è内部或外部倒带数据库。另外请注意,其余的答案指出了代码的另一个问题。Sry,我对代码有误解。不管我说什么。非常感谢。
#include <pwd.h>
#include <stdio.h>

struct passwd* Getpwnam_(const char* name)
{
        static struct passwd* passwd;

        while((passwd=getpwent())!=NULL)        /* get pw entry line by line */
        {
                if(strcmp(passwd->pw_name, name)==0)    /* find the same name */
                        return passwd;
        }

        if(passwd==NULL)        /* there is no matching name */
                return NULL;
}

int
main(void)
{
        printf("%ld %ld\n", (long)(Getpwnam_("root")->pw_uid), (long)(Getpwnam_("cho")->pw_uid));
}
printf("%ld\n", (long)(Getpwnam_("root")->pw_uid));
printf("%ld\n", (long)(Getpwnam_("cho")->pw_uid));