【深度解刨C语言】内存管理(详)


前言

前提:

  • 内存有基本的认识
  • 内存函数基本的了解

如果你对内存与内存函数太不清楚可以看:动态内存管理

目标:

  • 为什么要用动态内存?
  • 内存的布局
  • free只有一个参数,怎么将内存函数在堆上开辟的空间进行释放?

一.动态内存

1.动态内存的用处

int main()
{
	char arr[1024*1024]={0};
	return 0;
}

结果:
代码异常退出
在这里插入图片描述
当我们在栈上开辟1MB的大小的空间时超出了堆栈的大小

注意:
堆栈==栈
堆栈!=堆
本文的堆是程序的空间,而在数据结构中,堆是一种完全二叉树的非线性结构!

结论:

  • 栈的空间很小,大约为1MB。
  • 堆的空间很大,大约为2GB
  • 因此:动态内存,是为了满足更大数据的需求!
  • 为什么要用动态内存?

2.内存的布局

在这里插入图片描述

  • 这里的储存空间并不是内存!而是进程虚拟地址空间
  • 补充:具体涉及到操作系统的知识,只需了解即可!
简单证明内存布局
#include<stdio.h>
#include <stdlib.h>
int add()
{
  return 0;
}
int g_val;//初始化的全局变量
int g_val_1 = 0;//未初始化的全局变量
int main()
{

	int a = 0;//栈区的变量
	int* arr = (int*)malloc(sizeof(int) * 20);//将堆区的地址赋值给arr
	char* str = "abcdef";//将字符常量区的地址赋值跟str
	
	printf("字符常量区:            %p\n", str);
	printf("初始化的全局变的内存:  %p\n", &g_val_1);
	printf("未初始化全局变量的内存:%p\n", &g_val);
	printf("堆区:                  %p\n", arr);
	printf("栈区:                  %p\n", &a);

	free(arr);
	arr = NULL;
	return 0;
}
  1. 方法:假设法证明
  2. 结论成立:从字符常量区的变量的地址到栈区的地址呈现增大趋势

结果:
在这里插入图片描述
在这里插入图片描述

  • 总结:
  • 1.VS2019做了优化,我们看不到实际的内存地址。
  • 2.Linux下很显然栈的地址远远大于堆的地址。
    结论:假设成立,结论成立!
栈向下生长的证明

同理

  • 只需证明: 不断开辟变量,地址呈现减小的趋势
#include<stdio.h>

int main()
{
	
	int a = 0;
	int b = 0;
	int c = 0;
	int d = 0;
	printf("a:%p\n", &a);
	printf("b:%p\n", &b);
	printf("c:%p\n", &c);
	printf("d:%p\n", &d);

	return 0;
}

结果:
在这里插入图片描述
结论:假设成立,结论成立!

堆向上增长的证明

同理

  • 只需证明: 不断开辟变量,地址呈现增大的趋势
  • 注意:这里开辟的空间要尽可能大
#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* a = (int*)malloc(sizeof(int) * 1024);
	int* b = (int*)malloc(sizeof(int) * 1024);
	int* c = (int*)malloc(sizeof(int) * 1024);
	int* d = (int*)malloc(sizeof(int) * 1024);

	printf("%p\n", a);
	printf("%p\n", b);
	printf("%p\n", c);
	printf("%p\n", d);

	free(a);
	free(b);
	free(c);
	free(d);

	a = NULL;
	b = NULL;
	c = NULL;
	d = NULL;

	return 0;
}

结果:
在这里插入图片描述
结论:假设成立,结论成立!

3.malloc与free进一步理解

疑问产生:

  • free只有一个参数怎么准确的释放目标空间
  • malloc只开辟了我们想要的空间吗?

为了解决这两个问题,那我们调试走起!

调试代码:

#include<stdio.h>
#include<stdlib.h>
int main()
{

	char* arr = (char*)malloc(sizeof(char) * 10);
	if (arr == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		arr[i] = i;
	}
	free(arr);
	arr = NULL;
	return 0;
}

VS2019下调试
第一步:打开内存窗口
在这里插入图片描述
第二步:F9打断点
在这里插入图片描述
第三步:按F5走到断点处
第四步:在内存窗口输入arr加回车跳转到目标内存
在这里插入图片描述

假设:malloc只开辟这段空间,那么free只释放这段空间。
带着假设继续往下去:
第五步:按一下F10
在这里插入图片描述

很显然并不是只释放了这段空间。
因此:

  • malloc并不是只开辟指定的空间大小
  • free是通过malloc多开辟的空间来获取要释放空间的大小
    图解:
    在这里插入图片描述
    我们可以理解:
  • free传入arr,向上访问可以知道malloc空间的准确大小,以及相关信息。
  • 因此:free只传入一个参数即可释放开辟空间

疑问:那干脆数据都放在堆上算了,要栈有何用?

  • 假设数据很小——1字节
  • malloc开辟不止开辟1字节,还有相关信息(远大于1字节)
  • 这样空间利用率极低,不如在栈上开辟!
  • free只有一个参数,怎么将内存函数在堆上开辟的空间进行释放?
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
第一章关键字...................................................................................................................................9 1.1,最宽恒大量的关键字----auto..........................................................................................11 1.2,最快的关键字---- register............................................................................................... 11 1.2.1,皇帝身边的小太监----寄存器............................................................................. 11 1.2.2,使用register 修饰符的注意点.............................................................................11 1.3,最名不符实的关键字----static........................................................................................12 1.3.1,修饰变量...............................................................................................................12 1.3.2,修饰函数...............................................................................................................13 1.4,基本数据类型----short、int、long、char、float、double........................................... 13 1.4.1,数据类型与“模子”............................................................................................... 14 1.4.2,变量的命名规则...................................................................................................14 1.5,最冤枉的关键字----sizeof...............................................................................................18 1.5.1,常年被人误认为函数...........................................................................................18 1.5.2,sizeof(int)*p 表示什么意思?........................................................................18 1.4,signed、unsigned 关键字................................................................................................19 1.6,if、else 组合.................................................................................................................... 20 1.6.1,bool 变量与“零值”进行比较...............................................................................20 1.6.2, float 变量与“零值”进行比较.................................................................................21 1.6.3,指针变量与“零值”进行比较...............................................................................21 1.6.4,else 到底与哪个if 配对呢?...............................................................................22 1.6.5,if 语句后面的分号............................................................................................... 23 1.6.6,使用if 语句的其他注意事项.............................................................................. 24 1.7,switch、case 组合........................................................................................................... 24 1.7.1,不要拿青龙偃月刀去削苹果.............................................................................. 24 1.7.2,case 关键字后面的值有什么要求吗?.............................................................. 25 1.7.3,case 语句的排列顺序...........................................................................................25 1.7.4,使用case 语句的其他注意事项..........................................................................27 1.8,do、while、for 关键字................................................................................................... 28 1.8.1,break 与continue 的区别.....................................................................................28 1.8.2,循环语句的注意点...............................................................................................29 1.9,goto 关键字......................................................................................................................30 1.10,void 关键字....................................................................................................................31 1.10.1,void a?............................................................................................................31 1.10,return 关键字................................................................................................................. 34 1.11,const 关键字也许该被替换为readolny....................................................................... 34 1.11.2,节省空间,避免不必要的内存分配,同时提高效率.................................... 35 1.12,最易变的关键字----volatile.......................................................................................... 36 1.13,最会带帽子的关键字----extern.................................................................................... 37 1.14,struct 关键字..................................................................................................................38 1.14.1,空结构体多大?.................................................................................................38 1.14.2,柔性数组.............................................................................................................39 1.14.3,struct 与class 的区别.........................................................................................40 1.15,union 关键字..................................................................................................................40
### 回答1: 《C语言深度剖第三版》是一本经典的关于C语言的教材,该书是由高华编著的。本书的目的是帮助读者深入了C语言的底层原理和内部机制,以便更好地应用和理C编程。 这本书从C语言的历史和发展讲起,介绍了C语言的特点和优势,然后逐步深入C语言,包括C语言的基本语法、程序结构、数据类型、变量、运算符、指针等。本书特别着重介绍C语言的指针,因为指针是C语言最重要、也最有特色的特性之一。通过深度指针的概念、用法和原理,读者可以更好地理内存管理、数组和字符串的实现,以及函数的调用和参数传递等底层机制。 此外,本书还讲了一些C语言的高级特性,如结构体、共用体和位域等,以及文件的读写和数据结构的应用。它通过具体的例子和实际的编程练习,帮助读者巩固所学知识,逐步提高编程技能。 《C语言深度剖第三版》是一本适合有一定C语言基础的读者阅读的教材。读者可以通过阅读本书,更全面地理C语言的底层原理和内部机制,为更高效、更灵活地使用C语言提供了强有力的支持。无论是对于想要深入学习C语言的专业人士,还是对于对C语言感兴趣的初学者,本书都是一本值得推荐的经典之作。 ### 回答2: 《C语言深度剖第三版》是一本深入C语言的图书,针对C语言的底层实现和内部机制进行了全面的剖析。该书由多位专家撰写,以系统地介绍C语言的各个方面。 首先,该图书涵盖了C语言的基础知识,包括数据类型、运算符、控制结构等内容。通过对语法和语义的释,读者可以加深对C语言的理,并且能够编写出正确和高效的代码。 其次,该书还具有针对C语言的底层机制的深入分析。它细讲C语言内存管理、指针、数组和结构体等方面的实现原理。通过对这些底层机制的理,读者可以更好地掌握内存的使用和优化,提高程序的性能和效率。 此外,该书还介绍了C语言的输入输出(I/O)操作、文件操作和动态内存分配等高级主题。这些主题对于开发实际应用和系统级编程非常重要,而且在大型项目也经常使用到。通过学习这些高级特性,读者可以进一步提升自己的编程水平。 总之,《C语言深度剖第三版》是一本适合有一定C语言基础的读者学习和深入了C语言的图书。通过阅读该书,读者可以全面掌握C语言的各个方面,包括基础知识和底层实现机制,从而更好地应用C语言进行开发工作。 ### 回答3: 《C语言深度剖第三版》是一本经典的C语言学习教程。本书全面而深入地析了C语言的各个方面,包括语法、数据类型、运算符、控制结构、函数、指针、内存管理等。 首先,本书通过对C语言基本语法的细介绍,帮助读者建立起对C语言的基本认识。它从简单到复杂地讲C语言的各种语句和表达式,使读者能够掌握C语言的基本语法规则。 其次,本书深入讲C语言的数据类型和运算符。通过对整数、浮点数、字符等数据类型的介绍,读者可以了到不同数据类型之间的转换规则和运算规则。同时,本书析了C语言的各种运算符,包括算术运算符、关系运算符、逻辑运算符等,让读者能够灵活使用这些运算符进行编程。 此外,本书还对C语言的控制结构进行了深入剖析。通过对顺序结构、选择结构和循环结构的讲,读者可以学会如何编写具有逻辑结构的程序。 本书还对函数和指针的概念进行了全面的讲,并通过大量实例演示了函数和指针在C语言编程的应用。函数和指针是C语言非常重要的概念,理它们对于提高程序的效率和灵活性至关重要。 最后,本书还对C语言内存管理进行了细讲。包括对变量的存储方式、内存分配和释放的方法等进行了介绍。这对于程序的性能和资源利用非常重要。 总之,《C语言深度剖第三版》是一本适合初学者和进阶者的C语言学习好教材。无论是对于基础的语法知识还是对于高级的编程概念,本书都有尽的释和大量的实例,能够帮助读者全面掌握C语言编程的技巧和方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值