写在前面:学习的第一门语言是Java,之前对C也了解一点,也只是了解一点,在加上长时间没有接触了,基本就只会一个Hello World了。现在由于准备升本考试,不得不从头开始学C。这里从零开始,记录C语言学习点滴。欢迎正在学习C语言的小伙伴一起学习,未来可期,一起加油!
结构类型是一种允许把一些数据分量聚合成一个整体的数据类型。一个结构中包含的每个数据分量都有名字(类似于Java类),这些数据分量称为结构成员或者结构分量,结构成员可以是C语言中的任意变量类型,开发时可以使用结构类型来创造适合于问题的数据集合。像数组和指针一样,结构也是一种构造数据类型,他与数组的区别在于:数组中所有元素的数据类型必须是相同的,而结构中各成员的数据类型可以不同。
结构是C语言中一种新的构造数据类型,它能够把有内在联系的不同类型的数据汇聚成一个整体,使他们相互关联;同时,结构又是一个变量的集合,可以按照对基本数据类型的操作方法单独使用其成员变量。结构就是这样一种特殊的构造数据类型。结构类型定义的一般形式如下:
struct 结构名{
类型名 结构成员名1;
类型名 结构成员名2;
.....
类型名 结构成员名n;
};
struct定义结构类型的关键字,struct后面为结构名,它必须是一个合法的标识符。struct和结构名两者合起来共同组成结构类型名,如:struct student。 大括号中的内容是结构说包括的结构成员,也叫做机构分量,结构成员可以有多个。这样,大括号中定义的成员信息被聚合为一个整体并形成了一个新的数据类型。
关键字struct和它后面的结构名一起组成一个新的数据类型名。结构的定义以分号结束。
例如定义一个班级信息的结构。
struct class{
char name[10]; //班级名称
char teacher[10]; //老师
};
结构数据类型为struct class,结构中定义了两个结构成员班级名称和老师,类型都是字符数组类型(结构成员类型可以不同)。
上面讲述了结构的定义,由于结构和类型使用方法一样,所以结构成员中数据也可以是结构类型。比如定义学生结构类型时,学生属于那个班级。班级作为一个结构类型。如下图:
定义了学生结构,结构成员有姓名、学号、班级信息(班级为自定义的结构类型)。代码如下:
//班级
struct class{
char name[10]; //班级名称
char teacher[10]; //老师
};
//学生
struct student{
int number; //学号
char name[10]; //姓名
struct class cla; //归属班级
};
结构类型struct student的成员变量cla被定义成结构类型struct class,而struct class又包含了2个成员,即一个结构的成员被定义成另一个结构类型。结构类型的嵌套定义使成员数据被进一步细分。
在定义嵌套的结构类型时,必须先定义成员的结构类型,在定义主结构类型。
结构定义完成后就是使用了,结构变量定义有三种方式。
1、单独定义
单独定义是指先定义一个结构类型,再定义这种结构类型的变量。如:
#include
//班级
struct class{
char name[10]; //班级名称
char teacher[10]; //班主任
};
int main(){
//定义结构体变量
struct class cla = {"软件一班", "张老师"};
}
关键字struct和结构名class必须联合使用,因为他们合起来表示一个数据类型名。
2、混合定义
混合定义是指在定义结构类型的同时定义结构变量。
这种定义方法的形式为:
struct 结构名{
类型名 结构成员名1;
类型名 结构成员名2;
.....
类型名 结构成员名n;
}结构变量表;
例如:
struct class{
char name[10]; //班级名称
char teacher[10]; //老师
}cla1, cla2;
这种方式和第一种方式的实质是一样的,都是既定义结构类型struct class,也定义了结构变量。cla1,cla2为结构变量,如果有多个结构变量,中间用逗号分隔。
3、无类型名定义
无类型名定义是指在定义结构变量时省略结构名。
这种方式采用如下形式定义结构类型并同时定义结构变量:
struct {
类型名 结构成员名1;
类型名 结构成员名2;
.....
类型名 结构成员名n;
}结构变量表;
这种定义形式省略了结构名。要注意的是,由于没有给出结构名,在此定义语句后面无法再定义这个类型的其他结构变量,除非把定义过程再写一遍。一般情况下,不会使用这种定义方法。
结构变量初始化,即在定义时对其赋初值。例如:
#include
//班级
struct class{
char name[10]; //班级名称
char teacher[10]; //班主任
}cla1, cla2;
//学生
struct student{
int number; //学号
char name[10]; //姓名
struct class cla; //归属班级
};
int main(){
struct class cla = {"软件一班", "张老师"};
struct student stu = {123, "张三", cla};
return 0;
}
上述代码中定义了班级和学生结构类型的变量,并对其进行了初始化。结构变量的初始化采用初始化表的方法,大括号内各数据项间用逗号隔开,将大括号内的数据项按顺序对应地赋给结构变量内各个成员,要求数据类型一致。
结构类型变量的存储布局按其类型定义中成员的先后顺序排列。如上述定义的struct class cla结构变量,初始化后在内存中的存储形式如下:
通常,一个结构类型变量所占的内存空间是其各个成员所占内存空间之和。可以用sizeof计算其所需存储空间,如sizeof(struct class)或者sizeof(cla)。sizeof的运算对象可以是结构类型名,也可以是结构变量名,计算结果一字节为单位。
结构变量成员的引用
使用结构变量主要就是对其成员变量进行操作。使用结构成员操作符“ . ”来引用结构成员,格式为:结构变量名 . 结构成员名
对结构变量成员的使用方法与同类型的变量完全相同。对嵌套结构成员的引用方法和一般成员的引用方法类似,也是采用结构成员操作符“ . ”进行的。例如:
#include
#include
//班级
struct class{
char name[10]; //班级名称
char teacher[10]; //班主任
}cla1, cla2;
//学生
struct student{
int number; //学号
char name[10]; //姓名
struct class cla; //归属班级
};
int main(){
struct class cla = {"软件一班", "张老师"};
struct student stu = {123, "张三", cla};
printf("学号:%d\t姓名:%s\t班级:%s\n", stu.number, stu.name, stu.cla.name);
//修改学号和姓名
stu.number = 666;
strcpy(stu.name, "李四");
printf("学号:%d\t姓名:%s\t班级:%s\n", stu.number, stu.name, stu.cla.name);
return 0;
}
运行效果如下:
嵌套定义的结构变量中,每个成员按从左到右、从外到内的方式引用,与Web地址的用法相似。
如果两个结构变量具有相同的类型,可以将一个结构变量的值直接赋给另一个结构变量。赋值时,将赋值符号右边结构变量的每一个成员的值赋给了左边结构变量中相应的成员。如:
struct class cla = {"软件一班", "张老师"};
struct class cla1 = cla;
只有相同结构类型的变量之间才可以直接赋值。
结构变量作为函数参数
在多个函数组成的程序中,如果程序中含有结构类型的数据,就有可能需要用结构变量作为函数的参数或返回值,以便在函数间传递数据。
结构变量作为函数参数的特点是,可以传递多个数据且参数形式比较简单。当时,对于成员较多的大型结构,参数传递时进行的结构数据复制使得效率较低。
结构数组是结构与数组的结合体,与普通数组的不同之处在与每个数组元素都是一个结构类型的数据,可以包括多个成员项。
结构数组的定义方法与结构变量类似,如:
struct class cla[5];
定义了一个结构数组cla,它有5个数组元素,从cla[0]到cla[4],每个数组元素都是结构类型struct class,这样就可以存储5个班级的信息。
在定义结构数组时,也可以同时对其进行初始化,其格式为二维数组的初始化类似,如:
struct class cla[5] = {{"软件一班", "张老师"}, {"软件二班", "李老师"}};
编译程序为所有结构数组元素分配足够的存储单元,结构数组的元素是连续存放的。如上述代码,在初始化了cla[0]和cla[1]这两个数组元素,但对于其他数组元素,编译程序仍然会预分配内存空间,如下图:
由于每个结构数组元素的类型都是结构类型,其使用方法和相同类型的结构变量一样。例如,对于结构数组cla,既可以引用数组的元素,如cla[0],也可以引用结构数组元素的成员。对结构数组元素成员的引用是通过使用数组下标与结构成员操作符“ . ”相结合的方式来实现的,其一般格式为:
结构数组名[下标] . 结构成员名
如下案例:
#include
#include
//班级
struct class{
char name[10]; //班级名称
char teacher[10]; //班主任
}cla1, cla2;
//学生
struct student{
int number; //学号
char name[10]; //姓名
struct class cla; //归属班级
};
int main(){
struct class cla[5] = {{"软件一班", "张老师"}, {"软件二班", "李老师"}};
int i;
for(i = 0; i < 5; i++){
printf("班级:%s\t老师:%s\n", cla[i].name, cla[i].teacher);
}
printf("\n");
//改变结构数组中第一个结构数据
strcpy(cla[0].name, "软件班");
for(i = 0; i < 5; i++){
printf("班级:%s\t老师:%s\n", cla[i].name, cla[i].teacher);
}
return 0;
}
运行效果如下:
结构数组中所有元素都属于相同的结构类型,因此,数组元素之间可以直接赋值。
前面几章讲过指针的基本使用,指针可以指向任何一种类型的变量,而结构变量也是C语言中的一种合法变量,因此,指针也可以指向结构变量。即结构指针就是指向结构类型变量的指针。如:
struct class cla = {"软件一班", "张老师"}, *p;
p = &cla;
第一条语句定义了struct class类型的变量cla并初始化,另外还定义了一个结构指针变量p;第二条语句使结构指针p指向结构变量cla,如图:
结构类型的数据往往由多个成员组成,结构指针的值实际上是结构变量的首地址,即第一个成员的地址。
有了结构指针的定义,既可以通过结构变量cla直接访问结构成员,也可以通过结构指针变量p间接访问它所指向的结构变量中的各个成员。具体有两种方式。
1、用 *p访问结构成员
strcpy((*p).name, "软件二班");
其中*p表示的是p指向的结构变量。注意,(*p)中的括号是不可少的,因为成员运算符“ . ”的优先级高于“ * ”的优先级,若没有括号,则*p . name等价于*(p.name),是错误的。
2、用指向运算符 - >访问指针指向的结构成员
strcpy(p->name, "软件二班");
以上两种形式最终效果都是一样的。当在使用结构指针访问结构成员是,通常使用指向运算符->。
当p指向结构变量cla是,下面语句的效果都是一样的:
strcpy(cla.name, "软件二班");
strcpy((*p).name, "软件二班");
strcpy(p->name, "软件二班");
由于初学C语言,上述内容如有错误地方,恳请各位大佬指出!