01
- 定义一个结构的一般形式为:
struct 结构名
{
成员表列
};
成员表列由若干个成员组成,每个成员都是该结构的一个组成部分。对每个成员也必须作类型说明,其形式为:
类型说明符 成员名;
例:
struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }; |
- 可以采取以下3种方法定义结构体类型变量:
- 先声明结构体类型再定义变量名
例如:struct(类型名) student(结构体) student1(变量名)
定义了student1为struct student类型的变量,即它具有
struct student类型的结构。
- 在声明类型的同时定义变量,这种形式的定义的一般形式为:
struct 结构体名
{
成员表列
}变量名表列;
- 直接定义结构体类型变量,其一般形式为:
strcut
{
成员表列
}变量名表列;
3、结构的嵌套:
struct date{ Int month; Int day; Int year; }; |
struct{ int num; char name[20]; char sex; struct data birthday; float score; }boy1,boy2; |
- 在定义了结构体变量以后,当然可以引用这个变量。但应遵守以下规则:
- 不能将一个结构体变量作为一个整体进行输入和输出。
正确引用结构体变量中成员的方式为:
结构体变量名.成员名
“.”是成员(分量)运算符,它在所有的运算符中优先级最高,因此可以把student1.num作为一个整体来看待。
- 如果成员本身又属于一个结构体类型,则要用若干个成员运算符,一级一级地找到最低的一级的成员。只能对最低级的成员进行赋值或存取以及运算。
- 对结构体变量的成员可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)。
- 可以引用结构体变量成员的地址,也可以引用结构体变量的地址。
- 结构体变量的地址主要用作函数参数,传递结构体变量的地址。
02
1、结构体变量的初始化:
struct student{ int num; char *name; char sex; float score; }boy1,boy2={102,”Jane”,’M’,98.5}; boy1 = boy2; |
- 结构体数组:一个结构体变量中可以存放一组数据(如一个学生的学号、姓名、成绩等数据)。如果有10个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。
- 结构体数组与以前介绍过的数值型数组不同之处在于每个数组元素都是一个结构体类型的数据,它们都分别包括各个成员(分量)项。
- 定义结构体数组和定义结构体变量的方法相仿,只需说明其为数组即可。例如:
struct student{ int num; char name[20]; char sex; int age; float score; char addr[30]; }; struct student student[3]; |
struct student{ int num; char name[20]; char sex; int age; float score; char addr[30]; }student[3];
|
- 与其他类型的数组一样,对结构体数组可以初始化。例如:
struct student{ int num; char name[20]; char sex; int age; float score; char addr[30]; }stu[2]={{101,”lilin”,’M’,18,87.5,”beijing”}, {102,”zhangsan”,’F’,19,99,”shanghai”} }; |
- 结构体数组初始化另一种形式:即先声明结构体类型,然后定义数组为该结构体类型,在定义数组时初始化。
Struct student{ Int num; ... }; Struct student str[]={{...},{...},{...}}; |
- 指向结构体类型数据的指针:一个结构体变量的指针就是该结构体变量所占据的内存段的起始地址。
- 可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。
- 指针变量也可以用来指向结构体数组中的元素。
- 结构指针变量说明的一般形式为:
struct 结构名 *结构指针变量名
例如:在前面的例题中定义了stu这个结构,如要说明一个指向stu的指针变量pstu,可写为:struct stu *pstu;
当然也可以在定义stu结构时同时说明pstu。与前面讨论的各类指针变量相同,结构指针变量也必须要先赋值后才能使用。
- 赋值是把结构变量的首地址赋予该指针变量,不能把结构名赋予该指针变量。
12、
struct stu{ ... }boy; |
如果boy是被说明为stu类型的结构变量,则pstu=&boy是正确的;pstu=&stu是错误的。
因为结构名和结构变量是两个不同的概念。结构名只能表示一个结构形式,编译系统并不对它分配内存空间。只有当某变量被说明为这种类型的结构时,才对该变量分配存储空间。因此上面&stu这种写法是错误的,不可能去取一个结构名的首地址。
有了结构指针变量,就能更方便地访问结构变量的各个成员。
13、访问的一般形式:
- (*结构指针变量).成员名 (&pstu).num
- 结构指针变量->成员名 pstu->num
03
- 将一个结构体变量的值传递给另一个函数,有3个方法:
- 用结构体变量的成员作参数
#include<stdio.h> #include<string.h>
struct student{ int num; char name[20]; float score[3]; };
void print(struct student);
void main(){ struct student stu;
stu.num=8; strcpy(stu.name,"zhaoyuan");//可将name改为指针变量,后 //stu.name=”zhaoyuan”; stu.score[0]=98.5; stu.score[1]=90.5; stu.score[2]=96.5;
print(stu);
}
void print(struct student stu){ printf("\tnum :%d\n",stu.num); printf("\tname :%s\n",stu.name); printf("\tscore_1 :%5.2f\n",stu.score[0]); printf("\tscore_2 :%5.2f\n",stu.score[1]); printf("\tscore_3 :%5.2f\n",stu.score[2]); printf("\n"); } |
- 用结构体变量作实参
- 用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参。
#include<stdio.h> #include<string.h>
struct student{ int num; char *name; float score[3]; };
void print(struct student *);
void main(){ struct student stu;
stu.num=8; stu.name="zhaoyuan"; stu.score[0]=98.5; stu.score[1]=90.5; stu.score[2]=96.5;
print(&stu);
}
void print(struct student *p){ printf("\tnum :%d\n",p->num); printf("\tname :%s\n",p->name); printf("\tscore_1 :%5.2f\n",p->score[0]); printf("\tscore_2 :%5.2f\n",p->score[1]); printf("\tscore_3 :%5.2f\n",p->score[2]); printf("\n"); } |
- 常用的内存管理函数有以下3个:
- 分配内存空间函数:malloc、calloc。
- 释放内存空间函数:free。
- malloc函数:
函数原型为void *malloc(unsigned int size);
其作用是在内存的动态存储区中分配一个长度为size的连续空间(size是一个无符号数)。
此函数的返回值是一个指向分配域起始地址的指针(类型为void)。
如果此函数未能成功地执行(例如内存空间不足),则返回空指针(NULL)。
- calloc函数:
函数原型为void *calloc(unsigned n,unsigned size);
其作用是在内存的动态存储区中分配n个长度为size的连续空间。
函数返回一个指向分配域起始地址的指针。
如果分配不成功,则返回NULL。
用calloc函数可以为一维数组开辟动态存储空间,n为数组元素个数,每个元素长度为size。
- free函数:
函数原型为void free (void *p);
其作用是释放由p指向的内存区,使这部分内存区能被其他变量使用。
p是最近一次调用calloc或malloc函数时返回的值。
free函数无返回值。
- 链表是一种常见的重要的数据结构,是动态地进行存储分配的一种结构。
- 链表的组成:
头指针:存放一个地址,该地址指向第一个元素。
结点:用户需要的实际数据和链接节点的指针。
- 所谓建立动态链表是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。
04
- 实现链表输出:首先要知道链表第一个结点的地址,也就是要知道head的值。然后设一个指针变量p,先指向第一个结点,输出p所指的结点,然后使p后移一个结点,再输出,知道链表的尾结点。
- 链表的删除操作:从一个动态链表中删去一个结点,并不是真正从内存中把它抹掉,而是把它从链表中分离开来,只要撤销原来的链接关系即可。
05
- 对链表的插入操作:对链表的插入是将一个结点插入到一个已有的链表中。
为了能做到正确插入,必须解决两个问题:(1)怎样找到插入的位置(2)怎样实现插入
我们可以先用指针变量p0指向待插入的结点,p1指向第一个结点,。将p0->num与p1->num相比较,如果p0->num > p1->num,此时将p1后移,并使p2指向刚才p1所指的结点。
06
- 共用体的概念:使几个不同的变量共占同一段内存的结构称为“共用体”类型的结构。
定义共用体类型变量的一般形式为:
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; |
- 共用体和结构体的比较:结构体变量所占内存长度是各成员占的内存长度之和。每个成员分别占有其自己的内存单元。
共用体变量所占的内存长度等于最长的成员的长度。
例如:上面定义的“共用体”变量a,b,c各占4个字节(因为一个实/整型变量各占4个字节),而不是各占4+1+4=9个字节。
- 共用体变量的引用方式:只有先定义了共用体变量才能引用它,而且不能引用共用体变量,而只能引用共用体变量中的成员。
例如:前面定义了a、b、c为共用体变量
a.i:引用共用体变量中的整型变量i
a.ch:引用共用体变量中的字符变量ch
a.f:引用共用体变量中的实型变量f
4、共用体类型数据的特点:
(1)同一个内存段可以用来存放几种不同类型的成员,但在每一瞬间只能存放其中一种,而不是同时存放几种。
(2)共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员就失去作用。
(3)共用体变量的地址和它的各成员的地址都是同一地址。
(4)不能对共用体变量名赋值,也不能企图引用变量名来得到一个值,又不能在定义共用体变量时对它初始化。
(5)不能把共用体变量作为函数参数,也不能使函数带回共用体变量,但可以使用指向共用体变量的指针。
(6)共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。
5、在实际问题中,有些变量的取值被限定在一个有限的范围内。为此,有了枚举类型。
6、枚举变量的声明:设有变量a,b,c被说明为weekday,可采用下述任一种方式:
enum weekday {sum,mon,tue,wed,thu,fri,sat};
enum weekday a,b,c;
或者为:
enum weekday {sum,mon,tue,wed,thu,fri,sat}a,b,c;
或者为:
enum {sum,mon,tue,wed,thu,fri,sat}a,b,c;
- 枚举类型中需要注意的地方:
- 在枚举类型的定义中列举出所有可能的取值,被说明为该枚举类型的变量取值不能超过定义的范围。
- 枚举类型是一种基本数据类型,而不是一种构造类型,因为它不能再分解为任何基本类型。
- 在枚举值表中应罗列出所有可用值。这些值也称为枚举元素。
- 在c语言中,对枚举元素按常量处理,故称枚举常量。它们不是变量,不能对它们赋值。
- 枚举元素作为常量,它们是有值的,c语言编译按定义时的顺序使它们的值为0,1,2...
- 枚举值可以用来作判断比较。
- 一个整数不能直接赋给一个枚举变量。
07
- 用typedef声明新的类型名来代替已有的类型名。
声明INTEGER为整型:typedef int INTEGER
声明结构类型:
typedef struct{
Int month;
Int day;
Int year;
}DATE;
- 声明NUM为整型数组类型:typedef int NUM[100];
- 声明STRING为字符指针类型:typedef char* STRING;
- 声明POINTER为指向函数的指针类型,该函数返回整型值。:
typedef int (*POINTER)();
- 关于typedef的一些说明:
- 用typedef可以声明各种类型名,但不能用来定义变量。
- 用typedef只是对已经存在的类型增加一个类型名,而没有创造新的类型。
- 当不同源文件中用到同一类型数据时,常用typedef声明一些数据类型,把它们单独放在一个文件中,然后在需要用到它们的文件中用#include命令把它们包含进来。
- 使用typedef有利于程序的通用与移植。
- Typedef与#define有相似之处,例如:typedef int COUNT;
#define COUNT int的作用都是用COUNT代表int。但是,二者却有不同。#define是在预编译时处理的,它只能作简单的字符串替换,而typedef是在编译时处理的。实际上它并不是作简单的字符串替换,而是采用如同定义变量的方法那样来声明一个类型。
7.区别:typedef和define
Typedef (int*) p1;
#define p2 int*
另外,一个有分号,一个没有分号。