结构体与共用体

来源:互联网 发布:淘宝上的纳米矿晶真吗 编辑:程序博客网 时间:2024/06/05 02:53

 第一部分 结构体

“结构”是一种构造类型,它是由若干“成员”组成的。每个成员可以是一个基本数据类型或者又是一个构造类型。结构既然是一种“构造”而成的数据类型,那么在 说明和使用之前必须对它进行定义,也就是构造它。

1. 结构体的定义

   定义结构体的一般形式为:

    struct 结构名

     {成员列表};

   成员列表由若干成员组成,每个成员都是该结构的一个组成部分。对每个成员必须做类型说明,其形式为:

      类型说明符 成员名;

  应注意在右大括号后的分号是不可少的。结构定义后,即可进行变量说明。

 2. 结构类型变量的说明

  说明结构类型变量有以下3种方法。

1>>先定义结构,再说明结果变量

  struct stu

  {

     int num;

     char name[20];

     char sex;

     float score;

  };

  struct stu boy1,boy2;

  说明了boy1和boy2两个变量为stu结构类型。也可以用宏定义用一个符号常量来表示一个结构类型。如:

  #define STU structs 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;

  这种形式说明的一般形式为:

  struct 结构名

 {

   成员列表;

  }变量名列表;

  3>>直接说明结构变量

  struct

  {

     int num;

     char name[20];

     char sex;

     float score;

  }boy1,boy2;

  这种形式说明的一般形式为:

  struct

 {

   成员列表;

  }变量名列表;

 成员也可以又是一个结构,即构成了结构的嵌套。

 struct date

 {

   int month;

   int day;

   int year;

  }

  struct

  {

    int num;

    char name[20];

    char sex;

    struct date birthday;

    float score;

  }boy1,boy2;

  3. 结构变量成员的表示方法

  表示结构变量成员的一般形式是:结构变量名.成员名,如:

  boy1.num  boy2.sex

  如果成员本身又是一个结构则必须逐级找到最低级的成员才能使用。boy1.birthday.month

  4. 成员变量的赋值

  结构变量的赋值就是给个成员赋值。可用输入语句或赋值语句来完成。

 例1:为结构变量赋值并输出其值。

#include<stdio.h>
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:/n");
 scanf("%c%f",&boy1.sex,&boy1.score);
 boy2=boy1;
 printf("Number=%d/nName=%s/n",boy2.num,boy2.name);
 printf("Sex=%c/nScore=%f/n",boy2.sex,boy2.score);
}

 5. 结构变量的初始化

  和其他类型变量一样,对结构变量可以在定义时进行初始化赋值。

例2:对结构变量进行初始化。

#include<stdio.h>
main(){
 struct stu
 {
  int num;
  char * name;
  char sex;
  float score;
 }boy2,boy1={102,"Zhang ping",'M',78.5};
 boy2=boy1;
 printf("Number=%d/nName=%s/n",boy2.num,boy2.name);
 printf("Sex=%c/nScore=%f/n",boy2.sex,boy2.score);
}

 6. 结构数组的定义和使用

  数组的元素也可以是结构类型,由此可以构成结构型数组。结构数组的每一个元素都是具有相同结构类型的结构下标变量。在实际应用中,经常用结构数组来表示具有相同数据结构的一个群体。

例3:计算学生的平均成绩和不及格的人数。

#include<stdio.h>
struct stu
 {
  int num;
  char * name;
  char sex;
  float score;
 }boy[5]={{101,"Li ping",'M',5},{102,"Zhang ping",'M',62.5},{103,"He fang",'F',92.5},
  {104,"Cheng ling",'F',87},{105,"Wang ming",'M',58}};
main(){
 int i,c=0;
 float ave,s=0;
 for(i=0;i<5;i++){
  s+=boy[i].score;
  if(boy[i].score<60)c+=1;
 }
 printf("s=%f/n",s);
 ave=s/5;
 printf("average=%f/ncount=%d/n",ave,c);
}

 7. 结构指针变量的说明和使用

 1>>指向结构变量的指针

  一个指针变量当用来指向一个结构变量时,称之为结构指针变量。结构指针变量中的值是所指向的结构变量的首地址。即通过结构指针即可访问该结构变量,这与数组指针和函数指针的情况是完全相同的。

  结构指针变量说明的一般格式为: struct 结构名 * 结构指针变量名;如:struct stu *pstu;

  赋值是把结构变量的首地址赋予该指针变量,不能把结构名赋予该指针变量。结构名和结构变量是两个不同的概念。结构名只能表示一个结构形式,编译系统并不对它分配内存空间。只有当某个变量被说明为这种类型的时候,才对该变量分配存储空间。有了结构指针变量,就能更方便地访问结构变量的各个成员。其访问的一般形式为:(*结构指针变量).成员名 或为 结构指针变量->成员名

如:(*pstu).num或pstu->num

  注意(*pstu)两侧的括号不可少,因为成员符“.”的优先级高于“*”。

例5:结构体成员引用方法举例。

#include<stdio.h>
struct stu
 {
  int num;
  char * name;
  char sex;
  float score;
 }boy1={101,"Li ping",'M',5},*pstu;
main(){
 pstu=&boy1;
 printf("Number=%d/nName=%s/n",boy1.num,boy1.name);
 printf("Sex=%c/nScore=%f/n/n",boy1.sex,boy1.score);
 printf("Number=%d/nName=%s/n",(*pstu).num,(*pstu).name);
 printf("Sex=%c/nScore=%f/n/n",(*pstu).sex,(*pstu).score);
 printf("Number=%d/nName=%s/n",pstu->num,pstu->name);
 printf("Sex=%c/nScore=%f/n/n",pstu->sex,pstu->score);
}

 从运行结果为:

 结构变量.成员名

 (*结构指针变量).成员名

 结构指针变量->成员名

2>>指向结构数组的指针

  指针变量可以指向一个结构数组,这是结构指针变量的值是整个结构数组的首地址。结构指针变量也可指向结构数组的一个元素,这时结构指针变量的值是该结构数组元素的首地址。

例6:用指针变量输出结构数组

#include<stdio.h>
struct stu
 {
  int num;
  char * name;
  char sex;
  float score;
 }boy[5]={{101,"Li ping",'M',5},{102,"Zhang ping",'M',62.5},{103,"He fang",'F',92.5},
  {104,"Cheng ling",'F',87},{105,"Wang ming",'M',58}};
main(){
 struct stu * ps;
 printf("No/tName/t/t/tSex/tScore/t/n");
 for(ps=boy;ps<boy+5;ps++)
  printf("%d/t%s/t/t/t%c/t%f/t/n",ps->num,ps->name,ps->sex,ps->score);
}
 1.8 结构指针变量作为函数的参数

 由实参传向实参的只是地址,能减少时间和空间的开销。

例7:计算一组学生的平均成绩和不及格人数。用结构指针变量做函数的参数。

#include<stdio.h>
void ave(struct stu *ps);
struct stu
 {
  int num;
  char * name;
  char sex;
  float score;
 }boy[5]={{101,"Li ping",'M',5},{102,"Zhang ping",'M',62.5},{103,"He fang",'F',92.5},
  {104,"Cheng ling",'F',87},{105,"Wang ming",'M',58}};
main(){
 struct stu * ps;
 ps=boy;
 ave(ps);
 
}

void ave(struct stu *ps){
 int i,c=0;
 float s=0,ave;
 for(i=0;i<5;i++,ps++){
  s+=ps->score;
  if(ps->score<60)
   c++;
 }
 printf("s=%f/n",s);
 ave=s/5;
 printf("average=%f/ncount=%d/n",ave,c);
}

 1.9 动态存储分配

 C语言提供了一些内存管理函数,这些内存管理函数可以根据需要,动态的分配内存空间,也可把不再使用的空间回收待用,为有效的利用内存资源提供了手段。

  常用的内存管理函数有以下3个:

  1>>分配内存空间函数malloc

  调用形式:(类型说明符 *)malloc(size)

 功能:在内存的动态存储区中分配一块长度为“size”字节的连续区域。函数的返回值为该区域的首地址。

 说明:(1)“类型说明符”表示把该区域用于存储何种数据类型。(2)(类型说明符 *)表示把返回值强制转换为该类型指针。(3)“size”是一个无符号整数。

如:pc=(char *)malloc(100);

  表示分配100个字节的内存空间,并把存储数据的类型强制转换为字符数组类型,函数的返回值为指向该字符数组的指针,把该指针赋予指针变量pc。

  2>>分配内存空间函数calloc

   调用形式:(类型说明符 *) calloc(n,size)

   功能:在内存动态存储区中分配n块长度为“size”字节的连续区域。函数的返回值为该区域的首地址。

   说明:(1)(类型说明符 *) 用于强制类型转换。(2)calloc函数和malloc函数的区别仅在于后者一次可以分配n块区域。

  如:ps=(struct * stu)calloc(2,sizeof(struct stu));

  其中的sizeof(struct stu)是求stu结构的长度。该剧的意思是:按stu的长度分配2块连续区域,并将存储在该区域中的数据的类型强制转换为stu类型,并把其首地址赋予指针变量ps。

  3>>释放内存空间函数free

   调用形式为:free(void *ptr);

   功能:释放ptr所指向的一块内存空间,ptr是一个任意类型的指针变量,它指向被释放区域的首地址。被释放区应是由malloc或calloc函数所分配的区域。

例8:分配一块区域,用于输入一个学生数据。

#include<stdio.h>
struct stu
 {
  int num;
  char * name;
  char sex;
  float score;
 }*ps;
main(){
 ps=(struct stu *)malloc(sizeof(struct stu));
 ps->num=102;
 ps->name="Zhang ping";
 ps->sex='M';
 ps->score=62.5;
 printf("Number=%d/nName=%s/n",ps->num,ps->name);
 printf("Sex=%c/nScore=%f/n",ps->sex,ps->score);

free(ps);
 }

例9:动态数组的创建和使用

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
main(){
 int * array=0,num=0,i;
 printf("please input the number of element:/n");
 scanf("%d",&num);
 array=(int *)malloc(sizeof(int)*num);
 if(array==0){
  printf("out of memory,press any key to continue.../n");
  exit(0);
 }
 printf("please input %d elements:/n");
 for(i=0;i<num;i++)
  scanf("%d",array+i);
 printf("%d elements are:/n",num);
 for(i=0;i<num;i++)
  printf("%d,",*(array+i));
 printf("/n");
 free(array);
}

 第二部分 共用体

 共用体类型是将不同的数据项组织成一个整体,他们在内存中占用同一段存储单元。

 2.1 共用体的定义

  共用体的定义的一般格式为:

  union 共用体名

    {成员列表};

 如:union data

      {

         int a;

         float b;

         double c;

         char d;

      }obj;

例12:共用体类型和结构体类型占用内存空间的比较。

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
union data
{
 int a;
 float b;
 double c;
 char d;
}mm;
struct stu
{
 int a;
 float b;
 double c;
 char d;
}
main(){
 struct stu student;
 printf("%d,%d/n",sizeof(struct stu),sizeof(union data));
}

  程序的输出说明了结构体类型所占的内存空间为各成员所占内存空间之和。而形同结构体的共用体类型占用内存空间为其最长的成员所占的存储空间。

  说明:

 (1)系统采用覆盖技术,实现共用变量各成员的内存共享,所以在某一时刻,存放的并且其作用的是最后一次存入的成员值。

  例如,执行un1.i=1,un1.ch='c',un1.f=3.14,un1.f才是有效的成员。

 (2)由于所有成员共享同一内存空间,故共用变量与其各成员的地址相同。

  例如,&un1=&un1.i=&un1.ch=&un1.f。

 (3)不能对共用变量进行初始化(注意:结构体变量可以初始化);也不能将公用变量作为函数的参数,以及使函数返回一个共用体数据,但可以使用指向公用变量的指针。

  (4)共用体类型可以出现在结构体类型定义中,反之亦然。

 2.2 共用体变量的引用

   对共用体的成员的引用与结构体成员的引用方法相同。但由于共用体各成员共用同一段内存空间,使用时,根据需要使用其中的某一个成员。

例13:共用体变量的使用举例

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
union data
{
 int a;
 float b;
 double c;
 char d;
}mm;
main(){
 mm.a=6;
 printf("%d/n",mm.a);
 mm.c=67.2;
 printf("%5.1lf/n",mm.c);
 mm.d='W';
 mm.b=34.2;
 printf("%5.1lf,%c/n",mm.b,mm.c);
}

例14:通过共用体,显示其在内存中的存储情况。

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
struct time
{
 int year;
 int month;
 int day;
};
union dig
{
 struct time data;//嵌套的结构体类型
 char byte[6];
};
main(){
 union dig unit;
 int i;
 printf("enter a year:/n");
 scanf("%d",&unit.data.year);
 printf("enter a month:/n");
 scanf("%d",&unit.data.month);
 printf("enter a day:/n");
 scanf("%d",&unit.data.day);
 printf("year=%d month=%d day=%d/n",unit.data.year,unit.data.month,unit.data.day);
 for(i=0;i<6;i++)
  printf("%d ",unit.byte[i]);
 printf("/n");
}

 第三部分 枚举类型

   在“枚举”类型的定义中列举出变量的所有可能的取值,被说明为“枚举”类型的变量取值不能超过所定义的范围。枚举类型是一种基本数据类型,而不是一种构造类型,因为它不能再分解为任何基本类型。

  3.1 枚举类型的定义和枚举变量的说明

  1>>枚举类型定义的一般形式为: enum 枚举名{枚举值表};

  枚举值表中应罗列出所有可用值。

  2>>枚举变量的说明

  如:enum weekday{sun,mou,tue,wed,thu,fri,sat}; enum weekday a,b,c;

      或者为:enum weekday{sun,mou,tue,wed,thu,fri,sat}a,b,c;

      或者为:enum {sun,mou,tue,wed,thu,fri,sat}a,b,c;

  3.2 枚举类型变量的赋值和使用

  枚举类型在使用中有以下规定:

 (1)枚举值是常量,不是变量。不能在程序中用赋值语句在对它赋值。例如,对枚举weekday的元素再做以下赋值:

  sun=5;mon=2;sun=mon;都是错误的。

 (2)枚举元素本身由系统定义了一个表示序号的数值,从0开始顺序定义为0,1,2,3,···。如在weekday中,sun的值为0,mon的值为1,···sat值为6.

例15:枚举元素值的使用举例。

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
main(){
enum weekday
{sun,mou,tue,wed,thu,fri,sat}a,b,c;
a=sun;
b=mou;
c=tue;
printf("%d,%d,%d/n",a,b,c);
}

说明:只能把枚举值赋予枚举变量,不能把元素的数值直接赋予枚举变量。如:a=sun;b=mon;是正确的。而:a=0;b=1;是错误的。如一定要把数值赋予枚举变量,则必须用强制类型转换。如:a=(enum weekday)2;其意义是将序列号为2的枚举元素赋予枚举变量a,相当于:a=tue;

  还应说明的是枚举元素不是字符常量也不是字符串常量,使用时不要加单、双引号。

例16:枚举类型综合应用举例。

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
main(){
 enum body
 {a,b,c,d}month[3],j;
 int i;
 j=a;
 for(i=1;i<=30;i++)
 {
  month[i]=j;
  j++;
  if(j>d)
   j=a;
 }
 for(i=1;i<=30;i++)
 {
  switch(month[i])
  {
  case a:printf("%2d%c/t",i,'a');
   break;
  case b:printf("%2d%c/t",i,'b');
   break;
  case c:printf("%2d%c/t",i,'c');
   break;
  case d:printf("%2d%c/t",i,'d');
   break;
  default:break;
  }
 }
 printf("/n");
}
 第四部分 类型定义符typedef

 为了解决用户自定义数据类型名称的需求,C语言中引入类型重定义语句typedef,可以为数据类型定义新的类型名称,从而丰富数据类型所包含的属性信息。

  4.1 类型定义符typedef的概念和定义

  typedef,顾名思义,为“类型定义”,可理解为:将一种数据类型定义为某一个标识符,在程序中使用该标识符来实现相应数据类型变量的定义。

  关键字typedef用于定义一种数据类型,它代表已有数据类型,是已有数据类型的别名。

 如:typedef char NAME[20];表示NAME是字符数组类型,数组长度为20.然后可用NAME说明变量,如:NAME a1,a2,s1,s2;完全等效于:char a1[20],a2[20],s1[20],s2[20]

  又如:typedef struct stu{char name[20],int age,char sex}STU;定义STU表示stu的结构类型,然后可用STU来说明结构变量:STU body1,body2;

  typedef定义的一般形式为:typedef 原类型名 新类型名,其中原类型名中含有定义部分,新类型名一般用大写字母表示,以便与区别。

  4.2 typedef定义类型的使用方法

  1>>typedef定义类型的步骤:

  (1)按定义变量的方法先写出定义体,如“int i;”.

  (2)将变量名换成新类型名,如“int INTEGER;”。

  (3)最前面加typedef如“typedef int INTEGER;”。

  (4)用新类型名定义变量,如“INTEGER i,j;”。

  2>>typedef与#define的区别

  typedef int COUNT

  #define COUNT int

  typedef定义一种新的数据类型(COUNT),它是已有类型(int)的别名。在编译时,COUNT类型和int类型相同。#define定义一个宏(COUNT),在预编译时,把字符串COUNT替换为字符串int。