第九章
shyu
结构体:用户自定义的数据类型
如:在描述一个学生的相关信息时,需要整型变量来记录学号,字符数组来记录名字,等等,物品们可以通过定义结构体改变变量的数据类型,把这些信息整成一个变量
struct student 是类型,不是变量名,定义结构体变量的一般形式: struct 结构体名{成员表列};其中,对各个成员都要进行类型说明,成员名的命名规则与变量相同。
声明的一般形式:
Struct 结构名{
成员1的说明;
成员2的说明;
。。。。。。
成员n的说明;
}
也可以用宏来定义:
#define stu struct student
Stu{
成员1的说明;
成员2的说明;
。。。。。。
成员n的说明;
};
结构体变量的定义方法:
- 先定义结构体类型,在定义变量的名
{ int num;
char name [20];
char sex;
int age ;
};
struct student student1,student2;
这个意思是说,定义student1,student2;为struct student类型的变量
也可以用宏来帮助定义
- 在定义类型的时候定义变量
struct student
{ int num;
char name [20];
char sex;
int age ;
} student1,student2;
一般形式就是:
struct 结构体名
{
成员表列
}变量名表列;
- 直接定义结构体类型的变量:
一般形式就是:
struct
{
成员表列
}变量名表列;(此时不出现结构体名)
结构体变量的存储,一个结构体变量所占的字节数可以用sizeof运算符求出,一般形式就是:sizeof(变量名或者是类型标识符);
几点说明:
- 类型与变量的概念不要混淆,
- 结构体当中的成员也可以单独使用,作用和地位相当于普通变量;
- 成员也可以是一个结构体变量;
- 成员名可以与程序当中的变量名相同,但是二者不代表同一对象。
结构体变量的引用:
- 不能将一个结构体变量作为一个整体进行赋值和输出,只能对各个成员分别进行输出(引用形式为:结构体变量名.成员名),
- 若成员又是一个结构体变量,那么就只能对最低级的成员进行赋值或存取以及计算
- 成员变量可以和普通变量一样进行一系列的运算,
- 可以引用成员的地址,也可以引用结构体变量的地址
scanf(“%d”,&student1.num);就是输入student1.num的值
结构体变量的初始化:
对外部存储类型的结构体变量初始化:
struct student
{long int num;
char name[20];
char sex;
char addr[20];
} a={9801,”Wang hong”,’W’,”2 Linggong Road”};
main( )
{printf(“No.:%ld\nname:%s\nsex:%c\naddress:%s\n”,a.num,a.name,a.sex,a.addr);
}
结构体数组
每个数组元素都是一个结构体类型的数据
定义方式:
struct student struct student struct
{int num; {int num; {int num;
char name[20]; … …
char sex; } stu[3]; }stu[3];
int age;
char addr[30];
};
struct studnt stu[3];
结构体数组的初始化(只能对全局的或静态存储类别的数组初始化)
结构体数组的初始化的一般形式是在
定义数组后面加上:
={初值表列};
struct student
{int num;
char name[20];
char sex; int age;
char addr[30];
} stu[3]={{111,”Li”,’M’,18,”Dalian”},{…},{…}};
也可采用:struct student
{int num;
…
};
struct student stu[]={{…},{…},{…}};
结构体指针
1.指向结构体变量的指针:
定义格式为:
struct 结构名
{结构体};
struct 结构名 变量名1,变量名2,……,变量名n,*指针变量名1,*指针变量名2,……,*指针变量名n;
指针变量名1=&变量名1;
指针变量名2=&变量名2;
……
指针变量名n=&变量名n;
不允许如下的定义指针变量:
struct 结构名 *指针变量名1=&变量名1 ;
结构体变量的指针,是该结构体所占内存端的首地址。
2.指针变量的引用:
引用结果结构体成员的三种方式:
-
- 结构体变量名.成员名
- (*p).成员名
- P->成员名
->是指向运算符,运算优先级高于自增自减
试分析以下运算:
p->n 得到p指向的结构体变量中的成员n的值
p->n++ 得到p指向的结构体变量中的成员n的值,
用完后使它加1;
++p->n 得到p指向的结构体变量中的成员n的值
使其先加1
结构体与函数
1.结构体作为函数参数
结构体作为函数参数有三种方法:
-
- C语言允许结构变量成员作为函数参数
- C语言允许用结构变量做函数的参数
- 结构指针做函数参数
和普通变量一样,结构体变量作为函数参数,用于在函数之间传递数据。同时,函数的返回值也可以是结构变量。
结构变量作函数参数的传递方式与简单变量作函数参数的处理方式完全相同,即采用值传递的方式,形参结构变量中各成员值的改变,对相应实参结构变量不产生任何影响,但在函数定义时需要对其类型进行相应的说明。如:
int get_month(x)
struct month x;
{…
x.day=25;
…}
它说明了形参x是struct month型结构变量。
2.结构体类型的函数
结构体函数的一般定义形式为:
struct 结构类型名 函数名(形式参数列表)
{
函数体
}
其中,函数名func前面的类型说明符就是用于对函数返回值f的类型进行说明。
3.结构体指针型函数
当函数的返回值是结构体变量的首地址时,称该函数为结构体指针型函数,该函数的数据类型为结构体指针型例。如:
struct data *func(n)
float m;
{
struct data *f;
…
return(f);
}
结构体函数的一般定义形式为:
struct 结构类型名 *函数名(形式参数列表)
{
函数体
}
在调用结构体指针型函数时,用于接收结构体指针型函数返回值的变量应该是指向与该函数具有相同结构体类型的结构体指针变量。
结构体嵌套
如果一个结构成员是另一个结构体的成员变量,这种数据组织叫结构嵌套。
嵌套结构体变量的引用:
1、用成员运算符”.”
s1[1].h.post s1[1].birthday.year
2、用指针运算符“->”
struct stu *ps; ps=s1;
ps-> h.post ps-> birthday.year
用结构体指针操作链表
共用体:
使几个不同的变量共占同一段内存的结构,称为“共用体”类型的结构。
“共用体”类型变量的定义形式为:
union 共用体名
{成员表列
}变量表列;
例如:union data
{int i;
char ch;
float f;}a,b,c;
或
union data
{int i;
char ch;
float f;
};
union data a,b,c;
或
union
{int i;
char ch;
float f;
} a,b,c;
注意:只能引用共用体变量中的成员,不能引用共用体变量本身。如:
可以引用
a .i(引用共用体变量中的整型变量i)
a .ch(引用共用体变量中的字符变量ch)
a .f(引用共用体变量中的实型变量f)
不能只引用共用体变量,如:
printf(“%d”,a);
总之,和结构体非常相似,但也有所不同
结构体类型变量所占内存长度是各成员占的内存长度之和。
共用体类型变量所占内存长度等于最长的成员的长度。
共用体数据特点:
1.每一瞬时只有一个成员起作用 ;
2. 共用体变量中起作用的成员是最后一次存放的成员;
3.共用体变量的地址和它的各成员的地址都是同一地址;
4.不能对共用体变量名赋值,也不能企图引用变量名来得到成员的值,又不能在定义共用体变量时对它初始化。
5. 不能把共用体变量作为函数参数,也不能使函数带回共用体变量,但可使用指向共用体变量的指针;
6. 共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。而结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。
枚举类型:
若一个变量只有几种可能的值,可以定义为枚举类型。所谓“枚举”是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。
定义方法:
先定义枚举类型
enum weekday {sun, mon, tue, wed, thu, fri, sat};
再用此类型定义变量,如:
enum weekday workday, week_end;
或直接定义枚举变量。如:
enum weekday {sun, mon, tue, wed, thu, fri, sat}
workday,week_end;
几点说明:
1.枚举元素为常量,不是变量,故不能对它们赋值
2.枚举常量有值。如上面定义中,sun 、 mon 、 tue ······ sat的值依次为0、1、2······6
3.也可改变枚举元素的值,在定义时指出,如:
enum weekday{sun=7,mon=1,tue,wed,thu,fri,sat};
4.枚举值可用来作判断比较,如:
if(workday==mon) if(workday>sun)
5.一个整数不能直接赋值给一个枚举变量,应先进行强制类型转换才能赋值,如:
workday=(enum weekday)2; (相当于将序号为2的枚举元素值赋给workday , 即:workday=tue;
typedef类型声明
C语言允许用typedef说明一种新的数据类型名,其一般形式为:
typedef 类型名1 类型名2;
其中,关键字typedef用于给已有类型重新定义新类型名,类型名1为系统提供的标准类型名或是已定义过的其他类型名;类型名2为用户自定义的新类型名。它往往可以简化程序中变量的类型定义。例如:
typedef int WORD;
定义WORD等价于数据类型int,此后,就可用WORD对变量进行类型说明,如:
WORD a,b,c,*pa;
实际上,C编译程序把上述变量作为一般的整型变量处理。在这种情况下,变量所表示的含义较为清楚,从而增加了程序的可读性。
就是说:后面的类型具有与前面的类型相同的意思
对typedef的几点使用说明如下:
(1) typedef不能用于变量的定义,只能对已存在的类型增加新的类型名,而不能定义新的类型。
(2) 从表面上看,typedef与#define的使用方式十分相似,但两者本质上是不同。
例如:
typedef int COUNT
#define COUNT int
typedef定义的是一种新的数据类型,类型名为COUNT,它是系统标准类型(int)的别名,在预编译时,编译器会将COUNT与int作为同一个类型来处理。
#define定义的是一个宏,宏名为COUNT,在预编译时,编译器将进行宏替换,把字符串COUNT替换为字符串int。