
C语言6,动态内存
动态内存
6.1 常用函数
函数名 | 全部单词 | 作用 |
---|---|---|
malloc | memory allocation | 申请空间 |
calloc | contiguous allocation | 申请空间+数据初始化 |
realloc | re-allocation | 修改数据大小 |
free | free | 释放空间 |
在使用前,需导入 stdlib.h
头文件
#include<stdlib.h>
6.1.1 利用malloc函数申请一片连续的空间
单位为字节
int* p = malloc(100); // 100个字节
int* q = malloc(100 * sizeof(int)); //100个int类型
打印
printf("%d",*p);
6.1.2 赋值
第一种
#include<stdlib.h>
#include<stdio.h>
int main(){
for(int i = 0; i < 100; i++){
*(p + i) = (i + 1) * 10; //10,20,30,40,50………
}
return 0;
}
第二种
#include<stdlib.h>
#include<stdio.h>
int main(){
for(int i = 0; i < 100; i++){
p[i] = (i + 1) * 10; //另一种方式
}
return 0;
}
6.1.3 遍历
#include<stdlib.h>
#include<stdio.h>
int main(){
for(int i = 0; i < 100; i++){
*(p + i) = (i + 1) * 10; //10,20,30,40,50………
}
//遍历
for(int i = 0; i < 100; i++){
printf("%d", *(p + i));
}
return 0;
}
6.1.4 用calloc函数申请并初始化(了解)
初始化值均为0
int* p = calloc(10 * sizeof(int));
int* q = calloc(10, sizeof(int));
6.1.5 用realloc函数扩容(了解)
需要传入待扩容的内存和扩容后的空间大小
原来的数据不会发生改变
int* pp = realloc(p, 200 * sizeof(int));
6.1.6 用free释放函数
一旦空间不再使用,请一定要释放掉
free(p);
6.2 一些细节
- malloc 创建空间的单位是字节
- malloc 返回的是void类型的指针,没有步长的概念,也无法获取空间中的数据,需要强转
- malloc 返回的仅仅是首地址,没有总大小,最好定义一个变量记录总大小
- malloc 申请的空间不会自动消失,如果不能正确释放,会导致内存泄漏
- malloc 申请的空间过多,会产生虚拟内存
- malloc 申请的空间没有初始化值,需要先赋值才能使用
- free 释放完空间之后,空间中的数据叫做脏数据,可能是原来的值,可能被清空,可能被修改为其他值
- calloc 就是在 malloc 的基础上多一个初始化的动作
- realloc 修改之后的空间,地址值有可能发生变化,也有可能不会改变,但是原有的数据不会丢失
- realloc 修改之后,无需释放原来的空间,函数底层会进行处理
6.2.1 强转
不强转
/* void具有通用性,
可以转化为其他类型*/
void* p = malloc(100);
强转
int* p = malloc(100);
//int* :指针的步长
int* p = (int* ) malloc(100);
6.2.2 定义变量记录总大小
int* p = malloc(100);
int size = 100 / size(int);
遍历
#include <stdio.h>
#include <stdlib.h>
void method(int* p, int size);
int main(){
int* p = malloc(100 * sizeof(int));
int size = 100;
//赋值
for(int i = 0; i < 100; i++){
*(p + i) = (i + 1) * 10; //10,20,30,40,50………
}
//遍历
method(p,size);
//释放
free(p);
return 0;
}
void method(int* p, int size){
for(int i = 0; i < size; i++){
printf("%d ",p[i]);
}
printf("\n");
}
6.2.3 虚拟内存
在这个程序最终的结果中,申请空间的总大小可能大于电脑的总内存
虚拟:假的
当申请的空间过多,因为每一个内存空间不会再刚申请的时候就立马使用
所以C语言并不会立马就在内存中去开辟空间,而是什么时候存储数据了,才会真正的分配空间
目的:为了提高内存的使用效率
//一个遍历的代码
#include<stdio.h>
#include<stdlib.h>
int main() {
//表示申请空间大小为1个G
int number = 1024 * 1024 * 1024;
int count = 0;
while (1) {
//如果申请空间成功,则会返回这个空间的首地址
//如果申请空间失败,则会返回NULL
int* p = (int*)malloc(number);
count++;
if (p == NULL) {
printf("申请失败");
break;
}
printf("内存%d申请成功:%p\n", count, p);
}
return 0;
}
6.3 C语言的内存结构
6.3.1 分类
- 栈
- 堆
- 代码区
- 初始化静态区
- 未初始化静态区
- 常量区
6.3.2 代码区
运行时代码加载到这里
6.3.3 栈
函数运行的区域
非全局变量和数组也在这里
6.3.4 初始化静态区
已初始化的static全局变量
6.3.5 未初始化静态区
未初始化的static全局变量
6.3.6 常量区
指针加双引号定义的字符串(字符数组)在里面
6.3.7 堆
用malloc, calloc, realloc 申请出来的空间会在堆里面
6.3.8 栈和堆的区别
- 堆的空间比栈大得多
- 栈内数组的生命周期与函数相关,随函数消失;堆中的数组在free之前永远存在,直到程序结束
6.4 变量数组在内存中的运行情况
int main(){
int a = 10;
int b = 20;
int arr[] = {1,2,3};
return 0;
}
在这个程序运行时
这串代码会被临时加载到代码区中进行存储,但不会运行
编译器会从上往下依次检查代码
当检查到main函数后,就会自动的调用
main函数会加载到栈里面,赋予一定的空间,开始执行里面的代码
a,b和长度为3的arr数组会被加载到main函数的空间里面
当main函数执行完毕后,main函数就会从栈里面出去
函数空间里面的所有变量和数组也会消失
6.5 全局变量和static变量在内存中的运行情况
int a = 10;
int main(){
int* p = method();
printf("%d\n",p);
return 0;
}
int* method(){
static int b = 20;
return &b;
}
在这个程序运行时
这串代码会被临时加载到代码区中进行存储,但不会运行
编译器会从上往下依次检查代码
当检查到已赋值的全局变量a时
就会在初始化静态区中定义变量a
当检查到main函数后,就会自动的调用
main函数会加载到栈里面,赋予一定的空间,开始执行里面的代码
当main函数调用method函数时
method函数便会加载到栈当中
在method里面定义的static变量b会被加载到初始化静态区中
return返回变量b的内存地址,该地址会被返回到method函数的调用处,即main函数
用指针p进行记录
此方法是为了使main函数在method函数结束后也能访问b的值
6.6 字符串在内存中的运行情况
int main(){
char* str = "abc";
printf("%s\n",str);
str = "aaa";
printf("%s\n",str);
return 0;
}
在这个程序运行时
这串代码会被临时加载到代码区中进行存储,但不会运行
编译器会从上往下依次检查代码
当检查到main函数后,就会自动的调用
main函数会加载到栈里面,赋予一定的空间,开始执行里面的代码
char* str = "abc"
是用指针加双引号定义的字符串
会被放在常量区中,无法被修改,可以被复用(若常量区有一个同样的值,便不会再次创建)
指针str被存储在main函数的空间中
char* str = "aaa"
是用指针加双引号定义的字符串
会被放在常量区中,无法被修改,可以被复用(若常量区有一个同样的值,便不会再次创建)
指针str的值发生改变
6.7 malloc函数在内存中的运行情况
int main(){
int* p = (int* ) malloc(100);
*p = 10;
printf("%d\n", *p);
return 0;
}
在这个程序运行时
这串代码会被临时加载到代码区中进行存储,但不会运行
编译器会从上往下依次检查代码
当检查到main函数后,就会自动的调用
main函数会加载到栈里面,赋予一定的空间,开始执行里面的代码
malloc函数会被储存在堆中
指针p被储存在main函数的空间中