内存管理
变量
1.1 变量作用域
1.2 全局变量
出现在括号之外的变量,就是全局变量
extern int age; //有一个变量 类型是int 名字是age,已经在其他文件中定义了,可以直接使用
1.3 auto自动变量
默认的类型
auto int a1 = 0; //不写auto,C语言默认变量都是auto的 还有signed也是默认的
1.4 register寄存器变量
通常变量在内存当中,如果能把变量放到CPU的寄存器里面,代码的执行效率会很高
register int i = 0; //建议,如果有寄存器空闲,那么这个变量就放到寄存器
int *p = $i ; //报错,对应一个寄存器变量,是不能取地址操作。寄存器的变量是没有内存地址
1.5 静态变量
只初始化一次,而且程序运行期间,静态变量一直存在。一个代码块内的静态变量只能被代码块内部访问
void mystatic()
{
static int a = 0; //只执行一次,变量一直存在
//int a = 0; //如果是自动变量,此时总是从0开始的
printf("a = %d\n",a);
a++;
}
int main()
{
for ( int i = 0; i < 10; i++){
mystatic();
}
}
一旦全局变量定义为static,就只能在当前定义的文件内有效
1.6 全局函数和静态函数
默认是全局函数,如果在函数前面加了static 表示函数只能在当前文件内部使用
内存四区
int c = 0 //静态区
int main()
{
static int d = 0; //变量在静态区
int a = 0; //变量在栈区
int c = 0; //变量在栈区
return 0;
}
int *geta()
{
int a = 100;
return &a;
}//int a从这个地方出栈
int main()
{
int *p = geta(); //这里得到一个临时栈变量的地址,这个地址在函数geta调用完成之后就无效了,可能出现野指针错误
*p = 100; //可能出现错误,一定要注意
printf("%d\n",*p);
return 0;
}
1.1 代码区
程序被操作系统加载到内存的时候,所有的可执行代码放在代码区,这块内存是不可以在运行期间修改的。
1.2 静态区
存放静态变量和全局变量
1.3 堆区
堆是一个大容器,它的容量要远大于栈,但是在C语言中,堆内存空间的申请和释放需要手动通过代码来完成。
1.4 栈区
栈不会很大,一般都是以K为单位的
栈溢出:当栈空间已满,但还往栈内存压变量,这个就叫栈溢出
所有的自动变量,函数的形参都是有编译器自动释放出栈的,都放在栈区的
对于自动变量,什么时候入栈出栈,是不需要程序控制的,有C语言编译器实现
对于一个32位的操作系统,最大管理4G内存,其中1G是给操作系统自己用的,剩下的3G是给用户程序的,一个用户程序理论上可以使用3G的内存空间。
//模拟栈溢出的情况
int main()
{
//定义一个超大的数组,就会出现栈溢出
char array[1024 * 1024 * 100] = {0}; //数组在栈区,占100M的空间
array[0] = 'a';
return 0;
}
1.5 malloc和free
malloc和free要成对使用。一个内存不能free两次。
#include <stdlib.h>
int main()
{
//分配内存
int *p = (int *)malloc(sizeof(int) * 10);//在堆中间申请内存,在堆中申请了10个int大小的空间
//清空内存
memset(p, 0, sizeof(int) * 10);
//赋值
int i;
for(i = 0; i < 10; i++)
{
p[i] = i;
}
char *p1 = mallloc(sizeof(char) * 10);//在堆中申请了10个char大小的控件
//释放通过malloc分配的堆内存
free(p);
free(p1);
}
//错误,返回栈内存地址,会被释放掉
int *geta()
{
int a = 10;
return &a;
}
//合法,可以通过函数的返回值返回一个堆地址,但是一定要记得free
int *geta1()
{
int *p = malloc(sizeof(int));
return p;
}
//合法的,静态区的可以得到,但是不能free
int *geta2()
{
static int a = 0;
return &a;
}
会崩溃
函数的形参*p跟main函数的*p不是同一个,都在栈区 当前这个函数是值传递
void getheap(int *p){
p = malloc(sizeof(int) * 10);
}
int main()
{
int *p = NULL;
getheap(p);
p[0] = 1;
p[1] = 2;
free(p);
return 0;
}
1.6 堆、栈和内存映射
C/C++要手动释放内存
动态创建数组
int i;
scanf("%d",&i);
int *p = (int *)malloc(sizeof(int) * i);
c语言中,函数的形参是从右往左入栈
1.7 calloc和realloc
操作管理内存的最小单位是 页 不是字节 linux32位的操作系统一般一个内存页就是4K
calloc
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
int main()
{
//malloc,分配内存后,内容随机,需要手动清0
char *p = malloc(sizeof(char)*10); //分配堆内存,但是内容不知道
memset(p,0,10); //清空内存
//calloc,分配后内容已经是清0的
char *q = calloc(10,sizeof(char)); //分配堆内存,分配10个字节
//都需要free
free(p);
free(q);
}
realloc
int main()
{
//calloc申请内存
char *p1 = calloc(10 * sizeof(char));
//realloc,在原有内存基础之上,在堆中间增加连续的内存
//如果原有内存没有连续空间可扩展,那么会新分配一个控件,将原有内存拷贝到新控件,然后释放原有内存
//realloc和malloc一样,只分配,不清0 需要手动清0
char *p2 = realloc(p1,20); //在p1基础上再分配,总共20个
//释放(此时p1和p2地址是相同的)
free(p2);
//
char *ppp = realloc(NULL,5); //等同于malloc(5)
}