2024年最新C语言进阶:动态内存管理_内存释放不置空,大牛手把手教你

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上网络安全知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以点击这里获取

动态内存函数的介绍
开辟释放函数 malloc & free
函数声明
void\* malloc( size\_t size );

Return Value
malloc returns a void pointer to the allocated space, or NULL if there is insufficient(不充足) memory available. To return a pointer to a type other than void, use a type cast(转换) on the return value. Always check the return from malloc, even if the amount of memory requested is small.

Parameter
size - Bytes to allocate
    
Remarks
The malloc function allocates a memory block of at least size bytes. The block may be larger than size bytes because of space required for alignment and maintenance information.

void free( void\* memblock );

Return Value
None

Parameter
memblock - Previously allocated memory block to be freed

Remarks
The free function deallocates(解除) a memory block that was previously allocated. If memblock is NULL, the pointer is ignored. Attempting to free a memblock isn't allocated on heap may cause errors.

malloc函数在堆区上申请size个字节的空间,并返回该空间的起始地址。

free函数释放指针指向的动态开辟的空间,但不对指针造成任何影响。

函数用法
  • malloc返回通用类型的指针,将其强制转换为所需类型,并用该类型的指针维护该内存空间。
  • 开辟成功返回空间起始地址,开辟失败则返回NULL
  • 使用结束free释放内存以防内存泄漏,将指针置空避免成为野指针。
//申请空间
int\* p = (int\*)malloc(40);
//检查
if (p == NULL) {
    printf("%s\n", strerror(errno));
    return -1;
}
//使用
for (int i = 0; i < 10; i++) {
    \*(p + i) = i;
    printf("%d ", \*(p + i));
}
//释放空间
free(p);
//置空
p = NULL;

内存开辟函数 calloc
函数声明
void\* calloc( size\_t num, size\_t size );

Return Value
calloc returns a pointer to the allocated space. To get a pointer to a type other than void, use a type cast on the return value. 

Parameters
1. num - Number of elements
2. size - Length in bytes of each element

Remarks
The calloc function allocates storage space for an array of num elements, each of length size bytes. Each element is initialized to 0.

malloc函数在堆区上申请numsize大小的空间,返回起始地址并将内容初始化为0。

函数用法
int\* p = (int\*)calloc(10, sizeof(int));
if (p == NULL) {
    perror("");
    return -1;
}
for (int i = 0; i < 10; i++) {
    \*(p + i) = i;
    printf("%d ", p[i]);
}
free(p);
p = NULL;

内存调整函数 realloc
函数声明
void\* realloc( void\* memblock, size\_t size );

Return Value
realloc returns a void pointer to the reallocated memory block. The return value is NULL if there is not enough available memory to expand the block to the given size, then the original block is unchanged.

Parameters
1. memblock - Pointer to previously allocated memory block
2. size - New size in bytes

Remarks
The realloc function changes the size of an allocated memory block. The memblock parament points to the beginning of the memory block. If memblock is NULL, realloc behaves the same way as malloc. The contents of the block are unchanged, although the new block can be in a different location. 

realloc函数为已开辟的空间重新开辟大小。

函数用法
  • 当原空间后有足够大小时,就紧接原空间开辟剩余空间,并返回整个空间的起始地址。

  • 当原空间后无足够大小时,就在堆区寻找新空间,再将原空间的内容移动到新空间,返回新空间的地址且释放原空间。

  • 当剩余空间不够无法开辟时,增容失败,返回NULL
//1.
p = (int\*)realloc(p, 20 \* sizeof(int));
//2.
int\* ptr = (int\*)realloc(p, 20 \* sizeof(int));
if (ptr == NULL) {
    return -1;
}
p = ptr;

防止增容失败将原空间指针置空,故不可直接使用原指针接受返回值。判断非空后再赋给原指针。

常见的动态内存错误
1.不检查空指针
void test() {
	int\* p = (int\*)malloc(INT_MAX / 4);
	\*p = 20;
	free(p);
}

对指向动态开辟的空间的指针一定要做有效的判断。

2.越界访问
void test() {
	int i = 0;
	int\* p = (int\*)malloc(10 \* sizeof(int));
	if (NULL == p) {
		exit(EXIT_FAILURE);
	}
	for (int i = 0; i <= 10; i++) {
		\*(p + i) = i;
	}
	free(p);
    p = NULL;
}

作为程序员必须有意识地检查所写的代码是否有越界访问的问题。

3.释放非动态开辟内存
void test() {
	int a = 10;
	int\* p = &a;
	free(p);
    p = NULL;
}

不可用free释放非动态开辟的空间。

4.释放部分内存
int main()
{
	int\* p = (int\*)malloc(100);
	p++;
	free(p);
	return 0;
}

改变指向动态开辟内存的指针,内存将无法管理。释放不完全导致内存泄漏。

5.重复释放内存
void test() {
	int\* p = (int\*)malloc(100);
	free(p);
	free(p);
}

使用free释放已释放的空间,即访问非法内存。建议释放内存和指针置空搭配使用。

6.忘记释放内存
void test() {
    int \*p = (int\*)malloc(100);
    if(NULL != p) {
        \*p = 20;
    }
}
int main() {
    test();
    while(1);
}

使用结束不释放内存造成内存泄漏。程序不停止,系统也不会自动回收。

笔试题

调用下列test函数,解释运行结果。

Example 1
void GetMemory(char\* p) {
	p = (char\*)malloc(100);
}
void test() {
	char\* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
    free(str);
    str = NULL;
}

程序报错。

传值调用:并没有改变str的值仍为不予修改的空指针,可以使用二级指针接收str的地址。函数调用结束后指针销毁故无法释放空间以致内存泄漏。

Example 2
char\* GetMemory() {
	char p[] = "hello world";
	return p;
}
void test() {
	char\* str = NULL;
	str = GetMemory();
	printf(str);
    free(str);
    str = NULL;
}

程序打印随机值。

返回栈空间地址:数组p在函数内创建,出函数销毁,返回这部分空间的地址 ,属于访问非法空间。

Example 3
void GetMemory(char\*\* p,int num) {
	\*p = (char\*)malloc(num);
}
void test() {
	char\* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
	free(str);
    str = NULL;
}

程序运行成功,打印"hello"

传址调用:本题是例一的正确写法。

Example 4
void test(void) {
	char\* str = (char\*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL) {
		strcpy(str, "world");
		printf(str);
	}
}

程序报错。

野指针:动态开辟的内存释放后指针不置空,造成野指针访问非法内存。释放内存和指针置空应该搭配起来使用。

释放空间,销毁空间都是将内存空间归还给操作系统,即将此空间的使用权限归还操作系统。虽不会改变空间内容以致打印出所谓的“正确结果”,但可能在之后被操作系统分配给其他程序时发生修改。但无论改变与否,一旦空间归还后再去访问就是访问非法内存。

C/C++内存划分
用例展示

根据下列创建的各种变量,分析内存的划分。

int globalVar = 1;
static int staticGlobalVar = 1;
int main()
{
	static int staticVar = 1;
	
	int localVar = 1;
	int num1[10] = { 1,2,3,4 };


## 写在最后

**在结束之际,我想重申的是,学习并非如攀登险峻高峰,而是如滴水穿石般的持久累积。尤其当我们步入工作岗位之后,持之以恒的学习变得愈发不易,如同在茫茫大海中独自划舟,稍有松懈便可能被巨浪吞噬。然而,对于我们程序员而言,学习是生存之本,是我们在激烈市场竞争中立于不败之地的关键。一旦停止学习,我们便如同逆水行舟,不进则退,终将被时代的洪流所淘汰。因此,不断汲取新知识,不仅是对自己的提升,更是对自己的一份珍贵投资。让我们不断磨砺自己,与时代共同进步,书写属于我们的辉煌篇章。**


需要完整版PDF学习资源私我



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化资料的朋友,可以点击这里获取](https://bbs.csdn.net/topics/618540462)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

 = { 1,2,3,4 };


## 写在最后

**在结束之际,我想重申的是,学习并非如攀登险峻高峰,而是如滴水穿石般的持久累积。尤其当我们步入工作岗位之后,持之以恒的学习变得愈发不易,如同在茫茫大海中独自划舟,稍有松懈便可能被巨浪吞噬。然而,对于我们程序员而言,学习是生存之本,是我们在激烈市场竞争中立于不败之地的关键。一旦停止学习,我们便如同逆水行舟,不进则退,终将被时代的洪流所淘汰。因此,不断汲取新知识,不仅是对自己的提升,更是对自己的一份珍贵投资。让我们不断磨砺自己,与时代共同进步,书写属于我们的辉煌篇章。**


需要完整版PDF学习资源私我



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化资料的朋友,可以点击这里获取](https://bbs.csdn.net/topics/618540462)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值