1.  内存基本构成
可编程内存基本上可以分为3大部分:静态存储区、栈区和堆区。
静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。
栈区:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
堆区:亦称动态分配区。程序在运行的时候用mallocC)或newC++)申请任意大小的内存,程序员自己负责在适当的时候用freeC)或deleteC++)释放内存。mallocnew运算符返回的是一个指向所分配类型变量(对象)的指针。对所创建的变量或对象,都是通过该指针来间接操作的,而且动态创建的变量或对象本身没有名字。动态内存的生存期可以由我们决定,如果我们不释放内存,程序将在最后才释放掉动态内存。良好的编程习惯是:如果某动态内存不再使用,需要将其释放掉,否则,我们认为发生了内存泄漏现象。另外,同一空间重复释放也是危险的,因为该空间可能已另分配。所以必须妥善保存mallocnew返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。
2.  通过一些例子看一下数据在内存中是如何分配的
#include<iostream>
using namespace std;
void main()
{
  int a=5;
  int b=6;
  double f=3.141593;
  cout<<&a<<endl<<&b<<endl<<&f<<endl;
  cout<<a<<endl;
  cout<<*(&b+1)<<endl;
  cout<<*(&f+1)<<endl;
}
 
运行结果为:
0012FF7C
0012FF78
0012FF70
5
5
1.061e-313
通过运行结果我们可以看出,内存分配是由高地址向低地址分配的。那为什么最后一句
的运行结果不是我们想要的b的值呢?这就涉及到了内存对齐问题,所以不要妄想着通过cout<<*(&f+1)<<endl;来得到b的值。
我们再看一个例子:
#include<iostream>
using namespace std;
void main()
{
  int a[5]={1,2,3,4,5};
  int b[5]={6,7,8,9,10};
  cout<<b[8]<<endl;
}
 
运行结果为:4
为什么会出现这样的结果呢?b[8]不是已经越界了嘛,为什么还会输出结果呢。这是因
为内存分配是从高地址向低地址分配的,且数组中的值在内存中是连续存放的。b[4]=10;已经到了数组的边界了,但是因为b数组下边还存有a数组的元素,所以b[8]的值自然就是a[3]的值,也就是4啦。如果使用下边的语句cout<<b[10]<<endl;系统不会报错,但输出的是一个随机值。
我们可以通过下面的语句看一下b[8]a[3]的地址。
cout<<&b[8]<<endl;
          cout<<&a[3]<<endl;
运行结果为:
0012FF78
0012FF78
这个结果就更证实了上边的结果。
3.  看一些有关存储区的例子
1
#include<iostream>
using namespace std;
void main()
{
  char *p="I Love China.";
  char str[]="I Love China";
  p[13]='!';
  str[13]='!';
  cout<<str[13]<<endl;
}
 
这个程序编译时没有出现异常,但是运行时却出现了异常。通过加断点跟踪,发现是
p[13]=’!’;这条语句出错了,为什么会出错呢?难道通过指针不可以改变它所指向的内存单元中的内容吗?这个要视情况而定,例如下面的程序就可以:
2
#include<iostream>
using namespace std;
void main()
{
  char ch='a';
  char *p=&ch;
  *p='b';
  cout<<ch<<endl;
}
运行结果:b
这是为什么呢?这是因为例1p指向的是一个字符串常量的首地址,字符串常量是存放在静态存储区的,它的值是不能修改的。而数组时存放在栈区的,它的元素值是可以
修改的。例2中的ch是临时变量,是存储在栈区的,也是可以修改的。
栈区和堆区的区别有很多方面,大家可以上网搜一下,我就不在这里赘述了。