查看原文
其他

c语言基础语法——结构体

嵌入式ARM 2021-01-31


1、关于C语言结构体的引入


在实际问题中有时候我们需要几种数据类型一起来修饰某个变量。


例如一个学生的信息就需要学号(字符串),姓名(字符串),年龄(整形)等等。


这些数据类型都不同但是他们又是表示一个整体,要存在联系,那么我们就需要一个新的数据类型。


——结构体,它就将不同类型的数据存放在一起,作为一个整体进行处理。


2、C语言使用结构体变量进一步加强了表示数据的能力


2.1;结构体声明;


//申明一个结构体 struct book {char title[MAXTITL];//一个字符串表示的titile 题目 ;char author[MAXAUTL];//一个字符串表示的author作者 ;float value;//一个浮点型表示的value价格;};//注意分号不能少,这也相当于一条语句;


这个声明描述了一个由两个字符数组和一个float变量组成的结构体。


但是注意,它并没有创建一个实际的数据对象,而是描述了一个组成这类对象的元素。


因此,我们有时候也将结构体声明叫做模板,因为它勾勒出数据该如何存储,并没有实例化数据对象。


下面介绍一下上面的结构体声明;


1、首先使用关键字struct,它表示接下来是一个结构体。


2、后面是一个可选的标志(book),它是用来引用该结构体的快速标记。

     

因此我们以后就可以这样创建数据对象


struct book library;//把library设为一个可以使用book结构体的结构体变量,则library这个变量就包含了其book结构体中的所有元素


3、接下来就是一个花括号,括起了结构体成员列表,及每个成员变量,使用的都是其自己的声明方式来描述,用分号来结束描述;


例如:char title[MAXTITL];字符数组就是这样声明的,用分号结束;

注意:其中每个成员可以使用任何一种C数据结构甚至是其他的结构体,也是可以的;


4、在结束花括号后的分号表示结构体设计定义的结束。


2.2;关于其struct声明的位置,也就是这段代码要放到哪里。同样这也是具有作用域的。


这种声明如果放在任何函数的外面,那么则可选标记可以在本文件中,该声明的后面的所有函数都可以使用。


如果这种声明在某个函数的内部,则它的标记只能在内部使用,并且在其声明之后;



2.3;关于我们不断说的,标记名是可选的,那么我们什么时候可以省略,什么时候一定不能省略呢?


如果是上面那种声明定义的方法,并且想在一个地方定义结构体设计,而在其他地方定义实际的结构体变量,那么就必须使用标记;


可以省略,设计的同时就创建该结构体变量,但是这种设计是一次性的。


关于结构体类型的定义的总结;


一般格式就是;


struct 结构体名(也就是可选标记名){    成员变量;};//使用分号表示定义结束;


3、定义结构体变量


3.1;之前我们结构体类型的定义(结构体的声明)只是告诉编译器该如何表示数据,但是它没有让计算机为其分配空间。


我们要使用结构体,那么就需要创建变量,也就是结构体变量;


创建一个结构体变量;struct book library;


看到这条指令,编译器才会创建一个结构体变量library,此时编译器才会按照book模板为该变量分配内存空间,并且这里存储空间都是以这个变量结合在一起的。


这也是后面访问结构体变量成员的时候,我们就要用到结构体变量名来访问。


分析:


struct book的作用:


在结构体声明中,struct book所起到的作用就像int,,,,等基础数据类型名作用一样。


struct book s1,s2,*ss;


定义两个struct book结构体类型的结构体变量,还定义了一个指向该结构体的指针,其ss指针可以指向s1,s2,或者任何其他的book结构体变量。


其实;


struct book library;


等效于;


struct book{ 

char … 

…. 

….. 

}librar;

这两种是等效的,只是第一种可以减少代码的编写量;


3.2;现在还是回到刚才提及的那个问题,可选标志符什么时候可以省略;


其一;


struct

{

    char title[MAXTITL]; 

    char author[MAXAUTL];

float value;

}library;

//注意这里不再是定义声明结构体类型,而是直接创建结构体变量了,这个编译器会分配内存的;

//这样的确可以省略标识符也就是结构体名,但是只能使用一次;因为这是;声明结构体的过程和定义结构体变量的过程和在了一起;并且个成员变量没有初始化的;

//如果你想多次使用一个结构体模块,这样子是行不通的;


其二;


用typedef定义新类型名来代替已有类型名,即给已有类型重新命名;

一般格式为;typedef 已有类型 新类型名;

typedef int Elem; 

typedef struct{

    int date;

    .....

    .....

}STUDENT;

STUDENT stu1,stu2;



总结一下关于结构体变量的定义;


1;先定义结构体类型后再定义结构体变量;


格式为;struct 结构体名 变量名列表;


struct book s1,s2,*ss;//注意这种之前要先定义结构体类型后再定义变量;


2;在定义结构体类型的同时定义结构体变量;


格式为;


struct 结构体名{成员列表;}变量名列表;//这里结构体名是可以省的,但尽量别省;struct book{char title[MAXTITL];//一个字符串表示的titile 题目 ;char author[MAXAUTL];//一个字符串表示的author作者 ;float value;//一个浮点型表示的value价格;}s1,s2


3;直接定义结构体类型变量,就是第二种中省略结构体名的情况;


这种方式不能指明结构体类型名而是直接定义结构体变量,并且在值定义一次结构体变量时适用,无结构体名的结构体类型是无法重复使用的。


也就是说,后面程序不能再定义此类型变量了,除非再写一次重复的struct。


4、对于结构体变量的初始化


4.1;先回忆一下关于基本数据类型和数组类型的初始化;


int a = 0;


int array[4] = {1,2,3,4};//每个元素用逗号隔开 


回忆一下数组初始化问题;



再回到结构体变量的初始化吧?


关于结构体变量的初始化与初始化数组类似;


也是使用花括号括起来,用逗号分隔的初始化好项目列表,注意每个初始化项目必须要和要初始化的结构体成员类型相匹配。


struct book s1={//对结构体初始化 

        "yuwen",//title为字符串 

        "guojiajiaoyun",//author为字符数组 

        22.5    //value为flaot型 

    };

//要对应起来,用逗号分隔开来,与数组初始化一样;


4.2;加入一点小知识;


关于结构体初始化和存储类时期的问题;


如果要初始化一个具有静态存储时期的结构体,初始化项目列表中的值必须是常量表达式;


4.3;注意如果在定义结构体变量的时候没有初始化,那么后面就不能全部一起初始化了;


意思就是;


/////////这样是可以的,在定义变量的时候就初始化了;struct book s1={//对结构体初始化 "guojiajiaoyun",//author为字符数组 "yuwen",//title为字符串 22.5 };/////////这种就不行了,在定义变量之后,若再要对变量的成员赋值,那么只能单个赋值了;struct book s1; s1={ "guojiajiaoyun",//author为字符数组 "yuwen",//title为字符串 22.5 };//这样就是不行的,只能在定义的时候初始化才能全部赋值,之后就不能再全体赋值了,只能单个赋值;只能;s1.title = "yuwen";........//单个赋值;


4.4;对于结构体的指定初始化;



5、访问结构体成员


5.1;结构体就像一个超级数组,在这个超级数组内,一个元素可以是char类型,下个元素就可以是flaot类型,再下个还可以是int数组型,这些都是存在的。


在数组里面我们通过下标可以访问一个数组的各个元素,那么如何访问结构体中的各个成员呢?


用结构成员运算符点(.)就可以了;


结构体变量名.成员名; 


注意,点其结合性是自左至右的,它在所有的运算符中优先级是最高的;


例如,s1.title指的就是s1的title部分,s1.author指的就是s1的author部分,s1.value指的就是s1的value部分。


然后就可以像字符数组那样使用s1.title,像使用float数据类型一样使用s1.value;


注意,s1;虽然是个结构体,但是s1.value却是float型的。


因此s1.value就相当于float类型的变量名一样,按照float类型来使用;


例如;printf(“%s\n%s\n%f”,s1.title,s1.author,s1.value);//访问结构体变量元素


注意scanf(“%d”,&s1.value); 这语句存在两个运算符,&和结构成员运算符点。


按照道理我们应该将(s1。value括起来,因为他们是整体,表示s1的value部分)但是我们不括起来也是一样的,因为点的优先级要高于&。


5.2;如果其成员本身又是一种结构体类型,那么可以通过若干个成员运算符,一级一级的找到最低一级成员再对其进行操作;


结构体变量名.成员.子成员………最低一级子成员;


struct date{ int year; int month; int day;};struct student{ char name[10]; struct date birthday;}student1;//若想引用student的出生年月日,可表示为;student.brithday.year;brithday是student的成员;year是brithday的成员;


5.3;整体与分开


5.3.1;可以将一个结构体变量作为一个整体赋值给另一相同类型的结构体变量,可以到达整体赋值的效果;这个成员变量的值都将全部整体赋值给另外一个变量;


5.3.2;不能将一个结构体变量作为一个整体进行输入和输出;在输入输出结构体数据时,必须分别指明结构体变量的各成员;


-


总结;除开“相同类型的结构体变量可以相互整体赋值”外,其他情况下,不能整体引用,只能对各个成员分别引用;


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存