结构体
后面的自定义类型会更加深入的讲这部分内容。
char,int,float,double等,都只能描述单一变量。所以C语言就发明了结构体用于描述复杂对象。
结构体的定义
结构体的语法
结构体是值的集合,这些值被称为成员变量。结构体的每个成员可以具有不同类型。
c
struct tag //结构体名称
{
member-list;//成员列表
}variable-list;//变量列表(全局变量)在结构体声明的{}后面创建的变量是全局变量,如果我们只想创建局部变量,就在mian函数里创建。
c
struct tag // 这个叫结构体类型名,或者叫结构体类型
struct S s = { "abc", "man", 3.1415 }; // 这个用结构体定义的变量,叫结构体变量。结构体的声明
结构体用于描述复杂对象,必然有多个成员变量。结构体成员的类型可以是任意类型,也可是其他结构体。
c
struct book
{
char name[20];//书名
char author[15];//作者
float price;//价格
}b1,b2; //全局变量
struct point
{
int x;
int y;
};当然也可以把结构体类型声明在函数内部,此时仅函数内部可使用。
c
int main() {
struct book {
char name[20];
char author[15];
float price;
}b1, b2;
struct book b;
}还可以使用typedef对类型重命名,使用typedef就不能在声明后面直接创建全局变量。
c
typedef struct human {
char name[20];
int age;
char sex[10];
char id[20];
}human;
struct human man; //1.
human man; //2.
只是将struct human取名叫human。本质都是类型是不占用空间的,只有变量才会占用空间。
结构体的使用
c
struct book {
char name[20];
char author[15];
float price;
}b1, b2; // 全局变量仅定义
struct book b3 = { 0 }; // 全局变量定义和初始化c
int main() {
struct human man1 = { "张三",20,"女装大佬","20203100" }; // 局部变量定义和初始化
point p1 = { 1,2 };
return 0;
}c
struct S {
int a;
char c;
double d;
};
struct T {
struct S s;
char name[20];
int num;
};
int main() {
struct T t = { {10, 'x', 1.00}, "yourfriendyo", 21 }; // 嵌套定义和初始化
}结构体成员访问
.操作符
成员通过操作符.进行访问。.操作符具有两个操作数,左边是结构体变量名,右边是结构体成员名。
c
int main() {
struct T t = { {10, 'x', 1.00}, "yyx", 21 };
printf("%d %c %lf %s %d\n", t.s.a, t.s.c, t.s.d, t.name, t.num);
}
s是t的成员变量,a,c,d分别是s的成员变量,所以是t.s.a,t.s.c,t.s.d。
->和*操作符
有时须通过结构体的指针访问成员,就需要操作符->。
c
struct T* pt = &t;
printf("%d %c %lf %s %d\n", (*pt).s.a, (*pt).s.c, (*pt).s.d, (*pt).name, (*pt).num);
printf("%d %c %lf %s %d\n", pt->s.a, pt->s.c, pt->s.d, pt->name, pt->num);- 第一种是对指针解引用获得结构体变量,再通过
.访问。 - 第二种
->是专门在访问结构体时使用指针的方法,更高效。
结构体作参数
c
struct S {
char arr[100];
int num;
float f;
};
void Print(struct S ss) {
printf("%c %c %c %d %f\n", ss.arr[0], ss.arr[1], ss.arr[2], ss.num, ss.f);
}
void Print2(struct S* ps) {
printf("%c %c %c %d %f\n", ps->arr[0], ps->arr[1], ps->arr[2], ps->num, ps->f);
}
int main() {
struct S s = { {'1','2','3','4'}, 22, 3.14};
Print1(s);
Print2(&s);
}结构体作为函数参数,此时传址调用和传址调用就会有很大区别。
- 传值调用,
s本身占用空间很大,又创建一份一样大的形参拷贝,时间空间上浪费非常严重。 - 传址调用,无论
s占用空间有多大,都只传4个字节的地址。
故结构体传参通常使用传址调用。