内存管理
memset,memcpy,memcmp函数
//memset,memcpy,memcmp
#include <stdio.h>
/*****************************
#include <string.h>
void *memset(void *s, int c, size_t n); //通常情况用处清0
功能:将s的内存区域的前n个字节以参数c填入
参数:
s:需要操作内存s的首地址
c:填充的字符,c虽然参数为int,但必须是unsigned char , 范围为0~255
n:指定需要设置的大小
返回值:s的首地址
* ****************************/
#include <string.h>
#if 0 //memset
int main()
{
char num[10];
short num_int[10]; //int = 4字节
memset(num_int,0,sizeof(num_int));
memset(num,1,10); //-128 - 127
for(int i = 0; i < 10; i++)
{
printf("%d\n",num_int[i]);
}
return 0;
}
#endif
/**********************************
#include <string.h>
void *memcpy(void *dest, const void *src, size_t n);
功能:拷贝src所指的内存内容的前n个字节到dest所值的内存地址上。
参数:
dest:目的内存首地址
src:源内存首地址,注意:dest和src所指的内存空间不可重叠,可能会导致程序报错
n:需要拷贝的字节数
返回值:dest的首地址
* ****************************/
#if 0
int main()
{
int num_char1[10] = {1,2,3,4,5,6,7};
int num_char2[10];
memcpy(num_char2,num_char1,40);
for(int i = 0; i < 10; i++)
{
printf("%d\n",num_char2[i]);
}
return 0;
}
#endif
/**********************************
#include <string.h>
int memcmp(const void *s1, const void *s2, size_t n);
功能:比较s1和s2所指向内存区域的前n个字节
参数:
s1:内存首地址1
s2:内存首地址2
n:需比较的前n个字节
返回值:
相等:=0
大于:>0
小于:<0
* ****************************/
int main()
{
int num_char1[10] = {1,2,3,4,5,6,7};
int num_char2[10] = {1,2,3,3,5,6,7};
//memcpy(num_char2,num_char1,40);
if(memcmp(num_char1,num_char2,12) == 0)
{
printf("相等\n");
}
else
{
printf("不相等\n");
}
printf("%x\t%x\n",num_char1[3],num_char2[3]);
return 0;
}
万能指针
#include <stdio.h>
int main()
{
//说一下,万能指针 *void
//知道我非 *void 类型的指针都是只能只想自己类型的数值内存单元的
//而且非 *void 类型的指针的步长都是有大小的
int num_int = 10;
char num_char = 'A';
double num_double = 10.2f;
int *ptr_int = &num_int;
void *ptr_void = &num_int; //结果:*void万能指针可以指向 *int
ptr_void = &num_char; //结果:*void万能指针可以指向 *char
ptr_void = &num_double; //结果:*void万能指针可以指向 *duble
//1.通过上面三种结果可以推出,*void 万能指针可以指向任何类型的指针和地址
printf("ptr_void = %p\n",ptr_void);
ptr_void++; //最终体现是一个字节,其实步长为0,不建议万能指针做四则运算
printf("ptr_void = %p\n",ptr_void);
printf("sizeof(void *) = %ld\n",sizeof(ptr_void));
//最终结论:*void 经常用于传送地址
//char *ptr_char = #
}
动态内存分配
malloc函数与free 函数
#include <stdio.h>
//动态内存分配:分配堆空间的数据,由于栈空间大小有限,而堆空间内存远远大于栈空间
//一般情况:栈空间只分配:1M 堆空间分配:4G
//所以数据他大情况下使用对空间,那么接下来学习对空间的动态内存申请以及释放
//申请使用:malloc函数
/******************************************************
* 头文件:#include <stdlib.h>
* 函数名:void *malloc(size_t size);
* 功能:申请对空间的内存,申请的空间没有被初始化
* 参数:size:以字节为单位申请size字节个空间
* 返回值:万能指针类型,
* 成功:返回申请到的空间首地址
* 失败:返回NULL
* **************************************************/
//释放使用:free函数
/******************************************************
* 头文件:#include <stdlib.h>
* 函数名:void free(void *ptr);
* 功能:释放前面malloc申请的堆空间
* 参数:ptr:释放前面maloc申请的空间首地址ptr开始的直到出现断层
* 返回值:无
* **************************************************/
#include <stdlib.h>
#include <string.h>
int main()
{
//想申请10连续int类型的空间 }
int *p = malloc(sizeof(int) * 10);
//由于申请的堆空间没有被初始化所以需要手动初始化
memset(p,0,sizeof(int) * 10);
for(int i = 0 ; i < 10; i++)
{
printf("%d,",p[i]);
}
printf("\n");
free(p); //释放前面申请的空间
return 0;
}
误区解决:
虽然free释放了在堆中的内存,但是之前传给指针的地址还在指针中,指针中存储的还是上一次内存的地址;
宏替换与typedef
#include <stdio.h>
#define my_int int //单纯在预处理阶段做宏替换
typedef int mmy_int; //取别名
int main()
{
//size_t
my_int num = 10;
mmy_int num_typdef = 20;
printf("my_int num = %d\n",num);
printf("mmy_int num_typdef = %d\n",num_typdef);
return 0;
}
结构体
#include <stdio.h>
//在前面我们学习了,C语言系统内置类型,char,short,int,long,flaot,double,void
//接下来,C语言提供了三个用户可以定义类型的方法:结构体,公用体,枚举
//结构体:使用的关键字struct,何为结构体,属于自己的结构体,但是这个结构体是有用户定义的
//那么他在内存中是如何分配的呢?答:在内存中是连续的一片空间,根据不同用户定义的类型做内处理
//定义方法:
/******************
struct 结构体名字
{
数据类型1
数据类型2
.....
};
* **************/
*
/**************** 定义结构体时顺便定义变量
struct 结构体名字
{
数据类型1
数据类型2
.....
}变量名1,变量名2,...;
* ************/
/**************** 定义结构体时取别名,但是做了区别名就不能定义变量
typedef struct 结构体名字
{
数据类型1
数据类型2
.....
}别名1,别名2,...;
* ************/
typedef struct Box
{
int m_height; //盒子的高
int m_wight; //盒子的宽
long xxx;
}Box_t; //box是struct Box的变量
#include <string.h>
#include <stdlib.h>
int main()
{
//1.定义结构体方法 struct 结构体名字 变量名;
//struct Box box;
//结构体变量初始化与数组差不多
//1: Box_t box = {8,10}; //按照顺序初始化
Box_t box = {.m_wight = 20,.m_height = 50};
Box_t *box_ptr = NULL; //只分配了指针变量的空,并没有分配结构体变量的空间
box_ptr = (Box_t *)malloc(sizeof(Box_t));
if(box_ptr == NULL)
{
printf("box_ptr指向的空间申请失败\n");
return -1;
}
printf("sizeof(box_ptr) = %ld\n",sizeof(box_ptr));
printf("sizeof(box) = %ld\n",sizeof(box));
printf("sizeof(struct Box) = %ld\n",sizeof(struct Box));
//通过类型占用字节数可以看出,结构体占用字节是结构体内部成员数据的大小总和
//对已不同类型使用方法:1.普通变量类型 2.指针变量类型
//1.普通变量类型可以通过 . 操作符号去指向内部成员
printf("盒子的高:%d\t盒子的宽:%d\n",box.m_height,box.m_wight);
//2.指针变量类型可以通过 -> 操作符号去指向内部成员
box_ptr->m_height = 800;
box_ptr->m_wight = 700;
printf("盒子的高:%d\t盒子的宽:%d\n",box_ptr->m_height,box_ptr->m_wight);
}
个人误区解决:
结构体是一种数据类型,存放在栈中。
结构体的位域
#include <stdio.h>
struct Box //位域,把数据类型中所占的bit位给分割,:之后只占几个位
{
char LED1:1;
char LED2:1;
char LED3:1;
char LED4:1;
char LED5:1;
char LED6:1;
char LED7:1;
char LED8:1;
//由于以前单片机资源有限,所以使用位域方法
};
int main()
{
struct Box box;
printf("sizeof(struct Box) = %ld\n",sizeof(struct Box));
printf("sizeof(box) = %ld\n",sizeof(box));
box.LED5 = 1;
box.LED5 = 0;
//sizeof最小单位字节,并不是位
//printf("sizeof(box.LED5) = %d\n",sizeof(box.LED5));
return 0;
}
结构体中装其他结构体
#include <stdio.h>
typedef struct Sofa
{
int m_height;
int m_wight;
}Sofa_t;
typedef struct Bed
{
int m_height;
int m_wight;
}Bed_t;
typedef struct Home
{
Sofa_t sofa;
Bed_t bed;
}Home_t;
#include <string.h>
#include <stdlib.h>
int main()
{
Home_t home;
memset(&home,0,sizeof(Home_t));
printf("home is size = %ld\n",sizeof(Home_t));
home.sofa.m_height = 10;
home.sofa.m_wight = 20;
home.bed.m_height = 50;
home.bed.m_wight = 20;
#if 0
int *p = (int *)&home;
for(int i = 0 ; i < 4;i++)
{
printf("%d\t",p[i]);
}
printf("\n");
#endif
printf("home.sofa.m_height = %d\n",home.sofa.m_height);
printf("home.sofa.m_wight = %d\n",home.sofa.m_wight);
printf("home.bed.m_height = %d\n",home.bed.m_height);
printf("home.bed.m_wight = %d\n",home.bed.m_wight);
return 0;
}
指针的自我嵌套
#include <stdio.h>
typedef struct Box //定义结构体,不会分配空间
{
int m_height;
int m_wight;
struct Box *box; //原因指针分配的是指针类型,并不是普通变量类型,指针之分配8字节
}Box_t;
#include <stdlib.h>
int main()
{
Box_t box;
box.m_height = 100;
box.m_wight = 100;
//box.box = NULL;
printf("box.box = %p\n",box.box->box);
free(box.box);
return 0;
}
共用体
#include <stdio.h>
//公用体定义方式与结构体相似,使用union关键字
typedef struct Rfid
{
char secret_keyA[4];//密钥A
char secret_keyB[4];//密钥B
char date_block1[10];//数据块1
//....
char date_block32[10];//数据块32
}Rfid_t;
typedef struct Wifi
{
char m_user[20];//名称
char m_pass[4];//密钥B
char date_stack[10];//协议栈
//....
}Wifi_t;
union Init_hardware
{
/* data */
Rfid_t rfid;
Wifi_t wifi;
};
#include <string.h>
int main()
{
union Init_hardware init_hardware;
//初始化RFid
init_hardware.rfid.date_block1[0] = 'A';
init_hardware.rfid.date_block1[1] = 'B';
init_hardware.rfid.date_block1[2] = 'A';
//调用Rfid初始化函数init_hardware.rfid
//初始化Wifi
strcpy(init_hardware.wifi.m_user,"张三");
strcpy(init_hardware.wifi.m_pass,"张三");
//调用Wifi初始化函数init_hardware.wifi
return 0;
}
#if 0
union Box //
{
int m_height1;
int m_wight1;
int m_wight2;
int m_wight3;
int m_wight4;
int m_wight5;
int m_wight6;
long m_xxxx;
};
//公用体所有成员占用同一片空间,结构体大小以最大成员占用空间判决
//公用体:经常使用的地方,
int main()
{
union Box box;
printf("sizeof(union Box) = %ld\n",sizeof(union Box));
printf("sizeof(box) = %ld\n",sizeof(box));
box.m_height1 = 5;
box.m_wight6 = 10;
printf("box.m_height1 = %d\n",box.m_height1);
}
#endif
枚举
#include <stdio.h>
//三大自定义类型:枚举,定义方式与结构体相似,但是内部的成员为整型常量,且使用逗号结算
//经常使用的地方:用于函数的参和函数的返回值
//参数:例如,单片机LED:状体开和关,0|1,我们传入其他的就直接不执行
//返回值:返回值,程序以及机器的运行状态
//定义方式
enum error_code
{
normal = 0x00, //程序正常
one = 0x51, //函数错误
two = 0x12, //系统找不到指定文件
three = 0x33, //系统找不到指定路径
};
typedef enum error_code error_code_t;
error_code_t function(int num);
int main()
{
switch(function(3))
{
case normal:
printf("程序正常\n");
break;
case one:
printf("函数错误\n");
break;
case two:
printf("系统找不到指定文件\n");
break;
case three:
printf("系统找不到指定路径\n");
break;
}
return 0;
}
error_code_t function(int num)
{
switch(num)
{
case 1:
return one;
case 2:
return two;
case 3:
return three;
}
return normal; //程序正常
}