目录
1.为何需要结构体,什么是结构体 ?
对于日期,分数,数字,名字这些简单的对象我们可以用整形,浮点型,字符进行描述。而对于一个人(例如:学生)这种复杂对象时,我们难以仅仅用整形,浮点型进行描述,往往我们需要多个数据类型整合起来描述。
例如:学生,我们用姓名,年龄,性别,成绩描述
姓名——>字符数组
年龄——>整形
性别——>字符数组
成绩——>浮点数
这时候,我们就要引出
结构体的概念:
结构是一些值的集合,这些值成为成员变量。结构的每个成员可以是不同类型的变量。
2.结构体的声明
在main函数前面进行声明
注:变量列表里也可以不创建变量
依然以学生为例,
struct stu {
char name[20];//名字
int age;//年龄
char sex[10];//性别
float score;//成绩
};//不创建变量
struct stu {
char name[20];//名字
int age;//年龄
char sex[10];//性别
float score;//成绩
}s1,s2;//创建变量
注:s1,s2是通过struct stu类型创建的变量,s1,s2是全局变量
注:结尾有分号
struct stu {
char name[20];//名字
int age;//年龄
char sex[10];//性别
float score;//成绩
}s1,s2;
//s1,s2为全局变量
int main() {
struct stu s3; //注意:struct stu是结构体类型,此处struct不能省略
struct stu s4;
//此处s3,s4为局部变量
return 0;
}
注:s3,s4是局部变量
如果你感觉定义时麻烦,我们也可以简化一下,用typedef类型重定义,操作如下:
struct stu {
char name[20];//名字
int age;//年龄
char sex[10];//性别
float score;//成绩
}s1,s2;
typedef struct stu stu;
int main() {
stu s3;
stu s4;
//此处s3,s4为局部变量
return 0;
}
也可以在定义这个结构体时,对整个结构体类型重定义 ,操作如下
typedef struct stu {
char name[20];//名字
int age;//年龄
char sex[10];//性别
float score;//成绩
}stu;//注意这不是变量
int main() {
stu s3;
stu s4;
return 0;
}
特殊的声明:
在结构体声明时可以不完全声明:
//匿名结构体类型
struct {//省去了结构体标签
char name[20];
int age;
char sex[10];
float score;
}x;
此结构体只能用一次
struct {
char name[20];
int age;
char sex[10];
float score;
}x;
struct {
char name[20];
int age;
char sex[10];
float score;
}*p;
int main() {
p = &x;
}
若在主函数中p=&x,编译器报错
原因:匿名结构体成员如果一样,在编译器看来也是不同的类型
结构体变量定义和初始化
我们继续以学生举例:
struct stu {
char name[20];
int age;
char sex[10];
float score;
}s1;
int main() {
struct stu s2;
return 0;
}
这是定义了一个全局变量s1,和局部变量s2
初始化:定义变量的同时赋初值
这是初始化
struct stu {
char name[20];
int age;
char sex[10];
float score;
}s1 = {"zhangsan",18,"male",91}; //初始化
int main() {
struct stu s2 = {"lisi",19,"female",92}; //初始化
return 0;
结构体也可以嵌套初始化
struct subject {
float math;
float English;
};
struct stu {
char name[20];
int age;
char sex[10];
struct subject stu;
};
int main() {
struct stu s = { "lisi",19,"female",{90,91} };//注意括号中的括号
return 0;
}
结构体自引用
struct node {
int data;
struct node* next;
};
指针指向下一个同类型的自己
结构体成员的访问
访问结构体成员有两种方式: 第一个是用操作符 . 第二个是用操作符 ->
.操作符
形式为:结构体变量 . 结构体成员
#include<stdio.h>
struct stu {
char name;
int age;
char sex[10];
};
int main() {
struct stu s = {'w',19,"female"};
printf("%c\n", s.name);
printf("%d\n", s.age);
printf("%s\n",s.sex);
return 0;
}
也可以对已初始化的变量进行修改
#include<stdio.h>
struct stu {
char name;
int age;
char sex[10];
};
int main() {
struct stu s = { 'w',19,"female" };
s.name = 'c'; //修改
printf("%c\n", s.name);
printf("%d\n", s.age);
printf("%s\n", s.sex);
return 0;
}
->操作符
形式为:结构体指针 -> 结构体成员
#include<stdio.h>
struct stu {
char name;
int age;
char sex[10];
};
void print1(struct stu* stu) {
printf("%c\n", stu->name);
printf("%d\n", stu->age);
printf("%s\n", stu->sex);
}
int main() {
struct stu s = { 'w',19,"female" };
print1(&s);
return 0;
}
结构体传参
这里涉及到两种方式:一种是传址,一种是传值
传址:
#include<stdio.h>
struct stu {
char name;
int age;
char sex[10];
};
void print1(struct stu* stu) {
printf("%c\n", stu->name);
printf("%d\n", stu->age);
printf("%s\n", stu->sex);
}
int main() {
struct stu s = { 'w',19,"female" };
print1(&s);
return 0;
}
传值 :
#include<stdio.h>
struct stu {
char name;
int age;
char sex[10];
};
void print1(struct stu stu) {
printf("%c\n", stu.name);
printf("%d\n", stu.age);
printf("%s\n", stu.sex);
}
int main() {
struct stu s = { 'w',19,"female" };
print1(s);
return 0;
}
对比以上两种方式,我们应该尽量选择第一种传址
原因:函数传参时,参数是需要压栈的。如果传递一个结构体对象时,结构体过大,参数压栈的系统开销比较大,导致性能下降。
通俗来讲,传值时,实参传递给形参,形参是其一份临时拷贝,结构体过大导致拷贝的形参也过大,占用空间是原来的2倍,相比于传址占用的内存空间更大