第9章结构和杂类精Word文档格式.docx

上传人:b****5 文档编号:20407812 上传时间:2023-01-22 格式:DOCX 页数:27 大小:32.84KB
下载 相关 举报
第9章结构和杂类精Word文档格式.docx_第1页
第1页 / 共27页
第9章结构和杂类精Word文档格式.docx_第2页
第2页 / 共27页
第9章结构和杂类精Word文档格式.docx_第3页
第3页 / 共27页
第9章结构和杂类精Word文档格式.docx_第4页
第4页 / 共27页
第9章结构和杂类精Word文档格式.docx_第5页
第5页 / 共27页
点击查看更多>>
下载资源
资源描述

第9章结构和杂类精Word文档格式.docx

《第9章结构和杂类精Word文档格式.docx》由会员分享,可在线阅读,更多相关《第9章结构和杂类精Word文档格式.docx(27页珍藏版)》请在冰豆网上搜索。

第9章结构和杂类精Word文档格式.docx

struct 结构体名

      {

        成员表列

     }变量名表列;

3. 直接定义结构类型变量

  其一般形式为

struct

{

    成员表列

}变量名表列;

关于结构体类型,有几点要说明:

(1)类型与变量是不同的概念,不要混同。

只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。

在编译时,对类型是不分配空间的,只对变量分配空间。

(2)对结构体中的成员(即“域”),可以单独使用,它的作用与地位相当于普通变量。

(3)成员也可以是一个结构体变量。

如:

struct date/*声明一个结构体类型*/

   {int month;

int day;

int year;

   };

   {int num;

structdatebirthday;

/*birthday是structdate类型*/

先声明一个structdate类型,它代表“日期”,包括3个成员:

month(月)、day(日)、year(年)。

然后在声明structstudent类型时,将成员birthday 指定为structdate类型。

structstudent的结构见图11.3所示。

已声明的类型structdate与其他类型(如int,char)一样可以用来定义成员的类型。

(4)成员名可以与程序中的变量名相同,二者不代表同一对象。

例如,程序中可以另定义一个变量num,它与structstudent中的num是两回事,互不干扰。

9.3 结构体变量的引用

在定义了结构体变量以后,当然可以引用这个变量。

但应遵守以下规则:

(1)不能将一个结构体变量作为一个整体进行输入和输出。

例如,已定义student1和student2为结构体变量并且它们已有值。

不能这样引用:

printf("

%d,%s,%c,%d,%f,%s\n"

student1);

(2)如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到最低的一级的成员。

只能对最低级的成员进行赋值或存取以及运算。

例如,对上面定义的结构体变量student1,可以这样访问各成员:

student1.num

student1.birthday.month

注意:

不能用student1.birthday来访问student1变量中的成员birthday,因为birthday本身是一个结构体变量。

(3)对结构体变量的成员可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)。

例如:

student2.score=student1.score;

  sum=student1.score+student2.score;

  student1.age++;

  ++student1.age;

(4)可以引用结构体变量成员的地址,也可以引用结构体变量的地址。

scanf("

%d"

,&

student1.num);

(输入student1.num的值)printf("

%o"

student1);

(输出student1的首地址)但不能用以下语句整体读入结构体变量,如:

%d,%s,%c,%d,%f,%s"

结构体变量的地址主要用于作函数参数,传递结构体的地址。

9.4 结构体变量的初始化

和其他类型变量一样,对结构体变量可以在定义时指定初始值。

例9.1对结构体变量初始化。

main()

{structstudent

  {longintnum;

charname[20];

charsex;

charaddr[20];

}a={89031,"

LiLin"

,'

M'

,"

123BeijingRoad"

};

  printf("

NO.:

%ld\nname:

%s\nsex:

%c\naddress:

%s\n"

,a.num,a.name,a.sex,a.addr);

  }

  运行结果如下:

No.:

89031

  name:

LiLin

  sex:

M

  address:

123BeijingRoad

9.5 结构体数组

9.5.1 定义结构体数组

和定义结构体变量的方法相仿,只需说明其为数组即可。

structstudent

   {intnum;

intage;

charaddr[30];

   };

    structstudent stu[3];

以上定义了一个数组stu,其元素为structstudent类型数据,数组有3个元素。

也可以直接定义一个结构体数组,如:

  structstudent

}stu[3];

9.5.2结构体数组的初始化与其他类型的数组一样,对结构体数组可以初始化。

  struct student

    {int num;

char add[30];

    }

stu[3]={{10101,“LiLin”,‘M’,18,87.5,“103BeijingRoad”},{10102,“ZhangFun”,‘M’,19,99,“130ShanghaiRoad”},{10104,“WangMin”,‘F’,20,78.5,“1010ZhongshanRoad”}};

定义数组stu时,元素个数可以不指定,即写成以下形式:

stu[ ]={…},{…},{…};

编译时,系统会根据给出初值的结构体常量的个数来确定数组元素的个数。

当然,数组的初始化也可以用以下形式:

 struct student stu[ ]={{…},{…},{…}};

即先声明结构体类型,然后定义数组为该结构体类型,在定义数组时初始化。

从以上可以看到,结构体数组初始化的一般形式是在定义数组的后面加上:

={初值表列};

9.5.3 结构体数组应用举例

下面举一个简单的例子来说明结构体数组的定义和引用。

例:

对候选人得票的统计程序。

设有3个候选人,每次输入一个得票的候选人的名字,要求最后输出各人得票结果。

程序如下:

#include<

string.h>

structperson

  {charname[20];

intcount;

  }

leader[3]={"

Li"

,0,"

Zhang"

Fun"

,0};

  main()

  {int i,j;

char leader-name[20];

for (i=1;

i<=10;

i++)

{scanf("

%s"

,leader-name);

for(j=0;

j<3;

j++)

if(strcmp(leader-name,leader[j].name)==0)leader[j].count++:

}

 printf("

\n"

);

 for(i=0;

i<3;

    printf("

%5s:

%d\n"

,leader[i].name,leader[i].count);

  运行情况如下:

Li

  Li

  Fun

  Zhang

  Li∶4

  Zhang∶3

  Fun∶3

9.6 指向结构体类型数据的指针

一个结构体变量的指针就是该变量所占据的内存段的起始地址。

可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。

指针变量也可以用来指向结构体数组中的元素。

9.6.1 指向结构体变量的指针

下面通过一个简单例子来说明指向结构体变量的指针变量的应用。

例9.3指向结构体变量的指针的应用。

 {struct student

{long num;

struct student stu-1;

struct student *p;

p=&

stu-1;

stu-1.num=89101;

strcpy(stu-1.name,"

stu-1.sex='

stu-1.score=89.5;

printf("

No.:

%c\nscore:

%f\n"

,stu-1.num,stu-1.name,stu-1.sex,stu-1.score);

,(*p).num,(*p).name,(*p).sex,(*p).score);

程序运行结果如下:

No.:

89101      

LiLin

M

score:

89.500000

No:

89101

name:

sex:

在C语言中,为了使用方便和使之直观,可以把(*p).num改用p—>num来代替,它表示*p所指向的结构体变量中的num成员。

同样,(*p).name等价于p—>name。

也就是说,以下三种形式等价:

①结构体变量.成员名

②(*p).成员名

③p->

成员名

9.6.2 指向结构体数组的指针

  {intnum;

  };

  structstudentstu[3]={{10101,“LiLin”,‘M’,18},{10102,“ZhangFun”,‘M’,19},{10104,“WangMin”,‘F’,20}};

  {structstudent*p;

printf("

No.Namesexage\n"

for (p=stu;

p<stu+3;

p++)

%5d%-20s%2c%4d\n"

,p->

num,p->

name,p->

sex,p->

age);

运行结果如下:

No. Name sexage 

10101 LiLin M 18

10102 ZhangFunM 19 

10104 WangMinF 20

9.7 用指针处理链表

链表有一个“头指针”变量,链表中每一个元素称为“结点”,每个结点都应包括两个部分:

一为用户需要用的实际数据,二为下一个结点的地址。

可以看到,这种链表的数据结构,必须利用指针变量才能实现。

即:

一个结点中应包含一个指针变量,用它存放下一结点的地址。

  struct student

   float score;

   struct studentnext;

9.7.2 简单链表

下面通过一个例子来说明如何建立和输出一个简单链表。

例11.7建立一个如图11.11所示的简单链表,它由3个学生数据的结点组成。

输出各结点中的数据。

#defineNULL0

structstudent

{longnum;

floatscore;

structstudent*next;

};

main()

{structstudenta,b,c,*head,*p;

a.num=99101;

a.score=89.5;

b.num=99103;

b.score=90;

c.num=99107;

c.score=85;

/*对结点的num和score成员赋值*/

head=&

a;

/*将结点a的起始地址赋给头指针head*/

a.next=&

b;

/*将结点b的起始地址赋给a结点的next成员*/

b.next=&

c;

/*将结点c的起始地址赋给b结点的next成员*/

c.next=NULL;

/*c结点的next成员不存放其他结点地址*/

p=head;

/*使p指针指向a结点*/

do

{printf("

%ld%5.1f\n"

num,p->

score);

/*输出p指向的结点的数据*/

p=p->

next;

/*使p指向下一结点*/

}while(p!

=NULL);

/*输出完c结点后p的值为NULL*/

9.7.3 输出链表

将链表中各结点的数据依次输出。

要知道head的值。

然后设一个指针变量p,先指向第一个结点,输出p所指的结点,然后使p后移一个结点,再输出。

直到链表的尾结点。

编写一个输出链表的函数print。

  voidprint(structstudent*head)

  printf("

\nNow,These%drecordsare:

,n);

  p=head;

  if(head!

=NULL)

do

,p->num,p->score);

p=p->next;

}while(p!

=NULL);

  }

9.7.4 对链表的删除操作

与此相仿,从一个动态链表中删去一个结点,并不是真正从内存中把它抹掉,而是把它从链表中分离开来,只要撤消原来的链接关系即可。

删除结点的函数del如下:

  structstudentdel(structstudent*head,longnum)

{structstudent*p1,*p2;

if(head==NULL){printf("

\nlistnull!

);

return(head);

}

p1=head;

while(num!

=p1->

num&

&

p1->

next!

==NULL)/*p1指向的不是所要找的结点,并且后面还有结点/

{p2=p1;

p1=p1->next;

}/p1后移一个结点*/

   if(num==p1->num)/找到了*/

   {if(p1==head)head=p1->next;

/若p1指向的是首结点,把第二个结点地址赋予head/

    elsep2->

next=p1->

/*否则将下一结点地址赋给前一结点地址*/

    printf("

delete:

%ld\n"

,num);

   n=n-1;

    }

   elseprintf("

%ldnotbeenfound!

,num);

/找不到该结点/ 

   return(head);

  }

9.7.5 对链表的插入操作

插入结点的函数insert如下。

structstudent*insert(structstudent*head,structstudent*stud)

{structstudent*p0,*p1,*p2;

p1=head;

/使p1指向第一个结点/

p0=stud;

/p0指向要插入的结点/

if(head==NULL) /原来的链表是空表/

{head=p0;

p0->

next=NULL;

}/*使p0指向的结点作为头结点*/

else

{while((p0->

num>

p1->

num)&

(p1->

=NULL))

{p2=p1;

/*使p2指向刚才p1指向的结点*/

p1=p1->

}/*p1后移一个结点*/

if(p0->

num<p1->

num)

{if(head==p1)head=p0;

  /插到原来第一个结点之前*/

    elsep2->

next=p0;

 

/插到p2指向的结点之后*/

    p0->

next=p1;

{p1->

}}/*插到最后的结点之后*/

n=n+1;

 /结点数加1*/

return(head);

函数参数是head和stud。

stud也是一个指针变量,从实参传来待插入结点的地址给stud。

语句p0=stud的作用是使p0指向待插入的结点。

函数类型是指针类型,函数值是链表起始地址head。

9.7.6 对链表的综合操作

将以上建立、输出、删除、插入的函数组织在一个C程序中,即将例11.8~11.11中的4个函数顺序排列,用main函数作主调函数。

可以写出以下main函数(main函数的

位置在以上各函数的后面)。

  {structstudent*head,stu;

longdel-num;

inputrecords:

head=creat();

/返回头指针*/

print(head);

/输出全部结点*/

\ninputthedeletednumber:

"

scanf("

%ld"

del-num);

/输入要删除的学号*/

head=del(head,del-num);

/删除后链表的头地址/

\ninputtheinsertedrecord:

/输入要插入的结点*/

%ld,%f"

stu.num,&

stu.score);

head=insert(head,&

stu);

/返回地址/

/*输出全部结点*/

此程序运行结果是正确的。

它只删除一个结点,插入一个结点。

但如果想再插入一个结点,重复写上程序最后4行,共插入两个结点。

运行结果却是错误的。

 (建立链表)

  99101,90

  99103,98

  99105.76

  0,0

  Now,These3recordsare:

  99101 90.0

  99103 98.0

  99105 76.0

  inputthedeletednumber:

99103(删除)

  delete:

99103

  Now,These2recordsare:

  99101 90.099105 76.0

 inputtheinsertedrecord:

99102,90(插入第一个结点)

  99101 90.0

  99102 90.0

  99105 76.0

89104,99(插入第二个结点)

  Now,These4recordsare:

  99104 99.0

  …

 (无终止地输出99104的结点数据)

出现以上结果的原因是stu是一个有固定地址的结构体变量。

第一次把stu结点插入到链表中。

第二次若再用它来插入第二个结点,就把第一次结点的数据冲掉了。

实际上并没有开辟两个结点。

main 函数如下:

  {structstudent*head,*stu;

while(del-num!

=0)

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1