vlambda博客
学习文章列表

【C语言】11-结构体与共用体掌握

概述

1.数据的基本类型:整、实、字符。

2.数组是构造类型:每个元素为同一类型

3.有些问题仅用基本类型和数组来描述,无法反映其内在联系,如学生情况: 

【C语言】11-结构体与共用体掌握

上述数据互相独立又相互关联,如:均与学号和姓名关联。需要将其组合成一个有机的整体,C语言可以将由不同类型数据组成的这种数据结构组织成一个组合项,称为结构体(structure)。


一、结构体

1.结构体是一种构造数据类型。

   与其他高级语言中的“记录”类似。

2.定义:由相互关联的不同数据类型的数据组成的有机整体。

3.用途:为处理复杂的数据结构提供了手段。

                为函数间传递不同类型的参数提供了便利。

4.关键字:struct

注意:这只是声明一种数据类型并没有定义变量。


二、结构体类型定义

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握

注:结构体类型定义仅描述结构体的组成,不分配内存空间

定义结构体类型变量的方法

     声明结构体类型时不分配存储单元,使用该类型定义变量时才分配存储单元。定义变量方法3种:

一、先声明结构体类型,再定义结构体变量

【C语言】11-结构体与共用体掌握



二、声明结构体类型的同时定义结构体变量

【C语言】11-结构体与共用体掌握


三、直接定义结构体类型变量

【C语言】11-结构体与共用体掌握

四、说明

1.结构体类型与结构体变量概念不同

⊙类型:不分配内存;                      变量:分配内存

类型:不能赋值、存取、运算;     变量:可以

2.结构体变量中的成员可单独使用,方法如普通变量;

3.结构体可嵌套

4.结构体成员名与程序中变量名可相同

【C语言】11-结构体与共用体掌握

5.结构体成员名与程序中变量名可相同,两者不代表同一个对象。 

【C语言】11-结构体与共用体掌握

结构体变量的引用

一、引用规则

1. 结构体变量不能整体引用,只能引用变量成员

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握



2.结构体成员本身又是一个结构体类型,则需要找到最低一级的成员。 

【C语言】11-结构体与共用体掌握

3.结构体变量的成员与普通变量用法相同。

结构体变量的初始化

一、形式一

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握


二、形式二

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握


三、形式三 

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握

例:对结构体变量初始化

【C语言】11-结构体与共用体掌握


结构体数组

具有相同结构的结构体也可以组成数组

一、定义结构体数组:3种形式

【C语言】11-结构体与共用体掌握


二、结构体数组初始化

struct 结构名 结构数组名[数组长度]={初始数据};

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握


三、结构体数组应用

【C语言】11-结构体与共用体掌握

例: 统计候选人选票

【C语言】11-结构体与共用体掌握

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


一、指向结构体变量的指针

1.定义形式:

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握


2.使用结构体指针变量引用成员形式 

【C语言】11-结构体与共用体掌握

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

【C语言】11-结构体与共用体掌握


3.注意区分以下三种运算 

【C语言】11-结构体与共用体掌握


二、指向结构体数组的指针

1.结构体数组及其元素可用指针变量来指向

例: 指向结构体数组的指针的应用

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握


三、用结构体变量和指向结构体的指针作函数参数

将一个结构体变量的值传递给另一函数 ,方法有3种:

1.用结构体变量的成员作函数实参----值传递

⊙注意形、实的类型要一致。

传递的是结构体变量的地 址。

3.用结构体变量作参数----多值传递,效率低

将结构体变量所占的内存单元的内容全部顺序传递给形参,要求形参与实参同类型。函数调用是单值传递,且形参占用内存单元,若形参的值被改变,不会返回主调函数。 

例:    结构体变量stu有学号、姓名和3门课成绩,

                在main函数中赋值,在print函数中打印输出。 

【C语言】11-结构体与共用体掌握


例:   例11.5改为用结构体变量的指针作实参

【C语言】11-结构体与共用体掌握

用指针处理链表

一、链表概述

1.数组:静态分配存储单元,容易造成内存浪费。

2.链表:是重要的数据结构,它根据需要,动态分配内存单元 。

【C语言】11-结构体与共用体掌握

⊙数据部分:可有若干项(整、实、字符、结构体类型等)

4.链表各结点的特点:

链表的每个结点实际上是一个结构体变量,它有若干成员组成,包括的内容有两部分:

--数据部分:整、实、字符、结构体等类型。

【C语言】11-结构体与共用体掌握


二、简单链表

例:建立简单链表,它由3个学生数据的结点组成。

               输出各结点中的数据。 

#include <stdio.h>

#define   NULL    0 

struct  student 

{long num; float  score; struct  student *next; }; 

void main(  ) 

{struct   student  a,b,c,*head,*p; 

 a.num=99101;a.score=89.5; b.num=99102;b.score=90; 

 c.num=99103;c.score=85; head=&a;a.next=&b;b.next=&c; 

 c.next=NULL; p=head; 

 do  { printf(“%ld  %5.1f\n”,pnum,pscore); 

          p=pnext; 

        }while(p!=NULL); 

}

 P!=NULL条件不成立,循环结束。

 本例所有结点是在程序中定义的,不是临时开辟的,用完也不能释放,这种链表称“静态链表”。


三、处理动态链表所需的函数

为处理动态链表,C提供了开辟和释放存储单元的函数:

1.malloc函数

⊙函数原型:void  *malloc(unsigned  int  size);


2.calloc函数

函数原型:void  *calloc(unsigned n,unsigned  size);


3.free函数

函数原型:void  free(void  *p);

作用:释放由p指向的内存区,使这部分内存区能被其它变量使用。P所指向的是最近一次calloc或malloc分配的存储区域。free函数无返回值。 


4.注:旧版本提供的malloc和calloc函数得到的是指向字符型数据的指针。

 

四、建立动态链表

1.建立动态链表:是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。 

例:写一函数建立一个有3名学生数据的单向动态链表。 

思路:

⑴ 设置3个指针变量head、p1、p2

head:指向链表头的指针变量,初始化head=NULL。

p2:指向结点成员next的指针变量。

⑵ 循环方式用malloc函数开辟第1个结点。n=1

输入数据,如果p1num !=0,

                    则head=p1结点链入链表,反之不链入。

⑶ 开辟第2个结点:n=2

输入数据。

如果p1num !=0,链入2结点,

方法:p2next=p1

⑷ 为建立第3个结点做准备:

p2=p1,腾出p1 。

【C语言】11-结构体与共用体掌握


⑸ 重复⑶⑷两步开辟第3个结点,并链入链表。 

【C语言】11-结构体与共用体掌握

⑹ 再开辟新结点,由于num数据为0,退出循环。

并使p2next=NULL,虽然p1指向新结点但没有链入链表。 

【C语言】11-结构体与共用体掌握

1.

#include  “stdio.h”

#include  “malloc.h”

#define  NULL   0 

#define  LEN   sizeof (struct   student) 

struct   student 

 {long  num;  float   score;   struct  student  *next; }; 

int  n;

struct student *creat(void) 

{ struct student  *head;  struct student  *p1, *p2;  

   n=0; p1=p2=(struct student  *) malloc(LEN); 

   scanf(“%ld,%f”,&p1  num, &p1  score); 

   head=NULL; 

  while(p1  num !=0) 

     {n=n+1; 

         if(n==1)head=p1; 

         else  p2  next=p1; 

       p2=p1; p1=(struct  student  *)malloc (LEN); 

       scanf(“%ld,%f”,&p1  num, & p1  score); } 

  p2  next=NULL;  return(head); 

}



2.

#include  “stdio.h”          /*改进后*/

#include  “stdlib.h”

#define  NULL   0 

#define  LEN   sizeof (struct   student) 

struct   student 

 {long  num;  float   score;   struct  student  *next; }; 

int  n;

struct student *creat(void) 

{ struct student  *head;  struct student  *p1, *p2; flot  s; 

   n=0; p1=p2=(struct student  *) malloc(LEN); 

   scanf(“%ld,%f”,&p1  num,&s); p1  score=s; 

   head=NULL; 

  while(p1  num !=0) 

     {n=n+1; 

         if(n==1)head=p1; 

         else  p2  next=p1; 

       p2=p1; p1=(struct  student  *)malloc (LEN); 

       scanf(“%ld ,%f”,&p1  num,&s); p1  score=s; } 

  p2  next=NULL;  return(head); 

}


五、输出链表

思路:

【C语言】11-结构体与共用体掌握

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

【C语言】11-结构体与共用体掌握


六、对链表的删除操作

并不真从内存中抹掉,只是把它分离,再前后结点相链接。 

例:  写一函数删除动态链表中指定的结点。 

思路:本例以学号作为删除结点的标志(查找对象)。

⑴ 设两个指针变量p1和p2。从head开始,p1依次指向各结点查找num值是否等于要删除结点的学号。每次下移前使p2=p1。学号相等删除该结点,直至查到表尾。

【C语言】11-结构体与共用体掌握


⑵找到要删除的结点后:

①如果要删除的是第1结点,则head=p1next 。head指向第二结点,第一结点脱离。

【C语言】11-结构体与共用体掌握


②如果要删除的不是第1结点,则p2next=p1next 。P1指向的结点脱离。

③还要考虑链表为空和链表中没有要删除的结点的情况。

【C语言】11-结构体与共用体掌握

struct  student  *del(struct student *head,long num)

{ struct  student   *p1,*p2; 

   if(head = = NULL) {printf(“\n  list  null ! \n”); goto  end; } 

   p1=head; 

   while(num !=p1  num && p1  next != NULL) 

        { p2=p1; p1=p1  next; } 

   if(num == p1  num) 

     { if(p1 = = head) head=p1  next; 

        else p2  next = p1  next; 

        printf(“delete: %d\n”,num); 

        n=n-1; 

     } 

   else printf(“%ld  not  been  found ! \n”,num); 

   return(head); 

}


七、对链表的插入操作

1.假设结点按成员的学号从小到大排列,按排序顺序插入结点。

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握

2.将一个结点插入到链表中算法: 

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握


八、对链表的综合操作

1.用main函数作主调函数,调用前述建立、输出、删除、插入结点的函数。 

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握

共用体

一、共用体概念

1.构造数据类型,也叫联合体

2.用途:使几个不同类型的变量共占一段内存(相互覆盖)

3.类型定义形式:

【C语言】11-结构体与共用体掌握


4.共用体变量的定义 

【C语言】11-结构体与共用体掌握


二、共用体变量的引用方式

1.3种方式等价:

【C语言】11-结构体与共用体掌握


2.引用规则

⊙不能引用共用体变量, 只能引用其成员

【C语言】11-结构体与共用体掌握


三、共同体类型数据的特点

⑴ 同一个内存段可以用来存放几种不同类型的成员,但在每 一瞬时只能存放其中一种,而不是同时存放几种。

⑵ 共用体变量中起作用的成员是最后一次存放的成员

【C语言】11-结构体与共用体掌握

⑷ 不能对共用体变量名赋值,也不能在定义共用体变量时初始化。但可以用一个共用体变量为另一个变量赋值

【C语言】11-结构体与共用体掌握

⑸ 不能把共用体变量作为函数参数,也不能使函数带回共用体变量,但可以使用指向共用体变量的指针(与结构体变量的这种用法相仿)。

⑹共用体类型可出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可出现在共用体类型定义中,数组也可作为共用体的成员。


例:设有若干个人员的数据,其中有学生和教师。学生的数据中包括:姓名、号码、性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。现要求把它们放在同一表格中

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握

void main( )

{ int n,i;

  for(i=0;i<2;i++)

    { scanf(“%d,%s,%c,%c”,&person[i].num,&person[i].name,&person[i].sex,

                 &person.job);

       if(person[i].job==‘s’) scanf(“%d”,&person[i].category.banji);

       else  if(person[i].job==‘t’) scanf(“%s”,&person[i].category.position);

               else printf(“input error”);

    }

  printf(“\n”);

  printf(“No.     Name    sex    job    class/position\n”);

  for(i=0;i<2;i++)

     { if(person[i].job==‘s’)

           printf(“%-6d %-10s %-3c %-3c %-6d\n”,person[i].num,person[i].name, 

                          person[i].sex, person[i].job, person[i].category.banji);

        else

           printf(“%-6d %-10s %-3c %-3c %-6s\n”,person[i].num,person[i].name, 

                          person[i].sex, person[i].job, person[i].category.position);

     }

}

枚举类型

        枚举类型是ANSI C新标准所增加的。

如果一个变量只有几种可能的值,可以定义为枚举类型。所谓“枚举是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。


一、枚举类型及其变量的定义形式:

  enum  枚举类型名 {枚举元素列表} 枚举变量列表;

1.可以先声明类型再定义变量,或同时进行或直接定义变量。

【C语言】11-结构体与共用体掌握

           其中sun, mon, … , sat等称为枚举元素或枚举常量。它们是用户定义的标识符。

2.说明:

⊙在编译中,对枚举元素按常量处理,它们不是变量,不能对它们赋值。

枚举元素作为常量,它们是有值的,语言编译按定义时的顺序使它们的值为0,1,2,…。

枚举值可以用来做判断比较。如:

--if(workday = = mon)…

--if(workday > sun)…

一个整数不能直接赋给一个枚举变量。应先进行强制类型转换才能赋值。如:

--workday = (enum ewwkday)2;


例:口袋中有红、黄、蓝、白、黑5种颜色的球若干个。每次从口袋中先后取出3个球,问得到3种不同色的球的可能取法,打印出每种排列的情况。

要判断各球是否同色,应用枚举类型变量处理。设取出的球为i, j, k。根据题意,i、j、k分别是5种色球之一,并要求i≠j≠k。可以用穷举法,即一种可能一种可能地试,看哪一组符合条件。

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握


用typedef定义类型

一、功能:用自定义名字为已有数据类型命名

二、类型定义简单形式:   

【C语言】11-结构体与共用体掌握

例  typedef  int  INTEGER;


例  typedef  float    REAL;

【C语言】11-结构体与共用体掌握

三、typedef定义类型步骤

① 按定义变量方法写出定义体   如     int   i;

② 将变量名换成新类型名           如     int  INTEGER;

③ 最前面加typedef         如  typedef   int   INTEGER;

④ 用新类型名定义变量                   如   INTEGER i,j;


四、类型定义可嵌套

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握

【C语言】11-结构体与共用体掌握

 引致:教材

 C程序设计 (第二版)

          谭浩强编著 清华大学出版社


内容:提供更好的学习资源