本文介绍在Ubuntu12.10,g++环境下C++内存分配问题。并由此解释在用g++编译时,字符串常量赋值给字符指针类型时提示“warning:deprecated conversion from string constant to 'char *'”警告的原因。
一、C++内存分配

C++编译器将应用程序的内存空间分成四个部分,从内存低地址开始依次为:代码和常量区(用于存储只读的代码数据和常量值)、全局变量和静态变量区(用于存储全局变量和静态变量)、堆区(用于保存new、malloc申请的内存)、栈区(用于保存函数返回地址、局部变量等)。
我们将用如下代码来测试我们的假设:
01.
#include <iostream>
02.
#include <stdio.h>
03.
#include <string.h>
04.
#include <malloc.h>
05.
06.
using
namespace
std;
07.
08.
int
quanju;
/*全局变量,全局区/静态区(static)*/
09.
void
fun(
int
f_jubu);
/*代码区*/
10.
int
main(
void
)
11.
{
12.
int
m_jubu;
/*栈区(stack)*/
13.
static
int
m_jingtai;
/*静态变量,全局区/静态区(static)*/
14.
const
int
conInt = 5;
/*main中的局部变量,位于栈区,被const修饰,变量值不可变*/
15.
static
const
int
sconInt = 6;
/*常量,位于常量区*/
16.
char
*m_zifum,*m_zifuc =
"hello"
;
/*指针本身位于栈。指向字符串"hello",位于代码区/常量区*/
17.
char
* zifuc_hw =
"hello world"
;
/*字符串"hello world",位于常量区*/
18.
19.
/*正确的赋值方式*/
20.
char
*zif = (
char
*)
malloc
(
sizeof
(
char
) * 6);
21.
strcpy
(zif,
"hello"
);
22.
cout<<zif<<endl;
23.
cout<<m_zifuc<<endl;
24.
25.
void
(*pfun)(
int
);
/*栈区(stack)*/
26.
int
(*pmain)(
void
);
27.
pfun=&fun;
28.
pmain = &main;
29.
m_zifum = (
char
*)
malloc
(
sizeof
(
char
)*10);
/*指针内容指向分配空间,位于堆区(heap)*/
30.
pfun(1);
31.
cout<<
"全局变量 :"
<<&quanju<<endl;
32.
cout<<
"main静态变量 :"
<<&m_jingtai<<endl;
33.
cout<<
"main字符串常量(hello) :"
<<(
void
*)m_zifuc<<endl;
34.
cout<<
"main字符串常量(h w) :"
<<(
void
*)zifuc_hw<<endl;
35.
cout<<
"main局部变量(const修饰):"
<<&conInt<<endl;
36.
cout<<
"main静态整型常量 :"
<<&sconInt<<endl;
37.
cout<<
"fun函数代码地址 :"
<<(
void
*)pfun<<endl;
38.
cout<<
"main函数代码地址 :"
<<(
void
*)pmain<<endl;
39.
cout<<
"main字符串(堆分配) :"
<<(
void
*)m_zifum<<endl;
40.
cout<<
"main函数函数指针变量 :"
<<&pfun<<endl;
41.
cout<<
"main局部变量 :"
<<&m_jubu<<endl;
42.
cout<<
"main局部变量 :"
<<&m_zifuc<<endl;
43.
cout<<
"main局部变量 :"
<<&m_zifum<<endl;
44.
return
0;
45.
}
46.
void
fun(
int
f_jubu)
47.
{
48.
static
int
f_jingtai;
49.
char
* f_zifuc =
"hello"
;
50.
cout<<
"fun静态变量 :"
<<&f_jingtai<<endl;
/*静态变量,位于静态区*/
51.
cout<<
"fun字符串常量(hello) :"
<<(
void
*)f_zifuc<<endl;
/*常量,位于常量区,同main中的“hello”地址相同*/
52.
cout<<
"fun形参变量 :"
<<&f_jubu<<endl;
/*栈区(stack),但是与主函数中m_jubu位于不同的栈*/
53.
cout<<
"fun局部变量 :"
<<&f_zifuc<<endl;
54.
}
实验结果:
hello
fun字符串常量(hello) : 0x8048c58
main字符串常量(hello) : 0x8048c58
main字符串常量(hw) : 0x8048c5e
main静态整型常量 : 0x8048e64
main函数代码地址 : 0x80487dc
fun函数代码地址 : 0x8048a73
fun静态变量 : 0x804a0f8
main静态变量 : 0x804a0fc
全局变量 : 0x804a0f0
main字符串(堆分配) : 0x9ed0008
fun形参变量 : 0xbfe0e8b0
fun局部变量 : 0xbfe0e89c
main函数函数指针变量 : 0xbfe0e8d4
main局部变量 : 0xbfe0e8c8
main局部变量 : 0xbfe0e8d0
main局部变量 : 0xbfe0e8cc
main局部变量(const修饰) :0xbfe879d8
二、堆区和栈区的比较
两个区的主要区别在于以下几个方面:
1、管理方式不同;
2、空间大小不同;
3、能否产生碎片不同;
4、生长方向不同;
5、分配方式不同;
6、分配效率不同;
栈是一块连续的内存空间,具有后进先出的特点因此不存在内存碎片,而且计算机底层直接提供支持,分配效率高。无需程序员管理,编译器会自动申请和释放。
堆的管理方式一般是采用链表管理可用的内存块,当用户申请一块内存时,系统从可用内存块中查找一块满足要求的内存空间分配给用户使用;用户释放内存后,系统将其回收。因此堆的内存管理需要由程序员来进行,分配效率不如栈。
三、字符串赋值给指针变量的告警
在用g++作编译器时,将字符串常量赋值给指针变量将得到“warning:deprecated conversion from string constant to 'char *'”的警告。例如:char*ptrSt = “hello”;
这是因为将字符指针变量ptrSt指向一个位于常量区的字符串常量“hello”。如果在运行时修改ptrSt指向内存的值,例如:ptrSt[0]= 'j',将会抛出异常,在linux的g++下,抛出了“Segmentation fault”的异常。
因此我们在将一个字符串常量赋值给字符指针变量时,应该将该变量限定为const型,即const char*。如果需要在代码中修改字符指针指向的变量的值,应该采用如下两种方式:
1.
chars[] = “hello”;
2.
char
*ptrSt = s;
或者
1.
char
*ptrSt = (
char
*)
malloc
(
sizeof
(
char
) * 6);
2.
strcpy
(ptrSt,“hello”);