本文详解C语言的结构体初始化的7大类型,基础永远直接花85%时间去好好学习,小而汇多,建议收藏!
总的来说,如下:
类型①老祖宗:最传统的使用②简化 1:变量名紧贴类型后③简化 2:集中初始化④简化 3:结构体中直接初始化⑤简化 4:使用 typedef 脱离 struct⑥简化 5:匿名结构体⑦结构体数组初始化
下面详细讲解之:
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;
#endif
void 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种类型的初始化方式,让我们再来回顾回顾:
结构体初始化回顾1.结构体初始化方式从传统的老祖宗,历经了5大简化,分别是哪五大简化?2.给出简化1-变量名紧贴类型后的代码形式3.给出简化2-集中初始化方式的代码形式4.给出简化3-结构体中直接初始化的代码形式5.给出简化4-使用typedef脱离struct的代码形式6.给出简化5-匿名结构体的代码形式如果您不能对着这个表格给出每一项的讲解,那么,再把上面的内容好好复习一遍吧!
答案见评论区,欢迎大家讨论~
关于小希
😉嘿嘿嘿,我是小希,专注C语言、Linux内核和云计算领域。
下面是我的微信,期待与您学习交流!
(加微信请备注哦)~
小希的座右铭:别看简单,简单也是难。别看难,难也是简单。我的文章都是讲述简单的知识,如果你喜欢这种风格:
不妨关注、评论、转发,让更多朋友看到哦~~~🙈
下一期想看什么?在评论区留言吧!我们下期见!