??xml version="1.0" encoding="utf-8" standalone="yes"?>国产午夜电影久久,亚洲精品乱码久久久久久按摩,无码AV波多野结衣久久http://www.shnenglu.com/hyjune/category/7123.html专注ZLinux嵌入式系l的学习和研I?/description>zh-cnThu, 22 May 2008 08:34:16 GMTThu, 22 May 2008 08:34:16 GMT60[转]l典收藏?- C语言~程要点http://www.shnenglu.com/hyjune/articles/50769.html赉|v?/dc:creator>赉|v?/author>Thu, 22 May 2008 07:34:00 GMThttp://www.shnenglu.com/hyjune/articles/50769.htmlhttp://www.shnenglu.com/hyjune/comments/50769.htmlhttp://www.shnenglu.com/hyjune/articles/50769.html#Feedback0http://www.shnenglu.com/hyjune/comments/commentRss/50769.htmlhttp://www.shnenglu.com/hyjune/services/trackbacks/50769.html阅读全文

]]>
[转]l典收藏?- C++内存理详解http://www.shnenglu.com/hyjune/articles/50762.html赉|v?/dc:creator>赉|v?/author>Thu, 22 May 2008 06:54:00 GMThttp://www.shnenglu.com/hyjune/articles/50762.htmlhttp://www.shnenglu.com/hyjune/comments/50762.htmlhttp://www.shnenglu.com/hyjune/articles/50762.html#Feedback0http://www.shnenglu.com/hyjune/comments/commentRss/50762.htmlhttp://www.shnenglu.com/hyjune/services/trackbacks/50762.htmlfrom: http://dev.csdn.net/author/xpzhang/5f58e10eec1a4b76bd58ff37f05d30fb.html

伟大的Bill Gates 曄pQ?br>
  640K ought to be enough for everybody ?Bill Gates 1981

  E序员们l常~写内存理E序Q往往提心吊胆。如果不惌P唯一的解军_法就是发现所有潜伏的地雷q且排除它们Q躲是躲不了的。本文的内容比一般教U书的要深入得多Q读者需l心阅读Q做到真正地通晓内存理?br>
  1、内存分配方?/strong>

  内存分配方式有三U:

  Q?Q从静态存储区域分配。内存在E序~译的时候就已经分配好,q块内存在程序的整个q行期间都存在。例如全局变量Qstatic变量?br>
  Q?Q在栈上创徏。在执行函数Ӟ函数内局部变量的存储单元都可以在栈上创徏Q函数执行结束时q些存储单元自动被释放。栈内存分配q算内置于处理器的指令集中,效率很高Q但是分配的内存定w有限?br>
  Q?Q?从堆上分配,亦称动态内存分配。程序在q行的时候用malloc或new甌L多少的内存,E序员自p责在何时用free或delete释放内存。动态内存的生存期由我们军_Q用非常灵z,但问题也最多?br>
  2、常见的内存错误及其对策

  发生内存错误是g非常ȝ的事情。编译器不能自动发现q些错误Q通常是在E序q行时才能捕捉到。而这些错误大多没有明昄症状Q时隐时玎ͼ增加了改错的隑ֺ。有时用h气冲冲地把你找来,E序却没有发生Q何问题,你一赎ͼ错误又发作了?常见的内存错误及其对{如下:

  * 内存分配未成功,却用了它?br>
  ~程新手常犯q种错误Q因Z们没有意识到内存分配会不成功。常用解军_法是Q在使用内存之前查指针是否ؓNULL。如果指针p是函数的参数Q那么在函数的入口处用assert(p!=NULL)q行

  查。如果是用malloc或new来申请内存,应该用if(p==NULL) 或if(p!=NULL)q行防错处理?br>
  * 内存分配虽然成功Q但是尚未初始化引用它?br>
犯这U错误主要有两个起因Q一是没有初始化的观念;二是误以为内存的~省初值全为零Q导致引用初值错误(例如数组Q? 内存的缺省初值究竟是什么ƈ没有l一的标准,管有些时候ؓ零|我们宁可信其无不可信其有。所以无论用何种方式创徏数组Q都别忘了赋初|即便是赋零? 也不可省略,不要嫌麻烦?br>
  * 内存分配成功q且已经初始化,但操作越q了内存的边界?br>
  例如在用数l时l常发生下标“?”或?#8220;?”的操作。特别是在for循环语句中,循环ơ数很容易搞错,D数组操作界?br>
  * 忘记了释攑ֆ存,造成内存泄露?br>
  含有q种错误的函数每被调用一ơ就丢失一块内存。刚开始时pȝ的内存充I你看不到错误。终有一ơ程序突然死掉,pȝ出现提示Q内存耗尽?br>
  动态内存的甌与释攑ֿ配对,E序中malloc与free的用次C定要相同Q否则肯定有错误Qnew/delete同理Q?br>
  * 释放了内存却l箋使用它?br> 
  有三U情况:

  Q?Q程序中的对象调用关p过于复杂,实在难以搞清楚某个对象究竟是否已l释放了内存Q此时应该重新设计数据结构,从根本上解决对象理的؜乱局面?br>
  Q?Q函数的return语句写错了,注意不要q回指向“栈内?#8221;?#8220;指针”或?#8220;引用”Q因内存在函Cl束时被自动销毁?br>
  Q?Q用free或delete释放了内存后Q没有将指针讄为NULL。导致?#8220;野指?#8221;?br>
  【规?】用malloc或new甌内存之后Q应该立x查指针值是否ؓNULL。防止用指针gؓNULL的内存?br>
  【规?】不要忘Cؓ数组和动态内存赋初倹{防止将未被初始化的内存作ؓ叛_g用?br>
  【规?】避免数l或指针的下标越界,特别要当心发?#8220;?”或?#8220;?”操作?br>
  【规?】动态内存的甌与释攑ֿ配对,防止内存泄漏?br>
  【规?】用free或delete释放了内存之后,立即指针设|ؓNULLQ防止?#8220;野指?#8221;?br>
  3、指针与数组的对?/strong>

  C++/CE序中,指针和数l在不少地方可以怺替换着用,让h产生一U错觉,以ؓ两者是{h的?br>
  数组要么在静态存储区被创建(如全局数组Q,要么在栈上被创徏。数l名对应着Q而不是指向)一块内存,其地址与容量在生命期内保持不变Q只有数l的内容可以改变?br>
  指针可以随时指向Lcd的内存块Q它的特征是“可变”Q所以我们常用指针来操作动态内存。指针远比数l灵z,但也更危险?br>
  下面以字W串Z比较指针与数l的Ҏ?br>
  3.1 修改内容

CZ3-1中,字符数组a的容量是6个字W,其内容ؓhello。a的内容可以改变,如a[0]= ‘X’。指针p指向帔R字符?#8220;world”Q位于静态存储区Q内容ؓworldQ,帔R字符串的内容是不可以被修改的。从语法上看Q编译器q不觉得语句 p[0]= ‘X’有什么不妥,但是该语句企图修改常量字W串的内容而导致运行错误?br>

char a[] = “hello”;
a[0] = ‘X’;
cout << a << endl;
char *p = “world”; // 注意p指向帔R字符?br>p[0] = ‘X’; // ~译器不能发现该错误
cout << p << endl;
CZ3.1 修改数组和指针的内容

  3.2 内容复制与比?br>
  不能Ҏl名q行直接 复制与比较。示?-3-2中,若想把数la的内容复制给数组bQ不能用语句 b = a Q否则将产生~译错误。应该用标准库函数strcpyq行复制。同理,比较b和a的内Ҏ否相同,不能用if(b==a) 来判断,应该用标准库函数strcmpq行比较?br>
  语句p = a q不能把a的内容复制指针pQ而是把a的地址赋给了p。要惛_制a的内容,可以先用库函数malloc为p甌一块容量ؓstrlen(a)+1个字W的 内存Q再用strcpyq行字符串复制。同理,语句if(p==a) 比较的不是内容而是地址Q应该用库函数strcmp来比较?br>
// 数组…
char a[] = "hello";
char b[10];
strcpy(b, a); // 不能?b = a;
if(strcmp(b, a) == 0) // 不能?if (b == a)

// 指针…
int len = strlen(a);
char *p = (char *)malloc(sizeof(char)*(len+1));
strcpy(p,a); // 不要?p = a;
if(strcmp(p, a) == 0) // 不要?if (p == a)
CZ3.2 数组和指针的内容复制与比?br>
  3.3 计算内存定w

  用运符 sizeof可以计算出数l的定wQ字节数Q。示?-3-3QaQ中Qsizeof(a)的值是12Q注意别忘了’’Q。指针p指向aQ但? sizeof(p)的值却?。这是因为sizeof(p)得到的是一个指针变量的字节敎ͼ相当于sizeof(char*)Q而不是p所指的内存定w? C++/C语言没有办法知道指针所指的内存定wQ除非在甌内存时记住它?br>
  注意当数l作为函数的参数q行传递时Q该数组自动退化ؓ同类型的指针。示?-3-3QbQ中Q不论数la的容量是多少Qsizeof(a)始终{于sizeof(char *)?br>
char a[] = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12字节
cout<< sizeof(p) << endl; // 4字节
CZ3.3QaQ?计算数组和指针的内存定w

void Func(char a[100])
{
 cout<< sizeof(a) << endl; // 4字节而不?00字节
}

     CZ3.3QbQ?数组退化ؓ指针

  4、指针参数是如何传递内存的Q?br>
  如果函数的参数是一个指针,不要指望用该指针ȝ请动态内存。示?-4-1中,Test函数的语句GetMemory(str, 200)q没有str获得期望的内存,str依旧是NULLQؓ什么?

void GetMemory(char *p, int num)
{
 p = (char *)malloc(sizeof(char) * num);
}
void Test(void)
{
 char *str = NULL;
 GetMemory(str, 100); // str 仍然?NULL
 strcpy(str, "hello"); // q行错误
}
CZ4.1 试图用指针参数申请动态内?br>
  毛病出在函数GetMemory中。编译器L要ؓ函数的每 个参数制作时副本,指针参数p的副本是 _pQ编译器?_p = p。如果函C内的E序修改了_p的内容,导致参数p的内容作相应的修攏V这是指针可以用作输出参数的原因。在本例中,_p甌了新的内存,只是? _p所指的内存地址改变了,但是p丝毫未变。所以函数GetMemoryq不能输ZQ何东ѝ事实上Q每执行一ơGetMemory׃泄露一块内存,? 为没有用free释放内存?br>
  如果非得要用指针参数ȝ请内存,那么应该改用“指向指针的指?#8221;Q见CZ4.2?br>
void GetMemory2(char **p, int num)
{
 *p = (char *)malloc(sizeof(char) * num);
}
void Test2(void)
{
 char *str = NULL;
 GetMemory2(&str, 100); // 注意参数?&strQ而不是str
 strcpy(str, "hello");
 cout<< str << endl;
 free(str);
}
CZ4.2用指向指针的指针甌动态内?br>
  ׃“指向指针的指?#8221;q个概念不容易理解,我们可以用函数返回值来传递动态内存。这U方法更加简单,见示?.3?br>
char *GetMemory3(int num)
{
 char *p = (char *)malloc(sizeof(char) * num);
 return p;
}
void Test3(void)
{
 char *str = NULL;
 str = GetMemory3(100);
 strcpy(str, "hello");
 cout<< str << endl;
 free(str);
}
CZ4.3 用函数返回值来传递动态内?br>
  用函数返回值来传递动态内存这U方法虽然好用,但是常常有h把return语句用错了。这里强调不要用return语句q回指向“栈内?#8221;的指针,因ؓ该内存在函数l束时自动消亡,见示?.4?br>
char *GetString(void)
{
 char p[] = "hello world";
 return p; // ~译器将提出警告
}
void Test4(void)
{
 char *str = NULL;
 str = GetString(); // str 的内Ҏ垃圾
 cout<< str << endl;
}
CZ4.4 return语句q回指向“栈内?#8221;的指?br>
  用调试器逐步跟踪Test4Q发现执行str = GetString语句后str不再是NULL指针Q但是str的内容不?#8220;hello world”而是垃圾?br>如果把示?.4改写成示?.5Q会怎么P

char *GetString2(void)
{
 char *p = "hello world";
 return p;
}
void Test5(void)
{
 char *str = NULL;
 str = GetString2();
 cout<< str << endl;
}
CZ4.5 return语句q回帔R字符?br>
  函数Test5q行虽然不会出错Q但是函? GetString2的设计概念却是错误的。因为GetString2内的“hello world”是常量字W串Q位于静态存储区Q它在程序生命期内恒定不变。无Z么时候调用GetString2Q它q回的始l是同一?#8220;只读”的内存块?br>
  5、杜l?#8220;野指?#8221;

  “野指?#8221;不是NULL指针Q是指向“垃圾”内存的指针。h们一般不会错用NULL指针Q因为用if语句很容易判断。但?#8220;野指?#8221;是很危险的,if语句对它不v作用?“野指?#8221;的成因主要有两种Q?br>
  Q?Q指针变量没有被初始化。Q何指针变量刚被创建时不会自动成ؓNULL指针Q它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化Q要么将指针讄为NULLQ要么让它指向合法的内存。例?br>
char *p = NULL;
char *str = (char *) malloc(100);

  Q?Q指针p被free或者delete之后Q没有置为NULLQ让以ؓp是个合法的指针?br>
  Q?Q指针操作超了变量的作用范围。这U情况让人防不胜ԌCZE序如下Q?br>
class A
{
 public:
  void Func(void){ cout << “Func of class A” << endl; }
};
void Test(void)
{
 A *p;
 {
  A a;
  p = &a; // 注意 a 的生命期
 }
 p->Func(); // p?#8220;野指?#8221;
}


  函数Test在执行语句p->Func()Ӟ对象a已经消失Q而p是指向a的,所以p成?#8220;野指?#8221;。但奇怪的是我q行q个E序时居然没有出错,q可能与~译器有兟?/p>

  6、有了malloc/freeZ么还要new/deleteQ?br>
  malloc与free是C++/C语言的标准库函数Qnew/delete是C++的运符。它们都可用于申请动态内存和释放内存?br>
对于非内部数据类型的对象而言Q光用maloc/free无法满动态对象的要求。对象在创徏的同时要自动执行构造函敎ͼ对象在消亡之前要自动执行析构 函数。由于malloc/free是库函数而不是运符Q不在编译器控制权限之内Q不能够把执行构造函数和析构函数的Q务强加于malloc/free?br>
因此C++语言需要一个能完成动态内存分配和初始化工作的q算WnewQ以及一个能完成清理与释攑ֆ存工作的q算Wdelete。注? new/delete不是库函数。我们先看一看malloc/free和new/delete如何实现对象的动态内存管理,见示??br>

class Obj
{
 public :
  Obj(void){ cout << “Initialization” << endl; }
  ~Obj(void){ cout << “Destroy” << endl; }
  void Initialize(void){ cout << “Initialization” << endl; }
  void Destroy(void){ cout << “Destroy” << endl; }
};
void UseMallocFree(void)
{
 Obj *a = (obj *)malloc(sizeof(obj)); // 甌动态内?br> a->Initialize(); // 初始?br> //…
 a->Destroy(); // 清除工作
 free(a); // 释放内存
}
void UseNewDelete(void)
{
 Obj *a = new Obj; // 甌动态内存ƈ且初始化
 //…
 delete a; // 清除q且释放内存
}
CZ6 用malloc/free和new/delete如何实现对象的动态内存管?br>
  cObj的函? Initialize模拟了构造函数的功能Q函数Destroy模拟了析构函数的功能。函数UseMallocFree中,׃malloc/free? 能执行构造函C析构函数Q必调用成员函数Initialize和Destroy来完成初始化与清除工作。函数UseNewDelete则简单得多?br>
  所以我们不要企囄malloc/free来完成动态对象的内存理Q应该用new/delete。由于内部数据类型的“对象”没有构造与析构的过E,对它们而言malloc/free和new/delete是等L?br>
  既然new/delete的功能完全覆盖了malloc/freeQؓ什么C++不把malloc/free淘汰出局呢?q是因ؓC++E序l常要调用C函数Q而CE序只能用malloc/free理动态内存?br>
如果用free释放“new创徏的动态对?#8221;Q那么该对象因无法执行析构函数而可能导致程序出错。如果用delete释放“malloc甌的动态内? ”Q理Z讲程序不会出错,但是该程序的可读性很差。所以new/delete必须配对使用Qmalloc/free也一栗?br>
  7、内存耗尽怎么办?

  如果在申请动态内存时找不到够大的内存块Qmalloc和new返回NULL指针Q宣告内存申请失败。通常有三U方式处?#8220;内存耗尽”问题?br>
  Q?Q判断指针是否ؓNULLQ如果是则马上用return语句l止本函数。例如:

void Func(void)
{
 A *a = new A;
 if(a == NULL)
 {
  return;
 }
 …
}

  Q?Q判断指针是否ؓNULLQ如果是则马上用exit(1)l止整个E序的运行。例如:

void Func(void)
{
 A *a = new A;
 if(a == NULL)
 {
  cout << “Memory Exhausted” << endl;
  exit(1);
 }
 …
}

  Q?Qؓnew和malloc讄异常处理函数。例如Visual C++可以用_set_new_hander函数为new讄用户自己定义的异常处理函敎ͼ也可以让malloc享用与new相同的异常处理函数。详l内容请参考C++使用手册?br>
  上述Q?Q(2Q方式用最普遍。如果一个函数内有多处需要申请动态内存,那么方式Q?Q就昑־力不从心Q释攑ֆ存很ȝQ,应该用方式(2Q来处理?br>
  很多Z忍心用exit(1)Q问Q?#8220;不编写出错处理程序,让操作系l自p册不行Q?#8221;

  不行。如果发?#8220;内存耗尽”q样的事情,一般说来应用程序已l无药可救。如果不用exit(1) 把坏E序杀死,它可能会x操作pȝ。道理如同:如果不把歹徒LQ歹徒在老死之前会犯下更多的|?br>
有一个很重要的现象要告诉大家。对?2位以上的应用E序而言Q无论怎样使用malloc与newQ几乎不可能D“内存耗尽”。我在Windows 98下用Visual C++~写了测试程序,见示?。这个程序会无休止地q行下去Q根本不会终止。因?2位操作系l支?#8220;虚存”Q内存用完了Q自动用盘I间替。我只听 到硬盘嘎吱嘎吱地响,Window 98已经累得寚w盘、鼠标毫无反应?br>
  我可以得么一个结论:对于32位以上的应用E序Q?#8220;内存耗尽”错误处理E序毫无用处。这下可把Unix和WindowsE序员们乐坏了:反正错误处理E序不v作用Q我׃写了Q省了很多麻烦?br>
  我不惌D者,必须Q不加错误处理将DE序的质量很差,千万不可因小失大?br>
void main(void)
{
 float *p = NULL;
 while(TRUE)
 {
  p = new float[1000000];
  cout << “eat memory” << endl;
  if(p==NULL)
   exit(1);
 }
}


  CZ7试图耗尽操作pȝ的内?/p>

  8、malloc/free 的用要?br>
  函数malloc的原型如下:

void * malloc(size_t size);

  用malloc甌一块长度ؓlength的整数类型的内存Q程序如下:

int *p = (int *) malloc(sizeof(int) * length);

  我们应当把注意力集中在两个要素上Q?#8220;cd转换”?#8220;sizeof”?br>
  * mallocq回值的cd是void *Q所以在调用malloc时要昑ּ地进行类型{换,void * 转换成所需要的指针cd?br>
* malloc函数本nq不识别要申L内存是什么类型,它只兛_内存的d节数。我们通常C住int, float{数据类型的变量的确切字节数。例如int变量?6位系l下?个字节,?2位下?个字节;而float变量?6位系l下?个字节, ?2位下也是4个字节。最好用以下E序作一ơ测试:

cout << sizeof(char) << endl;
cout << sizeof(int) << endl;
cout << sizeof(unsigned int) << endl;
cout << sizeof(long) << endl;
cout << sizeof(unsigned long) << endl;
cout << sizeof(float) << endl;
cout << sizeof(double) << endl;
cout << sizeof(void *) << endl;

  在malloc?#8220;()”中用sizeofq算W是良好的风|但要当心有时我们会昏了头Q写?p = malloc(sizeof(p))q样的程序来?br>
  * 函数free的原型如下:

void free( void * memblock );

  Z么free函数不象malloc函数那样复杂呢?q是因ؓ指针p的类型以及它所指的内存的容量事先都是知道的Q语句free(p)能正? 地释攑ֆ存。如果p是NULL指针Q那么free对p无论操作多少ơ都不会出问题。如果p不是NULL指针Q那么free对pq箋操作两次׃DE序q? 行错误?br>
  9、new/delete 的用要?/strong>

  q算Wnew使用h要比函数malloc单得多,例如Q?br>
int *p1 = (int *)malloc(sizeof(int) * length);
int *p2 = new int[length];

  q是因ؓnew内置了sizeof、类型{换和cd安全查功能。对于非内部数据cd的对象而言Qnew在创建动态对象的同时完成了初始化工作。如果对象有多个构造函敎ͼ那么new的语句也可以有多UŞ式。例?br>
class Obj
{
 public :
  Obj(void); // 无参数的构造函?br>  Obj(int x); // 带一个参数的构造函?br>  …
}
void Test(void)
{
 Obj *a = new Obj;
 Obj *b = new Obj(1); // 初gؓ1
 …
 delete a;
 delete b;
}

  如果用new创徏对象数组Q那么只能用对象的无参数构造函数。例?br>
Obj *objects = new Obj[100]; // 创徏100个动态对?/td>

  不能写成

Obj *objects = new Obj[100](1);// 创徏100个动态对象的同时赋初?

  在用delete释放对象数组Ӟ留意不要丢了W号‘[]’。例?br>
delete []objects; // 正确的用?br>delete objects; // 错误的用?/td>

  后者相当于delete objects[0]Q漏掉了另外99个对象?br>
  10、一些心得体?/strong>

我认识不技术不错的C++/CE序员,很少有h能拍拍胸脯说通晓指针与内存管理(包括我自己)。我最初学习C语言时特别怕指针,D我开发第一个应? 软gQ约1万行C代码Q时没有使用一个指针,全用数组来顶替指针,实在蠢笨得过分。躲避指针不是办法,后来我改写了q个软gQ代码量~小到原先的一半?br>
  我的l验教训是:

  Q?Q越是怕指针,p要用指针。不会正用指针,肯定不上是合格的程序员?br>
  Q?Q必d?#8220;使用调试器逐步跟踪E序”的习惯,只有q样才能发现问题的本质?img src ="http://www.shnenglu.com/hyjune/aggbug/50762.html" width = "1" height = "1" />

]]>
99þùۺϾƷ| ҹþþþþýӰ| 91þþƷӰ| þþþavӰ | ɫݺݾþAVۺ| þ޾ƷAV| ҹþӰԺ| þþþ޾Ʒվ | þþþùƷ| 뾫ƷþѼ| þþþ18| ˾þþƷһ| þþƷAɫ| ˾þav| ݺɫ˾þþƷۺ| Ʒþþþþ | ˾þô߽| Ʒþˬۺ| þþþAVƬ| þþþùƷ| ԴӰȷþԴ| þҹ³˿Ƭϼ | ɫۺϾþ88ɫۺ| ˾þþƷӰԺ| һɫۺϾþ| ŷҹƷþþþþ˳| 91Ʒ91Ⱦþþþø | þùƷ-þþƷ| ޵һƷƷþ| ҹƷþþþþ˳| ƷѾþþþùһ| þ×Ʒþþþþ| þҹɫƷվ| һɫþ99һۺ| þ99ù龫Ʒ66| þþ뾫Ʒպý | ݹƷþþþ| þ99Ʒһ| ŷһþ| þþþþҹӰԺ| ޾ƷþþþþðĦ|