IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 关于C语言动态内存开辟的小题 -> 正文阅读

[C++知识库]关于C语言动态内存开辟的小题

C语言动态内存开辟

一、内存分配

1.1 内存分区管理
内存分成三部分,栈空间、堆空间和静态区。栈空间较小,速度较快,符合栈先进后出的特点,由系统自动管理空间;堆内存空间较大,由人员手动开辟和释放,返回空间地址给栈区指针变量管理,堆内存符合树形结构;静态区存放全局变量和用static修饰的变量。
1.2 变量在内存的分配
栈区内存:存放局部变量和参数、函数栈帧、函数调用完之后,释放栈帧和函数中的局部变量。如果调用函数过多,开辟栈帧过多,可能出现栈溢出的问题,如错误的递归调用。栈区内存管理由系统自动完成。
堆区内存:堆区空间远大于栈区空间,要使用堆空间,需由人员手动开辟,并在使用完后手动释放内存空间。开辟使用方式为:用malloc、calloc、realloc函数开辟空间并返回空间的起始地址给栈区的指针变量,用栈区的指针变量管理这部分空间,用free函数释放堆空间并将栈区的指针变量置为NULL。
静态区:存放全局变量和static修饰的变量。整个工程可见,全局变量在main函数调用之前就已开辟栈空间。

1.3 动态开辟内存的函数
动态开辟相关函数在头文件<stdlib.h>中。
mallocvoid * malloc(size_t sz); malloc函数接收一个无符号整型数值作为开辟堆空间的大小,单位为字节,返回空间的起始地址,当栈区的指针变量接收时要做指针类型转换。
如:int * p = (int *)malloc(40);//开辟40个字节大小的堆空间,起始地址赋值给指针变量p。
calloc:void * calloc(size_t num, size_t sz); calloc函数接收两个参数,第一个表示元素个数,第二个表示元素所含字节数,也就是说calloc函数开辟的空间大小为(num * sz)个字节。与malloc不同的是,calloc开辟的空间初始值都赋值为0,其他与malloc无异。
realloc:void * realloc(void * addr, size_t newsz); realloc函数用于自动扩容,重新分配内存。参数addr是原来开辟的旧地址,newsz是要开辟的新空间的大小。注意realloc返回值有两种情况,第一种是扩容空间足够,在原来旧地址的基础上在后面加上新空间,此时返回值还是原来的旧地址。当扩容的空间不够时,会重新开辟一块空间,并将原来空间内的内容拷贝到新空间,返回新空间的地址,原来的空间释放,如下图描述。
在这里插入图片描述
free():释放指针变量指向的堆内存空间,与开辟空间函数配合使用。

二、结合题目分析

1.1 题目描述
代码如下所示,分析出现的结果。

void getMemory(char * p)
{
	p = (char *)malloc(100);
}

void test(void)
{
	char * str = NULL;
	getMemory(str);
	strcpy(str, "hello world!");
	printf("%s\n", str);
}

int main()
{
	test();
	return 0;
}

1.2 题目分析
首先在main中调用test函数:
(1)在栈中创建一个指针变量str,设置为NULL,test中调用getMemory(),将str的值传递给形参p,p=NULL。
在这里插入图片描述
(2)在getMemory函数中,开辟100个字节的堆内存,并把起始地址赋给p。此时p中存的便是堆内存空间的地址。
在这里插入图片描述
(3)当getMemory函数调用完毕,栈帧释放,局部变量p被回收,而此时test中的str还是NULL,没有指向任何空间,堆空间中开辟的100个字节便成了脱缰野马,无法管理,发生内存泄漏。
在这里插入图片描述

1.3 题目改错
既然是因为失去缰绳,无法控制,那就设法将缰绳再次掌握起来,p是一个临时变量,函数调用完就释放,那么就设法让test内的str也能掌控开辟的空间。要改变str的值,那么可以传递str的地址给getMemory,有了地址,就可以改变str里面的内容。使用二级指针。

void getMemory(char ** p)
{
	*p = (char *)malloc(100);
}

void test(void)
{
	char * str = NULL;
	char ** pstr = &str;
	getMemory(pstr);
	strcpy(str, "hello world!");
	printf("%s\n", str);
	free(str);
	str = NULL;
}

int main()
{
	test();
	return 0;
}

(1)将str这个指针变量的地址传递给p,pstr内是str的地址。
char ** p = pstr;
在这里插入图片描述
(2)*p = (char *)malloc(100);
// 等价于 str=(char *)malloc(100);
将str的内容赋值为开辟的堆空间的地址。这样,当getMemory调用完毕,释放空间之后,str中的地址指向开辟的空间,这样野马就相当于有了缰绳,便不再是野马,可以管理。
在这里插入图片描述
(3)当使用完之后,要及时使用free释放空间,并置str=NULL;
free(str);
str = NULL;
(4)test函数调用完释放栈帧,main结束释放栈帧。
在这里插入图片描述

三、题目总结

  1. 题目中错误的方式是将指针变量的值传递给另一个函数的参数,参数改变只会发生在调用的函数内,原函数的变量值不发生改变,所以应该用地址传递,这样调用函数就可以改变原函数内指针变量str的值。
  2. 内存主要分为栈内存、堆内存以及静态区(自己的理解)。
    栈内存有用于分配局部变量空间和函数栈帧,参数压栈等功能。并且由cpu自动管理回收空间,无需人员手动释放,栈内存空间较小,速度较快,符合栈先进后出的特点;
    堆内存是需人员手动开辟的内存空间,空间比栈区大很多,用于开辟存储较大的对象,并返回开辟空间的引用(地址)给栈区的指针变量管理。用于开辟堆内存空间的常用函数有malloc、calloc、realloc、free四个,开辟空间并使用完之后一定要free()释放堆空间,并置栈区的引用指针为NULL,防止非法访问内存(在Java、Python中有垃圾回收机制自动回收闲置的堆空间);
    静态区存放全局变量和用static修饰的变量,全局变量在main函数之前就已经开辟空间存储。
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-15 11:29:21  更:2022-05-15 11:29:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:01:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码