老汤回味——C语言结构体和联合

C语言的结构体是不同数据类型的组合,可以实现对数据的整合,可以定义自己的数据集,结构体的定义如下

struct 结构体名 {

        类型 成员名1;

        类型 成员名2;

        ......

};


例如我们定义一个结构体代表用户

struct user {

        char username[255];

        char password[255];

扫描二维码关注公众号,回复: 1852479 查看本文章

        int age;

};


下面看一段代码,如何使用上面定义的结构体,这里使用了头文件stdio.h(printf函数)和string.h(memset,strncpy函数)

struct user user1 = {"user1", "123456", 20};
struct user user2;
memset(&user2, 0, sizeof(user2));
strncpy(user2.username, "user2", sizeof(user2.username) - 1);
strncpy(user2.password, "123456", sizeof(user2.password) - 1);
user2.age = 30;

printf("user1:\n");
printf("username=%s, password=%s, age=%d\n", user1.username, user1.password, user1.age);

printf("user2:\n");
printf("username=%s, password=%s, age=%d\n", user2.username, user2.password, user2.age);

user1是直接在定义时对结构体进行初始化,这样做的好处是方便;user2是更加严谨的使用方式,首先定义一个结构体变量user2,之后使用menset对结构体占用的内存空间清零,注意:C语言不会自动初始化结构体的变量。接下来,使用字符串安全拷贝函数strncpy对字符串进行拷贝。我们最多使用字符串数组大小减1的空间,预留一个/0,防止字符串没有终结符。可以看到,访问结构体变量的字段时,使用.运算符。程序的运行结果:

user1:
username=user1, password=123456, age=20
user2:
username=user2, password=123456, age=30


结构体也可以定义结构体指针,如

struct user *puser;


但是user结构体指针必须指向一个user结构体才可以访问,访问字段时使用->操作符,如:

puser->username


在实际使用中,我们常常使用C语言的typedef关键字,给结构体类型起一个别名,方便我们的使用,如上面的结构体我们可以这样定义:

typedef struct {
        char username[255];
        char password[255];
        int age;
} USER, *PUSER;


使用USER定义结构体变量,使用PUSER定义结构体指针,下面的代码逻辑类似于之前的代码,但我们使用了typedef后的结构体

USER user3 = {"user3", "123456", 10};
PUSER user4 = (PUSER)malloc(sizeof(USER));
memset(user4, 0, sizeof(USER));
strncpy(user4->username, "user4", sizeof(user4->username) - 1);
strncpy(user4->password, "123456", sizeof(user4->password) - 1);
user4->age = 40;

printf("user3:\n");
printf("username=%s, password=%s, age=%d\n", user3.username, user3.password, user3.age);

printf("user4:\n");
printf("username=%s, password=%s, age=%d\n", user4->username, user4->password, user4->age);

free(user4);
这里需要强调的主要是user4的相关代码,我们使用PUSER定义了一个名为user4的结构体指针,并使用stdlib.h中的malloc函数进行了动态内存分配,分配了一块大小为sizeof(USER)的空间,之后使用memset初始化内存,这里注意和之前的user2对比,user4本身已经是指针了,所以menset直接传递即可,而user2则需要取地址。最后记得调用free释放动态分配的内存空间。运行结果如下:

user3:
username=user3, password=123456, age=10
user4:
username=user4, password=123456, age=40


可以看到,结构体实现了数据的打包封装,是C语言实现面向对象开发的有力语法工具,后面我会写一篇文章结合自己的使用经验给大家讲讲如何用C语言写出良好的面向对象的代码。


再回到本文主题,下面我们看一下联合,联合是一块内存,我们可以使用它利用一块内存保存不同类型的数据,例如,一块大小为4字节的空间,我们可以用它来定义一个3个字符(加一个/0)的字符串数组,也可以定义一个4字节的整型变量,只是这块内存中的数据的解释方式不同,下面看一段使用union的代码:

union myunion {
        char a[4];
        int b;
};

int main(void) {
        union myunion u;
        memset(&u, 0, sizeof(u));
        strncpy(u.a, "123", 3);

        printf("u.a = %s\n", u.a);
        printf("u.b = %d\n", u.b);

        printf("&u.a = %p\n", u.a);
        printf("&u.b = %p\n", &u.b);
        printf("sizeof(u)=%ld\n", sizeof(u));

        return 0;
}

运行结果为

u.a = 123
u.b = 3355185
&u.a = 0x7ffe52e34614
&u.b = 0x7ffe52e34614
sizeof(u)=4


可以看到,字符串赋值为123,对应的ASCII码十六进制分别为0x31、0x32、0x33,由于我的Linux是小端,四个字节放在内存中的就是0x00333231,这个数值转换为十进制,就是3355185,最后打印了两个字段的地址,发现是同一个起使地址,联合的大小只有4字节。


猜你喜欢

转载自blog.csdn.net/yjp19871013/article/details/80781321