【C语言】结构体初始化方式总结
总的来说,如下:
下面详细讲解之:
1.最传统的使用
struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/};struct person_ person;
这里struct person_
写在一起,作为一个类型名(person_也称为类型标签
),去声明变量,如struct person_ person;
声明了一个struct person_类型的变量person
(就类似于int a
)。
2.简化1——变量名紧贴类型后
上面的声明语句struct person_ person;
是不是有点麻烦?可以简写!即在结构体类型名后面直接声明变量
即可!
struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/} person;
如上,这里的写法和①中是完全等价的,但是简洁了不少!
同时,变量名可以声明多个、多种类型
!如下:
struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/} person, person1[40], *person2;
这里声明了结构体
、结构体指针
、结构体数组
!
3.简化2——集中初始化
平时我们初始结构体
的方式常常如下:
struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/} person;person.age = 12;sprintf(person.name, \"%s\", \"Alice\");sprintf(person.hobby[0], \"eating\");sprintf(person.hobby[1], \"running\");
显然这里的成员初始化使用了3个语句
,略显繁杂,有没有简便的方式?比如化为一条语句?还真有!
在C99中,允许这样初始化结构体:
struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/};struct person_ person1={.age=12,.name=\"Alice\",.hobby={\"eating\",\"running\"}};
注意这里的精髓,使用.成员运算符来完成的,将多条语句化为一条了,很简洁,当然,你也可以省略.age等成员,直接像下面这样:
person = {12, \"Alice\", {\"eating\", \"running\"}};
但是不太明显,并且必须把每一个按照顺序来完成,个人推荐使用上面的显式的写法!
4.简化2——结构体中直接初始化
上面的各种都只是声明,不是初始化,这意味着在后面还要单独初始化,略显麻烦
。
可不可以直接初始化呢?当然可以!
类似于
int a;a=5;
显然这很麻烦!这里这里讲解的就是int a=5;
在结构体中的应用。
如下,这就是直接初始化的样式,注意一定使用=
。
struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/} person = { \"EthanYankang\", 100, {\"run\", \"cycle\", \"code\"},//注意这里指针指向的.rodata中的数据,所以并不是野指针!}, person1, *person2, person3 = { .age = 23, .name = \"Alice\", .hobby = {\"writting\", \"take photos\"}};
本例应该是比较综合的了!
5.简化3——使用typedef脱离struct
注意到,上面的结构体类型必须使用struct person
这两个(一个关键词、一个标签)的组合来完成变量的声明,写两个单词毕竟很繁琐,可不可以像int一样,变为一个单词的类型方便使用呢?当然可以——使用typedef
等同即可。
如下,将P_person
等同于struct person_
,后面就可以使用P_person
来声明变量了,例如P_person person
。
typedef struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/} P_person;P_person person;
当然,我们也可以等价struct person_*
为P_person
,这种形式如下:
(事实上这也是我们使用频次最多的形式)
typedef struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/} *P_person;P_person person;
可以看到,仅仅是在P_person前面加上一个*即可!注意不是在struct person_后面加!
6.简化4——匿名结构体
显然,上面的所有声明、初始化都新增了一种类型struct person_(或者P_person),我们可不可以不新增类型
完成结构体的声明、初始化呢?当然可以——使用匿名结构体
。
如下,结构体phone1、2会在它的生命周期结束后终止!
struct{ int price; char *name;} phone1 = { 8000, \"HUAWEI\",},phone2={ .price=3000, .name=\"XIAOMI\"};
注意这种形式中,没有类型名,只有变量名!
这种形式常常用于只使用该结构体一次的情况!因为不需要复用
,也就不必要新增类型!
7.结构体数组初始化
结构体数组的初始化只不过在增加一层维度罢了!其余的和上面的完全一致,只不过这里使用了数组罢了!这里仅不在赘述!
struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/} person4[3]={ {.age=1,.name=\"A\",.hobby={\"h1\",\"h2\"}}, {.age=2,.name=\"B\",.hobby={\"h3\",\"h4\"}}, {.age=3,.name=\"C\",.hobby={\"h5\",\"h6\"}}};
完整源码
#include #include #include #if 0/**写法1 * data descp:传统的结构体写法 */struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/};struct person_ person1;#endif/*其中,person_是结构体标签,要求和struct一起用,表明这是一个结构体类型,例如声明一个变量:struct person_ p后面的person是一个结构体实例,这是一种简便写法。*/#if 0/**写法2 * data descp: 简洁写法1-变量紧贴类型后 */struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/} person2; /*这是一个变量,类型是struct person_*//*可以看到,这样写,就省略了在单独来一次struct person_ person,方便了一些*/#endif#if 0/**写法3 * data descp: 简洁写法2-变量紧贴类型后,并初始化 */struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/} person3 = { \"EthanYankang\", 100, {\"run\", \"cycle\", \"code\", NULL},};#endif/*当然了,你也可以混着写,如下*/struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/} person4 = { \"EthanYankang\", 100, {\"run\", \"cycle\", \"code\"},}, person5, *person6, person7 = { .age = 23, .name = \"Alice\", .hobby = {\"writting\", \"take photos\"}}, person8[3] = {{.age = 1, .name = \"A\", .hobby = {\"h1\", \"h2\"}}, {.age = 2, .name = \"B\", .hobby = {\"h3\", \"h4\"}}, {.age = 3, .name = \"C\", .hobby = {\"h5\", \"h6\"}}};#if 0/**写法4 * data descp: 写法3——简化类型名 *//*注意到,我们前面要声明一个结构体,都必须使用struct person_这样的写法,是不是有时候太麻烦了?能不能像int a一样,仅仅使用一个标签就声明了呢?当然可以。*//*注意到,这里使用struct person_是因为struct是一个变类型大小的数据类型,不同的结构体有不同的大小,所以为了区分是哪一个结构体,必须在后面紧跟一个标签,例如struct person_表明,这是人结构体,大小为20B。int a可以成功的声明的原因是所有int都是4字节大小的,没有歧义。*//*我们通过typedef定义类型,将struct person_打包带走。声明P_person person就等同于struct person_,怎么样,是不是方便了很多!*/// /*另外,还可以使用指针的方式,更加灵活,如下.事实上,这也是我们最多的时候使用的!*/// typedef struct person_// {// char name[20];// int age;// char *hobby[20]; /*这是一个数组,而非指针*/// } *P_person;// P_person person;typedef struct person_{ char name[20]; int age; char *hobby[20]; /*这是一个数组,而非指针*/} P_person;P_person person9;#endifvoid print(struct person_ person){ printf(\"size:%d\\n\", sizeof(person)); printf(\"name:%s\\n\", person.name); printf(\"age:%d\\n\", person.age); for (int i = 0; person.hobby[i] && i < 20; i++) { printf(\"%s\\n\", person.hobby[i]); } printf(\"\\n\");}int main(){#if 0{ person1.age = 100; sprintf(person1.name, \"%s\", \"EthanYankang\"); for (int i = 0; i < 20; i++) { /*为每一个指针分配100个字节,完全足够了*/ person1.hobby[i] = (char *)malloc(sizeof(char) * 100); sprintf(person1.hobby[i], \"%s%d\", \"hobby-\", i); } // person1.hobby= /** * data descp: 这里一定要为person2分配内存,因为指针没有指向的内容,是野指针。! * (那为什么char*arr=\"NULL\"可以呢?因为这是指向的rodate段里面的数据地址(\"NULL\"编译器会为字面量默认分配内存)!) */}#endif#if 1 person6 = (struct person_ *)malloc(sizeof(struct person_)); person6->age = 20; sprintf(person6->name, \"%s\", \"NIUMA\"); // person6->hobby = {\"A\", \"B\", \"C\"}; /*数组除了初始化之外,不可以直接赋值!只能采用元素遍历的方式!这个你又别忘记了!*/ person6->hobby[0] = \"xidian\"; person6->hobby[1] = \"985\"; // person6->name = strdup(\"NIUMA\");//为什么这里使用strdup不行?因为strdup是在堆上分配内存的,针对数组,但是这里的name是字符数组,不能通过strdup来分配内存!也不能通过直接=赋值,只能通过覆写的方式来完成。#endif // print(person1); print(*person6); struct { int price; char *name; } phone = { 8000, \"HUAWEI\", }, p = {.price = 3000, .name = \"XIAOMI\"}; printf(\"price:%d,name:%s\\n\", phone.price, phone.name); printf(\"price:%d,name:%s\\n\", p.price, p.name); struct person_ person; person.age = 12; sprintf(person.name, \"%s\", \"Alice\"); person.hobby[0] = \"eating\"; person.hobby[1] = \"running\"; struct person_ person1 = {.age = 12, .name = \"Alice\", .hobby = {\"eating\", \"running\"}}; print(person); print(person1);}
结尾
好了这就是结构体常见的7种类型的初始化方式,让我们再来回顾回顾:
如果您不能对着这个表格给出每一项的讲解,那么,再把上面的内容好好复习一遍吧!
答案见评论区,欢迎大家讨论~
关于小希
😉嘿嘿嘿,我是小希,专注C语言
、Linux内核
和云计算
领域。
下面是我的微信,期待与您学习交流!
(加微信请备注哦)~
小希的座右铭:
别看简单,简单也是难。别看难,难也是简单
。我的文章都是讲述简单的知识,如果你喜欢这种风格:
不妨关注、评论、转发,让更多朋友看到哦~~~🙈
下一期想看什么?在评论区留言吧!我们下期见!