struct的初始化,拷贝及指针成员的使用技巧

    技术2026-03-27  9

    struct是C中重要的ADT。但是在一般讲C的书中,往往只介绍了struct的定义、顺序初始化及位域。 本文将笔者曾经用到的、看到的知识点罗列出来,与大家分享。 为了方便后面的介绍,先定义一个struct类型:         struct User         {             int id;             //id             char name[100];     //user name             char *home;         //home directory             int passwd;         //password         }; 1 初始化 struct数据有3中初始化方法:顺序,C风格及C++风格的乱序。 1)顺序 这种方法很常见,在一般的介绍C的书中都有介绍。顺序初始化的特点是: 按照成员定义的顺序,从前到后逐个初始化;允许只初始化部分成员;在被初始化的成员之前,不能有未初始化的成员;未显示初始化的自动设为0。 eg:         struct User oneUser = {10, "Lucy", "/home/Lucy"}; 初始化之后,oneUser各个成员的值为:         oneUser.id = 10;         oneUser.name = "Lucy";         oneUser.home = "/home/Lucy";         oneUser.passwd = 0; 2)乱序(C风格) 顺序的缺陷是必须按成员定义的顺序逐个初始化,不能间隔。而乱序的方式则很好的解决了这个问题,因为这种方式是按照成员名进行。 eg:         struct User oneUser = {                                .name = "Lucy",                                .id = 10,                                .home = "/home/Lucy"                               }; 3)乱序(C++风格) C++风格的乱序初始化方式跟C风格的一样,只是它更常用在C++代码里。 eg:         struct User oneUser = {                                name:"Lucy",                                id:10,                                home:"/home/Lucy"                               }; 不论是哪种方式,都允许只初始化部分成员;未被初始化的成员默认为0(指针类型的成员默认为NULL)。两种乱序初始化方法,既可以用在C代码中,也可以用在C++代码中。 2 拷贝 struct有两种拷贝方式,一是直接赋值(=),另一种是用 memcpy等库函数实行内存拷贝。 eg:         struct Temp a, b;         //Set value to members of b         a = b;         memcpy(&a, &b, sizeof(a)); 不管是哪种拷贝方式,都是将以&b开始的,大小为sizeof(struct Temp)的内存区域中的数据,简单地复制到以&a开始的,同样大小的内存区域。所以,这两种方式与按成员赋值是等价的:         a.id = b.id;         a.name = b.name;         a.home = b.home;         a.passwd = b.passwd; 由此,我们不难看出,上面两种拷贝方式都属于浅拷贝。              3 指针成员的两种使用技巧 1) 为多个指针成员同时分配内存 如果一个struct中有多个指针类型的成员,我们通常需要为每个指针逐个成员分配内存空间,并在使用完时释放它们;这样频繁调用 malloc/free,难免让人生厌。如果在分配内存之前,每个指针所指向内存区域的大小是确定的,那么,我们可以为所有指针一次性分配内存区域;并在使用完后,一次性释放。 eg:        struct Inode        {           int id;           char *file;           int fie_len;           char *path;           int path_len;           char *user;           int user_len;        };        struct Inode data = {                             .file_len = X,                             .path_len = Y,                             .user_len = X                             };        //Allocate memory        data.file = (char *)malloc(data.file_len + data.path_len + data.user_len);        data.path = data.file + data.file_len;        data.user = data.path + data.path_len;        //User        ...        //Free memory        free(data.file); 2)变长数组的另类实现 将下面的定义        struct File        {           TypeA dataA;           ......           char *data;           TypeN dataN;                }; 改成:        struct File        {           TypeA dataA;           ......                   TypeN dataN;             char data[0];             }; 即将指针成员换成大小为0的一维数组, 作为struct的最后一个成员(数据结构的可变部分必须作为最后一个成员),有两个优点: (1) 在紧邻struct处为data分配内存区域,这样在分配内存后无须为data赋值; (2) 利用数组的特性,以指针的方式通过越界访问data数组外的内存区域。 eg:        struct File *pVar = (struct File *)malloc(sizeof(struct File) + DATA_LEN);        strncpy(pVar->data, "Source data", DATA_LEN);

    最新回复(0)