目录
结构体类型的声明
结构的的基础知识
结构是一些值的结合,这些值称为成员变量。结构的每个成员可以是不同类型的变量
结构体的声明
以定义一名学生类型为例
struct Stu //学生类型
{
//成员变量
char name[20]; //名字
int age; //年龄
char id[20]; //学号
}s1,s2; //s1和s2是结构体变量
//s1和s2是全局变量
int main()
{
struct Stu s;//创建了一个对象s,s是局部变量
return 0;
}
结构成员的类型
结构的成员可以是标量、数组、指针,甚至是其它结构体
struct X
{
char a;
short b;
double c;
};
struct Stu
{
struct X sb; //结构体的成员可以是另一个结构体
char name[20];
int age;
char id[20];
};
结构体的成员可以是另一个结构体
结构体的初始化
struct X
{
char a;
short b;
double c;
};
struct Stu
{
struct X sb;
char name[20];
int age;
char id[20];
};
int main()
{
struct Stu s = { {'w', 3, 8.14}, "zhangsan", 40, "u2023"};//结构体的初始化
return 0;
}
结构体成员的访问
两个操作符(.)和(->)
(.)操作符
结构变量的成员是通过点操作符(.)访问的,点操作符(.)接受两个操作数
struct X
{
char a;
short b;
double c;
};
struct Stu
{
struct X sb;
char name[20];
int age;
char id[20];
};
int main()
{
struct Stu s = { {'w', 3, 8.14}, "zhangsan", 40, "u2023"};
printf("%c,%d,%lf,%s,%d,%s\n", s.sb.a, s.sb.b, s.sb.c, s.name, s.age, s.id);
return 0;
}
(->) 操作符
另外,在使用结构体指针时,访问结构成员也可以用( -> )操作符
struct X
{
char a;
short b;
double c;
};
struct Stu
{
struct X sb;
char name[20];
int age;
char id[20];
};
int main()
{
struct Stu s = { {'w', 3, 8.14}, "zhangsan", 40, "u2023"};
struct Stu * ps = &s; //结构体指针
printf("%c,%d,%lf,%s,%d,%s\n", (*ps).sb.a, (*ps).sb.b, (*ps).sb.c, (*ps).name, (*ps).age, (*ps).id);
printf("%c,%d,%lf,%s,%d,%s\n", ps->sb.a, ps->sb.b, ps->sb.c, s.name, s.age, s.id);
return 0; //用指针访问的两种方法
}
struct Stu * ps = &s;这句代码,“*”代表ps是指针变量,struct Stu代表指针指向的类型是一个结构体类型
结构体传参
传值调用
int main()
{
struct Stu s = { {'w', 3, 8.14}, "zhangsan", 40, "u2023"};
return 0;
}
现在我们想要写一个函数来打印s的内容
int main()
{
struct Stu s = { {'w', 3, 8.14}, "zhangsan", 40, "u2023"};
print1(s);
return 0;
}
在主函数中,将结构体变量s传入print1函数,因此我们也需要一个结构体变量来接收s
int main()
{
struct Stu s = { {'w', 3, 8.14}, "zhangsan", 40, "u2023"};
print2(&s);
return 0;
}
void print2(struct Stu* m)
{
}
传址调用(传地址)
也可以传入s的地址,比如下述代码
int main()
{
struct Stu s = { {'w', 3, 8.14}, "zhangsan", 40, "u2023"};
print2(&s);
return 0;
}
void print2(struct Stu* m)
{
}
如果要打印某数
struct X
{
char a;
short b;
double c;
};
struct Stu
{
struct X sb;
char name[20];
int age;
char id[20];
};
int main()
{
struct Stu s = { {'w', 3, 8.14}, "zhangsan", 40, "u2023"};
print1(s);
print2(&s);
return 0;
}
void print1(struct Stu m)
{
printf("%c\n", m.sb.a); //打印字符‘w’
}
void print2(struct Stu* ps)
{
printf("%c"\n", ps->sb.a); //打印字符‘w’
}
问:print1和print2哪一个更好?
答案:print2更好
原因:
1.print1是传值调用,实参传给形参,需要形参开辟一块与实参大小相同的空间来接收,在空间上有一些浪费,并且传递也需要时间
2.print2是传址调用,指针变量只有4个字节(32位机)或8个字节(64位机),print2的传参效率更高
3.print1中对m操作不会影响原来的s,print2可以改变s
4.函数传参的时候,参数是需要压栈的。如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,会导致性能的下降
结论:结构体传参的时候,要传结构体的地址
问:什么是函数调用的参数压栈
栈是一种数据结构,有着先进的后出,后进的先出的特点
比如我要存储1 2 3 4 5这五个数据
1 |
2 |
1 |
一个一个往下放
5 |
4 |
3 |
2 |
1 |
只能从下往上放置数据,这个行为叫做压栈
当要删除某一个元素时,只能从上往下删,这就是先进的后出,后进的先出