【问题标题】:How to loop over pointers to structs如何循环指向结构的指针
【发布时间】:2014-09-24 02:55:02
【问题描述】:

我有一个看起来像这样的 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 是一个类型定义的结构,它只是一个标准的struct statfs,添加了三个字段。对函数merge_statfs_structs() 的调用使用tmp 指向的标准结构中的值填充f_tmp 指向的扩展结构。对strcpy() 的三个调用填充了额外的三个字段。

代码编译正常,但我可以从一些 printf 调用中看到程序在调用 free() 时出现段错误。早些时候,我在循环外进行了声明和 malloc 调用,并尝试将两个结构都重置为 NULL,但这是在第二次调用 merge_statfs_structs 时出现段错误。

所以我想我的问题是如何在每次循环中“重置” 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 内部,在调用 free 期间。不幸的是,我的 glibc 不是用调试符号构建的,所以我不能使用 valgrind 来追踪它。

【问题讨论】:

  • 可能您在新字段中写得越界,strcpy 复制直到找到\0。您确定原始字段以\0 结尾吗?有时有固定大小,例如char field[16];
  • 不,我仔细检查了,甚至将 strcpy 更改为 strncpy 并完全匹配源/目标大小。我能够很好地打印这些值。通过 gdb 'backtrace' 运行它并得到:1 0x0000000000401303 in getfsstat_linux (buf=0x7fffffffdf90, bufsize=453452) at src/mount.h:165 第 165 行是对 free() 的第一次调用。
  • 您可能想展示如何定义struct statfs_fullstruct statfs
  • 已经这样做了,谢谢。
  • 请编译所有警告和调试信息 (gcc -Wall -g) 并使用调试器 (gdb)

标签: c pointers memory-management struct


【解决方案1】:

我自己想出来的。将 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 */
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-21
    • 2012-03-28
    • 1970-01-01
    相关资源
    最近更新 更多