1、1结构体型变量的定义,形式一, 类型、 变量分别定义:,struct staff char name20; /* 姓名 */char department20; /* 部门 */int salary; /* 工资 */int cost; /* 扣款 */int realsum; /* 实发工资 */; struct staff worker1, worker2;,2、内存的动态分配,2.1 动态分配内存的意义,2.2开辟和释放内存区的函数,1. malloc()函数它的函数原型为 void *malloc(unsigned size); 其功能是在内存的动态存贮区中分配长度为size个字节的连
2、续空间。 其返回值= 分配空间的起始地址 (分配成功)空指针NULL (分配失败, 一般是没有空间),2. free(p):释放由p指向的内存区,使这部分内存可以分配给其它变量,例 分配一个能放置双精度数的空间。,include main()double *p; p=(double *)malloc(sizeof(double); /* 注1 */if(p=0) printf(“malloc errorn“); exit(0); *p=78.786; printf(“*p=%fn“, *p); 运行结果: *p=78.786000,另外, 对注1行有两点说明: (1) 从malloc函数原形可
3、以得知,其返回值为void *型, 现在是对双精度型分配空间,所以要将其返回值强行转换为double * 型。 (2) 程序中出于易于移植的考虑,使用了sizeof(double)作为malloc函数的实参。因为不同机器上的双精度所占的字节数可能不同,用这种方法不论在哪种机器上都能为双精度型数据分配大小正确的空间。,另外两个相关函数是calloc()及realloc()其原型为 void *calloc(unsigned n, unsigned size);void *realloc(void *p, unsigned size);calloc()的功能是分配n个大小为size个字节的连续空间
4、, 它实际上是用于动态数组的分配。 realloc()的功能是将p所指出的已分配的内存空间重新分配成大小为size个字节的空间。它用于改变已分配的空间的大小,可以增减单元数。,9.4.3 链表概述,图 9.3 单向链表示意图,3建立链表,所谓建立链表即是从无到有的形成一个链表。 建立链表的思想很简单:逐个地输入各结点的数据,同时建立起各结点的关系。这种建立关系可能是正挂、倒挂或插入,下面介绍前两种: 建立链表方法一:正挂即先建立链头, 让链头指向首先开辟并输入数据的第一个结点;然后开辟并输入第二个结点数据,将其“挂”到第一个结点之后; 接着开辟第三个结点并输入实际数据,将其“挂”在第二个结点之
5、后,即按输入顺序将结点“挂”接在一起。 在实际编程时, 还有些细节要考虑, 如是否为空链等。,针对9.4.1节提出的问题, 我们建立一个职工工资链表, 现定义结点类型如下:,struct staffchar name20; int salary; struct staff *next;,(为了简化程序,减少了原有的数据成员项),在形成链表的过程中,首先要定义头指针,并且还需要两个工作指针p1、 p2 ,其定义如下: struct staff *head , *p1, *p2; ,具体步骤描述如下: (1)开始时先建一个空链表: head=NULL;形如:head (2) 开辟第一个结点空间并由
6、p1指向,即p1=(struct staff*)(malloc(LEN); LEN为结点结构体类型staff的一个变量所占字节数。之后, 执行语句: scanf(“%s %d“, p1-name, 读入其有效数据,(以工资大于0为有效数据),执行head = p1; 将其挂到链头上,(如虚线所示,其后的链表图类似)。 ,NULL,形如:,其中worker1代表第一个工人的姓名;至于head的具体内容是什么,即p1的值是多少,由系统决定,我们无需关心。,(3) 移动p2,使其指向最后一个结点,即执行p2=p1。形如:,(4) 再开辟下一个结点的空间由p1指向,即再次执行: p1=(struct
7、staff*)malloc(LEN);读入有效数据后,执行p2-next=p1;将其挂至链尾。,(5) 重复3、4两步,直至所读数据无效,即p2所指为真正尾结点, 此时令p2-next=NULL,建链结束。形如:,例 正向建立链表程序清单。,include define NULL 0define LEN sizeof(struct staff)struct staff char name20; int salary; struct staff *next; ; int n; main(), struct staff *creat1(); /* 二函数声明 */void print(struct
8、 staff *p ); struct staff *head; head=creat1(); /* 调子函数建立链表 */print(head); /* 从头开始显示链表各结点的数据信息 */ struct staff *creat1() struct staff *head, *p1, *p2; n=0; p1=(struct staff *)malloc(LEN); /* 开辟第一结点 */printf(“Input the workers name salary (salary=0 end): n“); scanf(“%s %d“, p1-name, /* 读入第一结点数据 */,he
9、ad=NULL; /* 建空链 */ while(p1-salary0) n=n+1; /* 结点数加1 */if(n=1) head=p1; /* “挂链” */else p2-next=p1; p2=p1; /* 移动指针p2*/p1=(struct staff *)malloc(LEN); /* 开辟下一结点空间 */scanf(“%s %d“, p1-name, /* 读入数据 */,p2-next=NULL; /* 数据无效置链尾 */return (head); /* 返回链头 */ void print(struct staff *head) struct staff *p; p
10、=head; /* p指向链头 */while(p! =NULL) /* 未至链尾,则显示结点数据信息 */ printf(“%ss salary is %dn“, p-name, p-salary); p=p-next; /* p后移一结点 */,程序运行情况: Input the workers name salary(salary=0 end):W1 1000 (输入)W2 2000 W3 3000 W 0 W1s salary is 1000 (输出)W2s salary is 2000W3s salary is 3000,4 链表的其它操作,1 遍历输出,图 9.7 遍历示意图,2
11、查找查找思路类似遍历输出,只是将输出换成比较, 在查找到所要找的一个或全部项后结束子函数。,3 删除删除是将某一结点从链中摘除,即将待删结点与其前一结点解除联系。如图9.8(a)(head=p1-next) 或图9.8(b) (p2-next =p1-next)。之后顺着链头就访问不到p1结点了,即p1所指的结点被删除了,不再是链表的一部分了。,图 9.8 删除链表示意图,4 插入,链表插入示意图,5 文 件,5.1 文件的概念,磁盘文件在DOS管理中被定义为存贮在外部介质上的程序或数据的集合, 是一批逻辑上有联系的数据每个文件都有一个文件名作为标识,每个文件在磁盘中的具体存放位置、格式都由操
12、作系统中的文件系统管理, 也就是说,操作系统是以文件为单位对程序或数据进行管理的。编辑后存于磁盘上的源程序文件*.C,经编译后得到的目标文件*.OBJ,连接之后形成的可执行文件*.EXE等。,在C语言中文件的含义更为广泛,不仅包含以上所述的磁盘文件,还包括一切能进行输入/输出的终端设备,它们被看成是设备文件。如键盘常称为标准输入文件,显示器称为标准输出文件。 文件是由磁盘文件和设备文件组成的。作为磁盘文件之一的数据文件是本章学习的主要对象。数据文件可以看作是C中最后一种数据类型, 是C语言重要的组成部分。根据文件内数据的组织形式,文件可分为文本(text)文件和二进制文件。文本文件又称为ASC
13、II码文件,它的每一个字节存放一个字符的ASCII码。,5.2 文件操作步骤,一般缓冲文件操作有三个必需的步骤: (1) 在使用文件前要调用打开函数将文件打开, 若打开失败,则返回一个空指针;若打开正常,可以得到一个文件指针,并利用它继续对文件操作。 (2) 可调用各种有关函数,利用该指针对文件进行具体处理,一般要对文件进行读或写操作。 (3) 在文件用完时,应及时调用关闭函数来关闭文件, 切断数据流,防止数据遗失或误操作破坏文件内容。,文件指针,文件类型FILE不是C语言的新类型,它是用typedef定义出来的有关文件信息的一种结构体类型。如Turbo C 2.0版的stdio.h文件中有如
14、下的定义:,typedef struct short level; /* 缓冲区“满”或“空”的程度 */unsigned flags; /* 文件状态标志 */char fd; /* 文件描述符 */unsigned char hold; /* 如无缓冲区不读取字符 */,short bsize; /* 缓冲区的大小 */unsigned char *buffer; /* 数据缓冲区的位置 */unsigned char *curp; /* 当前工作指针 */unsigned istemp; /* 临时文件, 指示器 */short token; /* 用于有效性检查 */ FILE;,5.
15、3 打开文件(fopen函数),打开函数fopen() 的调用方式是: FILE *fp; fp=fopen(文件名, 使用文件方式); 例如, fp=fopen(“A1.DAT“, “r“);,表 12.1 文件使用方式,5.4 关闭文件(fclose函数),在使用完一个文件后应该调用fclose函数关闭文件。fclose函数的调用格式为fclose(文件指针)。例如fclose(fp);就把指针fp所指的文件关闭了,也就是断开了打开文件时建立的数据流fp与具体文件的联系,即不能再通过fp对某个具体文件进行操作。,如果在程序终止之前不关闭文件, 将可能丢失缓冲区中最后一批未处理的数据,因为f
16、close函数的调用不仅释放文件指针,还刷新缓冲区。fclose函数将缓冲区中可能遗留的未装满送走的数据输入内存或输出至磁盘文件,以确保数据不丢失。当然,程序结束时会自动关闭文件,但用完文件后及时关闭是一个好的编程习惯。 fclose函数也返回一个值:0表示顺利返回,非0表示关闭错误。,5.5 fprinf函数和fscanf函数fprintf函数、fscanf函数与printf和scanf函数作用类似, 都是格式化读写函数。前二者的读写对象是磁盘文件,而后二者是终端设备。所以前二者函数调用参数中要多出一代表文件的文件指针。一般调用方式为 fprintf(文件指针, 控制字符串, 参量表); f
17、scanf(文件指针, 控制字符串, 参量表);,例 按格式键入字符型、整型、实型各一数,写入文件dform.dat,再读出送显。,includemain() int i, i1; char ch, ch1; float f, f1; FILE *fp; printf(“nInput ch i f: “); scanf(“%c %d %f“, ,if(fp=fopen(“dform.dat“, “w“)=NULL) /* 注1*/printf(“Can not open the filen“); exit(0); fprintf(fp, “%c %5d %4.1f“, ch, i, f); /
18、* 注2 */fclose(fp); /* 注3 */if(fp=fopen(“dform.dat“, “r“)=NULL)printf(“Can not open the filen“); exit(0); fscanf(fp, “%c %d %f“, ,5.6 . fread函数和fwrite函数,它们的一般调用形式为 fread(buffer, size, count, fp); fwrite(buffer, size, count, fp); 其中: buffer 是一个地址。对fread来说,它是读入数据将要存放处的地址。对fwrite来说,是要输出数据的地址(以上指的是起始地址)。
19、 size是要读写的一个数据块的字节数。 count是要进行读写数据块的个数。 fp是文件指针, 指向待读或写的文件。,例 建立一个有关工人工资的数据文件。,includedefine SIZE 6struct staff char name10; int salary; int cost; workerSIZE; void savef() FILE *fp; int i; if(fp=fopen(“work.dat“, “wb“)=NULL),printf(“Can not open the filen“); return; for(i=0; iSIZE; i+)if(fwrite( ,6
20、链表典型操作的各函数头的定义,struct student *creat(void) void print(struct student *head) struct student *del(struct student *head,int sno) struct student * insert(struct student *head,struct student *stud) struct student * sort(struct student *head,struct student *stud),#define NULL 0 #define LEN sizeof(struct s
21、tudent) struct student long num;char name12;char sex;int age;char tel15;char addr10; struct student *next; ;,将链表中的节点内容写到文件中,void save(struct student *head) struct student *p;FILE *fp;fp=fopen(“st_list“,“wb“); p=head;while(p!=NULL) fwrite(p,LEN,1,fp); p=p-next; fclose(fp); ,读取文件内容重构链表,struct student
22、*load() struct student *head,*p1,*p2;FILE *fp;n=0;head=NULL;fp=fopen(“st_list“,“rb“);,p2=p1=(struct student *)malloc(LEN); while(!feof(fp) fread(p1,LEN,1,fp);n+;if(n=1) head=p1;p2=p1;else p2-next=p1;p2=p1; p1=(struct student *)malloc(LEN);p2-next=NULL;return(head); ,需要用到的函数,清屏:#include system(“cls”),获取系统时间: #include time_t timer; /time_t获得当前时间到1900年1月1日之间的相隔秒数 struct tm *local_t; /tm 为一个时间格式,有年月天小时分钟秒等基本信息 char curtime20; time(,