C 语言动态分配内存, malloc 的出现就是来弥补静态内存分配的缺点
比如说我们在定义数组的时候, 数组的长度必须是一个常量, 不能改变的值, 假如我事先定义了数组, 一旦业务需求发生改变, 那么这个数组就不能再使用了.
传统的数组定义也就是静态分配, 是不能够手动释放的, 只能等待系统释放, 静态分配的内存, 是分配在栈中的, C 语言中的函数调用也是通过栈来实现的, 栈有一个特点就是先进后出, 在调用函数的时候, 是先压入栈, 然后从最上面的函数开始执行
我们先来看看内存四区, 分别为堆区, 栈区, 数据区, 代码区, 对于这四个区, 做了以下总结
代码区:
程序执行二进制码 (程序指令)
共享, 只读
数据区 :
初始化数据区 (data)
未初始化数据区 (bss)
常量区
栈区 :
系统为每一个程序分配一个临时的空间,
局部变量, 函数信息, 函数参数, 数组
栈区大小为: 1M
在 Windows 中可以扩展到 10M
在 Linux 中可以扩展到 16M
堆区 :
存储大数据, 图片, 音乐, 视频
手动开辟 malloc
手动释放 free
栈区大小为: 1M, 我们来验证一下
int zhan[8200000] = { 0 };
在 C 语言中, 我们定义了一个数组, 长度为 820000, 那么我们知道, 在栈中我们最多可分配 1M 的内存, 我们可以计算一下, 这八百二十万的长度占了多大的内存,
定义的是 int 类型, 所以 8200000*4=32800000(字节)
得到的结果再除以 1024,32800000/1024=32031.25(KB)
得到的结果再除以 1024,32031.25/1024=31.280517578125(M)
大约是 31M, 最终运行起来, 这个程序是会报错的.
接下来我们就开辟堆内存存储数据, 这就用到了函数 malloc
动态分配内存函数
malloc
使用函数之前我们要引用头文件 stdlib.h
#include<stdlib.h>
malloc 函数语法示例
int* p1 = (int*)malloc(sizeof(int))
返回值类型为 void* 类型, 也就是指针类型, int* p1 代表一个以 int 类型地址为内容的指针变量
int 类型在内存中占用的大小为 4 字节.
malloc 括号中就是你要开辟的空间大小, 单位是字节, 分配一块连续的区域
假如我要开辟一个空间, 里面存储 5 个数字, 那么代码如下
int* p1 = (int*)malloc(sizeof(int)*5);
这样的格式可以更容易的理解, 当然你也可以像下面这么写
int* p1 = (int*)malloc(20);
如果地址开辟成功, 返回一个内存地址, 否则返回 NULL, 需要注意的是, 如果开辟失败了, 那么在后边的程序中调用, 程序就会报错, 所以有时候还要加一个判断条件, 这点要注意
- if (p1 == NULL) {
- printf("程序异常");
- return -1;
- }
成功以后, 我们可以使用这个内存空间, 对它进行赋值.
在使用完之后, 也可以调用 free 函数释放, 代码如下
free(p1);
那么, 当我们释放这个 p1 之后, 这个内存空间还能调用吗? 其实还可以调用的. 在释放之后, 这个内存地址就变成了一个野指针, 还可以进行赋值
为了避免野指针, 在 free(p1) 后在加上一段代码
p1 = NULL;
赋值为 NULL, 这个是可有可无的.
我们再来看一个函数, 叫做内存操作函数
memset(),memcpy(),memmove(),
引用 string.h
#include<string.h>
1.memset() 参数, void*memset(void*s,intc,size_tn);
我们来看看它的示例
- int* p = (int*)malloc(sizeof(int) * 10);
- memset(p, 0, 40);
传入 p 这个内存地址, 重置为 0, 字节为 40 字节
它在重置为 0 时有效, 并不是真正意义上的重置
这个函数作用通常是一串连续的内存一起操作, 不会单独对变量进行操作.
2.memcpy(), 参数, void*memcpy(void*dest,constvoid*src,size_tn);
示例:
- int arr[] = { 1,2,3,4,5,6,7,8,9 };
- int* p = (int*)malloc(sizeof(int) * 9);
- memcpy(p, arr, sizeof(int) * 9);
arr 存在栈内存中, p 存在堆内存中, 我们现在要把 arr 中的数复制到 p 中, 这就用到了 memcpy() 函数
用法:
memcpy(新数据, 源数据, 内存大小 (字节))
它不同于 strcpy() 这个函数, strcpy() 是字符串拷贝遇到 \ 0 会停止, 而 memcpy() 拷贝的是内存, 拷贝的内容和字节有关.
如果参数 1 和参数 2 的内存地址重叠, 可能会导致程序报错, 应尽量避免
3.memmove()
memmove() 功能用法和 memcpy() 一样, 区别在于: dest 和 src 所指的内存空间重叠时, memmove() 仍然能处理, 不过执行效率比 memcpy() 低些.
4.memcmp(), 参数, intmemcmp(constvoid*s1,constvoid*s2,size_tn);
- int arr[] = { 1,2,3,4,5,6,7,8,9 };
- int arry[] = { 1,2,3,4,5 };
- int value = memcmp(arr, arry, 20);
第一个参数和第二个参数进行比较, 比较前 20 个字节, 也就是前 5 个数, 如果相等返回 0, 否则返回 - 1;
同样可以比较字符串, 代码如下:
- char arr[] = "hello\0 word";
- char arry[] = "hello\0 word";
- int value = memcmp(arr, arry, 11);
来源: https://www.cnblogs.com/NiuZiXiao/p/10233157.html