结构体【struct】
一.结构体定义
概念:结构体是由一系列不同或相同基本类型数据组合而成的新的复合数据集合,从而使这些数据项组合起来反应一个信息。
意义:结构体的使用为处理复杂的数据结构(如动态数据结构等)提供了有效的手段,而且,它们为函数间传递不同类型的数据提供了方便。
特点:
1.结构体类型是用户自行构造的;
2.它由若干不同的基本数据类型的数据构成。
3.它属于C语言的一种数据类型,与整型、实型相当。因此,定义它时不分配空间,只有用它定义变量时才分配空间。
4.结构体类型中的成员名可以与程序中的变量名相同,两者并不代表同一对象,编译程序可 以自动对他们进行区分。
结构体类型的定义:
一般形式
Struct 结构体名
{
数据类型 成员名1;
数据类型 成员名2;
……
};
①.先定义结构,再说明结构变量。这种是C语言中定义结构体类型变量最常见的方式。
Struct 结构体名
{
成员列表;
};
Struct 结构体名 变量名;
如:
[cpp] view plaincopy
1. struct Clerk //职工信息
2. {
3. long num;
4. char name[20];
5. int age;
6. };
7. struct Clerk p1,p2; //变量p1和p2同为 Clerk结构类型。
也可以用宏定义使一个符号常量来表示一个结构类型, 例如:
[cpp] view plaincopy
1. #define CLERK struct Clerk
2. CLERK
3. {
4. Long num;
5. char name[20];
6. int age;
7. };
8. CLERK p1,p2;
②.在定义结构类型的同时说明结构变量。这种形式的定义为:
Struct 结构体名
{
成员列表;
} 变量名;
实例如:
[cpp] view plaincopy
1. struct Clerk
2. {
3. Long num;
4. char name[20];
5. int age;
6. } p1,p2;
③.直接说明结构变量。这种形式的定义为:
Struct // 没有结构体名
{
成员列表;
} 变量名;
例如:
[cpp] view plaincopy
1. struct
2. {
3. Long num;
4. char name[20];
5. int age;
6. } p1,p2;
二.结构体的大小:
一个结构体变量占用内存的实际大小,可以利用sizeof来求出。它的运算表达式为:
Sizeof(运算量) //求出给定的运算量占用内存空间的字节数
其中运算量可以是变量、数组或结构体变量,可以是数据类型的名称。
例如:
Sizeof(struct clerk)
Sizeof(p1)
三.结构体类型嵌套
结构体类型中可包含以定义的结构体类型。
[cpp] view plaincopy
1. struct date{
2. int month;
3. int day;
4. int year;
5. } ;
6. struct Clerk
7. {
8. Long num;
9. char name[20];
10. struct date birthday;
11. } ;
变量定义:如:struct Clerk p1,p2;
成员引用:p1.num, p1.name,
P1.bd.year , p1.bd.month, p1.bd.day
初始化:struct clerk p={0017482, “Li shan”,{1986,6,15}};
△注意:结构体类型和变量也有全局和局部之分
定义在所有函数之外的结构体类型(变量)称为全局(或外部)结构体类型(变量)。
定义在函数内部的结构体类型(变量)称为局部(或内部)结构体类型(变量)。
结构体类型一般定义为全局的,定义位置一般在主函数之前。
结构体变量初始化时,初始值类型对应成员的数据类型一致,否则会出错。
四.结构体变量的初始化
与其他类型变量一样,也可以给结构的每个成员赋初值,这称为结构体的初始化。一种是在定义结构体变量时进行初始化。语法格式如下:
Struct 结构体名 变量名={初始数据表};
另一种是在定义结构体类型时同时进行结构体变量的初始化。
Struct 结构体名
{
成员列表;
}变量名={初始数据表}; 如:
[cpp] view plaincopy
1. struct Clerk
2. {
3. Long num;
4. char name[20];
5. struct date birthday;
6. } p1={0017482, “Li shan”,{1986,6,15}};
还有一种是在main函数中进行初始化。
Struct 结构体名 变量名;
变量名.成员名 = 数值;
变量名.成员名 = 数值;
……
[cpp] view plaincopy
1. Struct clerk p2;
2. P2.num = 0017482;
3. P2.name =” lishan”;
4. P2.birthday = {1986,6,15}};
五.结构体数组
§1.结构体数组的定义
**具有相同结构体类型的结构体变量也可以组成数组,即为结构体数组。结构体数组的每一个数组元素都是结构体类型的数据,他们都分别包含各个成员项。
其定义形式如下:
Struct 结构体名
{
成员列表;
};
Struct 结构体名 数组名[元素个数];
[cpp] view plaincopy
1. Struct student
2. {
3. Char name[20];
4. Char sex;
5. Int age;
6. Char addr[20];
7. };
8. Struct student stu[3];
§2.结构体数组的初始化
Struct 结构体名
{
成员列表;
};
Struct 结构体名 数组名[元素个数]={初始数据表};
OR
Struct 结构体名
{
成员列表;
} 数组名[元素个数]={初始数据表};
§3.结构体数组的使用
一个结构体数组的元素相当于一个结构体变量,因此有关结构体变量的规则也适用于结构体数组的元素。
⑴.引用某一元素中的成员。
如要引用数组第一个元素的name成员,则可写为:
stu[1].name
⑵.可以将一个结构体数组元素赋值给同一结构体类型的数组的另一个元素,或赋给同一类型的变量,如:
Struct student stu[3] , student1;
现在定义了一个结构体类型的数组,它有3个元素,又定义了一个结构体类型变量student1,
则下面的赋值是合法的。
Student1 = stu[0];
Stu[0] = stu[1];
Stu[1] = student1;
⑶.不能把结果体数组元素作为一个整体直接进行输入输出。如:
Printf(“.......”,stu[0]);
scanf(“.......”,&stu[0]);
都是错误的。
只能是以单个成员为对象进行输入输出,如:
scanf(“.......”,&stu[0].name);
scanf(“.......”,&stu[0].num);
Printf(“.......”,stu[0].name);
Printf(“.......”,stu[0].num);
六.结构体指针
△1.指向结构体变量的指针
结构体变量所占内存的首地址称为结构变量的指针。
结构体指针变量的定义:
Struct结构体名称*结构体指针变量名;
例如
[cpp] view plaincopy
1. Struct clerk
2. {
3. Long num;
4. Char name[20];
5. Struct data bd;
6. }a,*pa;
例如:
[cpp] view plaincopy
1. struct clerk b,*pb;
注意:结构体指针变量必须先赋值后使用。
△2.结构体指针变量赋初始值
将结构体变量的首地址赋给指针变量,如:
Struct clerk a,*pa=&a;
Struct clerk b,*pb;
pb=&b;
△3.通过结构体指针变量引用结构体成员
一般形式:(*指针变量).成员名
如:(*pa).num=10; 等价于 a.num=10;
Get((*pa).name); 等价于 get(a.name);
(*pa).bd.year=1986; 等价于 a.bd.year=1982;
△4.指向运算符:“->”直观地引用结构体成员。
例如:上例可改写为:
pa->num=10; get(pa->name);pa->bd.year=1986;
△5.指向结构体数组的指针
#结构体数组的首地址,称为结构体数组的指针。例如
[cpp] view plaincopy
1. Struct clerk
2. {
3. Int num;
4. Char name[20];
5. Struct date birthday;
6. }a[3],*p;
或:struct clerk a[3],*p;
P=a;
则:p->a[0];p+1->a[1];p+2->a[2];
#通过指针访问数组元素的成员:
P->num=10; 等价于 a[0].num=10;
scanf(“%s”,p->name); 等价于 scanf(“%s”,a[0].name);
如果:p++;则 p->a[1];
p->num=10; 等价于 a[1].num=10;
[cpp] view plaincopy
1.
2. /* 应用举例:利用指向结构体的数组的指针输出结构体数组*/
3. struct clerk
4. {
5. int num;
6. char name[20];
7. int age;
8. char addr[40];
9. };
10. int main()
11. {struct clerk *p, a[3]={{101,"zhangsan",26,"shanghai"},
12. {102,"lishan",27,"hubei"},
13. {103,"wangwu",28,"changsha"}};
14. int i;
15. for(i=0,p=a; i<3;i++,p++)
16. printf("%d,%s,%d,%s\n",p->num,p->name,p->age,p->addr);
17. }
18.
七.如何取出结构体变量中的每一个成员?
总结三种方法:①.结构体变量.成员名
②.(*指针变量).成员名
③.结构体变量—>成员名
八.结构体变量和结构体指针变量作为函数参数传递的问题。
#结构体变量做函数参数
[cpp] view plaincopy
1. struct clerk
2. {
3. int num;
4. char name[20];
5. int age;
6. char addr[40];
7. };
8. void func(struct clerk a);
9. int main(void)
10. {
11. struct clerk a={101,"zhangsan",26,"shanghai"};
12. func(a);
13. }
14. void func(struct clerk b)
15. {
16. printf("%d,%s,%d,%s\n",b.num,b.name,b.age,b.addr);
17. }
#结构体指针作函数参数:赋地址传递
[cpp] view plaincopy
1. struct clerk
2. {
3. int num;
4. char name[20];
5. int age;
6. char addr[40];
7. };
8. void output(struct clerk*p);
9. int main(void)
10. {
11. struct clerk*p,a[3]={{101,"zhangsan",26,"shanghai"},
12. {102,"lishan",27,"hubei"},
13. {103,"wangwu",28,"changsha"}};
14. p=a;
15. output(p);
16. }
17. void output(struct clerk *p)
18. {
19. int i;
20. for(i=0;i<3;i++,p++)
21. printf("%d,%s,%d,%s\n",p->num,p->name,p->age,p->addr);
22. return 0;
23. }
结构体变量作为函数参数数据传递方式是赋值传递(单向值传递),实参把它每一个的成员的值依次传递形参,运行时间与存储空间的开销很大,程序运行效率很低。实际应用中,一般使用结构体指针作为函数参数。