【C语言-52】叮咚~~,自定义类型部分知识点大放送啦~~~~

目录

 

 

结构体类型创建:

结构体:

匿名结构体类型:

结构体的自引用:

结构体变量的定义和初始化:

变量定义:

结构体初始化:

结构体内存对齐:

代码示例:

得到结果:

结构体对齐规则:

附加题:

内存对其原因:

修改默认对齐数:

结构体传参:

位段,位段计算机大小:

什么是位段?

位段的内存分配:

枚举+联合。

枚举类型定义:

枚举的优点:

联合(共同体):

联合类型的定义:

联合的特点:

 


 

  • 结构体类型创建:

结构体:

  1. 结构体是一个数据类型定义:
结构体原型:
struct tag   {

      member-list;

}variable-list;


例如:
  struct  stu {
    char name[20];  //名字
    int age ;//年龄
    char sex ;  //性别
};    //必须有分号
  1. struct  不能省略,如果省略,必须要  typedef  的方式进行类型重定义;

匿名结构体类型:

  1. 代码如下:
struct {   //结构体没有名字.
  int a;
  char b;
  } X;             x是变量

//创建了一个匿名结构体,匿名结构体的变量名是x;



struct  {

   int a;
   char b;
}a[20],*p;


//上面两个结构体声明时省略了结构体标签tag;





结构体的自引用:

  1. 一个结构体里面不能包含结构体本身;
  2. 正确的自引用方式:

strcut node{
     int date;
     struct node* nest;
};
  • 结构体变量的定义和初始化:

变量定义:

  1. 变量定义代码示例:
strcut point{
      int x;
      int y;
      int z;

}p1;    //声明类型的同时定义了变量p1;
 
struct point p2;  //定义结构体变量p2;
 

结构体初始化:

  1. 定义变量的同时赋初值;
struct point p3={x,y};


struct stu {
      char  name[20];
      int age;
};
struct stu s={"jingyu",20};  //初始化

//结构体嵌套初始化
  struct node{
      int date;
        struct  point p;
        struct  node* nest;
}n1={10,{4,5},NULL};

struct node n2={30,{6,8},NULL};//结构体嵌套初始化
  • 结构体内存对齐:

代码示例:

  1. #include<stdio.h>
    #include<stdlib.h>
    struct test {
    	int a;
    	int b;
    	int c;
    	int d;
    };  //结构体包含了四个整型变量成员
    int main() {
    
    	struct  test t;
    
    	printf("&t=%p\n", &t);
    
    	printf("&t.a=%p\n", &t.a);
    	printf("&t,b=%p\n", &t.b);
    	printf("&t.c=%p\n", &t.c);
    	printf("&t.d=%p\n", &t.d);
    
    	printf("sizeof(t)=%d\n",sizeof(t));
    
    	system("pause");
    	return 0;
    }

    得到结果:

&t=0098FB88
&t.a=0098FB88
&t,b=0098FB8C
&t.c=0098FB90
&t.d=0098FB94
sizeof(t)=16
请按任意键继续. . .

 

  1. 如果代码改动:  int a;  变成char a;
  2. j结果不变:
  3. 代码示例二:
  4. #include<stdio.h>
    #include<stdlib.h>
    
    struct s1 {
    	char a;
    	int b;
    	char c;
    };  
    
    struct s2 {
    	char a;
    	char b;
    	int  c;
    };
    
    struct s3 {
    	double a;
    	char b;
    	int c;
    };
    
    struct s4 {
    	char a;
    	struct  s3  b;
    	double  c;
    };
    
    
    
    int main() {
    
    	printf("sizeof(struct s1)=%d\n", sizeof(struct s1));
    	printf("sizeof(struct s2)=%d\n", sizeof(struct s2));
    	printf("sizeof(struct s3)=%d\n", sizeof(struct s3));
    	printf("sizeof(struct s4)=%d\n", sizeof(struct s4));
    
    	system("pause");
    	return 0;
    }

     

得到结果:

sizeof(struct s1)=12
sizeof(struct s2)=8
sizeof(struct s3)=16
sizeof(struct s4)=32
请按任意键继续. . .

结构体对齐规则:

  1. 结构体第一个成员位置    在结构体变量偏移量为0的地址处;

  2. 其他成员变量对齐到  对齐数的整数倍的地址;

  3. 对齐数  =   编译器默认的一个对齐数 与该成员大小比较的较小值;    vs 中默认对齐数8;  linux 默认是4;

  4. 结构体总大小是结构体对齐数的整数倍;

  5. 嵌套结构体:   嵌套结构体对齐自己的最大对齐数的整数倍,结构体的大小是最大对齐数的整数倍;结构体的整体大小就是所有最大对齐数(含嵌套结构体对齐数)的整数倍;

附加题:

struct  s5 {
	
	char a;
	float  b;
	short c;
	double d;
	int e;
	char f;
	float g;
	int h;
	
};
  得到结果:
sizeof(struct s5)=40
请按任意键继续. . .

内存对其原因:

  1. 平台原因:不是所有硬件平台都能访问任意地址上的任意数据; 某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常;
  2. 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐;原因在于,为了访问未对齐的内存,处理器需要做两次内存访问,而对齐的内存访问仅需要一次访问;
  3. 设计结构体时,既要满足对齐,又要节省空间,让空间小的成员变量尽量集中在一起:
  4. 如下代码:
  5. #include<stdio.h>
    #include<stdlib.h>
    struct s1 {
    	char a;
    	int b;
    	char c;
    
    };
    
    struct s2 {
    	char a;
    	char b;
    	int c;
    
    };
    
    
    int main() {
    	printf("sizeof(s1)=%d\n", sizeof(struct s1));
    	printf("sizeof(s2)=%d\n", sizeof(struct s2));
    
    	system("pause");
    
    }

    结果:

  6. sizeof(s1)=12
    sizeof(s2)=8
    请按任意键继续. . .

     

  7. 我们可以看到,s1和s2类型成员一模一样,但是所占空间大小有区别;

修改默认对齐数:

  1. #pragma 这个预处理指令可以用来使用改变对齐数;
  2. #include<stdio.h>
    #include<stdlib.h>
    #pragma pack(8)   //设置默认对齐数为8
    
    struct s1 {
    	char a;
    	int b;
    	char c;
    
    };
    #pragma pack()   //取消设置的默认对齐数,还原默认
    
    #pragma pack(1)  //设置默认对齐数为1
    
    struct s2 {
    	char a;
    	char b;
    	int c;
    
    };
    #pragma pack()   //取消设置的默认对齐数,还原默认
    
    
    
    int main() {
    	printf("sizeof(s1)=%d\n", sizeof(struct s1));
    	printf("sizeof(s2)=%d\n", sizeof(struct s2));
    
    	system("pause");
    
    }

    得到结果:

  3. sizeof(s1)=12
    sizeof(s2)=6
    请按任意键继续. . .

 

结构体传参:

  1.  传参两种方式;
  2. #include<stdio.h>
    #include<stdlib.h>
    #pragma pack(8)   //设置默认对齐数为8
    
    struct S {
    	int date[1000];
    	int num;
    };
    struct S s = { {1,2,3,4},1000 };
    
    //结构体传参
    void printf1(struct S s) {
    	printf("%d\n", s.num);
    }
    
    //结构体地址传参
    void printf2(struct S *ps) {
    	printf("%d\n", ps->num);
    }
    
    
    
    
    int main() {
    	printf1(s);  //传结构体
    	printf2(&s);  //传地址
    
    	system("pause");
    	return 0;
    
    }

    首选printf2函数;

  3. 函数传参的时候,参数需要压栈,会有时间和空间的开销;

  4. 如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以导致性能下降;

  5. 结论就是:  结构体传参的时候,要传结构体的地址;

  • 计算结构体中某变量对于首地址的偏移:
  • struct test {
    	char a;
    	int b;
    };
    
    
    int main() {
    	struct test t;
    	int ret =(char*)&t.b - (char*)&t;
    	printf("%d\n", ret);
    	
    	system("pause");
    	return 0;
    
    }
  • 位段,位段计算机大小:

什么是位段?

  1. 位段的声明和结构体类似;
  2. 位段的声明必须有一个冒号和数字;
  3. 位段定义和大小:
    #include<stdio.h>
    #include<stdlib.h>
    
    struct A {
    	int _a:2;
    	int _b : 5;
    	int _c : 10;
    	int _d : 20;
    };
    //A就是一个位段类型
    
    int main() {
    	printf("sizeof(struct A)=%d\n", sizeof(struct A));//位段大小
    	
    	system("pause");
    	return 0;
    
    }

    结果:

    sizeof(struct A)=8
    请按任意键继续. . .

 

位段的内存分配:

  1. 位段的成员可以是 int ,unsigned int,signed  int或者 char 类型;
  2. 位段空间按照需要以4个字节(int)或者1个字节(char)的方式来开辟;
  3. 位段不跨平台;
  4. 位段跨平台时:  int位段被当成有符号数还是无符号数不确定;      位段中最大位的数目不能确定;   位段中成员在内存从左到右还是从右到左分派尚未定义;  
  5. 和结构体相比,位段可以很好的节省空间,但是不可以跨平台:
  6.  
  • 枚举+联合。

枚举类型定义:

  1. 星期,性别,颜色都可以采用枚举的方式定义:
  2. enum Day {   //星期枚举
       Mon;
       Tues;
       Wed;
       Thur;
       Fri;
       Sat;
       Sun;
    
    };
    
    enum color{
        red =1;
        green =2;
        blue =3;
    
    };
    enum color clr = green;//利用枚举常量给枚举变量赋值,才不会有类型差异;
    
  3. 这里的enum Day 是枚举类型;  { }中的内容是枚举类型的可能取值,也叫枚举常量;

枚举的优点:

  1. 增加代码的可读性和可维护性;
  2. 和#define 定义的标识符比较,枚举有类型检查,国家严谨;
  3. 防止了命名污染;
  4. 便于调试;
  5. 使用方便.可以一次定义多个常量;

联合(共同体):

联合类型的定义:

  1. 联合也是一种自定义类型,这种类型定义变量包含了一系列的成员,特征是这些成员公用同一块空间;(所以联合也叫 共同体);
  2. 联合类型声明:
//联合类型的声明
union Un {
	char c;
	int i;
};
//联合变量的定义





int main() {
	// 联合变量的定义
	union Un un;
	printf("sizeof(un)=%d\n", sizeof(un));
	
	system("pause");
	return 0;

}

sizeof(un)=4
请按任意键继续. . .

联合的特点:

  1. 联合的成员共同用一块内存空间;
  2. 一个联合变量的大小,至少是最大成员的大小;
  3. 这里看一个示例程序:
  4. #include<stdio.h>
    #include<stdlib.h>
    //联合类型的声明
    union Un {
    	char c;
    	int i;
    };
    
    union Un1 {
    	char c[1];
    	int i;
    };
    
    union Un2 {
    	short c[4];
    	int i;
    };
    union Un3 {
    	short c[7];
    	int i;
    };
    union Un4 {
    	short c[12];
    	int i;
    };
    
    
    int main() {
    	// 联合变量的定义
    
    	union Un un;
    	printf(" &un.c=%d\n", &un.c);
    	printf(" &un.i=%d\n", &un.i);
    
    	un.c = 0x11223344;
    	un.i = 0x55;
    	printf(" &un.c=%d\n", &un.c);
    	printf(" &un.i=%d\n", &un.i);
    
    	printf("sizeof(union Un1)=%d\n", sizeof(union Un1));
    	printf("sizeof(union Un2)=%d\n", sizeof(union Un2));
    	printf("sizeof(union Un3)=%d\n", sizeof(union Un3));
    	printf("sizeof(union Un4)=%d\n", sizeof(union Un4));
    	
    	system("pause");
    	return 0;
    
    }

     运行结果:

  5.  &un.c=11533460
     &un.i=11533460
     &un.c=11533460
     &un.i=11533460
    sizeof(union Un1)=4
    sizeof(union Un2)=8
    sizeof(union Un3)=16
    sizeof(union Un4)=24
    请按任意键继续. . .

晚安,

2018年的5月8日,北京奥运会火炬成功登顶珠穆朗玛峰!!!!!

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值