好好学习,天天向上,自学网欢迎您!
当前位置:首页 >  考试 >  计算机类 > 内容页

C语言的布局与结合的实例剖析

2021-08-30 07:30:01计算机类访问手机版149

  C语言的布局与结合的实例剖析

  引导语:布局体是由一系列具有不异范例或差别范例的数据构成的数据汇合。以下是小编分享给大师的C语言的布局与结合的实例剖析,欢送阅读!

   布局范例界说和布局变量阐明

  在实际成绩中,一组数据常常具有差别的数据范例。比方, 在学生注销表中,姓名应为字符型;学号可为整型或字符型; 春秋应为整型;性别应为字符型;成果可为整型或实型。 显然不克不及用一个数组来寄存这一组数据。 因为数组中各元素的范例和长度都必需分歧,以便于编译系统处置。为懂得决这个成绩,C语言中给出了另外一种机关数据范例——“布局”。 它相当于别的初级语言中的记实。

  “布局”是一种机关范例,它是由多少“成员”构成的。 每个成员可以是一个根本数据范例大概又是一个机关范例。 布局既是一种“机关”而成的数据范例, 那么在阐明和使用之前必需先界说它,也就是机关它。好像在阐明和调用函数之前要先界说函数一样。

  1、布局的界说

  界说一个布局的一样平常方式为:

  struct 布局名

  成员表列

  ;

  成员表由多少个成员构成, 每一个成员都是该布局的一个构成局部。对每一个成员也必需作范例阐明,其方式为:

  范例阐明符 成员名;

  成员名的定名应合适标识符的书写规则。比方:

  struct stu

  int num;

  char name[20];

  char sex;

  float score;

  ;

  在这个布局界说中,布局名为stu,该布局由4个成员构成。 第一个成员为num,整型变量;第二个成员为name,字符数组;第三个成员为sex,字符变量;第四个成员为score,实型变量。 应注意在括号后的分号是不成少的。布局界说之后,便可进行变量阐明。 凡阐明为布局stu的变量都由上述4个成员构成。因而可知, 布局是一种复杂的数据范例,是数目固定,范例差别的多少有序变量的汇合。

  2、布局范例变量的阐明

  阐明布局变量有以下三种办法。以上面界说的stu为例来加以阐明。

  1. 先界说布局,再阐明布局变量。如:

  struct stu

  int num;

  char name[20];

  char sex;

  float score;

  ;

  struct stu boy1,boy2;

  阐明了两个变量boy1和boy2为stu布局范例。也能够用宏界说使一个标记常量来透露表现一个布局范例,比方:

  #define STU struct stu

  STU

  int num;

  char name[20];

  char sex;

  float score;

  ;

  STU boy1,boy2;

  2. 在界说布局范例的同时阐明布局变量。比方:

  struct stu

  int num;

  char name[20];

  char sex;

  float score;

  boy1,boy2;

  3. 间接阐明布局变量。比方:

  struct

  int num;

  char name[20];

  char sex;

  float score;

  boy1,boy2;

  第三种办法与第二种办法的差别在于第三种办法中省去告终构名,而间接给出布局变量。三种办法中阐明的boy1,boy2变量都具有图1.1所示的布局。阐明了boy1,boy2变量为stu范例后,便可向这两个变量中的各个成员赋值。在上述stu布局界说中,所有的成员都是根本数据范例或数组范例。成员也能够又是一个布局, 即构成为了嵌套的布局。比方,图1.2给出了另外一个数据布局。 按图1.2可给出以下布局界说:

  struct date

  int month;

  int day;

  int year;

  struct

  int num;

  char name[20];

  char sex;

  struct date birthday;

  float score;

  boy1,boy2;

  首先界说一个布局date,由month月、day日、year年 三个成员构成。 在界说并阐明变量 boy1 和 boy2 时, 此中的成员birthday被阐明为data布局范例。成员名可与顺序中别的变量同名,互不搅扰。布局变量成员的透露表现办法在顺序中使用布局变量时, 常常不把它作为一个整体来使用。

  在ANSI C中除了答应具有不异范例的布局变量彼此赋值以外, 一样平常对布局变量的使用,包含赋值、输入、输出、 运算等都是经由过程布局变量的成员来实现的。

  透露表现布局变量成员的一样平常方式是: 布局变量名.成员名 比方:boy1.num 即第一小我私家的学号 boy2.sex 即第二小我私家的性别 假如成员自身又是一个布局则必需逐级找到最初级的成员才干使用。比方:boy1.birthday.month 即第一小我私家出身的月份成员可以在顺序中独自使用,与普通变量完全不异。

  布局变量的赋值

  后面曾经介绍,布局变量的赋值就是给各成员赋值。 可用输入语句或赋值语句来完成。

  [例1.1]给布局变量赋值并输出其值。

  main

  struct stu

  int num;

  char *name;

  char sex;

  float score;

  boy1,boy2;

  boy1.num=102;

  boy1.name="Zhang ping";

  printf"input sex and score ";

  scanf"%c %f",&boy1.sex,&boy1.score;

  boy2=boy1;

  printf"Number=%d Name=%s ",boy2.num,boy2.name;

  printf"Sex=%c Score=%f ",boy2.sex,boy2.score;

  struct stu

  int num;

  char *name;

  char sex;

  float score;

  boy1,boy2;

  boy1.num=102;

  boy1.name="Zhang ping";

  printf"input sex and score ";

  scanf"%c %f",&boy1.sex,&boy1.score;

  boy2=boy1;

  printf"Number=%d Name=%s ",boy2.num,boy2.name;

  printf"Sex=%c Score=%f ",boy2.sex,boy2.score;

  本顺序顶用赋值语句给num和name两个成员赋值,name是一个字符串指针变量。用scanf函数静态地输入sex和score成员值,然后把boy1的所有成员的值整体付与boy2。最后辨别输出boy2 的各个成员值。本例透露表现告终构变量的赋值、输入和输出的办法。

   布局变量的初始化

  假如布局变量是全局变量或为静态变量, 则可对它作初始化赋值。对部分或自动布局变量不克不及作初始化赋值。

  [例1.2]外部布局变量初始化。

  struct stu /*界说布局*/

  int num;

  char *name;

  char sex;

  float score;

  boy2,boy1=102,"Zhang ping",'M',18.5;

  main

  boy2=boy1;

  printf"Number=%d Name=%s ",boy2.num,boy2.name;

  printf"Sex=%c Score=%f ",boy2.sex,boy2.score;

  struct stu

  int num;

  char *name;

  char sex;

  float score;

  boy2,boy1=102,"Zhang ping",'M',18.5;

  main

  boy2=boy1;

  ……

  本例中,boy2,boy1均被界说为外部布局变量,并对boy1作了初始化赋值。在main函数中,把boy1的值整体付与boy2, 然后用两个printf语句输出boy2各成员的值。

  C语言的布局与结合的实例剖析

  [例1.3]静态布局变量初始化。

  main

  static struct stu /*界说静态布局变量*/

  int num;

  char *name;

  char sex;

  float score;

  boy2,boy1=102,"Zhang ping",'M',18.5;

  boy2=boy1;

  printf"Number=%d Name=%s ",boy2.num,boy2.name;

  printf"Sex=%c Score=%f ",boy2.sex,boy2.score;

  static struct stu

  int num;

  char *name;

  char sex;

  float score;

  boy2,boy1=102,"Zhang ping",'M',18.5;

  本例是把boy1,boy2都界说为静态部分的布局变量, 同样可以作初始化赋值。

  布局数组

  数组的元素也能够是布局范例的。 因此可以构成布局型数组。布局数组的每个元素都是具有不异布局范例的下标布局变量。 在实际应用中,常常用布局数组来透露表现具有不异数据布局的一个群体。如一个班的学生档案,一个车间职工的工资表等。

  布局数组的界说办法和布局变量相似,只需阐明它为数组范例便可。比方:

  struct stu

  int num;

  char *name;

  char sex;

  float score;

  boy[5];

  界说了一个布局数组boy1,共有5个元素,boy[0]~boy[4]。每一个数组元素都具有struct stu的布局方式。 对外部布局数组或静态布局数组可以作初始化赋值,比方:

  struct stu

  int num;

  char *name;

  char sex;

  float score;

  boy[5]=

  101,"Li ping","M",45,

  102,"Zhang ping","M",62.5,

  103,"He fang","F",92.5,

  104,"Cheng ling","F",81,

  105,"Wang ming","M",58;

  当对全部元素作初始化赋值时,也可不给出数组长度。

  [例1.4]较量争论学生的平均成果和不合格的人数。

  struct stu

  int num;

  char *name;

  char sex;

  float score;

  boy[5]=

  101,"Li ping",'M',45,

  102,"Zhang ping",'M',62.5,

  103,"He fang",'F',92.5,

  104,"Cheng ling",'F',81,

  105,"Wang ming",'M',58,

  ;

  main

  int i,c=0;

  float ave,s=0;

  fori=0;i<5;i++

  s+=boy[i].score;

  ifboy[i].score<60 c+=1;

  printf"s=%f ",s;

  ave=s/5;

  printf"average=%f count=%d ",ave,c;

  本例顺序中界说了一个外部布局数组boy,共5个元素, 并作了初始化赋值。在main函数顶用for语句逐个累加各元素的score 成员值存于s当中,如score的值小于60不合格即计数器C加1, 循环完毕后较量争论平均成果,并输出全班总分,平均分及不合格人数。

  [例1.5]设立建设同学通讯录

  #include"stdio.h"

  #define NUM 3

  struct mem

  char name[20];

  char phone[10];

  ;

  main

  struct mem man[NUM];

  int i;

  fori=0;i

  printf"input name: ";

  getsman[i].name;

  printf"input phone: ";

  getsman[i].phone;

  printf"name phone ";

  fori=0;i  printf"%s %s ",man[i].name,man[i].phone;

  本顺序中界说了一个布局mem,它有两个成员name和phone 用来透露表现姓名和德律风号码。在主函数中界说man为具有mem 范例的布局数组。在for语句中,用gets函数辨别输入各个元素中两个成员的值。然后又在for语句顶用printf语句输出各元素中两个成员值。

  布局指针变量

  布局指针变量的阐明和使用一个指针变量当用来指向一个布局变量时, 称之为布局指针变量。

  布局指针变量中的值是所指向的布局变量的首地点。 经由过程布局指针便可拜访该布局变量, 这与数组指针和函数指针的环境是不异的。布局指针变量阐明的一样平常方式为:

  struct 布局名*布局指针变量名

  比方,在后面的例1.1中界说了stu这个布局, 如要阐明一个指向stu的指针变量pstu,可写为:

  struct stu *pstu;

  固然也可在界说stu布局时同时阐明pstu。与后面评论辩论的各种指针变量不异,布局指针变量也必需要先赋值后才干使用。赋值是把布局变量的首地点付与该指针变量, 不克不及把布局名付与该指针变量。假如boy是被阐明为stu范例的布局变量,则: pstu=&boy是正确的,而: pstu=&stu是过错的。

  布局名和布局变量是两个差别的观点,不克不及混合。 布局名只能透露表现一个布局方式,编译系统其实不对它分派内存空间。 只有当某变量被阐明为这种范例的布局时,才对该变量分派存储空间。 因此上面&stu这种写法是过错的,不成能去取一个布局名的首地点。 有告终构指针变量,就可以更便当地拜访布局变量的各个成员。

  其拜访的一样平常方式为: *布局指针变量.成员名 或为:

  布局指针变量->成员名

  比方: *pstu.num大概: pstu->num

  该当注意*pstu两侧的括号不成少, 因为成员符“.”的优先级高于“*”。如去掉括号写作*pstu.num则等效于*pstu.num,这样,意义就完全不合错误了。 下面经由过程例子来阐明布局指针变量的具体阐明和使用办法。

  [例1.6]

  struct stu

  int num;

  char *name;

  char sex;

  float score;

  boy1=102,"Zhang ping",'M',18.5,*pstu;

  main

  pstu=&boy1;

  printf"Number=%d Name=%s ",boy1.num,boy1.name;

  printf"Sex=%c Score=%f ",boy1.sex,boy1.score;

  printf"Number=%d Name=%s ",*pstu.num,*pstu.name;

  printf"Sex=%c Score=%f ",*pstu.sex,*pstu.score;

  printf"Number=%d Name=%s ",pstu->num,pstu->name;

  printf"Sex=%c Score=%f ",pstu->sex,pstu->score;

  本例顺序界说了一个布局stu,界说了stu范例布局变量boy1 并作了初始化赋值,还界说了一个指向stu范例布局的指针变量pstu。在main函数中,pstu被付与boy1的地点,因此pstu指向boy1 。然后在printf语句内用三种方式输出boy1的各个成员值。 从运行成果可以看出:

  布局变量.成员名

  *布局指针变量.成员名

  布局指针变量->成员名

  这三种用于透露表现布局成员的方式是完全等效的。布局数组指针变量布局指针变量可以指向一个布局数组, 这时候布局指针变量的值是整个布局数组的首地点。 布局指针变量也可指向布局数组的一个元素,这时候布局指针变量的值是该布局数组元素的首地点。设ps为指向布局数组的指针变量,则ps也指向该布局数组的0号元素,ps+1指向1号元素,ps+i则指向i号元素。 这与普通数组的环境是分歧的。

  [例1.1]用指针变量输出布局数组。

  struct stu

  int num;

  char *name;

  char sex;

  float score;

  boy[5]=

  101,"Zhou ping",'M',45,

  102,"Zhang ping",'M',62.5,

  103,"Liou fang",'F',92.5,

  104,"Cheng ling",'F',81,

  105,"Wang ming",'M',58,

  ;

  main

  struct stu *ps;

  printf"No Name Sex Score ";

  forps=boy;ps  printf"%d %s %c %f ",ps->num,ps->name,ps->sex,ps->

  score;

  在顺序中,界说了stu布局范例的外部数组boy 并作了初始化赋值。在main函数内界说ps为指向stu范例的指针。在循环语句for的表达式1中,ps被付与boy的首地点,然后循环5次,输出boy数组中各成员值。 该当注意的是, 一个布局指针变量固然可以用来拜访布局变量或布局数组元素的成员,但是,不克不及使它指向一个成员。 也就是说不答应取一个成员的地点来付与它。因此,下面的赋值是过错的。 ps=&boy[1].sex;而只能是:ps=boy;付与数组首地点

  大概是:

  ps=&boy[0];付与0号元素首地点

  布局指针变量作函数参数

  在ANSI C规范中答应用布局变量作函数参数进行整体传送。 但是这种传送要将全部成员逐个传送, 出格是成员为数组时将会使传送的时间和空间开销很大,严重地低落了顺序的服从。 因此最好的方法就是使用指针,即用指针变量作函数参数进行传送。 这时候由实参传向形参的只是地点,从而减少了时间和空间的开销。

  C语言的布局与结合的实例剖析

  [例1.8]标题问题与例1.4不异,较量争论一组学生的平均成果和不合格人数。

  用布局指针变量作函数参数编程。

  struct stu

  int num;

  char *name;

  char sex;

  float score;boy[5]=

  101,"Li ping",'M',45,

  102,"Zhang ping",'M',62.5,

  103,"He fang",'F',92.5,

  104,"Cheng ling",'F',81,

  105,"Wang ming",'M',58,

  ;

  main

  struct stu *ps;

  void avestruct stu *ps;

  ps=boy;

  aveps;

  void avestruct stu *ps

  int c=0,i;

  float ave,s=0;

  fori=0;i<5;i++,ps++

  s+=ps->score;

  ifps->score<60 c+=1;

  printf"s=%f ",s;

  ave=s/5;

  printf"average=%f count=%d ",ave,c;

  本顺序中界说了函数ave,其形参为布局指针变量ps。boy 被界说为外部布局数组,因此在整个源顺序中有效。在main 函数中界说阐明告终构指针变量ps,并把boy的首地点付与它,使ps指向boy 数组。然后以ps作实参调用函数ave。在函数ave 中完成较量争论平均成果和统计不合格人数的工作并输出成果。与例1.4顺序比拟,由于本顺序全部采纳指针变量作运算和处置,故速度更快,顺序服从更高。.

  topoic=静态存储分派

  在数组一章中,曾介绍过数组的长度是预先界说好的, 在整个顺序中固定不变。C语言中不答应静态数组范例。比方: int n;scanf"%d",&n;int a[n]; 用变量透露表现长度,想对数组的大小作静态阐明, 这是过错的。但是在实际的编程中,常常会发作这种环境, 即所需的内存空间取决于实际输入的数据,而无法预先断定。关于这种成绩, 用数组的方法很难办理。为懂得决上述成绩,C语言供给了一些内存办理函数,这些内存办理函数可以按必要静态地分派内存空间, 也可把再也不使用的空间收受接管待用,为有效天时用内存资源供给了本领。 经常使用的内存办理函数有以下三个:

  1.分派内存空间函数malloc

  调用方式: 范例阐明符* malloc size 功效:在内存的静态存储区中分派一块长度为"size" 字节的连气儿地区。函数的返回值为该地区的首地点。 “范例阐明符”透露表现把该地区用于何种数据范例。范例阐明符*透露表现把返回值逼迫转换为该范例指针。“size”是一个无标记数。比方: pc=char * malloc 100; 透露表现分派100个字节的内存空间,并逼迫转换为字符数组范例, 函数的返回值为指向该字符数组的指针, 把该指针付与指针变量pc。

  2.分派内存空间函数 calloc

  calloc 也用于分派内存空间。调用方式: 范例阐明符*callocn,size 功效:在内存静态存储区中分派n块长度为“size”字节的连气儿地区。函数的返回值为该地区的首地点。范例阐明符*用于逼迫范例转换。calloc函数与malloc 函数的差别仅在于一次可以分派n块地区。比方: ps=struet stu* calloc2,sizeof struct stu; 此中的sizeofstruct stu是求stu的布局长度。因此该语句的意思是:按stu的长度分派2块连气儿地区,逼迫转换为stu范例,并把其首地点付与指针变量ps。

  3.释放内存空间函数free

  调用方式: freevoid*ptr; 功效:释放ptr所指向的一块内存空间,ptr 是一个随意率性范例的指针变量,它指向被释放地区的首地点。被释放区应是由malloc或calloc函数所分派的地区:[例1.9]分派一块地区,输入一个学生数据。

  main

  struct stu

  int num;

  char *name;

  char sex;

  float score;

  *ps;

  ps=struct stu*mallocsizeofstruct stu;

  ps->num=102;

  ps->name="Zhang ping";

  ps->sex='M';

  ps->score=62.5;

  printf"Number=%d Name=%s ",ps->num,ps->name;

  printf"Sex=%c Score=%f ",ps->sex,ps->score;

  freeps;

  本例中,界说告终构stu,界说了stu范例指针变量ps。 然后分派一块stu大内存区,并把首地点付与ps,使ps指向该地区。再以ps为指向布局的指针变量对各成员赋值,并用printf 输出各成员值。最后用free函数释放ps指向的内存空间。 整个顺序包括了申请内存空间、使用内存空间、释放内存空间三个步调, 实现存储空间的静态分派。链表的观点在例1.9中采纳了静态分派的方法为一个布局分派内存空间。每一次分派一块空间可用来寄存一个学生的数据, 我们可称之为一个结点。有几多个学生就该当申请分派几多块内存空间, 也就是说要设立建设几多个结点。固然用布局数组也能够完成上述工作, 但若预先不克不及准确掌握学生人数,也就无法断定数组大小。 并且当学生留级、退学之后也不克不及把该元素占用的空间从数组中释放出来。 用静态存储的办法可以很好地办理这些成绩。 有一个学生就分派一个结点,不必预先断定学生的准确人数,某学生退学, 可删去该结点,并释放该结点占用的存储空间。从而节俭了珍贵的内存资源。 另外一方面,用数组的办法必需占用一块连气儿的内存地区。 而使用静态分派时,每一个结点之间可以是不连气儿的结点内是连气儿的。 结点之间的接洽可以用指针实现。 即在结点布局中界说一个成员项用来寄存下一结点的首地点,这个用于寄存地点的成员,常把它称为指针域。可在第一个结点的指针域内存入第二个结点的首地点, 在第二个结点的指针域内又寄存第三个结点的首地点, 如此串联下去直到最后一个结点。最后一个结点因无后续结点连接,其指针域可赋为0。这样一种连接体式格局,在数据布局中称为“链表”。图1.3为链表的表示图。

  在图1.3中,第0个结点称为头结点, 它寄存有第一个结点的首地点,它没有数据,只是一个指针变量。 以下的每一个结点都分为两个域,一个是数据域,寄存各类实际的数据,如学号num,姓名name,性别sex和成果score等。另外一个域为指针域, 寄存下一结点的首地点。链表中的每个结点都是同一种布局范例。比方, 一个寄存学生学号和成果的结点应为以下布局:

  struct stu

  int num;

  int score;

  struct stu *next;

  前两个成员项构成数据域,后一个成员项next构成指针域, 它是一个指向stu范例布局的指针变量。链表的根本操纵对链表的次要操纵有以下几种:

  1.设立建设链表;

  2.布局的查找与输出;

  3.拔出一个结点;

  4.删除一个结点;

  下面经由过程例题来阐明这些操纵。

  [例1.10]设立建设一个三个结点的链表,寄存学生数据。 为复杂起见, 我们假定学生数据布局中只有学号和春秋两项。

  可编写一个设立建设链表的函数creat。顺序如下:

  #define NULL 0

  #define TYPE struct stu

  #define LEN sizeof struct stu

  struct stu

  int num;

  int age;

  struct stu *next;

  ;

  TYPE *creatint n

  struct stu *head,*pf,*pb;

  int i;

  fori=0;i

  pb=TYPE* mallocLEN;

  printf"input Number and Age ";

  scanf"%d%d",&pb->num,&pb->age;

  ifi==0

  pf=head=pb;

  else pf->next=pb;

  pb->next=NULL;

  pf=pb;

  returnhead;

  在函数外首先用宏界说对三个标记常量作了界说。这里用TYPE透露表现struct stu,用LEN透露表现sizeofstruct stu次要的目的是为了在以下顺序内减少书写并使阅读加倍便当。布局stu界说为外部范例,顺序中的各个函数都可使用该界说。

  creat函数用于设立建设一个有n个结点的链表,它是一个指针函数,它返回的指针指向stu布局。在creat函数内界说了三个stu布局的指针变量。head为头指针,pf 为指向两相邻结点的前一结点的指针变量。pb为后一结点的指针变量。在for语句内,用malloc函数设立建设长度与stu长度相等的空间作为一结点,首地点付与pb。然后输入结点数据。假如以后结点为第一结点i==0,则把pb值 该结点指针付与head和pf。如非第一结点,则把pb值付与pf 所指结点的指针域成员next。而pb所指结点为以后的最后结点,其指针域赋NULL。 再把pb值付与pf以作下一次循环筹办。

  creat函数的形参n,透露表现所建链表的结点数,作为for语句的循环次数。图1.4透露表现了creat函数的执行过程。

  [例1.11]写一个函数,在链表中按学号查找该结点。

  TYPE * search TYPE *head,int n

  TYPE *p;

  int i;

  p=head;

  while p->num!=n && p->next!=NULL

  p=p->next; /* 不是要找的结点后移一步*/

  if p->num==n return p;

  if p->num!=n&& p->next==NULL

  printf "Node %d has not been found! ",n

  本函数中使用的标记常量TYPE与例1.10的宏界说不异,即是struct stu。函数有两个形参,head是指向链表的指针变量,n为要查找的学号。进入while语句,逐个查抄结点的num成员是不是即是n,假如不即是n且指针域不即是NULL不是最后结点则后移一个结点,持续循环。如找到该结点则返回结点指针。 如循环结束仍未找到该结点则输出“未找到”的提示信息。

  [例1.12]写一个函数,删除链表中的'指定结点。删除一个结点有两种环境:

  1. 被删除结点是第一个结点。这种环境只需使head指向第二个结点便可。即head=pb->next。其过程如图1.5所示。

  2. 被删结点不是第一个结点,这种环境使被删结点的前一结点指向被删结点的后一结点便可。即pf->next=pb->next。其过程如图1.6所示。

  函数编程如下:

  TYPE * TYPE * head,int num

  TYPE *pf,*pb;

  ifhead==NULL /*如为空表, 输出提示信息*/

  printf" empty list! ";

  goto end;

  pb=head;

  while pb->num!=num && pb->next!=NULL

  /*当不是要删除的结点,并且也不是最后一个结点时,持续循环*/

  pf=pb;pb=pb->next;/*pf指向以后结点,pb指向下一结点*/

  ifpb->num==num

  ifpb==head head=pb->next;

  /*如找到被删结点,且为第一结点,则使head指向第二个结点,

  不然使pf所指结点的指针指向下一结点*/

  else pf->next=pb->next;

  freepb;

  printf"The node is d ";

  else

  printf"The node not been foud! ";

  end:

  return head;

  函数有两个形参,head为指向链表第一结点的指针变量,num删结点的学号。 首先断定链表是不是为空,为空则不成能有被删结点。若不为空,则使pb指针指向链表的第一个结点。进入while语句后逐个查找被删结点。找到被删结点之后再看是不是为第一结点,若是则使head指向第二结点即把第一结点从链中删去,不然使被删结点的前一结点pf所指指向被删结点的后一结点被删结点的指针域所指。如若循环结束未找到要删的结点, 则输出“末找到”的提示信息。最后返回head值。

  [例1.13]写一个函数,在链表中指定地位拔出一个结点。在一个链表的指定地位拔出结点, 要求链表自身必需是已按某种纪律排好序的。比方,在学生数据链表中, 要求学号挨次拔出一个结点。设拔出结点的指针为pi。 可在三种差别环境下拔出。

  1. 原表是空表,只需使head指向拔出结点便可。见图1.1a

  2. 拔出结点值最小,应拔出第一结点之前。这种环境下使head指向拔出结点,拔出结点的指针域指向本来的第一结点则可。即:pi->next=pb;

  head=pi; 见图1.1b

  3. 在别的地位拔出,见图1.1c。这种环境下,使拔出地位的前一结点的指针域指向拔出结点,使拔出结点的指针域指向拔出地位的后一结点。即为:pi->next=pb;pf->next=pi;

  4. 在表末拔出,见图1.1d。这种环境下使原表末结点指针域指向拔出结点,拔出结点指针域置为NULL。即:

  pb->next=pi;

  pi->next=NULL; TYPE * TYPE * head,TYPE *pi

  TYPE *pf,*pb;

  pb=head;

  ifhead==NULL /*空表拔出*/

  head=pi;

  pi->next=NULL;

  else

  whilepi->num>pb->num&&pb->next!=NULL

  pf=pb;

  pb=pb->next; /*找拔出地位*/

  ifpi->num<=pb->num

  ifhead==pbhead=pi;/*在第一结点之前拔出*/

  else pf->next=pi;/*在别的地位拔出*/

  pi->next=pb;

  else

  pb->next=pi;

  pi->next=NULL; /*在表末拔出*/

  return head;

  本函数有两个形参均为指针变量,head指向链表,pi 指向拔出结点。函数中首先断定链表是不是为空,为空则使head指向拔出结点。表若不空,则用while语句循环查找拔出地位。找到之后再断定是不是在第一结点之前拔出,若是则使head 指向拔出结点拔出结点指针域指向原第一结点,不然在别的地位拔出, 若拔出的结点大于表中所有结点,则在表末拔出。本函数返回一个指针, 是链表的头指针。 当拔出的地位在第一个结点之前时, 拔出的新结点成为链表的第一个结点,因此head的值也有了改动, 故必要把这个指针返回主调函数。

  [例1.14]将以上设立建设链表,删除结点,拔出结点的函数构造在一块儿,再建一个输出全部结点的函数,然后用main函数调用它们。

  #define NULL 0

  #define TYPE struct stu

  #define LEN sizeofstruct stu

  struct stu

  int num;

  int age;

  struct stu *next;

  ;

  TYPE * creatint n

  struct stu *head,*pf,*pb;

  int i;

  fori=0;i

  pb=TYPE *mallocLEN;

  printf"input Number and Age ";

  scanf"%d%d",&pb->num,&pb->age;

  ifi==0

  pf=head=pb;

  else pf->next=pb;

  pb->next=NULL;

  pf=pb;

  returnhead;

  TYPE * TYPE * head,int num

  TYPE *pf,*pb;

  ifhead==NULL

  printf" empty list! ";

  goto end;

  pb=head;

  while pb->num!=num && pb->next!=NULL

  pf=pb;pb=pb->next;

  ifpb->num==num

  ifpb==head head=pb->next;

  else pf->next=pb->next;

  printf"The node is d ";

  else

  freepb;

  printf"The node not been found! ";

  end:

  return head;

  TYPE * TYPE * head,TYPE * pi

  TYPE *pb ,*pf;

  pb=head;

  ifhead==NULL

  head=pi;

  pi->next=NULL;

  else

  whilepi->num>pb->num&&pb->next!=NULL

  pf=pb;

  pb=pb->next;

  ifpi->num<=pb->num

  ifhead==pb head=pi;

  else pf->next=pi;

  pi->next=pb;

  else

  pb->next=pi;

  pi->next=NULL;

  return head;

  void printTYPE * head

  printf"Number Age ";

  whilehead!=NULL

  printf"%d %d ",head->num,head->age;

  head=head->next;

  main

  TYPE * head,*pnum;

  int n,num;

  printf"input number of node: ";

  scanf"%d",&n;

  head=creatn;

  printhead;

  printf"Input the d number: ";

  scanf"%d",&num;

  head=head,num;

  printhead;

  printf"Input the ed number and age: ";

  pnum=TYPE *mallocLEN;

  scanf"%d%d",&pnum->num,&pnum->age;

  head=head,pnum;

  printhead;

  本例中,print函数用于输出链表中各个结点数据域值。函数的形参head的初值指向链表第一个结点。在while语句中,输出结点值后,head值被改动,指向下一结点。若保存头指针head, 则应另设一个指针变量,把head值付与它,再用它来替代head。在main函数中,n为设立建设结点的数目, num为待删结点的数据域值;head为指向链表的头指针,pnum为指向待插结点的指针。 main函数中各行的意义是:

  C语言的布局与结合的实例剖析

  第六行输入所建链表的结点数;

  第七行调creat函数设立建设链表并把头指针返回给head;

  第八行调print函数输出链表;

  第十行输入待删结点的学号;

  第十一行调函数删除一个结点;

  第十二行调print函数输出链表;

  第十四行调malloc函数分派一个结点的内存空间, 并把其地点付与pnum;

  第十五行输入待拔出结点的数据域值;

  第十六行调函数拔出pnum所指的结点;

  第十七行再次调print函数输出链表。

  从运行成果看,首先设立建设起3个结点的链表,并输出其值;再删103号结点,只剩下105,108号结点;又输入106号结点数据, 拔出后链表中的结点为105,106,108。结合“结合”也是一种机关范例的数据布局。 在一个“结合”内可以界说多种差别的数据范例, 一个被阐明为该“结合”范例的变量中,答应装入该“结合”所界说的任何一种数据。 这在后面的各类数据范例中都是办不到的。比方, 界说为整型的变量只能装入整型数据,界说为实型的变量只能付与实型数据。

  在实际成绩中有很多这样的例子。 比方在黉舍的教员和学生中填写以下表格: 姓名 春秋 职业 单元 “职业”一项可分为“教员”和“学生”两类。 对“单元”一项学生应填入班级编号,教员应填入某系某教研室。 班级可用整型量透露表现,教研室只能用字符范例。 要求把这两种范例差别的数据都填入“单元”这个变量中, 就必需把“单元”界说为包括整型和字符型数组这两种范例的“结合”。

  “结合”与“布局”有一些相似的地方。但二者有实质上的差别。在布局中各成员有各自的内存空间, 一个布局变量的总长度是各成员长度之和。而在“结合”中,各成员共享一段内存空间, 一个结合变量的长度即是各成员中最长的长度。该当阐明的是, 这里所谓的共享不是指把多个成员同服装入一个结合变量内, 而是指该结合变量可被付与任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。如后面介绍的“单元”变量, 如界说为一个可装入“班级”或“教研室”的结合后,就答应付与整型值班级或字符串教研室。要么付与整型值,要么付与字符串,不克不及把二者同时付与它。结合范例的界说和结合变量的阐明一个结合范例必需颠末界说之后, 才干把变量阐明为该结合范例。

  1、结合的界说

  界说一个结合范例的一样平常方式为:

  union 结合名

  成员表

  ;

  成员表中含有多少成员,成员的一样平常方式为: 范例阐明符 成员名 成员名的定名应合适标识符的规则。

  比方:

  union perdata

  int class;

  char office[10];

  ;

  界说了一个名为perdata的结合范例,它含有两个成员,一个为整型,成员名为class;另外一个为字符数组,数组名为office。结合界说之后,便可进行结合变量阐明,被阐明为perdata范例的变量,可以寄存整型量class或寄存字符数组office。

  2、结合变量的阐明

  结合变量的阐明和布局变量的阐明体式格局不异, 也有三种方式。即先界说,再阐明;界说同时阐明和间接阐明。以perdata范例为例,阐明如下:

  union perdata

  int class;

  char officae[10];

  ;

  union perdata a,b; /*阐明a,b为perdata范例*/

  大概可同时阐明为:

  union perdata

  int class;

  char office[10]; a,b;或间接阐明为: union

  int class;

  char office[10]; a,b

  经阐明后的a,b变量均为perdata范例。 它们的内存分派表示图如图1—8所示。a,b变量的长度应即是 perdata 的成员中最长的长度, 即即是

  office数组的长度,共10个字节。从图中可见,a,b变量如付与整型值时,只使用了2个字节,而付与字符数组时,可用10个字节。

  结合变量的赋值和使用

  春联合变量的赋值,使用都只能是对变量的成员进行。 结合变量的成员透露表现为: 结合变量名.成员名 比方,a被阐明为perdata范例的变量之后,可以使用 a.class a.office 不答应只用结合变量名作赋值或别的操纵。 也不答应春联合变量作初始化赋值,赋值只能在顺序中进行。还要再强调阐明的是,一个结合变量, 每次只能付与一个成员值。换句话说,一个结合变量的值就是结合变员的某一个成员值。

  [例1.15]设有一个教员与学生通用的表格,教员数据有姓名,春秋,职业,教研室四项。学生有姓名,春秋,职业,班级四项。

  编程输入人员数据, 再以表格输出。

  main

  struct

  char name[10];

  int age;

  char job;

  union

  int class;

  char office[10];

  depa;

  body[2];

  int n,i;

  fori=0;i<2;i++

  printf"input name,age,job and department ";

  scanf"%s %d %c",body[i].name,&body[i].age,&body[i].job;

  ifbody[i].job=='s'

  scanf"%d",&body[i].depa.class;

  else

  scanf"%s",body[i].depa.office;

  printf"name age job class/office ";

  fori=0;i<2;i++

  ifbody[i].job=='s'

  printf"%s = < %d ",body[i].name,body[i].age

  ,body[i].job,body[i].depa.class;

  else

  printf"%s = < %s ",body[i].name,body[i].age,

  body[i].job,body[i].depa.office;

  本例顺序用一个布局数组body来寄存人员数据, 该布局共有四个成员。此中成员项depa是一个结合范例, 这个结合又由两个成员构成,一个为整型量class,一个为字符数组office。在顺序的第一个for语句中,输入人员的各项数据,先输入布局的前三个成员name,age和job,然后辨别job成员项,如为"s"则春联合depa·class输入对学生赋班级编号不然对depa·office输入对教员赋教研组名。

  在用scanf语句输入时要注意,凡为数组范例的成员,不管是布局成员还是结合成员,在该项前不克不及再加"&"运算符。如顺序第18行中

  body[i].name是一个数组范例,第22行中的body[i].depa.office也是数组范例,因此在这两项之间不克不及加"&"运算符。顺序中的第二个for语句用于输出各成员项的值:

  本章小结

  1. 布局和结合是两种机关范例数据,是用户界说新数据范例的紧张本领。布局和结合有很多的相似的地方,它们都由成员构成。成员可以具有差别的数据范例。成员的透露表现办法不异。都可用三种体式格局作变量阐明。

  2. 在布局中,各成员都占有本人的内存空间,它们是同时存在的。一个布局变量的总长度即是所有成员长度之和。在结合中,所有成员不克不及同时占用它的内存空间,它们不克不及同时存在。结合变量的长度即是最长的成员的长度。

  3. “.”是成员运算符,可用它透露表现成员项,成员还可用“->”运算符来透露表现。

  4. 布局变量可以作为函数参数,函数也可返回指向布局的指针变量。而结合变量不克不及作为函数参数,函数也不克不及返回指向结合的指针变量。但可使用指向结合变量的指针,也可以使用结合数组。 5. 布局界说答应嵌套,布局中也可用结合作为成员,构成布局和结合的嵌套。

  6. 链表是一种紧张的数据布局,它便于实现静态的存储分派。本章介绍是单向链表,还可构成双向链表,循环链表等。