C语言期末知识点复习6

结构体

1、基本定义

​ 注:①结构体不可以自引用!但可以在结构体内定义该结构体类型的指针!

 

​ ②定义结构体本质是新增一种类型;

 

​ ③结构体传参要传结构体地址(指针),以此提高效率。

 

struct node1{

 int a;

 int b;

};

 

typedef struct node2 {

 int c;

 int d;

}node2;//通过typedef为结构体变量定义一个别名node2,在以后使用中可以使用别名以此提高编写效率

 

int main(){

 struct node1 s;//用结构体定义变量

 node2 q;//用别名定义变量

}

​ **注:**结构体不可以自引用!但可以在结构体内定义该结构体类型的指针!

 

struct Node

{

 int data;

 struct Node next;

};//错误

 

struct Node

{

 int data;

 struct Node* next;

};//正确

 

typedef struct Node

{

 int data;

 struct Node* next;

}Node;//正确

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

struct Point1

{

 int x;

 int y;

}p1; //声明类型的同时定义变量p1

struct Point p2; //定义结构体变量p2

 

typedef struct Point2

{

 int x;

 int y;

}p;

p p1;

p p2;

在定义结构体变量时,可以在初始化的部分定义其内容,也可以在之后定义。

 

typedef struct Point2

{

 int x;

 int y;

}p;

p p1;

p1.x=1;

p1.y=2;//可以直接用结构体类型的变量进行定义

 

typedef struct Point2

{

 int x;

 int y;

}p;

p* p2=(p*)malloc(sizeof(p));

p2->x=1;

p2->y=2;//定义一个指向结构体的指针并为其分配空间即可进行定义

3、结构体的内存对齐(结构体的占用大小的计算)

结构体内存空间占用的大小并不是单纯的元素相加,而是通过浪费一定量的空间来换取目标数据读取速度的加快

 

计算方式:

 

① 第一个成员在与结构体变量偏移量为0的地址处。

 

② 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

 

​ (起始偏移量要能整除该成员的对齐数)

 

对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。

​ VS中默认的值为8

 

③ 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

 

④ 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处(即结构体大小),结构体的整

 

体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

 

样例:

 

struct S1

{

    char a;

    int b;

    char C;

};

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

1

2

3

4

5

6

7

char 为1个字节, int 为4个字节;

char a 从0偏移开始,占用一个字节;偏移量为1,接下来存放 int b,偏移量1不是对齐数4 的整数倍,所以向后继续偏移一直到4,4是对齐数4的整数倍,所以将int b存放在偏移地址为4处,占用4个字节;偏移量变为8,存放 char c ,占一个字节,偏移量9不是最大对齐数4的整数倍,所以向后继续偏移直到偏移处为12的地方。

7f038dd1973a4340aef833632819e725.png

 自主设置默认对齐数

 

#pragma pack(a)//通过该指令可设置默认对齐数为a

1

位断

位段的声明和结构是类似的,有两个不同:

1.位段的成员必须是 int、unsigned int 、signed int或者char(同属于整型家族);

2.位段的成员名后边有一个冒号和一个数字。

 

struct A

{

int _a:2;

int _b:5;

int _c:10;

int _d:30;

};

注: ① 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型;

 

② 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的;

 

③ 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段;

 

④位断不需要考虑内存对齐问题所以较为节省空间。

 

总而言之, 跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。

 

枚举

即一一列举

 

enum Day//星期

{

 Mon,

 Tues,

 Wed,

 Thur,

 Fri,

 Sat,

 Sun //最后一个不加逗号

};

enum Sex//性别

{

 MALE,

 FEMALE,

 SECRET

};

与宏定义相比枚举的优点:

① 增加代码的可读性和可维护性;

② 和#define定义的标识符比较枚举有类型检查,更加严谨;

③ 防止了命名污染(封装);

④ 便于调试;

⑤ 使用方便,一次可以定义多个常量 。

 

联合体

联合也是一种特殊的自定义类型

这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体), 联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

 

//联合类型的声明

union Un

{

 char c;

 int i;

};

//联合变量的定义

union Un un;

注:联合体需要考虑内存对齐,要求为最大内存数的整数倍。

动态内存管理

​ 程序开始运行后在堆上开辟大量空间(数组之类的空间开辟在栈上进行),而在堆上开辟的空间使用完毕后需要在使用完成后由free函数进行释放,然后令指向该空间的指针指空,如果只申请不释放会造成内存泄漏问题。

 

动态申请空间主要涉及三个函数:malloc函数,calloc函数,relloc函数。

 

void* malloc (size_t size);

1

​ 只申请空间,不对空间进行初始化,传入的参数size为要开辟的空间大小;

 

void* calloc (size_t num, size_t size);

1

​ 申请空间,与malloc唯一的不同之处在于calloc会初始化为0,传入的参数size为单个空间的大小,参数a为所需要的单个空间的数量;

 

void* realloc (void* ptr, size_t size);

1

将分配size个大小的空间,然后在调整原内存空间大小的基础上,将原来内存中的数据移动到新的空间,返回值为调整之后的内存起始位置。

 

由于realloc可能会申请失败返回NULL所以不建议直接用原指针接收返回地址,正确使用方法为:

 

int* ptr = (int*)malloc(100);

int* p = NULL;

p = realloc(ptr, 1000);

if (p = !NULL) {

 ptr = p;

}

内存释放操作

 

int* p=(int*)malloc(100);

......

free(p);

p = NULL;

 

柔性数组

1、定义

​ 在结构体内大小为0(a[0])或空(a[])的数组(必须为结构体内最后一个元素且不能是唯一元素)

 

这样可以在结构体内具有一个变长数组包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配

 

的内存应该大于结构的大小,以适应柔性数组的预期大小 ,sizeof 返回的这种结构大小不包括柔性数组的内存 。

 

2、使用方法

typedef struct st_type

{

 int i;

 int a[0];//柔性数组成员

}type_a;

printf("%d\n", sizeof(type_a));//输出的是4

//初始化

type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));

p->i = 100;

for(i=0; i<100; i++)

{

 p->a[i] = i;

}

free(p);

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值