【保姆级讲解】C语言---结构体精华

本文详细介绍了C语言中的结构体和共用体,包括结构体的定义、成员访问、类型定义、变量定义、赋值方式、嵌套结构体、空间大小计算、位字段、结构体数组和指针。同时,提到了共用体的特点和用途,强调了数据对齐和内存布局的重要性。结构体和共用体在编程中常用于表示复杂的数据结构,提高代码的可读性和效率。
摘要由CSDN通过智能技术生成

结构体介绍(块)

1.1 结构体概述

结构体是一种构造数据类型,使用关键字“struct”来表示。是指一系列相同数据类型或者不同数据类型的数据构成的集合。结构体中的成员变量跟数组中的元素一样,在存储空间中都是连续存储的。

指一系列相同数据类型或者不同数据类型的数据构成的集合----联想起数组;

数组为相同数据类型的集合;

结构体想用/不同数据类型的集合;

数据类型:基本数据类型、构造数据类型、空类型;

基本数据类型:char字符型 short短整型 int 整型 long 长整型 float 单精度浮点型 double双精度浮点型;

构造数据(以基本数据类型为依据):数组(基本数据类型+[])、指针(基本数据类型+*)、结构体(基本数据类型+struct)、共用体、枚举;

1.2 结构体定义

  1. 结构体类型定义格式

struct 结构体名

{

成员(成员变量)1;

成员(成员变量)2;

成员(成员变量)3;

….

成员(成员变量)n;

};

  1. struct:结构体类型关键字,表示这是一个结构体类型,即我们在构造并且声明一种结构体类型。
  2. 结构体名: 自定义标识符,命名规则同变量。建议使用突出类型意义的词汇。
  3. 成员: 数据在结构体中叫做成员变量。
  4. 每个成员变量都有自己的数据类型和变量名,因为每个成员含义不同,所以类型不同
  5. 成员变量之间类型可以相同也可以不同;
  6. 成员变量的类型,可以是基本数据类型,也可以是构造数据类型(数组、指针类型、结构体类型)。

但是这个构造数据类型必须存在。

  1. 末尾的分号不能省略,这个分号表示结构体类型声明结束。
  2. 结构体类型定义在全局的位置,让所有的函数都可以直接调用。

注:结构体声明是一个声明语句,在结构体声明的最后必须加上一个分号(;)来作为语句的结束。并且在声明结构体类型的时候,结构体的成员不能有值。

#include<stdio.h>

#include<string.h>

//struct->表示这是一个结构体类型,即我们在构造并且声明一种结构体类型 C11版本

//Person->自定义标识符,命名规则同变量。建议使用突出类型意义的词汇。

//{}作用域->结构体内不能出现重名问题

struct Person{

int W; //数据在结构体中叫做成员变量

int H; //成员变量

int Age; //成员变量之间类型可以相同也可以不同

char Name[30]; //基本数据类型,也可以是构造数据类型

void (*Action)(void); //行为

};//末尾的分号不能省略,这个分号表示结构体类型声明结束。

//对于结构体所放位置: 结构体类型定义在全局的位置,让所有的函数都可以直接调用。一般是放在.h中

//由于只是构造与声明所以不能进行赋值

//不管是哪种编译器 都用最通用原则 先进行声明,再进行定义

struct Person a; //全局变量

int main()

{

struct Person b; //栈区变量

printf("%d\n",a.W);

printf("%d\n",b.W);

return 0;

}

1.3 结构体类型变量定义

定义的步骤:

    1. 结构体类型声明
    2. 使用声明好的结构体类型定义结构体变量

格式:“结构体关键字struct 结构体类型名person 变量名a”

例1:先声明结构体类型,在使用声明好的结构体类型去定义结构体变量。

#include<stdio.h>

#include<string.h>

//构造与声明结构体 类型-> struct Person

struct Person{

int W;

int H;

int Age;

char Name[30];

void (*Action)(void);

};

//先声明结构体类型,在使用声明好的结构体类型去定义结构体变量。

struct Person a; //全局变量

int main()

{

struct Person b; //栈区变量

printf("%d\n",a.W);

printf("%d\n",b.W);

return 0;

}

在声明结构体类型的同时定义结构体变量。

例1:

#include<stdio.h>

#include<string.h>

//构造与声明结构体 类型-> struct Person

struct Person{

int W;

int H;

int Age;

char Name[30];

void (*Action)(void);

}xiaoming,xiaohua; //在声明结构体类型的同时定义结构体变量->全局变量xiaoming xiaohua

//xiaoming xiaohua为struct Person类型变量

int main()

{

printf("%d\n",xiaoming.W);

printf("%d\n",xiaoming.W);

return 0;

}

例2:

讨论:结构体构造与声明时作用域知识点:

#include<stdio.h>

#include<string.h>

//这种使用的比较少而已

int main()

{

//构造与声明结构体 类型-> struct Person

struct Person{

int W;

int H;

int Age;

char Name[30];

void (*Action)(void);

}xiaoming,xiaohua; //在声明结构体类型的同时定义结构体变量->局部变量xiaoming xiaohua

//xiaoming xiaohua为struct Person类型变量

printf("%d\n",xiaoming.W);

printf("%d\n",xiaoming.W);

return 0;

}

讨论:结构体构造与声明时作用域知识点:

#include<stdio.h>

#include<string.h>

//这种使用的比较少而已

int main()

{

{

//构造与声明结构体 类型-> struct Person

struct Person{

int W;

int H;

int Age;

char Name[30];

void (*Action)(void);

}xiaoming,xiaohua; //在声明结构体类型的同时定义结构体变量->局部变量

//xiaoming xiaohua为struct Person类型变量

printf("%d\n",xiaoming.W);

printf("%d\n",xiaoming.W);

}

return 0;

}

讨论:结构体构造与声明时定义变量并且结构体类型名忽略的知识点:

#include<stdio.h>

#include<string.h>

//这种使用的比较少而已

int main()

{

{

//构造与声明结构体 类型-> struct Person

struct{

int W;

int H;

int Age;

char Name[30];

void (*Action)(void);

}xiaoming,xiaohua; //在声明结构体类型的同时定义结构体变量->局部变量

//xiaoming xiaohua为struct Person类型变量

printf("%d\n",xiaoming.W);

printf("%d\n",xiaoming.W);

}

return 0;

}

结构体类型名可以不写,但是这种结构体类型只能在声明的同时定义变量,往后不能再用此结构体类型单独去定义其他变量。

注:在声明结构体类型的同时,定义结构体变量,结构体类型名可以不写,但是这种结构体类型只能在声明的同时定义变量,往后不能再用此结构体类型单独去定义其他变量。

  1. 利用类型重定义去重新定义结构体类型的名称,然后利用新的结构体类型名称定义结构体变量。

例:

#include<stdio.h>

#include<string.h>

//利用类型重定义去重新定义结构体类型的名称,然后利用新的结构体类型名称定义结构体变量

//类型重定义关键字:typedef

typedef struct person{

int W;

int H;

int Age;

char Name[30];

void (*Action)(void);

}PERSON;

//typedef->  将struct person类型重命名为PERSON  重定义 原名/现名都能使用 避免了类型冲突

//PERSON a;

struct person b; //随着使用这种定义方式不如PERSON a;

/********************************************************

忽略结构体类型名,匿名类型重命名问题:

typedef struct{

int W;

int H;

int Age;

char Name[30];

void (*Action)(void);

}PERSON;

typedef 将匿名类型重命名为PERSON

常用方式如上:

*********************************************************/

/********************************************************

结构体类型名与重命名名出现冲突问题:

typedef struct person{

int W;

int H;

int Age;

char Name[30];

void (*Action)(void);

}person;

typedef 将struct person类型重命名为person 可以实现但是多此一举;

*********************************************************/

int main()

{

return 0;

}

1.4 结构体成员变量访问方式

  1. 通过结构体变量名访问: 结构体变量名.成员变量名

#include <stdio.h>

#include <string.h>

typedef struct person{

int W;

int H;

int Age;

char Name[30];

void (*Action)(void);

}PERSON;

int main()

{

PERSON a;

//1.通过结构体变量名访问: 结构体变量名.成员变量名

a.W =100;

a.H =170;

a.Age = 18;

strcpy(a.Name,"小明");

printf("%s 体重:%d  身高:%d 年龄:%d\n",a.Name,a.W,a.H,a.Age);

struct person b; //C99

//1.通过结构体变量名访问: 结构体变量名.成员变量名

b.W =100;

b.H =170;

b.Age = 18;

strcpy(b.Name,"小明");

printf("%s 体重:%d  身高:%d 年龄:%d\n",b.Name,b.W,b.H,b.Age);

return 0;

}

  1. 通过指针访问: 指针名->成员变量名,(*指针名).成员变量名

#include <stdio.h>

#include <string.h>

typedef struct person{

int W;

int H;

int Age;

char Name[30];

void (*Action)(void);

}PERSON;

int main()

{

PERSON a;

//2.通过指针访问: 指针名->成员变量名,(*指针名).成员变量名

PERSON *pa = &a;

pa->W =100;

pa->H =170;

pa->Age = 19;

strcpy(pa->Name,"小花");

printf("%s %d %d %d\n",pa->Name,pa->Age,pa->W,pa->H);

//(*指针名).成员变量名

printf("%s %d %d %d\n",(*pa).Name,(*pa).Age,(*pa).W,(*pa).H);

return 0;

}

  1. 结构体变量首地址: &变量名

注:“.”的优先级高于“*”,取内容的时候一定要加(),一般在结构体中使用“->”来访问结构体指针变量中的数据。“.”一般用于结构体变量,“->”只适用于结构体指针。

1.5 结构体赋值

  1. 初始化赋值

初始化赋值是指在定义结构体变量的时候,直接给结构体变量里的成员变量进行赋值。在直接赋值的时候,未赋值的成员变量,默认为0。

#include <stdio.h>

#include <string.h>

typedef struct person{

int W; //体重

int H; //身高

int Age; //年龄

char Name[30];       //名字

void (*action)(void); //函数指针 指定行为

}PERSON;

void emotion(void)

{

printf("充满爱\n");

}

int main()

{

//初始化全赋值

PERSON xiaoming={100,170,18,"小明",emotion};//初始化赋值内容顺序一定要和声明时成员的顺序保持一致

printf("%s %d %d %d\n",xiaoming.Name,xiaoming.W,xiaoming.H,xiaoming.Age);

xiaoming.action();

//初始化部分赋值---未赋值的成员默认为0

PERSON xiaohua={50};  //NULL 0

printf("%s %d %d %d\n",xiaohua.Name,xiaohua.W,xiaohua.H,xiaohua.Age);

return 0;

}

注:初始化赋值内容顺序一定要和声明时成员的顺序保持一致,并且结构体只能在初始化赋值时对结构体进行整体直接赋值。但是,同类型的结构体之间可以进行直接赋值。

例:

//同类型的结构体之间可以进行直接赋值 特性 满足数组的缺点

#include <stdio.h>

#include <string.h>

typedef struct {

char Name[30];

}nameArrBuff;

int main()

{

nameArrBuff a={"小明"};

nameArrBuff b;

b=a; //数组不可以整体赋值,把数组规整成结构体即可支持整体赋值

printf("%s\n",a.Name);

printf("%s\n",b.Name);

return 0;

}

  1. 逐一赋值

#include <stdio.h>

#include <string.h>

//2. 逐一赋值

typedef struct {

int W;

int H;

int Age;

char Name[30];

void (*action)(void);

}Person;

void emotion()

{

printf("充满爱\n");

}

int main()

{

//逐一赋值

Person a;

a.W = 100;

a.H = 170;

a.Age = 18;

//数组不能整体赋值

strcpy(a.Name,"小明");

a.action = emotion;

printf("%s\n",a.Name);

printf("%d\n",a.Age);

printf("%d\n",a.W);

printf("%d\n",a.H);

a.action();

return 0;

}

  1. 整体赋值

整体赋值是指相同数据类型的结构体变量之间可以相互赋值。

#include <stdio.h>

#include <string.h>

//2. 逐一赋值

typedef struct {

int W;

int H;

int Age;

char Name[30];

void (*action)(void);

}Person;

void emotion()

{

printf("充满爱\n");

}

int main()

{

//逐一赋值

Person a;

a.W = 100;

a.H = 170;

a.Age = 18;

//数组不能整体赋值

strcpy(a.Name,"小明");

a.action = emotion;

printf("%s\n",a.Name);

printf("%d\n",a.Age);

printf("%d\n",a.W);

printf("%d\n",a.H);

a.action();

Person b;

//结构体 同类型之间可以进行整体赋值

b = a;

printf("%s\n",b.Name);

printf("%d\n",b.Age);

printf("%d\n",b.W);

printf("%d\n",b.H);

b.action();

return 0;

}

赋值方式:初始化赋值、逐一赋值、整体赋值;

1.6 结构体嵌套

结构体嵌套是指一个结构体类型内嵌套另外一个结构体类型,在访问被嵌套的结构体的成员变量之前,需要先访问被嵌套的结构体变量名,再访问被嵌套的结构体的成员变量。

#include <stdio.h>

#include <string.h>

//荣誉

typedef struct {

int precedence;

float money;

}Honor;

//人类

typedef struct {

int W;

int H;

int Age;

char Name[30];

Honor status;  //前提先要有该类型

void (*action)(void);

}Person;

void emotion()

{

printf("充满爱\n");

}

int main()

{

Person a={100,170,18,"小明",{1,10000.00},emotion};

printf("名字:%s\n",a.Name);

printf("年龄:%d\n",a.Age);

printf("体重:%d\n",a.W);

printf("身高:%d\n",a.H);

//先访问被嵌套的结构体变量名,再访问被嵌套的结构体的成员变量

printf("位次:%d\n",a.status.precedence);

printf("财富:%lf\n",a.status.money);

a.action();

return 0;

}

注:在结构体嵌套时需要注意被嵌套的结构体成员变量的结构体类型,一定要在嵌套结构体数据的成员变量的结构体类型之前声明。

1.7 结构体类型空间大小

计算结构体类型空间大小的原则:结构体的有效对齐值

  1. 数据对齐原则---内存按结构体成员的先后顺序排列,当排到该成员时,其前面已开辟的空间字节数必须是该成员类型所占字节数的整数倍,如果不够则补齐,依次向后类推。
  2. 整体空间是占用空间最大的成员类型所占字节数的整数倍(系统对齐方式和结构体自身默认对齐方式,俩者取最小的)。

例1:不关心多少位操作系统前提下

#include <stdio.h>

#include <string.h>

typedef struct{

char a;

short b;

int c;

}StructSizeof;

int main()

{

printf("%d\n",sizeof(StructSizeof));

return 0;

}

例2:关心多少位操作系统前提下

例如32位操作系统:对齐方式按4字节对齐;-------特例:double 8字节大小(分割为2块);

例如64位操作系统:对齐方式按8字节进行对齐;

32位机

64位机

#include <stdio.h>

#include <string.h>

typedef struct{

char a;

double d;

}StructSizeof;

int main()

{

printf("%d\n",sizeof(StructSizeof));

return 0;

}

#include <stdio.h>

#include <string.h>

typedef struct{

char a;

double d;

}StructSizeof;

int main()

{

printf("%d\n",sizeof(StructSizeof));

return 0;

}

1.8 对齐指令

一般情况下不使用(导致系统访问结构体成员时对齐方式不按系统位数走,会导致低效率访问);

西瓜2个:每次你抱一个2次抱完;

如果西瓜切成10*2块 要分10次拿;效率降低;

#pragma pack(n) //(1、2、4、8、.....)

#pragma pack()

这两个配合使用,表示一个区间,只有这个区间内的结构体按照n字节对齐。

设置为1,就是不对齐

如果n设置的小,充分利用内存空间,牺牲了速度,降低了访问效率。

如果n设置的大,提高效率、性能,牺牲了内存空间。

用这个指令指定的对齐方式和结构体自身默认对齐方式,俩者取最小的。

#pragma指示使每个编译程序在保留C和C++语言的整体兼容性时提供不同机器和操作系统特定的功能。编译指示被定义为机器或操作系统特定的,并且通常每种编译程序是不同的。

N=1的时候 不对齐

#include <stdio.h>

#include <string.h>

#pragma pack(1)

typedef struct{

char a; //1

double d; //8

}StructSizeof;

int main()

{

printf("%d\n",sizeof(StructSizeof));  //9

return 0;

}

N=2的时候 2字节对齐

#include <stdio.h>

#include <string.h>

#pragma pack(2)

typedef struct{

char a; //1  补空1字节

double d; //8  double分为4块 每块2字节

}StructSizeof;

int main()

{

printf("%d\n",sizeof(StructSizeof));  //10

return 0;

}

N=3的时候 3字节对齐

#include <stdio.h>

#include <string.h>

#pragma pack(3)

typedef struct{

char a; //1  补空2字节

double d; //8  double分为3块 每块3字节  后补1字节

}StructSizeof;

int main()

{

printf("%d\n",sizeof(StructSizeof));  //12  //警告提示不能是3

return 0;

}

#pragma pack(4)//设置对齐字节数

用这个指令指定的对齐方式和结构体自身默认对齐方式(成员大小),俩者取最小的。

#include <stdio.h>

#include <string.h>

#pragma pack(4)

typedef struct{ //数据类型大小   

char a; //1

char b; //1

}StructSizeof;

int main()

{

printf("%d\n",sizeof(StructSizeof));  //2

return 0;

}

#pragma pack(8)//设置对齐字节数

用这个指令指定的对齐方式和结构体自身默认对齐方式(系统位数/成员大小),俩者取最小的。

#include <stdio.h>

#include <string.h>

#pragma pack(8)

typedef struct{ //数据类型大小   8字节对齐方式  4字节对齐

char a; //1 1 1

char b; //1 1+6空 1+2空

double d; //8 8 8 (4+4)

}StructSizeof;

int main()

{

printf("%d\n",sizeof(StructSizeof));  //12

return 0;

}

1.9 位字段

专用于结构体,有时侯,结构体成员表示的数据很小,就用几个位来表示。

结构体成员的类型必须是 int 或者 unsigned int,单个成员大小不能超过一个int大小(32位)

注意 :字段不可取地址,因为地址最小单位为字节。

struct data

{

        unsigned a : 1;  // 1就是一个bit,范围:0~1,超出表示范围时,自动截取低位

        unsigned b : 2;  // 2就是er个bit,范围:0~3

        unsigned c : 2; // 2bit

};

例:

#include <stdio.h>

#include <string.h>

//一个字节转换为位

struct ByteToBits{

unsigned int bit0:1; //只占用1位

unsigned int bit1:1; //只占用1位

unsigned int bit2:1; //只占用1位

unsigned int bit3:1; //只占用1位

unsigned int bit4:1; //只占用1位

unsigned int bit5:1; //只占用1位

unsigned int bit6:1; //只占用1位

unsigned int bit7:1; //只占用1位

};

int main()

{

unsigned char data = 0x13; //将1字节转换为8位数据

struct ByteToBits *datap = (struct ByteToBits*)&data; //强制类型转换

printf("%d %d %d %d %d %d %d %d\n",datap->bit7,datap->bit6,datap->bit5,datap->bit4,datap->bit3,datap->bit2,datap->bit1,datap->bit0);

//字段不可取地址,因为地址最小单位为字节。

//ByteToBits a; &a.bit2;不能

printf("struct ByteToBits:%d\n",sizeof(struct ByteToBits));

return 0;

}

#include <stdio.h>

#include <string.h>

//一个字节转换为位

struct sex{

int flage:1; //0--1范围 0表示女 1表示男

};

//位字段优势:在限制数据范围方面

int main()

{

struct sex S;

S.flage =1;

printf("%s\n",S.flage?"男":"女");

S.flage =0;

printf("%s\n",S.flage?"男":"女");

//超出表示范围时,自动截取所需要的低位数据

S.flage =3; //0000 0011

printf("%s\n",S.flage?"男":"女");

S.flage =2; //0000 0010

printf("%s\n",S.flage?"男":"女");

return 0;

}

1.10 结构体数组

结构体数组本质上是一个数组,数组中元素的类型是结构体类型。使用“结构体关键字 结构体类型 变量名[数组长度]”的格式来定义一个结构体数组。例:struct STD x[10];     /* 定义了长度为10的结构体数组x*/

例:

#include <stdio.h>

#include <string.h>

struct sex{

unsigned int sexFlage:1;//性别只有两种 0 1

};

typedef struct{

int ID; //学号

int Age; //年龄

char Name[30]; //名字

struct sex Sex; //性别 //int sex; 但是有可能出现赋值异常 3?男还是女

}STU;

int main()

{

//学生结构体数组

STU stu[100]; //最多存放100学生信息

stu[0].ID =1;

stu[0].Age =18;

strcpy(stu[0].Name,"小明");

stu[0].Sex.sexFlage =1;

printf("%s %d  %d %s\n",stu[0].Name,stu[0].ID,stu[0].Age,stu[0].Sex.sexFlage?"男":"女");

stu[1].ID =2;

stu[1].Age =19;

strcpy(stu[1].Name,"小小");

stu[1].Sex.sexFlage =0;

printf("%s %d  %d %s\n",stu[1].Name,stu[1].ID,stu[1].Age,stu[1].Sex.sexFlage?"男":"女");

return 0;

}

1.11 结构体指针

结构体指针本质上是一个指针,指针的类型是结构体类型。使用“结构体关键字 结构体类型 *变量名”的格式来定义一个结构体指针。例如:struct AAA *x ; /* 定义一个结构体指针x */

例:

#include <stdio.h>

#include <string.h>

struct sex{

unsigned int sexFlage:1;//性别只有两种 0 1

};

typedef struct{

int ID; //学号

int Age; //年龄

char Name[30]; //名字

struct sex Sex; //性别 //int sex; 但是有可能出现赋值异常 3?男还是女

}STU;

int main()

{

//学生结构体数组

STU stu[100]; //最多存放100学生信息

stu[0].ID =1;

stu[0].Age =18;

strcpy(stu[0].Name,"小明");

stu[0].Sex.sexFlage =1;

printf("%s %d  %d %s\n",stu[0].Name,stu[0].ID,stu[0].Age,stu[0].Sex.sexFlage?"男":"女");

//结构体指针

STU  *stup = &stu[0];//stu

printf("%s %d  %d %s\n",stup->Name,stup->ID,stup->Age,stup->Sex.sexFlage?"男":"女");

return 0;

}

    1. 共用体、枚举介绍
      1. 共用体

共用体是一个特殊的结构体,使用关键字“union”来表示一个共用体。共用体中的数据成员共用一个内存空间,成员变量的最新赋值会把之前的数据覆盖掉。共用体变量在存储器中占用的存储空间就是共用体最大成员变量占用的空间,并且是最大成员变量的数据类型所占空间的整数倍。使用“union 共用体类型{成员1,成员2,成员3…. 成员n};”的格式定义一个共用体

#include <stdio.h>

#include <string.h>

//对于共用体 占用一块内存空间

union Mem{

char data;

short data0;

int data1;

float data2;

double data3;

};

int main()

{

printf("%d\n",sizeof(union Mem));

return 0;

}

#include <stdio.h>

#include <string.h>

union shortToTwoByte{

unsigned short ShortData; //短整型

unsigned char  ByteBuff[2]; //字节

};

int main()

{

/***需要将短整型数据分割为2字节数据******/

//原始方法 ---举例:

unsigned short data =0x1234;

unsigned char dataH = data>>8;//高八位

unsigned char dataL = (unsigned char)data;

printf("%x  %x\n",dataH,dataL); //12 34

//现在方法 ---举例:

printf("%d\n",sizeof(union shortToTwoByte));//2

union shortToTwoByte a;

a.ShortData = 0x1234;

printf("%x  %x\n",a.ByteBuff[1],a.ByteBuff[0]); //12  34

return 0;

}

面试会有一个面试题:测量大小端 该设备为大端存储还是小端存储? 

方法:

小端字节序存储:低字节放在低地址处;0x12 34 56

大端字节序存储:低字节放在高地址处;

PC机或者单片机为小端存储

#include <stdio.h>

#include <string.h>

union shortToTwoByte{

unsigned short ShortData; //短整型

unsigned char  ByteBuff[2]; //字节

};

int main()

{

//现在方法 ---举例:

printf("%d\n",sizeof(union shortToTwoByte));//2

union shortToTwoByte a;

a.ShortData = 0x1234;

printf("%p:%x\n",&a.ByteBuff[1],a.ByteBuff[1]);

printf("%p:%x\n",&a.ByteBuff[0],a.ByteBuff[0]);

return 0;

}

共用体用途还有哪些呢?

#include <stdio.h>

#include <string.h>

//提高

typedef struct {

int id;

int functionID;

int data1;

int data2;

int data3;

}Info;

//有利于将整型数据分割为一个个字节

union InfoToByte{

Info  info;

char buff[20];

};

int main()

{

union InfoToByte a;

a.info.id =10;

a.info.functionID = 3;

a.info.data1 =1;

a.info.data2 =2;

a.info.data3 =3;

//单片机设备或者大部分设备都是字节发送  运算符进行转字节

a.buff//

return 0;

}

      1. 共用体类型的数据特点
  1. 同一内存段可以用来存放几种不同类型的成员,但是每次只能存放其中一种,而不能同时存放所有的类型。也就是说在共用体中,只有一个成员起作用,其他成员不起作用
  2. 共用体变量中起作用的成员是最后一次存放的成员。在存入一个新成员后,原有的成员就失去作用
  3. 共用体变量的地址和它的各成员的地址是一样的
  4. 不能对共用体变量名赋值,也不能企图引用变量名来得到一个值。

#include <stdio.h>

#include <string.h>

//提高

typedef struct {

int id;

int functionID;

int data1;

int data2;

int data3;

}Info;

//有利于将整型数据分割为一个个字节

union InfoToByte{

Info  info;

char buff[20];

};

int main()

{

union InfoToByte b;

b =10;                 × 不能这样赋值   不能对共用体变量名赋值,也不能企图引用变量名来得到一个值。

return 0;

}

不能将所有成员进行赋值处理:

#include <stdio.h>

#include <string.h>

union Data{

int data1;

short data2;

float data3;

};

int main()

{

//union Data b={1,2,3.0}; //这种是错误的 C89中直接报错误

union Data b={1};

printf("%d\n",b.data2);

return 0;

}

      1. 枚举

枚举类型实际上是一组整型常量,使用关键字“enum”来表示一个枚举类型。使用“enum 枚举类型名{枚举常量1,枚举常量2,枚举常量3,….,枚举常量n};”的格式定义一个枚举变量。枚举变量默认从0开始,后面一个是前面的成员变量加1。

例:

#include <stdio.h>

#include <string.h>

enum TIMBUFF{TIM0=0,TIM1,TIM2,TIM3,TIM4};

//原来

void oldStart(int num)

{

switch(num)

{

case 0: printf("定时器0\n");break;

case 1: printf("定时器1\n");break;

case 2: printf("定时器2\n");break;

}

}

//代码可读性增强

void newStart(enum TIMBUFF num)

{

switch(num)

{

case TIM0: printf("定时器0\n");break;

case TIM1: printf("定时器1\n");break;

case TIM2: printf("定时器2\n");break;

}

}

int main()

{

oldStart(1); //底层源码才能获知1 2 意思

newStart(TIM1);

return 0;

}

#include <stdio.h>

#include <string.h>

enum TIMBUFF{TIM0=10,TIM1=99,TIM2,TIM3,TIM4};

//原来

void oldStart(int num)

{

switch(num)

{

case 0: printf("定时器0\n");break;

case 1: printf("定时器1\n");break;

case 2: printf("定时器2\n");break;

}

}

//代码可读性增强

void newStart(enum TIMBUFF num)

{

switch(num)

{

case TIM0: printf("定时器0\n");break;

case TIM1: printf("定时器1\n");break;

case TIM2: printf("定时器2\n");break;

}

}

int main()

{

oldStart(1); //底层源码才能获知1 2 意思

newStart(TIM1);

printf("TIM2:%d\n",TIM2);

return 0;

}

    1. 前期知识疑惑

1.函数的栈区、堆区、文本常量区、全局变量区、代码段还是存在疑惑?

栈区:函数内部定义变量(除static变量)、形参

2.为什么用结构体,不用结构体可以吗?还有结构体变量必须全局?

有三个变量xiaoming xiaohua xiaoxiao;描述他们的体重身高年龄名字

原有方式:

Int main()

{

//体重

Int xiaomingW, xiaohuaW,xiaoxiaoW;

//身高

Int xiaomingH, xiaohuaH,xiaoxiaoH;

//年龄

Int xiaomingAge, xiaohuaAge,xiaoxiaoAge;

//名字

Char xiaomingName[30]={0};

Char xiaohuaName[30]={0};

Char xiaoxiaoName[30]={0};

}

Void fun(int a,intb,intc,char*name)//需要几个参数4参数  需要在内存开辟空间 复制4份

{

  

}

原有方式描述一个”对象”代码可读性比较差,传参烦多;效率不高(4份);

现有结构体方式:

Struct stu{

  Int W;

  Int H;

  Int Age;

  Char Name[30];

};

Int main()

{

Struct stu  xiaoming;

Xiaoming.W =100;

Xiaoming.H = 200;

Xiaoming.Age =18;

}

Void fun(Struct stu a)//需要几个参数1参数  需要在内存开辟空间 复制1份  结构体为块操作对齐 会导致结构体变量值复制效率比较高

{

  

}

现有方式描述一个”对象”代码可读性比较高,传参少;效率高(块对齐);

3.结构体对齐;需要思维改变

符合三条标准:

①数据对齐原则---内存按结构体成员的先后顺序排列,当排到该成员时,其前面已开辟的空间字节数必须是该成员类型所占字节数的整数倍,如果不够则补齐,依次向后类推。

②整体空间是占用空间最大的成员类型所占字节数的整数倍;

③系统对齐方式和结构体自身默认对齐方式,俩者取最小的。

Struct stu{char a; char b;};结构体自身默认对齐大小为1字节(最大成员char),系统32位默认为4字节,采用两者最小char1字节;

Struct stu{char a; char b;double c};结构体自身默认对齐大小为8字节,系统位数为32位默认采用4字节,采用4字节 4字节对齐;  把double进行切割为4字节的;

Struct stu{char a[10]; char b; };结构体自身默认对齐大小为1字节,系统位数为32位默认采用4字节,采用1字节 ;

4.共用体用途?

概念:共用体内部所有成员共用一块内存空间,其空间大小为最大成员空间大小;

用途1:节省内存;

2.可以实现类型转换 int 转换为字节

强制类型转换:(unsigned char)0x12345678将4字节数据进行强制转换为8位数据,只截取最低八位数据;

5.指针存放地址问题;

指针:存放的是地址  存放不合理即出现段错误;

线上/线下  本周六 本周天合理安排时间

链表:指针与结构体结构;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

面试僧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值