下载Windows Debug 工具, http://www.easck.com/whdc/devtools/debugging/default.mspx
安装后,使用其中的gflags.exe工具打开PageHeap,
gflags -p /enable MainD.exe /full
重新使用VS用调试方式运行,很快就找到了出错位置,因为在某个静态函数中笔误导致
在编写稳定的服务器程序时,这个工具尤为有用。
第二部分 数组的动态分配及实例
一、动态分配二维数组的一般方法是这样:假设数组存的数据类型是int
int **p=NULL;
p=new int*[nWidth];
if (!p){
return NULL;
}
for (int j=0;j<nWidth;j++){
p[j]=new int[nHeight];
if (!p[j]){
return NULL;
}
}
这段代码浅显易懂,先分配第1维,在循环分配第2维。假设二维数组是3×2的,每一句运行完后的内存情况如图所示(方格表示内存,xx表示随机数。下面是内存地址。当然,这个地址是个示意,事实不会分配到那的。):
第一句完后分配了3个内存单元
循环分配后,注意下面3段内存是不连续的。这样用下表p[n][m]操作数组没问题,如果整块内存操作就会有问题了。
原意是想把下面的3块6个内存单元清0,可是事与愿违,把从p开始后面6个内存单元清0了,p[]不能用了。p后面只有3个已分配的内存单元,却要操作6个,另外3个是未知区域。清了后面虚线的3块未知区域,这就很危险了,可能导致程序崩溃。
这样分配的内存需要循环释放。
对这个方法有一改进,如下:
int **p=NULL;
p=new int *[nWidth];
if (!p){
return NULL;
}
p[0]=new int[nWidth*nHeight];
if (!p[0]){
delete[] p;
return NULL;
}
ZeroMemory(p[0],nWidth*nHeight*sizeof(int));
for (int i=1;i<nWidth;i++){
p[i]=p[i-1]+nHeight;
}
这段代码解决了分配的空间不连续的问题。每一句运行完后的内存情况如图所示:
第一句和上面一样。
这6个内存单元是一次分配的,所以连续。
这个二维数组的数据首地址是p[0],p是第2维的索引首地址。所以如果要对二维数组进行整体的内存(缓冲区 buffer)操作,要以p[0]为操作对象的首地址。
到此,索引与对应的数据地址关联上了。这个二维数组既可以通过下表p[][]来操作,又可以操作缓冲区。操作缓冲区的函数比如memcpy,cfile的writehuge和readhuge使用起来很方便,省去了2次循环的麻烦。
至于释放,不必循环释放。因为new了2次,所以只需delete2次就行了:
if(!p){
return;
}
delete []p[0];
p[0]=NULL;
delete[] p;
p=NULL;
二 实例
<span style="font-size:14px;">// malloc2d.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
//第一种方法,分配连续空间
void **malloc2d(int row,int col,int size)
{
void **arr;
int indexsize=sizeof(void*)*row;//空出indexsize大小的空间用作? void*为什么不行?
int totalsize=size*row*col;
arr=(void**)malloc(indexsize+totalsize);
if(arr!=NULL)
{
unsigned char *head;//博客中是void *head版本,但编译都通过不了,改成unsigned char* 后编译通过,但不明白运行结果为什么不对
head=(unsigned char *)arr+indexsize;
memset(arr,0,indexsize+totalsize);
for(int i=0;i<row;i++)
arr[i]=head+size*i*col;
}
return arr;
}
void free2d(void **arr)
{
if(arr!=NULL)
free(arr);
}
//第二中方法,分配连续空间,C++的实现版,
template <typename T>
T **darray_new(int row, int col)
{
int size=sizeof(T);
void **arr=(void **) malloc(sizeof(void *) * row + size * row * col);
if (arr != NULL)
{
unsigned char * head;
head=(unsigned char *) arr + sizeof(void *) * row;
for (int i=0; i<row; ++i)
{
arr[i]= head + size * i * col;
for (int j=0; j<col; ++j)
new (head + size * (i * col + j)) T;//这一句比较有意思,想一想为什么?
}
}
return (T**) arr;
}
template <typename T>
void darray_free(T **arr, int row, int col)//注意要一个一个delete了,蛋疼,不过对于自定义的数据类型,很有必要
{
for (int i=0; i<row; ++i)
for (int j=0; j<col; ++j)
arr[i][j].~T();//这是什么玩意儿?!模板析构?因为使用了new?所以用析构函数的delete?
if (arr != NULL)
free((void **)arr);
}
int _tmain(int argc, _TCHAR* argv[])
{
//一维数组动态分配
//int n;
//cin>>n;
////int *p=new int[n];//一维数组动态分配方法一
//int *p=(int*)malloc(n*sizeof(int));//一维数组动态分配方法二
//for(int i=0;i<n;i++)
// cin>>p[i];
//cout<<endl;
//for(int i=0;i<n;i++)
// cout<<p[i]<<" ";
//二维变长数组的动态分配,本人喜欢这种方法,虽然空间不连续,但同样可以进行p[i][j]的寻址,为什么博客中特意写上面介绍的函数来实现还没找到太好的理由
//int n;
//cin>>n;
//int *p[2];
//p[0]=new int[n];
//p[1]=new int[n+1];
//for(int i=0;i<n;i++)
// cin>>p[0][i];
//cout<<&p[0]<<" "<<&p[1]<<endl;//p[0],p[1]是连续的
//cout<<&p[0]<<" "<<&p[0][0]<<" "<<&p[0][1]<<endl;//p[0]!=p[0][0],但p[0][0],p[0][1]是连续的
////C版本的,分配连续空间
//int**m=(int**)malloc2d(5,5,sizeof(int));
//int i,j;
//for( i=0;i<5;i++) //void* 泛型指针,有待剖析
// for( j=0;j<5;j++)
// m[i][j]=0;
//for( i=0;i<5;i++)
//{
// for( j=0;j<5;j++)
// cout<<m[i][j]<<" ";
// cout<<endl;
//}
//free2d((void**)m);
int** m=darray_new<int>(5,5);//注意模板函数怎么实现的 <int>!
int i,j;
for( i=0;i<5;i++)
for( j=0;j<5;j++)
m[i][j]=1;
for( i=0;i<5;i++)
{
for( j=0;j<5;j++)
cout<<m[i][j]<<" ";
cout<<endl;
}
darray_free(m,5,5);
return 0;
}
</span>










