您的位置:首页 > 编程语言 > C语言/C++

5C语言内存分区

2019-11-24 21:18 1421 查看


1)代码区:可执行程序代码存放区,这个我们不用关心;
2)全局区:
1全局与静态变量区:存放全局变量与静态变量,又可以区分为已经初始化的全局变量和静态变量区以及为初始化的全局变量和静态变量区;
2常量区:字符串常量与const修饰的常量存放在常量区;

3)堆区:用户动态申请的内存区,需要用户进行释放,否则有可能会造成内存泄漏;
4)栈区:该区内存由系统自动分配和释放,存放局部变量以函数实参等。
1全局区分析
看一段代码:

char *get_str()
{
char *p="abcd";//文字常量区
return p;
}
char *get_str1()
{
char *q="abcd";//文字常量区
return q;
}
int main()
{
char *p=NULL;
char *q=NULL;
p=get_str();
q=get_str1();
//%s,打印指针指向内存区域的内容
//%d打印p本身的值
printf("p=%s,p=%d\n",p,p);
printf("q=%s,q=%d\n",q,q);

return 0;
}

运行结果:

原因:

看图,从主函数main开始,在栈区定义了两个指针变量p、q为空,占4个字节;
下面调用get_str();函数返回地址,在get_str();函数中又定义了一个p这个p给主函数中的p目前没有关系,在get_str();函数中把字符串abcd赋值给p,而abcd是在文字常量区定义的,假如地址为oxaabb,只有程序结束,才会被释放。
有get_str();返回的是地址oxaabb给主函数中的p,指针指向谁,就把谁的地址赋给谁,所以当get_str();释放后,主函数的p已经指向了文字常量区的abcd,同样的原理,由于get_str1()也是把相同的字符串abcd赋值给q,q也是指向文字常量区的0xaabb,所以他们两个地址是相同的,当然如是在赋值的字符串不同,那地址一定不同。
赋值字符串不同时:

char *get_str()
{
char *p="abcd1";//文字常量区
return p;
}
char *get_str1()
{
char *q="abcd2";//文字常量区
return q;
}
int main()
{
char *p=NULL;
char *q=NULL;
p=get_str();
q=get_str1();
//%s,打印指针指向内存区域的内容
//%d打印p本身的值
printf("p=%s,p=%d\n",p,p);
printf("q=%s,q=%d\n",q,q);

return 0;
}

运行结果:


2栈区分析

char *get_str2()
{
char str[]="abcd";
printf("str=%s\n",str);
return str;//返回str数组的地址
}
int main()
{
char buf[100]={0};
strcpy(buf,get_str2());
printf("buf = %s\n",buf);

return 0;
}

运行出错。

char *get_str2()
{
char str[]="abcd";
printf("str=%s\n",str);

return str;//返回str数组的地址
}
int main()
{
//char buf[100]={0};
//strcpy(buf,get_str2());
char *p=NULL;
p=get_str2();

// printf("buf = %s\n",buf);
printf("p= %s\n",p);

return 0;
}

运行结果:

为什么p为空那?

看图,有于get_str2()函数调用完被释放,str空间被回收,str空间的内容就未知,p指向就没有了,p没有指向会报错或乱码或为NULL。注意这里的char str[]="abcd";是赋值,并不是指针的指向。
3堆区分析

char *get_str3()
{
//堆区手动分配空间
char *str=(char *)malloc(sizeof (char)*100);
if(str==NULL)//分配失败
{
return NULL;//返回空
}
//分配成功
strcpy(str,"abcd");
return str;//返回地址
}
int main()
{
//char buf[100]={0};
//strcpy(buf,get_str2());
char *p=NULL;
p=get_str3();
if(p!=NULL)//p不为空
{
printf("p= %s\n",p);//打印
free(p);//手动释放
p=NULL;//赋值为空
}
// printf("buf = %s\n",buf);
return 0;
}

运行结果:


4函数调用模型

注:main函数在栈区开辟的内存,所有子函数都可以使用
main函数在堆区开辟的内存,所有子函数都可以使用
子函数开辟的栈区内存,只有其内部子函数才能使用
子函数在堆区开辟的内存,主函数与子函数内部的子函数都可以使用
子函数在全局区开辟的内存,主函数与子函数内部的子函数都可以使用

5栈的生长方向和内存存放的方向

int main()
{
int a;
int b;
printf("&a=%d,&a=%d\n",&a,&b);//栈区生长方向是向下的

char *p=(char *)malloc(10);
char *q=(char *)malloc(10);
printf("p=%d,q=%d\n",p,q); //堆区生长方向是向上的

int buf[4];
printf("&buf[0]=%d,&buf[1]=%d\n",&buf[0],&buf[1]); //数组生长方向是向上的
return 0;
}

运行结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: