如何循环指向结构的指针

时间:2014-09-24 02:55:03

标签: c pointers memory-management struct

我有一个看起来像这样的for循环:

for (i2 = 0; i2 < n_lines; i2++) {
    statfs_full *f_tmp;
    f_tmp = malloc(sizeof(statfs_full));
    struct statfs *tmp;
    tmp = malloc(sizeof(statfs));

    statfs(fse[i2].fs_file, tmp);

    merge_statfs_structs(tmp, &f_tmp);
    strcpy(f_tmp->f_fstypename, fse[i2].fs_vsftype);
    strcpy(f_tmp->f_mntonname, fse[i2].fs_file);
    strcpy(f_tmp->f_mntfromname, fse[i2].fs_spec);

    free(f_tmp); 
    free(tmp); 

它是更大功能的一部分。 statfs_full是一个typdef'ed结构,只是一个标准struct statfs,添加了三个字段。对函数merge_statfs_structs()的调用使用tmp指向的标准结构中的值填充f_tmp指向的扩展结构。对strcpy()的三次调用填充了额外的三个字段。

代码编译好了,但我可以从一些printf调用看到该程序在free()的调用中是segfaulting。之前我在循环外部进行了声明和malloc调用,并尝试将两个结构重置为NULL,但这是第二次调用merge_statfs_structs时的segfaulting。

所以我想我的问题是如何通过循环每次'重置'f_tmp和tmp指向的结构?

编辑:添加merge_statfs_structs的来源以防万一...

int merge_statfs_structs(struct statfs *buf, statfs_full **buf_full) {
    int i;
    (*buf_full)->f_type    = buf->f_type;
    (*buf_full)->f_bsize   = buf->f_bsize;
    (*buf_full)->f_blocks  = buf->f_blocks;
    (*buf_full)->f_bfree   = buf->f_bfree;
    (*buf_full)->f_bavail  = buf->f_bavail;
    (*buf_full)->f_files   = buf->f_files;
    (*buf_full)->f_ffree   = buf->f_ffree;
    (*buf_full)->f_fsid    = buf->f_fsid;
    (*buf_full)->f_namelen = buf->f_namelen;
    (*buf_full)->f_frsize  = buf->f_frsize;

    for (i = 0; i < 5; i++)
        (*buf_full)->f_spare[i]   = buf->f_spare[i];
    return 0;
}

编辑2:添加mounted_fs_entrystruct statfs_full的定义:

#define FS_TYPE_LEN      90
#define MNT_FLAGS_LEN    256

typedef struct _mounted_fs_entry {
    char fs_spec[PATH_MAX];           /* device or special file system path */
    char fs_file[PATH_MAX];           /* mount point */
    char fs_vsftype[FS_TYPE_LEN];     /* file system type */
    char fs_mntops[MNT_FLAGS_LEN];    /* mount flags */
    int  fs_freq;                     /* dump */
    int  fs_passno;                   /* pass */
} mounted_fs_entry;

#if __WORDSIZE == 32
#define __WORD_TYPE int
#else /* __WORDSIZE == 64 */
#define __WORD_TYPE long int
#endif

typedef struct _statfs_full {
    __WORD_TYPE  f_type;             /* type of filesystem */
    __WORD_TYPE  f_bsize;            /* optimal transfer block size */
    fsblkcnt_t   f_blocks;           /* total data blocks in filesystem */
    fsblkcnt_t   f_bfree;            /* free blocks in fs */
    fsblkcnt_t   f_bavail;           /* free blocks available to unprivileged user */
    fsfilcnt_t   f_files;            /* total file nodes in filesystem */
    fsfilcnt_t   f_ffree;            /* free file nodes in fs */
    fsid_t       f_fsid;             /* filesystem id */
    __WORD_TYPE  f_namelen;          /* maximum length of filenames */
    __WORD_TYPE  f_frsize;           /* fragment size (since Linux 2.6) */
    __WORD_TYPE  f_spare[5];

    /* these extra fields add path info as in the *BSD versions of statfs() */
    char f_fstypename[FS_TYPE_LEN];  /* fs type name */
    char f_mntonname[PATH_MAX];      /* directory on which mounted */
    char f_mntfromname[PATH_MAX];    /* mounted file sytem */
} statfs_full; 

我自己没有定义struct stafs,它在/usr/include/sys/statfs.h中定义,或者您只能man statfsmounted_fs_entry是for循环中fse[i2]引用的结构。如果你想看一下,我在github here上有整个文件。

我在gdb中一直在玩这个,在免费调用期间,段内故障发生在glibc中。不幸的是我的glibc不是用调试符号构建的,所以我不能用valgrind来跟踪它。

1 个答案:

答案 0 :(得分:0)

自己想出来。移动了循环外的malloc / free调用,并在定义结构时删除了typedef语句。现在工作得很好。这是更新的代码(没有删除错误检查):

struct statfs_ext *sas = malloc(sizeof(struct statfs_ext) * n_lines);

struct statfs_ext *f_tmp;
f_tmp = malloc(sizeof(struct statfs_ext));
if (f_tmp == NULL) {
    perror("unable to malloc");
    exit(EXIT_FAILURE);
}

struct statfs *s_tmp;
s_tmp = malloc(sizeof(struct statfs));
if (s_tmp == NULL) {
    perror("unable to malloc");
    exit(EXIT_FAILURE);
}

for (i2 = 0; i2 < n_lines; i2++) {

    if (statfs(fse[i2].fs_file, s_tmp) != 0) {
        perror("statfs() failed");
        continue; /* might not be fatal */
    }
    merge_statfs_structs(s_tmp, &f_tmp);

    strncpy(f_tmp->f_fstypename, fse[i2].fs_vsftype, FS_TYPE_LEN);      
    strncpy(f_tmp->f_mntonname, fse[i2].fs_file, PATH_MAX);
    strncpy(f_tmp->f_mntfromname, fse[i2].fs_spec, PATH_MAX);

    sas[i2] = *f_tmp;

}

free(s_tmp);
free(f_tmp);

结构定义:

#define FS_TYPE_LEN      90
#define MNT_FLAGS_LEN    256

struct mounted_fs_entry {
    char fs_spec[PATH_MAX];           /* device or special file system path */
    char fs_file[PATH_MAX];           /* mount point */
    char fs_vsftype[FS_TYPE_LEN];     /* file system type */
    char fs_mntops[MNT_FLAGS_LEN];    /* mount flags */
    int  fs_freq;                     /* dump */
    int  fs_passno;                   /* pass */
};

#if __WORDSIZE == 32
#define __WORD_TYPE int
#else /* __WORDSIZE == 64 */
#define __WORD_TYPE long int
#endif

struct statfs_ext {
    __WORD_TYPE  f_type;             /* type of filesystem (see below) */
    __WORD_TYPE  f_bsize;            /* optimal transfer block size */
    fsblkcnt_t   f_blocks;           /* total data blocks in filesystem */
    fsblkcnt_t   f_bfree;            /* free blocks in fs */
    fsblkcnt_t   f_bavail;           /* free blocks available to unprivileged user */
    fsfilcnt_t   f_files;            /* total file nodes in filesystem */
    fsfilcnt_t   f_ffree;            /* free file nodes in fs */
    fsid_t       f_fsid;             /* filesystem id */
    __WORD_TYPE  f_namelen;          /* maximum length of filenames */
    __WORD_TYPE  f_frsize;           /* fragment size (since Linux 2.6) */
    __WORD_TYPE  f_spare[5];

    /* these extra fields add path info as in the *BSD versions of statfs() */
    char f_fstypename[FS_TYPE_LEN];  /* fs type name */
    char f_mntonname[PATH_MAX];      /* directory on which mounted */
    char f_mntfromname[PATH_MAX];    /* mounted file sytem */
};