9.构造类型

一、结构体

1.产生及意义

2.类型的描述

使用格式:结构体成员是不占用内存空间的,类比于int属于类型范畴。

struct [结构体名]
{
    //成员间的数据类型可以不同
    数据类型 成员1;
    数据类型 成员2;
    ······
}[one or more struct variables];

3.嵌套描述

struct data
{
    int year;
    int month;
    int day;
};

struct info
{
    int id;
    char str[STRSIZE] address;
    struct data birth;
    char level;
}

上述 struct data data; 可转换为:

struct info
{
    int id;
    char str[STRSIZE] address;
    struct data
    {
        int year;
        int month;
        int day;
    }birth;  //注意结构体定义只是一个类型,因此需要定义变量 birth 
    char level;
}

嵌套结构体引用:定义时初始化变量使用嵌套定义:
struct info a = {100001,"hello0",{2022,9,28},'A'};
部分引用:struct info a = (.id = 10001,.birth.day = 28);
如果引用结构体ainfo中的month:a.birth.month

4.定义变量(变量、数组、指针),初始化及成员引用

成员引用1:变量名.成员名

示例代码:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 struct sim
  5 {
  6     int i;
  7     float f;
  8     char ch;
  9 };
 10 
 11 int main()
 12 {
 13     //  TYPE    NAME  = VALUE
 14     struct sim    a   = {23,23.22222,'a'};  //initiallization     
 15     a.i = 45;  //variable references
 16 
 17     printf("%d %f %c\n",a.i,a.f,a.ch);
 18 
 19     exit(0);
 20 }

输出结果:

jxs@jxs-ubuntu:~/Desktop/c  language/creat_type$ ./struct
45 23.222219 a

成员引用2:指针->成员名

成员引用3:(*指针).成员名

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 #define N 128
  5 
  6 struct birth
  7 {
  8     int year;
  9     int month;
 10     int day;
 11 };
 12 
 13 struct info
 14 {
 15     int id;
 16     struct birth bir;
 17     char name[N];
 18     float math;
 19     float chinese;
 20 };
 21 
 22 int main()
 23 {
 24     struct info stu_arr[2] = {{10001,{2022,9,28},"Alan",97.99,98},{10002,{2022,9,28},"Jack",96,56}};
 25     struct info *p = &stu_arr[0];
 26     struct info stu = {10001,{2022,9,28},"Bobo",97.99,98};
 27     struct info *q = &stu;  //need &!
 28     int i;
 29   
 30     for(i = 0; i < 2; i++, p++)  // p + 1 表示跳过一个结构体的大小
 31     {
 32         printf("%d %d-%d-%d %s %f %f\n",p -> id, p -> bir.year, p -> bir.month, p -> bir.day, p -> name, p -> math, p -> chinese);       
 33     }
 34     printf("%d %d-%d-%d %s %f %f\n",(*q).id, (*q).bir.year, (*q).bir.month, (*q).bir.day, (*q).name, (*q).math, (*q).chinese);
 35 
 36     exit(0);
 37 }

输出结果:

jxs@jxs-ubuntu:~/Desktop/c  language/creat_type$ ./struct1
10001 2022-9-28 Alan 97.989998 98.000000
10002 2022-9-28 Jack 96.000000 56.000000
10001 2022-9-28 Bobo 97.989998 98.000000

5.占用内存空间大小

示例代码:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 //#define N 128
  5 
  6 struct birth
  7 {
  8     char ch;
  9     int year;
 10     int month;
 11     int day;
 12   
 13 };
 14 
 15 int main()
 16 {   
 17     struct birth bir = {'a',2022,9,28};
 18     struct birth *p = &bir;
 19     printf("bir.ch --> %p\nbir.year --> %p\nbir.month --> %p\nbir.day --> %p\n", &bir.ch, &bir.year, &bir.month, &bir.day);
 20     printf("size of bir : %ld\n",sizeof(bir));
 21     printf("size of bir : %ld\n",sizeof(p));
 22     
 23     exit(0);
 24 }

输出结果:

jxs@jxs-ubuntu:~/Desktop/c  language/creat_type$ ./structsize 
bir.ch --> 0x7ffd83def2d0
bir.year --> 0x7ffd83def2d4
bir.month --> 0x7ffd83def2d8
bir.day --> 0x7ffd83def2dc
size of bir : 16
size of bir : 8

结构体所占用空间大小按照类型来计算时,应该为 1 + 4 + 4 + 4 = 13,但该结构体实际占用的内存为16。原因在于编译器的地址对齐!

使用下面这种方式就会等于13

  6 struct birth
  7 {
  8     char ch;
  9     int year;
 10     int month;
 11     int day;
 12   
 13 }__attribute__((packed));
bir.ch --> 0x7ffc9c4a4e1b
bir.year --> 0x7ffc9c4a4e1c
bir.month --> 0x7ffc9c4a4e20
bir.day --> 0x7ffc9c4a4e24
size of bir : 13
size of bir : 8

6.函数传参(值传递、地址传递)

使用值传递会增大形参的空间开销,使用指针则可以减少空间开销。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 //#define N 128
  5 
  6 struct birth
  7 {
  8     char ch;
  9     int year;
 10     int month;
 11     int day;
 12 
 13 };
 14 
 15 void func1(struct birth *i)
 16 {
 17     printf("size of point : %ld\n",sizeof(i));
 18 }
 19 
 20 void func2(struct birth i)
 21 {
 22     printf("size of struct : %ld\n",sizeof(i));
 23 
 24 }
 25 
 26 int main()
 27 {
 28     struct birth a;
 29     struct birth *p = &a;
 30 
 31     func2(a);
 32     func1(p);
 32     func1(p);
 33 
 34     exit(0);
 35 }
jxs@jxs-ubuntu:~/Desktop/c  language/creat_type$ ./structfunc 
size of struct : 16
size of point : 8   //因此一般使用指针进行传参
  • 微型学生管理系统

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #define NAMESIZE 128
  6 
  7 struct info
  8 {   
  9     int id;
 10     char name[NAMESIZE];
 11     int math;
 12     int chinese;
 13 };
 14 
 15 void menu(void)
 16 {   
 17     printf("\n1.set_info\n2.rename\n3.show_info\n\n");
 18     printf("Please input num to choose the function :");
 19 }
 20 
 21 
 22 void set_info(struct info *a)
 23 {   
 24     printf("Please input info [id name math chinese]: \n");
 25     scanf("%d%s%d%d",&(*a).id,(*a).name,&(*a).math,&(*a).chinese);
        //scanf("%d%s%d%d", &a->id, a->name, &a->math, &a->chinese);
 26 }
    /*
      void set_info(struct info *a)
      {   
          printf("Please input info [id name math chinese]: \n");
          
          //scanf("%d%s%d%d",&(*a).id,(*a).name,&(*a).math,&(*a).chinese);
          a->name = malloc(NAMEMAX);  //Assign NAMEMAX bytes for name
          
          if(a->name == NULL)
               exit(1);
          scanf("%d%s%d%d",&a->id,a->name,&a->math,&a->chinese);
          free(a->name);
       }
    */
 27 
 28 void change_name(struct info *p, const char *newname)
 29 {   
 30     strcpy(p->name,newname);
 31 }
 32 
 33 void show_info(struct info *p)
 34 {
 35     printf("id\tname\tmath\tchinese\n");
 36     printf("%d\t%s\t%d\t%d\n",p->id,p->name,p->math,p->chinese);
 37 }
 38 
 39 int main()
 40 {
 41     struct info stu;
 42     struct info *q = &stu;
 43     int num;
 44     int ret;
 45     char newname[NAMESIZE];
 46     do
 47     {
 48         menu();
 49         scanf("%d",&num);
 50         if(num != 1 && num != 2 && num != 3)
 51             printf("Please input the right value!\n\n");
 52 
 53         switch(num)
 54         {
 55             case 1:
 56                 set_info(&stu);
 57                 break;
 58             case 2:
 59                 printf("Please input a new name :");
 60                 scanf("%s",newname);
 61                 change_name(&stu,newname);
 62                 break;
 63             case 3:
 64                 show_info(&stu);
 65                 break;
 66             default:
 67                 break;
 68         }
 69 
 70     }while(1);
 71 
 72     exit(0);
 73 }

执行结果:

1.set_info
2.rename
3.show_info

Please input num to choose the function :3
id	name	math	chinese
2021170116	liming	98	56

二、共用体

1.产生及意义

共用体是一种特殊的数据类型,允许在相同的内存位置存储不同的数据类型。可以定义一个带有多成员的共用体,但是任何时候只有一个成员带有值,共用体提供了一种使用相同内存位置的有效方式。

共用体与结构体不同之处在于,前者由于是多个成员共用一个内存位置,因此成员的值只能择其一。结构体所有的成员都可以有各自的值。

2.类型的描述

union [共用体名]
{
    数据类型 成员名1;
    数据类型 成员名2;
    ······
}[one or more union variables];

3.嵌套定义

与结构体类似,无特殊之处。并且可以与结构体进行嵌套。

计算32位无符号数高十六位与低十六位相加的和。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <stdint.h>
  4 
  5 int main()
  6 {
  7     uint32_t i = 0x11223344;
  8     printf("%x\n",(i >> 16) + i & 0xFFFF);
  9 
 10 
 11     exit(0);
 12 }

使用共用体:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <stdint.h>
  4 
  5 union
  6 {
  7     struct
  8     {
  9         uint16_t i;
 10         uint16_t j;
 11     }b;
 12     uint32_t k;
 13 }a;
 14 
 15 int main()
 16 {   
 17     a.k =  0x11223355;
 18     printf("%x + %x = %x\n", a.b.i, a.b.j, a.b.i + a.b.j);
 19     printf("a.k: %p\na.b.i: %p\na.b.j: %p\n", &a.k, &a.b.i, &a.b.j);
 20     printf("size of union a : %ld\n",sizeof(a));
 21     
 22     exit(0);
 23 }
jxs@jxs-ubuntu:~/Desktop/c  language/creat_type$ ./uint1
3355 + 1122 = 4477
a.k: 0x556a58f3a014
a.b.i: 0x556a58f3a014
a.b.j: 0x556a58f3a016
size of union a : 4

union中的内存分配:

"高尾端(big-endian)"与"低尾端(little-endian)" (数据地位由左到右依次降低)

如果将一个数视为一个字符串,如11223344视为"11223344",末尾是\0,11 22 33 44各占用一个存储单位(1个字节),那么其尾端是44。尾端的高低定义取决于尾端放在高地址还是低地址。

//大端:数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中
//小端:数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中
int a = 0x123;
//在内存中,int类型有4个字节,2个二进制数为一个字节
//所以有8个十六进制进制数
//补齐0是  0x 00 00 01 23(23是尾端)
//  数据高位------(降低)-------数据地位
//  内存中:
//   大端    00 00 01 23
//   小端    23 01 00 00
//  低地址-----------------高地址

4.定义变量(变量、数组、指针),初始化以及成员引用

5.占用内存大小

共用体占用的内存应足够存储占用内存最大的变量。

6.函数传参(值传递、地址传递)

7.位域

三、枚举

使用格式:enum 枚举名 {枚举元素1,枚举元素2,……};
使用方式类似于#define,例如:

#define MON  1
#define TUE  2
#define WED  3
#define THU  4
#define FRI  5
#define SAT  6
#define SUN  7

//等同于:
enum DAY
{
    MON=1, TUE, WED, THU, FRI, SAT, SUN  //成员皆变量
};
//枚举变量定义:
1.先定义枚举类型,再定义枚举变量
enum Day
{
     MON, TUE, WED, THU, FRI, SAT, SUN  //注意没有分号`;`
};
enum day;
2.定义枚举类型同时定义枚举变量
enum Day
{
     MON, TUE, WED, THU, FRI, SAT, SUN
}day;
3.省略枚举名,直接定义枚举变量名
enum 
{
     MON, TUE, WED, THU, FRI, SAT, SUN
}day;

第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个的基础上加1.不论是中间的哪一个值被赋值,其后未被赋值的成员的值仍满足上述规定。

示例代码:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 enum DAY
  5 { 
  6     MON = 1,TUS,THR,WES,FRI,SAT,SUN  //MON之后的变量依次加一
  7 };
  8 
  9 int main()
 10 {
 11     enum DAY day2 = TUS;
 12     enum DAY day5 = FRI;
 13 
 14     printf("day2 = %d and size of day2 = %ld\n",day2,sizeof(day2));
 15     printf("day5 = %d and size of day5 = %ld\n",day5,sizeof(day5));
 16 
 17     exit(0);
 18 }

输出结果:

day2 = 2 and size of day2 = 4
day5 = 5 and size of day5 = 4

使用场景:比如判断服务器的状态让其执行相应的任务。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <time.h>
  4 
  5 struct job
  6 {   
  7     int id;
  8     int state;
  9     time_t start,end;
 10 };
 11 
 12 enum
 13 {   
 14     STATE_RUNNING = 1,
 15     STATE_CANCELED,
 16     STATE_OVER
 17 };
 18 
 19 int main()
 20 {
 21     struct job job1;
 22 
 23     //obtain the assignment state
 24     switch(job1.state)
 25     {
 26         case STATE_RUNNING:   //这里未定义enum 变量,但可以直接使用该变量的值,就相当于宏定义
 27             printf("This job is running!\n");
 28             break;
 29              
 30         case STATE_CANCELED:
 31             printf("This job is dennied!\n");
 32             break;
 33 
 34         case STATE_OVER:
 35             printf("This job is over!\n");
 36             break;
 37 
 38         default:
 39             abort();  //异常进程终止
 40 
 41     }
 42 
 43     exit(0);
 44 }
 45 
  • typedef:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 typedef int INT;  //typedef 数据类型(包含构造类型) 类型别名
  5 //#define INT int //#define [marco name] [marco body] :replace all the 'INT' to 'int'
  6 
  7 //difference:
  8 /*1.typedef int * INT
  9  *def: INT p, q;  --> int *p, int *q;
 10  *
 11  *
 12  *2.#define INT int*
 13  *def: INT p, q;  --> int *p, int q;
 14  */
 15 
 16 /*detailes in typedef
 17  * 1.arr: typedef int ARR[6] (int [6] -->  ARR);
 18  * ARR a;  -->  int a[6];
 19  *
 20  *
 21  * 2.struct
 22  * struct node_st
 23  * {
 24  *      int i;
 25  *      float j;  
 26  * };
 27  *
 28  * 1)typedef node_st NODE; -->  struct node_st NODE;
 29  * NODE a;  -->  struct node_st a;
 30  * NODE *p;  -->  struct node_st *p;
 31  *
 32  * 2)typedef node_st *NODEP; -->  struct node_st *NODEP;
 33  * NODEP p;  -->  struct node_st *p;
 34  *
 35  * 3)typedef struct 
 36  * {
 37  *      int i;
 38  *      float j;
 39  * }NODE,*NODEP;  equal to def of 1) and 2).
 40  *
 41  *
 42  * 3.functions:
 43  * 1)typedef int FUNC(int);  -->  int FUNC(int);
 44  * FUNC f;  -->  int f(int);
 45  *
 46  * 2)typedef int *FUNCP(int);  --> int *FUNCP(int);
 47  * FUNCP p;  -->  int *p(int);
 48  *
 49  * 3)typedef int *(*FUNCPP)(int);  -->  int *(*FUNCPP)(int);
 50  * FUNCPP q;  -->  int *(*q)(int);  
 51  */
 52 
 53 
 54 
 55 int main()
 56 {
 57     INT i = 4;
 58     printf("i = %d\n",i);
 59 
 60     exit(0);
 61 }

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #define NAMEMAX 128
  6 
  7 typedef struct info
  8 {   
  9     int id;
 10     char *name;
 11     int math;
 12     int chinese;
 13 }STU;
 14 
 15 void menu(void)
 16 {   
 17     printf("\n1.set_info\n2.rename\n3.show_info\n4.exit\n\n");
 18     printf("Please input num to choose the function :");
 19 }
 20 
 21 
 22 void set_info(STU *a)
 23 {   
 24     printf("Please input info [id name math chinese]: \n");
 25     //scanf("%d%s%d%d",&(*a).id,(*a).name,&(*a).math,&(*a).chinese);
 26     a->name = malloc(NAMEMAX);  //Assign NAMEMAX bytes for name
 27     if(a->name == NULL)
 28         exit(1);
 29     scanf("%d%s%d%d",&a->id,a->name,&a->math,&a->chinese);
 30     free(a->name);
 31 }
 32 
 33 void change_name(STU *p, const char *newname)
 34 {   
 35     strcpy(p->name,newname);
 36 }
 37 
 38 void show_info(STU *p)
 39 {   
 40     printf("id\tname\tmath\tchinese\n");
 41     printf("%d\t%s\t%d\t%d\n",p->id,p->name,p->math,p->chinese);
 42 }
 43 
 44 int main()
 45 {
 46     STU stu;
 47     STU *q = &stu;
 48     int num;
 49     int ret;
 50     char newname[NAMEMAX];
 51     do
 52     {
 53         menu();
 54         scanf("%d",&num);
 55         if(num != 1 && num != 2 && num != 3 && num != 4)
 56             printf("Please input the right value!\n\n");
 57 
 58         switch(num)
 59         {
 60             case 1:
 61                 set_info(&stu);
 62                 break;
 63             case 2:
 64                 printf("Please input a new name :");
 65                 scanf("%s",newname);
 66                 change_name(&stu,newname);
 67                 break;
 68             case 3:
 69                 show_info(&stu);
 70                 break;
 71             case 4:
 72                 exit(0);
 73             default:
 74                 break;
 75         }
 76 
 77     }while(1);
 78 
 79     exit(0);
 80 }
posted @ 2023-06-29 17:07  假行僧me  阅读(10)  评论(0编辑  收藏  举报