内存管理 万能指针 宏替换与typedef 结构体 共用体

本文探讨了C语言中的内存管理,包括memset, memcpy, memcmp等函数的使用,以及动态内存分配的重点——malloc和free函数。同时,文章介绍了万能指针的概念,并详细讲解了结构体的使用,如位域、嵌套结构体和指针自我嵌套。此外,还讨论了共用体和枚举等数据类型。" 104004354,9190291,matplotlib数据可视化详解:从Numpy到复杂图表,"['数据科学', '可视化', 'Python', 'numpy', 'matplotlib']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内存管理

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 = &num;
}

动态内存分配

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;  //程序正常
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值