C语言学习(八)typedef 虚拟内存 malloc/free

2024-05-12 13:36

本文主要是介绍C语言学习(八)typedef 虚拟内存 malloc/free,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 一、typedef 类型重定义
    • (一)使用
    • (二)define和typedef的区别
      • 1. 编译处理的阶段不同
      • 2. 功能不同
  • 二、虚拟内存
    • (一)虚拟内存分布
    • (二)内存分布
      • 1. 静态分配
      • 2. 动态分配
  • 三、malloc/free函数
    • (一) malloc函数
        • (1)定义
        • (2)使用
    • (二) free函数
    • (三) 使用
  • 四、内存泄漏
    • (一)概念
    • (二) 规避方法
    • (三)示例

一、typedef 类型重定义

(一)使用

typedef <数据类型> <标识符>

typedef int int32_t; typedef int arr_t[2][3];//两行三列的二维数组类型typedef int(*fun_t)(int,int); //定义int(*)(int,int)类型

(二)define和typedef的区别

1. 编译处理的阶段不同

define在预处理阶段,typedef参与编译阶段

  • 注:编译的过程:
  • 预处理:展开头文件,删除注释,宏替换
    gcc - E hello.c -o hello.i
    hello.i 就是预处理文件。预处理不会检查语法错误。
  • 编译:语法统计,词法统计,语义分析
    gcc -S hello.i -o hello.s
    生成一个汇编文件。编译会检查语法错误
  • 汇编
    gcc -c hello.s -o hello.o
    生成一个二进制文件。
  • 链接:链接库文件,生成一个可执行的二进制文件
    gcc hello.o -o hello

2. 功能不同

define是字符串原样替换;typedef是用于类型重定义

二、虚拟内存

(一)虚拟内存分布

图片1

  • 内核空间:(0xcccc cccc~0xffff ffff)程序共用,不允许用户使用
  • 栈区:空间自动申请,自动释放;向下生长
    主要存放局部变量,未初始化时是乱值。
    (栈区空间,windows是2M,可以调至10M;在Linux中是8M)
  • 堆区:手动申请,手动释放;向上生长
    malloc / realloc / calloc
    (堆区空间,大概1.9G)
  • 常量区
    .bss段:未初始化的全局变量
    .data段 :初始化的全局变量
    .readonly段:只读段
    .text段 (代码区):程序代码

mmu固件:将虚拟内存映射到物理内存中。

eg:分析以下数据存放在内存中的位置:number1 , number2, number3, number4, p1, p2 ,p3 *p1,*p3, function, *p2

include <stdio.h>int number1;  
未初始化的全局变量:常量区-->.bss段
int number2 = 10;   
初始化的全局变量:常量区-->.data段
字面量值10存储在常量区。int function() 代码:常量区-->代码区
{int number3 = 30;  初始化的局部变量:栈区int number4;  未初始化的局部变量:栈区
}
int main() 代码:常量区-->代码区
{char * p1 = "hello world";  p1 局部变量:栈区*p1:常量区-->readonly段char p2[]= "abc"  p2 局部变量:栈区*p2:栈区char *p3 = (char *)malloc(20);   p3 局部变量:栈区; p3指向的内存空间 堆区free(p3);p3 = NULL;
}
  • 注:当程序加载到内存中时,number2的内存空间(在.data段)会被分配,
    并且其值会被初始化为10(这个值来源于常量区,但在运行时它是存储在.data段中的)。

(二)内存分布

C语言分配内存的方法:静态分配 动态分配

1. 静态分配

在编译节点的时候,已经确定了分配空间大小。
eg:int a=10; intarr[2][2];

2. 动态分配

编写程序时,不确定要申请多少空间,在执行时根据需要进行的空间分配。
eg:malloc分配的空间就属于动态分配。

三、malloc/free函数

(一) malloc函数

(1)定义
头文件(标准库文件):
#include <stdlib.h>函数原型:
void *malloc(size_t size);函数功能:在内存中(堆)区中开辟指定大小的地址连续的空间。函数参数:size_t  无符号整型,size表示开辟多少字节空间。函数返回值:成功,返回开辟空间的首地址;失败,返回一个NULL
(2)使用

申请空间为一段连续的空间:
① 可以使用下标进行访问
②可以通过指针进行访问

(二) free函数

头文件(标准库文件):
#include <stdlib.h>函数原型:
void free(void *ptr);函数功能:释放手动申请的空间。函数参数:void* ptr: malloc/realloc/calloc申请的空间的首地址
  • 注:释放已经释放过的指针会造成程序错误。
  • 但是指针指向NULL时,释放多次都不会报错。

(三) 使用

#include <stdio.h>
#include <stdlib.h>int main()
{//申请空间int *p =mymalloc(20);if(!p){printf("create fail!\n");return -1;}//向空间内写值*p = 10;*(++p)= 20;//读值for (int i=0;i<20;i++){printf("%d ",*(p+i));}//释放空间free(p);p = NULL;/*释放完空间后,将指针指向NULL/指向NULL后,再次释放不会报错*/
}int mymalloc(int size)
{int *p = (int *)malloc(size);if(!p){printf("fail!\n");return -1;}else{prnintf("sucess:%p\n",p);}return 0;
}

eg
功能需求
定义一个函数: create 功能: 在内存中申请n个字节大小. n是一个参数.
这个函数的返回值是指针类型.
set(指针)函数 功能: 从键盘中输入n个值, 将N个值存入 create创建的空间中.
sort函数():使用冒泡排序对这n个值进行排序.
max函数(): 返回空间中的最大值
min函数(): 返回空间中的最小值.、

代码实现

#include <stdio.h>
#include <stdlib.h>int min(int *arr,int len);
int max(int *arr,int len);
void sort(int *arr,int len);
void set(int *a,int n);
int* create(int size);
void show(int *arr,int size);
void create_noReturn(int **p,int size);//使用二级指针传参int main()
{int size;//申请空间printf("please input size:");scanf("%d",&size);/*** * int *p = NULL;* create_noReturn(&p,size);***/int *p = create(size);//20个字节,5个int//判断p空间是否申请成功if(p!){printf("create fail!!");return -1;}//向空间内写值set(p,size);//排序,读值sort(p,size);show(p,size);printf("MAX:%d\n",max(p,size));printf("MIN:%d\n",min(p,size));//释放空间free(p);p = NULL;
}
void show(int *p,int size)
{for(int i=0;i<5;i++){printf("%d ",*(p+i));}putchar(10);
}
//申请n字节大小,返回值是申请空间的指针
int* create(int size)
{int *p = (int *)malloc(4*size);if(!p){printf("fail!\n");return NULL;}return p;
}
//无返回值的空间分配
void create_noReturn(int **p,int size)
{int s=4*size;*p =(int*)malloc(s);}   void set(int *a,int n)
{for(int i=0;i<n;i++){printf("please input %d num:",i+1);scanf("%d",a+i);                                                                                                                                                                                                                                                                                                       }
}//排序
void sort(int *arr,int len)
{int flag = 0;for(int i=0;i<len-1;i++){flag = 0;for(int j=0;j<len-i-1;j++){if(*(arr+j)>*(arr+j+1)){int temp=*(arr+j);*(arr+j)=*(arr+j+1);*(arr+j+1)=temp;flag=1;}}if(!flag) break;}
}//最大值
int max(int *arr,int len)
{int max = *arr;for(int i=0;i<len;i++){if(max<(*(arr+i)))max = *(arr+i);}return max;
}//最小值
int min(int *arr,int len)
{int min = *arr;for(int i=0;i<len;i++){if(min>(*(arr+i)))min = *(arr+i);}return min;
}

四、内存泄漏

(一)概念

在C语言中调用malloc/calloc/realloc函数时,申请内存后没有调用free函数进行释放内存,导致内存越用越少。

(二) 规避方法

当空间使用完毕后,及时释放内存。

(三)示例

int main()
{int * p =malloc(20);p = malloc(20);free(p);return 0;
}

此时p指向第二次申请的内存空间,没有指针指向第一次申请的内存空间。

这篇关于C语言学习(八)typedef 虚拟内存 malloc/free的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/982775

相关文章

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

Go语言使用Gin处理路由参数和查询参数

《Go语言使用Gin处理路由参数和查询参数》在WebAPI开发中,处理路由参数(PathParameter)和查询参数(QueryParameter)是非常常见的需求,下面我们就来看看Go语言... 目录一、路由参数 vs 查询参数二、Gin 获取路由参数和查询参数三、示例代码四、运行与测试1. 测试编程路

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

Go语言使用net/http构建一个RESTful API的示例代码

《Go语言使用net/http构建一个RESTfulAPI的示例代码》Go的标准库net/http提供了构建Web服务所需的强大功能,虽然众多第三方框架(如Gin、Echo)已经封装了很多功能,但... 目录引言一、什么是 RESTful API?二、实战目标:用户信息管理 API三、代码实现1. 用户数据

Go语言网络故障诊断与调试技巧

《Go语言网络故障诊断与调试技巧》在分布式系统和微服务架构的浪潮中,网络编程成为系统性能和可靠性的核心支柱,从高并发的API服务到实时通信应用,网络的稳定性直接影响用户体验,本文面向熟悉Go基本语法和... 目录1. 引言2. Go 语言网络编程的优势与特色2.1 简洁高效的标准库2.2 强大的并发模型2.

Go语言使用sync.Mutex实现资源加锁

《Go语言使用sync.Mutex实现资源加锁》数据共享是一把双刃剑,Go语言为我们提供了sync.Mutex,一种最基础也是最常用的加锁方式,用于保证在任意时刻只有一个goroutine能访问共享... 目录一、什么是 Mutex二、为什么需要加锁三、实战案例:并发安全的计数器1. 未加锁示例(存在竞态)

C语言自定义类型之联合和枚举解读

《C语言自定义类型之联合和枚举解读》联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率... 目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.2.1 特点11.2.2 特点21.2.3 特点31.3 联合体的大小1