静态开辟内存与动态开辟内存
1.使用C语言API文档
c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
// 看文档的思路:
// 1.看到文档,不要Copy,初学者
// 2. 传入 &t &p 可以直接传递 NULL 尝试
// 时间单位 给他才行
srand((unsigned) time(NULL));
int i;
for (i = 0; i< 10 ; i++) {
printf("随机数%d\n", rand() % 100);
}
return(0); // return 0;
}
// 字符串的Copy工作
/*函数名: strcpy
功 能: 串拷贝
用 法: char *strcpy(char *str1, char *str2);
程序例:*/
#include <stdio.h>
#include <string.h>
int main(void)
{
char string[10]; // 定义一个数组
char *str1 = "abcdefghi"; // 字符串定义
strcpy(string, str1); // 就是把 str1 复制到 数组
printf("%s\n", string); // 打印数组
return 0;
}
// C中的 布尔
int main() {
// Java Boolean
// 非0即true, 0就是false
if (0) {
printf("真\n");
} else {
printf("假\n");
}
if (43665) {
printf("真\n"); // 1 走
} else {
printf("假\n"); // 2
}
if (-545) {
printf("真\n"); // 1
} else {
printf("假\n"); // 2
}
return 0;
}
bash
假
真
真
2.静态开辟
c
#include <stdio.h>
#include <unistd.h> // 小写的
// 函数进栈 定义一个int arr[5]; 定义一个 int i; (静态的范畴)
// 进栈
void staticAction() {
int arr[5]; // 静态开辟 栈区 (栈成员)
for (int i = 0; i <5; ++i) {
arr[i] = i;
printf("%d, %p\n", *(arr + i), arr + i);
}
} // 函数的末尾会弹栈(隐士):执行完毕会弹栈 会释放所有的栈成员
// 2.静态开辟。
int main() {
// int 4 * 10 = 40M
// int arr[10 * 1024 * 1024]; // 10M * 4 = 40M 会栈溢出
// int arr[1 * 1024 * 1024]; 会栈溢出
int arr[(int)(0.2 * 1024 * 1024)]; // 不会栈溢出
// 栈区:占用内存大小 最大值: 大概 2M 大于2M会栈溢出 平台有关系的
// 堆区:占用内存大小 最大值: 大概80% 40M没有任何问题,基本上不用担心 堆区很大的
// 大概80%: Windows系统 给我们的编译器给予的空间 的 百分之百八十
while (9) {
sleep(100);
staticAction(); // 调用开辟20
}
return (0);
}
3.动态开辟
c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // 小写的
/// 函数进栈 定义一个int arr[5]; 定义一个 int i; (静态的范畴)
// malloc 在堆区开辟的内存空间 , (动态的范畴)
// C的开发过程中,不能出现,野指针,悬空指针
void dynamicAction() {
int * p; // 野指针 没有地址的,空的
// void * 可以任意转变 int* double *
int * arr = malloc(1 * 1024 * 1024); // 堆区开辟 4M
printf("dynamicAction函数,arr自己的内存地址:%p,堆区开辟的内存地址:%p\n", &arr, arr);
// C工程师,堆区开辟的空间,必须释放
free(arr); // 释放掉
arr = NULL; // 重新指向一块内存地址00000
printf("dynamicAction函数2 堆区开辟的内存地址:%p\n", arr); // 悬空指针
}
int main() {
while (9) {
// sleep(100);
dynamicAction(); // 调用开辟20
}
return 0;
}
4.动态库开辟的使用场景
c
#include <stdio.h>
#include <stdlib.h>
// 动态开辟的使用的场景
int main() {
// 静态开辟的内存空间大小,是不能修改的,如果不需要动态修改空间大小,当然使用 栈区 【尽量使用 静态开辟的,如果实在是需要动态改变,才使用下面】
// int arr [6];
// =================================== 下面是 动态开内存的使用场景
// 开辟的空间 想要变化, 动态范畴
int num;
printf("请输入数的个数:");
// 获取用户输入的值
scanf("%d", &num);
// 动态开辟 用户输入的值 空间的大小 【堆区】
int * arr = malloc(sizeof(int) * num);
// int arr2 [] == int * arr 一样的了
int print_num;
// 循环接收
for (int i = 0; i < num; ++i) {
printf("请输入第%d个的值:", i);
// 获取用户输入的值
scanf("%d", &print_num);
arr[i] = print_num;
printf("每个元素的值:%d, 每个元素的地址:%p\n", *(arr + i), arr + i);
}
// for 循环打印
for (int i = 0; i < num; ++i) {
printf("输出元素结果是:%d\n", arr[i]); // arr[i] 隐士 等价与 * (arr + i)
}
getchar();
return 0;
}
5.动态开辟之realloc
c
#include <stdio.h>
#include <stdlib.h>
// 动态开辟之realloc
int main() {
int num;
printf("请输入个数");
// 获取用户输入的值
scanf("%d", &num);
// 5个值
int * arr = (int *) malloc(sizeof(int) * num);
for (int i = 0; i < num; ++i) {
arr[i] = (i + 10001); // arr[i]的内部隐士 == *(arr+i)
}
printf("开辟的内存指针: %p\n", arr);
// 打印 内容
for (int i = 0; i < num; ++i) {
// Derry装B的打印
// &取出内存地址 *然后去值
// &取出内存地址 *然后去值
// &取出内存地址 *然后去值
// .....
printf("元素的值:%d, 元素的地址:%p\n",
*&*&*&*&*&*&*&*&
*&*&*&*&*&*&*&*&*&
*&*&*&*&*&*&*&*&
*&*&*&*&*&*&*&*&
*&*&*&*&*&*&*&*&
*&*&*&*&
*&*(arr + i)
,
(arr + i)
);
}
// ================================= 在堆区开辟新的空间 加长空间大小
// C的岗位
// C工程师的面试题: realloc 为什么一定要传入 arr指针,为什么要传总大小
// 新增
int new_num;
printf("请输入新增加的个数");
scanf("%d", &new_num);
// 原来的大小4 + 新增加的大小4 = 总大小 8
// void *realloc (void *前面开辟的指针, size_t总大小);
int * new_arr = (int *) realloc(arr, sizeof(int) * (num + new_num));
if (new_arr) { // new_arr != NULL 我才进if 【非0即true】
int j = num; // 4开始
for (; j < (num + new_num); j++) { // 5 6 7 8
arr[j] = (j + 10001);
}
printf("新 开辟的内存指针: %p\n", new_arr);
// 后 打印 内容
for (int i = 0; i < (num + new_num); ++i) {
printf("新 元素的值:%d, 元素的地址:%p\n",
*(arr + i),
(arr + i)
);
}
}
// 我已经释放
free(new_arr);
new_arr = NULL;
// 1000行代码
// 。。。
// 重复释放/重复free VS会奔溃, CLion会优化(发现不奔溃) [错误的写法]
/*free(new_arr);
new_arr = NULL;*/
// 必须释放【规则】
/*if (arr) {
free(arr); // 如果不赋值给NULL,就是悬空指针了
arr = NULL;
}*/
if (new_arr) {
free(new_arr); // 如果不赋值给NULL,就是悬空指针了
new_arr = NULL;
}
return 0;
}
| 对比项 | malloc |
realloc |
|---|---|---|
| 参数 | 只需新内存大小 | 需要原指针 + 新大小 |
| 返回值 | 新内存地址(失败返回 NULL) |
新内存地址(可能和原地址相同,也可能不同;失败返回 NULL) |
| 原内存处理 | 无(因为是新分配) | 自动释放旧内存(如果移动了) |
malloc示例
c
int *arr = malloc(4 * sizeof(int)); // 分配4个int
if (arr) {
for (int i = 0; i < 4; i++) arr[i] = i;
free(arr);
}
realloc示例
c
int *arr = malloc(4 * sizeof(int));
// ... 使用 arr ...
// 扩展到8个int
int *new_arr = realloc(arr, 8 * sizeof(int));
if (new_arr) {
arr = new_arr; // ⚠️ 必须更新指针!
for (int i = 4; i < 8; i++) arr[i] = i; // 初始化新增部分
free(arr);
} else {
// realloc 失败,原 arr 仍有效
free(arr);
}