C语言提供了众多的基本类型,但现实生活中的对象一般都不是单纯的整型、浮点型或字符串,而是这些基本类型的综合体。比如一个学生,典型地应该拥有学号(整型)、姓名(字符串)、分数(浮点型)、性别(枚举)等不同侧面的属性,这些所有的属性都不应该被拆分开来,而是应该组成一个整体,代表一个完整的学生。
在C语言中,可以使用结构体来将多种不同的数据类型组装起来,形成某种现实意义的自定义的变量类型。结构体本质上是一种自定义类型。
结构体标签: 用来区分各个不同的结构体。
成员: 是包含在结构体内部的数据,可以是任意的数据类型。
struct 结构体标签
{
成员1;
成员2;
...
}; // 此处有;号
#include
// 自定义结构体类型
// (1)、普通的结构体定义
// 1、学生结构体
struct student // 结构体标签:用来区分各个不同的结构体的
{
char name[128]; // 成员:包含在结构体内存的数据,可以是任意的类型(甚至包括结构体本身、函数指针等)
char phone[128];
int id;
int gender;
int class;
int score;
int height;
int weight;
int age;
};
// 2、数据节点结构体
struct data_node1
{
int num;
struct data_node1 *p;
};
// (2)、使用typedef给结构体取别名
typedef unsigned long size_t;
typedef struct
{
char name[128];
char phone[128];
int id;
int gender;
int class;
int score;
int height;
int weight;
int age;
}stu_t, *stu_p; // 你可以在此处写这个结构体的别名,没有结构体标签,意味着你只能够使用此处的给它的别名
// (3)、二合一法
typedef struct data_node2
{
int num;
struct data_node2 *p;
}node_t, *node_p;
// 主函数
int main(int argc, char const *argv[])
{
// (1)、普通结构体的定义
struct student qingge; // 信息不够集中(类似于这种写法:int num才好点) 2、数据类型名字固定死了,含义有局限性 3、而且有时会出现歧义
struct data_node1 n1;
// (2)、使用typedef给结构体取别名
stu_t fanggong; // 普通变量
stu_p fzetc; // 指针变量
// (3)、二合一法:
struct data_node2 n2; // 普通变量,普通结构体定义
struct data_node2* n3; // 指针变量,普通结构体定义
node_t n4; // 普通变量,typedef表达
node_p n5; // 指针变量,typedef表达
return 0;
}
结构体跟普通变量一样,涉及定义、初始化、赋值、取址、传值等等操作,这些操作绝大部分都跟普通变量别无二致,只有少数操作有些特殊性。这其实也是结构体这种组合类型的设计初衷,就是让开发者用起来比较顺手,不跟普通变量产生太多差异。
结构体相当于一个集合,内部包含了众多成员,每个成员实际上都是独立的变量,都可以被独立地引用。引用结构体成员非常简单,只需要使用一个成员引用符即可:
结构体.成员
示例代码:
#include
// 自定义结构体类型(学生结构体)
typedef struct stu
{
// int hoppy;
char name[128];
char phone[128];
int id;
int gender;
int class;
int score;
int height;
int weight;
int age;
}stu_t, *stu_p;
// 主函数
int main(int argc, char const *argv[])
{
// (1)、结构体的初始化
// 1、普通初始化
struct stu stu1 = {"qingge", "13430343954", 9127, 1, 2503, 99, 185, 160, 18};
/*
局限性:
结构体增加一个新成员时,有可能会报以下警告
warning: initialization makes integer from pointer without a cast [-Wint-conversion]
overflow in implicit constant conversion [-Woverflow]
....
原因:
不能够指定成员初始化,只能够顺序初始化,初始化的值一定要和类型相匹配,所以后续增加结构体成员
的时候,就会出现错误,不方便后面程序的升级 cfm手游(屎山代码,为什么不重构??)前面的开发,对后面的开发造成了影响
*/
// 2、指定成员初始化
struct stu stu2 =
{
.age = 18, // 初始化的次序可以改变
.class = 2503, // 小圆点 ==》 "当前结构体里面的"什么什么成员
.gender = 1,
.height = 180,
//.id = 9127, // 可以只初始化一部分成员
.name = "fanggogn",
.phone = "110",
.score = 99,
.weight = 150
};
// (2)、结构体的引用
// 1、非字符串的赋值
stu1.age = 20;
stu1.score = 100;
// 2、字符串的赋值
// stu1.phone = "12345678"; // 错误,这句话的意思是,将字符串"12345678"的首字符的地址,赋值给数组(但是数组名不可被赋值)
strcpy(stu1.phone, "12345678"); // 正确,通过strcpy函数,将字符串数据复制到数组的内存空间中
return 0;
}
跟普通变量别无二致,可以定义指向结构体的指针,也可以定义结构体数组。
#include
#include
#include
// 自定义结构体类型(学生结构体)
typedef struct student
{
char name[128];
char phone[128];
int id;
int gender;
int class;
int score;
int height;
int weight;
int age;
}stu_t, *stu_p;
// 初始化结构体函数
// 方法一: struct student *STU_Init(void)
// 方法二: stu_t *STU_Init(void)
// 方法三: stu_p STU_Init(void)
stu_p STU_Init(void) // 返回值为stu_p结构体类型(是一个结构体指针类型)
{
// 1、给结构体申请堆空间
stu_p p = malloc(sizeof(struct student));
if ( p != NULL) // 申请堆空间成功
{
strcpy(p->name, "a");
strcpy(p->phone, "0");
p->id = 0;
p->gender = 0;
p->age = 0;
// ....剩下不写了
}
else
{
free(p); // 申请堆空间失败,释放掉内存(释放资源)
return NULL;
}
// 2、成功,返回指向这个结构体堆空间的内存的地址
return p;
}
// 主函数
int main(int argc, char const *argv[])
{
// (1)、结构体数组
struct student stu[5] = {0}; // 因为是结构体数组,成员数量太多,建议都初始化为0先
// 为结构体数组的第一个成员进行赋值操作
stu[0].age = 18;
stu[0].class = 2503;
strcpy(stu[0].name, "qingge");
// (2)、结构体指针
// 1、这个结构体指针指向的内存空间在栈区
stu_t fanggong = {0};
fanggong.age = 18;
stu_p fzetc = &fanggong;
fzetc->age = 20;
/*
解析:
一般获取结构体成员的时候,使用小圆点(.),则一般这个结构体内存属于这个变量的
一般获取结构体成员的时候,使用箭头(->),则一般这个结构体内存属于这个变量指向的
*/
// 2、这个结构体指针指向的内存空间在堆区
stu_p p = STU_Init();
p->age = 20;
strcpy(p->name, "fanggong");
printf("p->age == %d\n", p->age);
printf("p->name == %s\n", p->name);
return 0;
}
至此,希望看完这篇文章的你有所收获,我是Bardb,译音八分贝,道友,下期见!