struct 结构体
struct即结构体,C程序中经常需要用相关的不同类型的数据来描述一个数据对象。例如,描述学生的综合信息时,需要使用学生的学号、姓名、性别等不同类型的数据时,像这种数据类型总是在一起出现,那么我们不如把这些变量装入同一个“文件夹”中,这时用的关键字struct声明的一种数据类型就是表示这个“文件夹”的使用。那么在说明和使用之前必须先定义它,也就是构造它。如同在说明和调用函数之前要先定义一样。
结构体是一种集合,它里面包含了多个变量或数组,它们的类型可以相同,也可以不同,每个这样的变量或数组都称为结构体的成员,结构体也是一种数据类型,它由程序员自己定义,可以包含多个其他类型的数据,成员又称为成员变量,它是结构体所包含的若干个基本的结构类型,必须用“{}”括起来,并且要以分号结束,每个成员应表明具体的数据类型,成员一般用名字访问。结构体和数组类似,也是一组数据的集合,整体使用没有太大的意义。数组使用下标[ ]获访问元素,结构体使用点号.访问单个成员。通过这种方式可以获取成员的值,也可以给成员赋值
数组:a[0]=10; 结构体:today.day (指针结构体用->访问)结构体的成员可以包含其他结构体,也可以包含指向自己结构体类型的指针,而通常这种指针的应用是为了实现一些更高级的数据结构如链表和树等。
声明定义结构:
struct关键字+结构体的标志名+大括号里边是成员+}后面的声明此结构变量+末尾分号,一般有这些:
struct week{定义一
int x;
char y;
};
struct week p1,p2;
//声明变量p1,p2,里边都是week的值
//里边有x和y的值
//用.访问 :p1.x p2.x// p1.y, p2.y
struct{定义二
int x;
char y;
}p1,p2;//在这里声明变量
//p1和p2都是一种无名结构,
// 里边有X和y 访问一样用.
struct week {定义三
int x;
int y;
}p1,p2;
//常用的一种结构定义声明形式
对于第一和第三种形式,都声明了结构名week,但是第二种没有声明结构名,只是定义了两个结构变量,
这种叫无名结构
无名结构: 可以定义无名结构体类型的变量。编译器对无名结构体的处理是随机生成一个不重复的变量名。
无名结构的定义方式就是定义无名结构体时必须定义该结构体类型的至少一个变量。
优点:无名结构体的妙用就是可以避免相同类型的结构体的重复定义,
这样可以对每一个具体类型的队列都可以定义一个结构体来管理该队列的头尾指针,
即使定义多个相同具体类型的队列也不会引发重复定义的编译错误。这样定义了两个队列,
其元素类型均为int类型,同时各得到了一个维护队列头尾指针的结构体
缺点:这里定义了一个无名的结构体,同时声明了三个此种类型的变量。
但是,因为没有名字,我们在这句之后,无法内再定义与那三种变量相同类型的变量了。
除非你再容次去定义一个这样的相同的结构体类型。
还有一个重要的原因就是没有办法在其他位置定义我们所需要的结构体变量,
每次需要新定义结构体变量的时候都必须要找到最开始结构体代码书写的位置才能定义新的结构体
所以实际编程中无名结构并不常用
注意:
1、结构体本身并不会被作为数据而开辟内存,真正作为数据而在内存中存储的是这种结构体所定义的变量。
2、先声明结构体类型,再定义该类型的变量,声明结构体类型,不分配空间定义结构体类型变量,就要分配内存空间
3、量使用占为少的类型,如,在可能的时候使用short代替int,按数据类型本身占用的位置从大到小排
4、除了可以对成员进行逐一赋值,也可以在定义时整体赋值:p1={struct week}{5,10}; 相当于 p1.x=5,p1.y=10;
p1=p2 表示 p1.x=p2.x , p1.y=p2.y; 不过整体赋值仅限于定义结构体变量的时候,在使用过程中只能对成员逐一赋值
5、结构体变量不能相加,相减,也不能相互乘除,但结构体可以相互赋值,也就是说,可以将一个结构体变量赋值给另一个结构体变量。但是前提是这两个结构体变量的结构体类型必须相同
结构体的运算:要访问整个结构,直接用结构变量的名字,对于整个结构,可以做赋值,取地址,也可以传递给函数参数
结构体数值
嵌套的结构体:
struct week{
int x;
int y;
strcut week at;//在结构体又定义了名为at的一个和week同样参数的结构体变量
//其中可以用.运算符访问 see.at.x see.at.y
}see;
但是其实这样的方式是不建议(非法)的,因为这种声明实际上是一个无限循环,成员at是一个结构体,
at的内部还会有成员是结构体,依次下去,无线循环。在分配内存的时候,由于无限嵌套,
也无法确定这个结构体的长度,所以这种方式是非法的
正确的方式是使用《结构体指针》,因为指针的长度是确定的:
struct week{
int x;
int y;
strcut week *at;//在结构体内定义了一个指向和week一样类型的结构指针
}see; 但是注意用指针访问时要用->运算符 see.at->x
结构体相互引用:
一个结构体A中包含一个或多个与结构体B相关的成员, 且结构体B中也包含一个或多个与结构体A相关的成员称为结构体的互引用.
但是要注意: 如果已经定义了两个结构A和B ,在定义结构体A的成员b时,结构体B对A还未可见,故此时编译器会报数据类型B未定义
解决的办法是使用不完整声明:
strcut A;//不完整声明
strcut B;//不完整声明
strcut _A{ strcut _B{
int x; int x;
int y; int y;
struct _B a; struct _A b; //在结构B中定义了一个名为b的和A结构一样类型的结构变量
//其中可以用点访问 A.a.x B.b.x
}A; }B;
//但是注意这种方式犯了一个和上面第一个嵌套结构的错误,就是结构体A和B都是直接包含了对方,
正确的用法还是使用指针:
strcut _A{ strcut _B{
int x; int x;
int y; int y;
struct _B *a; struct _A *b; //在结构B中定义了一个名为b的和A结构一样类型的结构指针
//其中指针要用->访问 A.a->x B.b->x
}A; }B;
//但是注意这种方式犯了一个和上面第一个嵌套结构的错误,就是结构体A和B都是直接包含了对方,正确的用法还是使用指针:
strcut _A{ strcut _B{
int x; int x;
int y; int y;
struct _B *a; struct _A *b; //在结构B中定义了一个名为b的和A结构一样类型的结构指针
//其中指针要用->访问 A.a->x B.b->x
}A; }B;
//所以使用互引用要注意:至少有一个结构必须在另一个结构体中以指针的形式被引用。
结构体函数与函数参数
结构体做函数形参:
整个结构可以作为参数的值传入函数,这时候是在函数内新建一个结构变量,并复制调用者结构的值,也可以返回一个值,这和数组完全不同
用结构体变量作实参时,采取的也是“值传递”方式,将 结构体变量所占的内存单元的内容(结构体变量成员列表) 全部顺序传递给形参,这里形参也得是结构体变量。
#include<stdio.h>
typedef struct _node {
int n;
char a[100];
}NODE;
void add(NODE a);//这种形式只是用来做值的传递
int main(void) {
//以传值方式传递结构需要对整个结构做一份拷贝
NODE t;
scanf("%d %d", &t.a[0], &t.n);//输入1 3
printf("1-%d %d\n",t.a[0],t.n);//输出 1 3
add(t);
printf("3-%d %d\n", t.a[0], t.n);//输出1 3
//也就是说在add函数里边做修改根本就影响不了主函数这边的值
}
void add(NODE a) {