美文网首页
C语言笔记(五)----struct,enum,typedef等

C语言笔记(五)----struct,enum,typedef等

作者: 坚持到底v2 | 来源:发表于2018-06-22 16:44 被阅读0次

    第十一章 结构体与共用体

    1. 定义结构的一般形式:

    struct 结构名  {
      成员表列
    };
    

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

    例如:

    struct stu {
      int num;
      char name[20];
      char sex;
      float score;
    };
    

    注意,最后括号外面的;分号是不可少的
    结构定义之后,才可以进行变量声明。
    凡声明为结构 stu 的变量都由上述4个成员组成。
    由此可见,结构是一种复杂的数据类型,是数目固定,类型不同的若干有序变量的集合。

    2. 结构类型变量的声明

    声明结构变量 有以下三种方法。

    使用上面定义的stu为例:

    (1)先定义结构,再声明结构变量。

    如:

    struct stu {
      int num;
      char name[20];
      char sex;
      float score;
    };
    
    struct stu boy1,boy2;
    

    也可以用宏定义使一个符号常量来表示一个结构类型。例如:

    #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;
    

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

    struct 结构名 {
     成员表列
    } 变量名表列;
    

    (3)直接声明结构变量。

    例如:

    struct {
     int num;
     char name[20];
     char sex;
     float score;
    } boy1,boy2;
    

    这种声明的一般形式为:

    struct { 
      成员表列
    } 变量名表列;
    

    第三种方法与第二种方法的区别在于第三种方法中省去了结构名,而直接给出结构变量。

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

    在程序中使用结构变量时,往往不把她作为一个整体来使用。
    在ANSI C中除了允许有相同类型的结构变量相互赋值以外,一般对结构变量的使用,包括 赋值、输入、输出、运算 等都是通过结构变量的成员来实现的。
    表示结构变量成员的一般形式为:
    结构变量名.成员名

    例如:boy1.num boy2.sex

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

    4. 结构变量的赋值:

    结构变量的赋值就是给各成员赋值。

    5. 结构变量的初始化:

    struct stu {
      int num;
      char name[20];
      char sex;
      float score;
    } boy2,boy1={102,"张平",'M',78.5};
    
    boy2=boy1;
    

    6. 结构数组的定义:

    数组的元素也可以是结构类型的。
    因此可以构成结构型数组。

    struct stu {
      int num;
      char name[20];
      char sex;
      float score;
    } boy[5];
    

    初始化赋值:

    struct stu {
     int num;
     char name[20];
     char sex;
     float score;
    } boy5= {
        {101,"李平","M",45},
        {102,"张平","M",54},
        ...
     }
    

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

    • 1)指向结构变量的指针: struct 结构名 *结构指针变量名
      例如:struct stu *pstu;

    当然也可以在定义 stu结构 时同时声明 pstu。
    赋值是把结构变量的首地址赋予该指针变量,不能把结构名赋予该指针变量。
    如果 boy 是被声明为 stu类型 的结构变量。
    则:

    pstu=&boy;// 正确
    pstu=&stu;// 错误,不能使用结构名
    

    有了结构指针变量,就能更方便地访问结构变量的各个成员。
    其访问的一般形式为:
    (*结构指针变量).成员名

    结构指针变量->成员名
    例如:(*pstu).numpstu->num

    • 2)指向结构数组的指针:

    • 3)结构指针变量作函数参数:
      在ANSI C标准中允许用结构变量作函数参数进行整体传送。
      但是这种传送要将全部成员逐个传送,特别是成员为数组时将会使传送的时间和空间开销很大,严重地降低了程序的效率。
      因此最好的办法就是使用指针,即用指针变量作为函数参数进行传送。
      这时由实参传向形参的只是地址,从而减少了时间和空间的开销。

    例如:

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

    8. 动态存储分配:

    介绍数组的时候,曾介绍过数组的长度是预先定义好的,在整个程序中固定不变。
    C语言中不允许动态数组类型。
    例如:

    int n;
    scanf("%d",&n);
    int a[n];//错误!
    

    但是又有此需求,为了解决这个问题,C语言提供了一些内存管理函数,这些内存管理函数可以按需要动态地分配内存空间,也可把不再使用的空间回收待用,为有效地利用内存资源提供了手段。

    常用的内存管理函数

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

    • 1)分配内存空间函数 malloc
      调用形式: (类型声明符*)malloc(size)

      功能:在内存的动态存储区内分配一块长度为"size"字节的连续区域。函数的返回值为该区域的首地址。
      “类型声明符” 表示把该区域用于何种数据类型。
      “size”是一个无符号数。
      例如:pc=(char *)malloc(100);
      表示分配100个字节的内存空间,并强制转换为字符数组类型,函数的返回值为指向该字符数组的指针,把该指针赋予指针变量 pc 。

    • 2)分配内存空间函数 calloc
      calloc也用于分配内存空间。
      调用形式:(类型声明符 *)calloc(n,size)
      功能:在内存动态存储区中分配n块长度为“size”字节的连续区域。函数的返回值为该区域的首地址。
      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函数所分配的区域。

    例子:分配一块区域,输入一个学生数据

    main() {
     struct stu {int num;
      char *name;
      char sex;
      float score;
     } *ps;
    
     ps=(struct stu*)malloc(sizeof(struct stu));
     ps->num=102;
     ps->name="zhang Ping";
     ps->sex='M';
     ps->score=62.5;
     free(ps);
    }
    

    9. 链表的概念:

    上面的例子采用了动态分配的办法为一个结构分配内存空间。
    每一次分配一块空间可用来存放一个学生的数据,我们可称之为一个节点。
    有多少个学生就应该申请分配多少块内存空间,也就是说要建立多少个节点。
    当然用结构数组也可以完成上述工作,但如果预先不能准确把握学生人数,也就无法确定数组大小。
    而且当学生留级、退学之后也不能把该元素占用的空间从数组中释放出来。
    用动态存储的方法可以很好地解决这些问题。
    有一个学生就分配一个节点,无须预先确定学生的准确人数,某学生退学,可删去该节点,并释放该节点占用的存储空间,从而节约了宝贵的内存资源。
    另一方面,用数组的方法必须占用一块连续的内存区域。
    而使用动态分配时,每个节点之间可以是不连续的(节点内是连续的)。
    节点之间的关系可以用指针实现。
    即在节点结构中定义一个成员项来存放下一节点的首地址,这个用于存放地址的成员,常把他称为指针域。
    可在第一个节点的指针域内 存入第二个节点的首地址,在第二个节点的指针域内 又存入第三个节点的首地址,如此串联下去直到最后一个节点。
    最后一个节点因无后续节点连接,其指针域可赋值 0
    这种连接方式,在数据结构中称为“链表”。

    链表的基本操作主要有以下几种:

    • 1)建立链表。
    • 2)结构的查找与输出
    • 3)插入一个节点
    • 4)删除一个节点

    例子:建立一个三个节点的链表,存放学生数据。为简单起见,我们假定学生数据结构中只有学号和年龄两项。可编写一个建立链表的函数create。程序如下:

    #define NULL 0
    #define TYPE struct stu
    #define LEN size(struct stu)
    TYPE {
      int num;
      int age;
      TYPE *next;
    }
    
    TYPE *create(int n) {
      TYPE *head,*pf,*pb;
      int i;
      for (i=0;i<n;i++)  {
        pb=(TYPE*)malloc(LEN);
        printf("input Number and Age \n");
        scanf("%d%d",&pb->num,&pb->age);
        if(i==0)
         pf=head=pb;
        else
         pf->next=pb;
     
        pb->next=NULL;
        pf=pb;
     }
     return(head);
    }
    

    create函数 用于建立一个有 n个节点 的链表,他是一个指针函数,他返回的指针指向 stu结构。
    在create函数内定义了三个 stu结构 的指针变量。
    head为头指针,pf为指向两相邻节点的前一节点的指针变量。
    pb为后一节点的指针变量。

    10. 枚举类型:

    枚举是一种 基本数据类型 ,而不是一种 构造类型 ,因为他不能再分解为任何基本类型。

    (1)枚举类型的定义和枚举变量的声明:

    枚举定义形式:

    enum 枚举名{ 枚举值表 };

    例如:enum weekday { sun,mou,tue,wed,thu,fri,sat };

    枚举变量的声明:

    enum weeakday 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;

    (2)枚举类型变量的赋值和使用:

    • a)枚举值是常量,不是变量。
      不能在程序中用赋值语句再对他赋值。
      例如对枚举weekday的元素再作以下赋值都是错误的。
      sun=5;mon=2 //错误!!

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

    例子:

    main() {
     enum weekday { sun,mou,tue,wed,thu,fri,sat } a,b,c;
    
     a=sun;b=mon;c=tue;
     printf("%d,%d,%d",a,b,c);
    }
    

    说明:
    只能把枚举值赋予枚举变量,不能把元素的数值直接赋予枚举变量。如:
    a=sun;b=mon; 是正确的
    a=0;b=1; 是错误的。

    如果一定要把数值赋予枚举变量,则必须使用强制类型转换。
    如:a=(enum weekday)2;

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

    main() {
     enum body {a,b,c,d} month[31],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");
    }
    

    11. 类型定义符 typedef

    typedef定义的一般形式为:
    typedef 原类型名 新类型名
    其中原类型名中含有定义部分,新类型名一般用大写表示,一般用大写表示,以便于区别。
    有时也可用 宏定义 来代替 typedef 功能,但是 宏定义 是由 预处理 完成的,而 typedef 则是 在编译时 完成的,后者更为灵活方便。

    使用typedef 定义数组、指针、结构等类型将带来很大的方便,不仅使书写简单而且使意义更加明确,因而增强了可读性。
    例如:

    typedef char NAME[20];  
    NAME a1,a2,s1,s2;
    
    // 完全等效于:
    char a1[20],a2[20],s1[20],s2[20];
    

    又如:

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

    相关文章

      网友评论

          本文标题:C语言笔记(五)----struct,enum,typedef等

          本文链接:https://www.haomeiwen.com/subject/ubczuxtx.html