C语言学习笔记之结构体
文章目录
- 1、结构体介绍
- 1.1 结构体类型变量的定义方法
- 1.2 结构体的大小
- 1.3 结构体的变量的使用形式
- 1.4 结构体变量的初始化
- 2、结构体数组
- 2.1 结构体数组的定义
- 2.2 结构体数组的初始化
- 2.3 结构体数组的使用
- 3、结构体指针
1、结构体介绍
简述
- 在实际的处理对象中,有许多信息是由多个不同类型的数据组合在一起进行描述,而且这些不同类型的数据是互相联系组成了一个有机的整体。此时,就要用到一种新的构造类型数据——结构体(structure),简称结构。
- 结构体的使用为处理复杂的数据结构(如动态数据结构等)提供了有效的手段,而且,它们为函数间传递不同类型的数据提供了方便。
概念
- 结构体是用户自定义的新数据类型,在结构体中可以包含若干个不同数据类型和不同意义的数据项(当然也可以相同),从而使这些数据项组合起来反映某一个信息。
- 例如,可以定义一个职工worker结构体,在这个结构体中包括职工编号、姓名、性别、年龄、工资、家庭住址、联系电话。这样就可以用一个结构体数据类型的变量来存放某个职工的所有相关信息。并且,用户自定义的数据类型worker也可以与int、double等基本数据类型一样,用来作为定义其他变量的数据类型
定义:
-
定义一个结构体类型的一般形式为:
struct 结构体名 { 数据类型 成员名1; 数据类型 成员名2; : 数据类型 成员名n; };
-
在大括号中的内容也称为“成员列表”或“域表”。
-
其中,每个成员名的命名规则与变量名相同;
-
数据类型可以是基本变量类型和数组类型,或者是一个结构体类型;
-
用分号“;”作为结束符。整个结构的定义也用分号作为结束符
例如:
#include <stdio.h> #include <string.h>struct student //在定义完结构体后可以直接省略名字 {int num; //****char name[10]; //**** **** **** 字节对其,补充空间float grade; //**** }stu3 = {3,"wu",87.5};int main(int argc, const char* argv[]) {struct student stu1;struct student stu2 = { 2,"li",90.5 };stu1.num = 1;//stu1.name = "zhangsan"; 错误用法 #if 0stu1.name[0] = 'z';stu1.name[1] = 'h';stu1.name[2] = 'i';stu1.name[3] = 's';stu1.name[4] = 'a';stu1.name[5] = 'n'; #endifstrcpy(stu1.name, "zhisan");stu1.grade = 85.5;printf("%d %s %f\n", stu1.num, stu1.name, stu1.grade);printf("%d %s %f\n", stu2.num, stu2.name, stu2.grade);printf("%d %s %f\n", stu3.num, stu3.name, stu3.grade);printf("%d\n",sizeof(struct student));//查看结构体的大小return 0; }
-
1.1 结构体类型变量的定义方法
先定义结构体类型再定义变量名(这是C语言中定义结构体类型变量最常见的方式)
struct 结构体名
{成员列表;
};
struct 结构体名 变量名;
例如:定义几个职工变量:struct worker
{long number;char name[20];char sex;int age;float salary;char address[80];char phone[20];
};
struct worker worker1,worker2;
-
注意事项:
-
“struct worker”代表类型名,不能分开写
struct worker1,worker2;
//错误,没有指明是哪种结构体类型worker worker1,worker2;
//错误,没有struct关键字//系统不认为worker是结构体类型 -
为了使用上的方便,程序员通常用一个符号常量代表一个结构体类型。即在程序开头加上下列语句:
#define WORKER struct worker;
这样在程序中,WORKER与struct worker完全等效。
例如:
WORKER { long number;char name[20];char sex;int age;float salary;char address[80];char phone[20]; }; WORKER worker1,worker2;
此时,可以直接用WORKER定义worker1、worker2两个变量,而不必再写关键字struct。
-
在定义类型的同时定义变量
-
这种形式的定义的一般形式为:
struct 结构体名 { 成员列表; }变量名;
例如:
struct worker { long number;char name[20];char sex;int age;float salary;char address[80];char phone[20]; } worker1,worker2;
直接定义结构类型变量:
-
其一般形式为:
struct //没有结构体名 { 成员列表; }变量名;
例如:
struct {long number;char name[20];char sex;int age;float salary;char address[80];char phone[20]; } worker1,worker2;
1.2 结构体的大小
一个结构体变量占用内存的实际大小,也可以利用sizeof求出。它的运算表达式为:
-
sizeof(运算量) //求出给定的运算量占用内存空间的字节数
-
其中运算量可以是变量、数组或结构体变量,可以是数据类型的名称。
-
例如:
sizeof(struct worker) sizeof(worker1)
-
1.3 结构体的变量的使用形式
结构体变量是不同数据类型的若干数据的集合体。在程序中使用结构体变量时,一般情况下不能把它作为一个整体参加数据处理,而参加各种运算和操作的是结构体变量的各个成员项数据。
结构体变量的成员用以下一般形式表示:
-
结构体变量名.成员名
例如,上面给出的结构体变量worker1具有下列七个成员:
worker1.number;worker1.name;worker1.sex;worker1.phone;worker1.age;worker1.salary;worker1.address;
在定义了结构体变量后,就可以用不同的赋值方法对结构体变量的每个成员赋值。例如:
-
strcpy(worker1.name,”Zhang San”); worker1.age=26; strcpy(worker1.phone,”1234567”); worker1.sex=’m’;
除此之外,还可以引用结构体变量成员的地址以及成员中的元素。例如:引用结构体变量成员的首地址&worker1.name;引用结构体变量成员的第二个字符worker1.name[1];引用结构体变量的首地址&worker1。
注意:
-
不能将一个结构体类型变量作为一个整体加以引用,而只能对结构体类型变量中的各个成员分别引用。
-
例如,对上面定义的结构体类型变量wan,下列引用都是错误的:
cout<<wan; cin>>wan;
但是可以如下引用
cout<<wan.name; cin>>wan.name;
-
-
如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到最低的一级成员。只能对最低级的成员进行赋值或存取以及运算。
-
例如,对上面定义的结构体类型变量worker1,可以这样访问各成员:
worker1.age worker1.name worker1.birthday.year worker1.birthday.month worker1.birthday.day
注意:不能用worker1.birthday来访问worker1变量中的成员birthday,因为birthday本身是一个结构体变量。
-
-
对成员变量可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)。例如:
-
worker2.age=worker1.age; sum=worker1.age+worker2.age; worker1.age++;
-
-
在数组中,数组是不能彼此赋值的,而结构体类型变量可以相互赋值。
- 在C程序中,同一结构体类型的结构体变量之间允许相互赋值,而不同结构体类型的结构体变量之间不允许相互赋值,即使两者包含有同样的成员。
1.4 结构体变量的初始化
与其他类型变量一样,也可以给结构体的每个成员赋初值,这称为结构体的初始化。一种是在定义结构体变量时进行初始化,语法格式如下:
struct 结构体名 变量名={初始数据表};
另一种是在定义结构体类型时进行结构体变量的初始化。
struct 结构体名
{
成员列表;
}变量名={初始数据表};
- 前述student结构体类型的结构体变量wan在说明时可以初始化如下:
struct student wan={”Wan Jun”,’m’,20,” SuZhou Road No.100”};
-
等价于下列代码:
-
strcpy(wan.name,” Wan Jun”); wan.sex = ’m’; wan.age = 20; strcpy(wan.addr, ” SuZhou Road No.100”);
-
2、结构体数组
2.1 结构体数组的定义
具有相同结构体类型的结构体变量也可以组成数组,称它们为结构体数组。结构体数组的每一个数组元素都是结构体类型的数据,它们都分别包括各个成员(分量)项。
定义结构体数组的方法和定义结构体变量的方法相仿,只需说明其为数组即可。可以采用三种方法:
-
先定义结构体类型,再用它定义结构体数组。
-
结构体数组的定义形式如下:
struct 结构体名 {成员表列; };struct 结构体名
-
例如:
struct student {char name[20];char sex;int age;char addr[20]; }; struct student stu[3];
-
-
在定义结构体类型同时定义结构体数组。
-
结构体数组的定义形式如下:
struct 结构体名 {成员表列; }数组名[元素个数];
-
例如:
struct student {char name[20];char sex;int age;char addr[20]; }stu[3];
-
-
直接定义结构体数组
-
结构体数组的定义形式如下:
struct //没有结构体名 { 成员表列; }数组名[元素个数];
-
例如:
struct {char name[20];char sex;int age;char addr[20]; }stu[3];
-
代码示例:
#include <stdio.h>#include <string.h>struct student{int num;char name[10];float grade;
}s1[1] = {4 , "zhang", 80.5};//第三种int main(int argc, const char *argv[])
{struct student s[4] = {{1,"zhi",90.5},{2,"li",80.5},{3,"zhao",77.5}};//第二种/* 第一种struct student s[4];s[0].num = 1;#if 0stu1.name[0] = 'Z' ;stu1.name[1] = 'H' ;stu1.name[2] = 'i' ;#endifstrcpy(s[0].name, "ZHi");s[0].grade = 90.5;
*/printf("%d %s %f\n",s[0].num ,s[0].name ,s[0].grade);printf("%d %s %f\n",s[1].num ,s[1].name ,s[1].grade);printf("%d %s %f\n",s[2].num ,s[2].name ,s[2].grade);printf("%d %s %f\n",s1[0].num ,s1[0].name ,s1[0].grade);return 0;
}
2.2 结构体数组的初始化
结构体数组在定义的同时也可以进行初始化,并且与结构体变量的初始化规定相同,只能对全局的或静态存储类别的结构体数组初始化。
结构体数组初始化的一般形式是:
struct 结构体名
{
成员列表;
};
struct 结构体名 数组名[元素个数]={初始数据表};
或是
struct 结构体名
{
成员表列;
}数组名[元素个数]={初始数据表};
由于结构体变量是由若干不同类型的数据组成,而结构体数组又是由若干结构体变量组成。所以要特别注意包围在大括号中的初始数据的顺序,以及它们与各个成员项间的对应关系。
2.3 结构体数组的使用
一个结构体数组的元素相当于一个结构体变量,因此前面介绍的有关结构体变量的规则也适应于结构体数组元素。以上面定义的结构体数组stu[3]
为例说明对结构体数组的引用:
-
引用某一元素中的成员。
- 若要引用数组第二个元素的name成员,则可写为:
stu[1].name
- 若要引用数组第二个元素的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[1].num); printf(“…”,stu[0].name); printf(“…”,stu[1].num);
-
代码举例:
#include <stdio.h>#include <string.h>struct student{int num;char name[10];float grade;
}s1[1] = {4 , "zhang", 80.5};//第三种int main(int argc, const char *argv[])
{struct student s[4] = {{1,"zhi",90.5},{2,"li",80.5},{3,"zhao",77.5}};//第二种/* 第一种struct student s[4];s[0].num = 1;#if 0stu1.name[0] = 'Z' ;stu1.name[1] = 'H' ;stu1.name[2] = 'i' ;#endifstrcpy(s[0].name, "ZHi");s[0].grade = 90.5;
*/printf("%d %s %f\n",s[0].num ,s[0].name ,s[0].grade);printf("%d %s %f\n",s[1].num ,s[1].name ,s[1].grade);printf("%d %s %f\n",s[2].num ,s[2].name ,s[2].grade);printf("%d %s %f\n",s1[0].num ,s1[0].name ,s1[0].grade);return 0;
}
3、结构体指针
可以设定一个指针变量用来指向一个结构体变量。此时该指针变量的值是结构体变量的起始地址,该指针称为结构体指针。
结构体指针与前面介绍的各种指针变量在特性和方法上是相同的。与前述相同,在程序中结构体指针也是通过访问目标运算“*
”访问它的对象。结构体指针在程序中的一般定义形式为:
-
struct 结构体名 *结构指针名
;其中的结构体名必须是已经定义过的结构体类型。
例如,对于上面中定义的结构体类型
struct student
,可以说明使用这种结构体类型的结构指针如下:struct student *pstu;
其中
pstu
是指向struct student
结构体类型的指针。结构体指针的说明规定了它的数据特性,并为结构体指针本身分配了一定的内存空间。但是指针的内容尚未确定,即它指向随机的对象。
当表示指针变量p所指向的结构体变量中的成员时,“(*结构体指针名).成员名
”这种表示形式总是需要使用圆括号,显得很不简炼。因此,对于结构体指针指向的结构体成员项,给出了另外一种简洁的表示方法,如下表示:
-
结构体指针名->成员名
它与前一种表示方法在意义上是完全等价的。
例如,结构体指针p指向的结构体变量中的成员name可以表示如下:
(*p).name 或 p->name
代码举例:
#include <stdio.h>#include <string.h>struct student{int num;char name[10];float grade;
};int main(int argc, const char *argv[])
{struct student *p;struct student stu1 = {1,"zhao",98};p = &stu1;/* 可能会出现内存分配的问题p->num = 1;strcpy(p->name , "zhao");p->grade = 90.5;
*/printf("%d %s %f\n",stu1.num ,stu1.name ,stu1.grade);printf("%d %s %f\n",(*p).num ,(*p).name ,(*p).grade);//一种方式printf("%d %s %f\n",p->num ,p->name ,p->grade);//常用的一种方式return 0;
}