赞
踩
我们开辟空间的时候,空间的大小是固定的。
在数组申明的函数,必须要指定数组的长度,它所需要的内存在编译时分配的。
但是如果想要开辟不固定大小的空间,该怎么办?
解决方式就是动态进行内存的分配,即在堆上开辟空间。
本篇博客将介绍如何动态开辟空间。
一、动态内存函数
C语言中与动态内存管理相关的函数,主要有四个malloc、free、calloc和realloc。
1.malloc
void* malloc(size_t size);
该函数是开辟一个大小为size字节大小的空间。
返回值:若开辟失败,则返回一个NULL指针,因此malloc的返回值一定要作检查。若开辟成功,则返回这块空间的指针,因为该指针为void*类型,所以具体使用时可以进行强转。
2.free
void free(void* ptr);
该函数是用来释放ptr指针指向的一块空间的。
如果参数ptr指向的空间不是动态开辟的,则free函数的行为是未定义的。
若果参数ptr是NULL指针,则该函数什么都不做。
一般用了malloc申请空间,在使用之后一定要释放该空间,不然会造成资源泄露。
- #include <stdio.h>
- #include <stdlib.h>
- //malloc和free函数在该头文件里
- int main()
- {
- int num = 0;
- scanf("%d", &num);
- int* ptr = (int*)malloc(num * sizeof(int));
- if (NULL != ptr)
- {
- for (int i = 0; i < num; ++i)
- {
- *(ptr + i) = i;
- printf("%d ", *(ptr + i));
- }
- printf("\n");
- }
- free(ptr);
- ptr = NULL;//防止其成为野指针
- system("pause");
- return 0;
- }

最后一定要ptr设为NULL,不然会变成野指针。
3.calloc
void* calloc (size_t num, size_t size);
该函数功能是为num个大小为size的元素开辟一块空间,并且开辟完之后该空间的每个字节都会初始化为0。
其实该函数就是malloc加上初始化。
返回值:若开辟失败,则返回一个NULL指针。若开辟成功,则返回这块空间的指针,因为该指针为void*类型,所以具体使用时可以进行强转。
其开辟完空间,在这个空间使用完之后也一定要调用free函数将其释放掉。
- #define _CRT_SECURE_NO_WARNINGS 1
- #include <stdio.h>
- #include <stdlib.h>
- //calloc和free函数在该头文件里
- int main()
- {
- int num = 0;
- scanf("%d", &num);
- //int* ptr = (int*)malloc(num * sizeof(int));
- int* ptr = (int*)calloc(num, sizeof(int));
- if (NULL != ptr)
- {
- printf("使用之前,会自动初始化:\n");
- for(int i = 0; i < num; ++i)
- {
- printf("%d ", *(ptr + i));
- }
- printf("\n");
- printf("使用之后:\n");
- for(int i = 0; i < num; ++i)
- {
- *(ptr + i) = i;
- printf("%d ", *(ptr + i));
- }
- printf("\n");
- }
- free(ptr);
- ptr = NULL;
- system("pause");
- return 0;
- }

不难发现,该函数作用和malloc一样,只不过比malloc多了一个初始化。
4.realloc
void* realloc (void* ptr, size_t size);
该函数是当我们发现过去申请的空间太小了、或者太大了的时候,可以用该函数对动态开辟内存大小调整。
ptr是要调整的空间的指针。
size是调制之后的新大小。
返回值为调整之后的内存起始位置。
该函数在调整原内存空间大小的基础上,还会将原来内存中的数据移到新的空间中。
realloc在调整内存空间时会出现两种情况:①原有空间之后本身就有足够大的空间,此时只需要在原有内存之后直接追加空间,原来空间的数据不发生变化。 ②原有空间之后没有足够大的空间,此时要在堆上重新找一个适合大小的连续空间进行使用,此情况下函数返回的是一个新的内存地址。
- #define _CRT_SECURE_NO_WARNINGS 1
-
- #include <stdio.h>
- #include <stdlib.h>//ralloc和free函数在该头文件里
-
-
- int main()
- {
- int* ptr = (int*)malloc(5 * sizeof(int));
- if (NULL != ptr)
- {
- for (int i = 0; i < 5; ++i)
- {
- *(ptr + i) = i;
- printf("%d ", *(ptr + i));
- }
- printf("\n");
- }
-
- //用realloc扩容
- int* ptr2 = NULL;
- ptr2 = (int*)realloc(ptr, 6 * sizeof(int));
- if (NULL != ptr2)
- {
- ptr = ptr2;
- }
- //之前的数据都在
- *(ptr + 5) = 5;
- for (int i = 0; i < 6; ++i)
- {
- printf("%d ", *(ptr + i));
- }
- printf("\n");
-
- free(ptr);
- ptr = NULL;
-
- system("pause");
- return 0;
- }

二、常见的动态内存错误
对NULL指针的解引用
- #define _CRT_SECURE_NO_WARNINGS 1
-
- #include <stdio.h>
- #include <stdlib.h>
-
-
- int main()
- {
- int* ptr = (int*)malloc(2 * sizeof(int));
- *ptr = 20;//不判断
- free(ptr);
- ptr = NULL;
- system("pause");
- return 0;
- }
此时没有对ptr进行判断,则申请失败时ptr值为NULL,那么就会有问题。
对动态开辟空间越界访问
- #include <stdio.h>
- #include <stdlib.h>//malloc和free函数在该头文件里
-
-
- int main()
- {
- int* ptr = (int*)malloc(5 * sizeof(int));
- if (NULL != ptr)
- {
- for (int i = 0; i < 6; ++i)
- {
- *(ptr + i) = i;
- printf("%d ", *(ptr + i));
- }
- printf("\n");
- }
- free(ptr);
- ptr = NULL;
- system("pause");
- return 0;
- }

上面 *(ptr + 5) 就是越界访问了。
对不是动态开辟的内存使用了free函数进行释放
- #include <stdio.h>
- #include <stdlib.h>
-
-
- int main()
- {
- int i = 20;
- int* ptr = ⅈ
- free(ptr);//
- ptr = NULL;
- system("pause");
- return 0;
- }
此时程序会崩。
对同一块动态内存多次释放
- #include <stdio.h>
- #include <stdlib.h>
-
-
- int main()
- {
- int* ptr = (int*)malloc(5 * sizeof(int));
- if (NULL != ptr)
- {
- for (int i = 0; i < 6; ++i)
- {
- *(ptr + i) = i;
- printf("%d ", *(ptr + i));
- }
- printf("\n");
- }
- free(ptr);
- free(ptr);
- ptr = NULL;
- system("pause");
- return 0;
- }

此时程序会崩。
使用free函数释放一块动态开辟内存的一部分
- #define _CRT_SECURE_NO_WARNINGS 1
-
- #include <stdio.h>
- #include <stdlib.h>//malloc和free函数在该头文件里
-
-
- int main()
- {
- int* ptr = (int*)malloc(5 * sizeof(int));
-
- ++ptr;//ptr不再指向该动态内存的起始位置了。
- free(ptr);
- ptr = NULL;
- system("pause");
- return 0;
- }

程序依旧会崩。
当我们动态开辟内存空间时,使用完之后忘记使用free函数释放之后就会造成内存泄漏。
三、C语言内存开辟
C语言中程序的内存区域划分
栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统回收。分配方式类似于链表。
数据段(静态区)(static):存放全局变量、静态数据。程序结束后由系统释放。
代码段:存放函数体(类成员函数和全局函数)的二进制代码。
————————————————
版权声明:本文为CSDN博主「Sheena爽」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Sheena997/java/article/details/103701171
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。