在二维动态分配的字符串数组中获取单个字符串的长度

时间:2018-12-07 19:06:25

标签: c unix etcpasswd

我正在尝试查找UNIX系统中用户所属的所有组,以及每个用户的组。实现必须在C中。这是我的代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>


static void error_fatal(char* msg) 
{ perror(msg); exit(EXIT_FAILURE); }

int main(int argc, char** argv) {

    struct group* grp;
    struct passwd* pwd;
    char *name;
    int i = 0;

    setpwent();

    while((pwd = getpwent()) != NULL){

        if(  ( name = (char*) malloc( (strlen(pwd->pw_name)+1)*sizeof(char))) == NULL  ) error_fatal("malloc");
        strcpy(name, pwd->pw_name);
        printf("%s:\n", name); 

        setgrent();
        while( (grp = getgrent()) != NULL ) {
            for( i=0; i < (sizeof(grp->gr_mem)/sizeof(grp->gr_mem[0])); i++ ){
                if( /*strlen(&grp->gr_mem[i][0]) == strlen(name) && */ !strcmp(grp->gr_mem[i], name) )
                     printf("%s\n", name);
}                           }

        endgrent(); 
        free(name);

}
    endpwent();

    return 0;
}

但是在“ root:”输出后出现分段错误。 我很确定问题出在访问/ etc / group文件第四个字段中的成员列表(有关详细信息,请参见man 5组)。

所以,基本上我的问题是找出每个组有多少个成员,所以我的计数器(程序中的i,最后一个for循环)将具有很好的上限。

2 个答案:

答案 0 :(得分:1)

您的问题在这里:

for( i=0; i < (sizeof(grp->gr_mem)/sizeof(grp->gr_mem[0])); i++ ){

struct group定义为:

       struct group {
           char   *gr_name;        /* group name */
           char   *gr_passwd;      /* group password */
           gid_t   gr_gid;         /* group ID */
           char  **gr_mem;         /* NULL-terminated array of pointers
                                      to names of group members */
       };

您假设gr_mem是一个数组,但不是。它是指向数组第一个元素的指针。因此sizeof(grp->gr_mem)/sizeof(grp->gr_mem[0])为您提供了一个指针的大小,在您的系统上可能为8。因此,如果用户少于8个组,您最终将读取数组gr_mem指向数组开头的末尾。

由于gr_mem所指向的数组以NULL终止,因此发现终止符会告诉您何时完成循环:

for( i=0; grp->gr_mem[i]; i++ ){

答案 1 :(得分:0)

运行您的代码,我发现您的问题在grp->gr_mem[i] == NULL调用中使用之前没有验证strcmp

if (grp->gr_mem[i] == NULL)
  continue;

strcmp呼叫之前添加这些行对我来说是有效的。

此外,不要忘记释放正在使用的内存。我不知道这是否是您的完整代码,但是在这里您应该考虑在while循环中使用free(name)