1、结构体的声明
1.1、结构的基础知识
结构是一些值得集合,这些值称为成员变量。结构的每一个成员可以是不同类型的变量。
char、short、int、long、long、float、double是内置类型。
比如说,我们想要描述单一的成绩,身高我们直接用int类型就可以搞定了。
但是如果我想要描述人的特征,那这个就有点复杂,因为人包含:身高,性别,电话,名字等等信息。
书包含:书名,作者,定价,书号。
而针对此复杂对象的描述就需要用到结构体。
1.2、结构的声明
struct Peo
{
char name[20];
char tele[12];
char sex[5];
int high;
};
//或者下面的写法
struct Peo
{
char name[20];
char tele[12];
char sex[5];
int high;
}p1,p2;
//p1,p2是使用struct Peo结构体类型创建的2个变量/对象。
//并且p1,p2是全局变量。
//我们常说尽量不要创建全局变量,所以我们在使用struct Peo创建变量时,通常不这样创建。
//我们通常这样创建结构体变量(如下:)
int main()
{
struct Peo p1; //结构体变量的创建
return 0;
}
1.3、结构成员类型
结构的成员可以是变量,数组,指针,甚至是其它结构体。
1.4、结构体变量的定义和初始化
有了结构体类型,那如何定义变量,其实很简单。
struct Point
{
int x;
int y;
}p1; //全局变量p1
struct Point p2; //全局变量p2
int main()
{
struct Point p3; //局部变量p3;
return 0;
}
初始化结构体变量:
#include <stdio.h>
struct Peo
{
char name[20];
char tele[12];
char sex[5];
int high;
};
int main()
{
struct Peo p1 = {"张三","12345678912","男",180};
return 0;
}
那如果是嵌套结构体初始化呢?并且读取值呢?
如下代码:
#include <stdio.h>
struct Peo
{
char name[20];
char tele[12];
char sex[5];
int high;
};
struct St //新的结构体
{
struct Peo p; //嵌套一个结构体变量
int num;
float f;
};
int main()
{
struct Peo p1 = {"张三","12345678912","男",180};
struct St s = {
{"里斯","98765432101","女",169},12,3.14f}; //嵌套结构体初始化。
printf("%s %s %s %d\n", p1.name, p1.tele, p1.sex, p1.high);
printf("%s %s %s %d %d %f\n", s.p.name,s.p.tele,s.p.sex,s.p.high ,s.num, s.f);
return 0;
}
输出:
2、结构体成员的访问
2.1、使用.
操作符来访问结构体成员
此结构是:结构体对象.
结构体成员变量,eg:结构体对象.结构体成员变量,eg:(*ps).name
2.2、使用->
操作符来访问结构体成员变量
此结构是:结构体指针->结构体成员,eg:ps->name
#include <stdio.h>
struct Peo
{
char name[20];
char tele[12];
char sex[5];
int high;
};
void print(struct Peo* sp)
{
printf("%s %s %s %d\n", sp->name, sp->tele, sp->sex, sp->high);
}
int main()
{
struct Peo p1 = {"张三","12345678912","男",180};
print1(&p1);
return 0;
}
3、结构体传参
结构体传参有两种方式:
- 传结构体对象本身,这样可以使用结构体对象
.
结构体成员变量的方法进行成员变量读取。 - 传结构体对象的地址,这样可以使用结构体指针->结构体成员的方法进行成员变量读取。
我们想一想那个方法好呢?
是方法二:传结构体对象的地址
好。具体原因:如果我们使用方法一:传结构体本身
的话,前面说过,直接传结构体本身,形参知识实参的一份临时拷贝,如果大概这个结构体对象存储的数据非常之庞大时,拿在使用传结构体本身
的话,优惠为形参拷贝一份如此庞大的数据,拿着空间和时间上会得不偿失。所以说使用方法二:传结构体对象的地址
最好。
函数传参的时候,参数时需要压栈的。
如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降。
结论:结构体传参时,要传结构体的地址。
直接上代码:
#include <stdio.h>
struct Peo
{
char name[20];
char tele[12];
char sex[5];
int high;
};
void print1(struct Peo* sp)
{
printf("%s %s %s %d\n", sp->name, sp->tele, sp->sex, sp->high);
}
void print2(struct Peo pp) //pp形参是p1实参的临时拷贝
{
printf("%s %s %s %d\n", pp.name, pp.tele, pp.sex, pp.high);
}
int main()
{
struct Peo p1 = { "张三","12345678912","男",180 };
print1(&p1); //传入结构体地址
print2(p1); //传入结构体本身
return 0;
}
输出:
一道练习题(细看)
分析:这里的struct S a,*p = &a;
,可以拆分为:
- struct S a;
- struct S* p = &a; //这里取地址取得是结构体对象a的地址。
而结构体对象a里面又包含了变量a和变量b。
然后下一步:a.a=99; 意识就是结构体对象a调用结构体变量a进行赋值为99。所以结构体变量a的值为99。
然后现在问题就是,想要打印结构体变量a的值。
A选项:就是题目中的形式,可以。
B选项:不行,p.a,这里的.
的优先级是比`\`的优先级高的,所以*p.a就变成了,先p.a,在*解引用的过程。因为p指针对象,指针对象只能p->a的形式。所以B选项错误。
C选项:可以
D选项:(p).a,这里括号里面的优先级最高,\p解引用后就是结构体对象a了,然后转化为a.a和A选项一样,所以D选项也可以。