主要分为5个区:
1、栈区(stack):由编译器自己分配和释放,存放函数的参数值,局部变量的值等,存取的方法与数据结构学的栈差不多。
2、堆区(heap):这个区的内存由程序员自己运用,分配与释放都需要程序员malloc和free,如果程序员申请了一块内存但是不释放,会造成内存泄漏,就只能等到程序结束后由系统回收。
3、全局区/静态区(static):全局变量和静态变量是放在一块的,初始化过的全局变量和静态变量放在一个区域,未初始化的又放在另一个区域。
4、文字常量区:常量字符串 存放区,程序结束后由系统回收。
5、程序代码区:存放二进制函数代码。
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456\0在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456\0放在常量区
}
注意:
①栈是从高地址到低地址生长,而堆区和全局区/静态变量区是从低地址到高地址生长。
②一定要注意的点是,进程会为每个函数分配一个栈内存,这个栈只会在函数执行期间存在,当函数执行完返回之后,栈就释放掉了,所以必须注意,在返回值为指针的时候,这个指针指向的内存地址是否为栈,如果是这个函数的栈,会被释放掉,可能会产生段错误。例如一下代码:
char *Strcpy(char const * str){
char a[];
int i = 0;
if(!str) return NULL;
while(str != '\0'){
a[i] = str[i];
i++;
}
a[i] = '\0';
return a;
}
看起来好像就只是把传进来的字符串复制到一个字符数组中,然后返回这个数组的指针,曾经我以为这段程序一点毛病都没有,但其实调用这个函数得到的指针并不会得到一个新的字符数组,因为调用这个函数的时候,进程会为他创建一个栈区,用来放局部变量,就像是代码中的数组a[ ]一样,这些局部变量在函数结束后就会被释放掉。所以我们并不能通过对返回来的指针取值来得到我们想要的字符串。也就是这个原因,malloc函数才有其存在的价值,有些时候必须要程序员在堆区申请内存来进行不同函数之间的变量传递。