﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-依睛(IT blog) 我回来了，PHP&lt;--&gt;C/C++ LINUX</title><link>http://www.cnitblog.com/guopingleee/</link><description>笨鸟
</description><language>zh-cn</language><lastBuildDate>Wed, 29 Apr 2026 05:57:39 GMT</lastBuildDate><pubDate>Wed, 29 Apr 2026 05:57:39 GMT</pubDate><ttl>60</ttl><item><title>Fedora 11安裝 Apache+PHP+MySql</title><link>http://www.cnitblog.com/guopingleee/archive/2009/11/24/62791.html</link><dc:creator>向左向右走</dc:creator><author>向左向右走</author><pubDate>Tue, 24 Nov 2009 03:58:00 GMT</pubDate><guid>http://www.cnitblog.com/guopingleee/archive/2009/11/24/62791.html</guid><wfw:comment>http://www.cnitblog.com/guopingleee/comments/62791.html</wfw:comment><comments>http://www.cnitblog.com/guopingleee/archive/2009/11/24/62791.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/guopingleee/comments/commentRss/62791.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/guopingleee/services/trackbacks/62791.html</trackback:ping><description><![CDATA[源地址：	
http://www.txtbar.cn/?p=403




	<pre>

Fedora 11安裝 Apache+PHP+MySql
[root@fedora ~]# yum install httpd mysql-server php php-devel php-mysql
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
mysql-server i586 5.1.36-1.fc11 updates 11 M
php-devel i586 5.2.9-2.fc11 fedora 583 k
Installing for dependencies:
autoconf noarch 2.63-2.fc11 fedora 941 k
automake noarch 1.11-2.fc11 updates 579 k
mysql i586 5.1.36-1.fc11 updates 3.7 M
perl-DBD-MySQL i586 4.010-1.fc11 fedora 171 k
perl-DBI i586 1.607-2.fc11 fedora 782 k

Transaction Summary
================================================================================
Install 7 Package(s) 
Update 0 Package(s) 
Remove 0 Package(s) 
Total download size: 17 M

Is this ok [y/N]: y
 




<strong>第二步</strong>

LAMP是Linux, Apache, MySQL, PHP的缩写.这篇教程将教你如何在一台Fedora 11服务器上安装Apache2web服务器+PHP(mod_php) +MySQL .

我已经测试无误，你可以放心使用。

1. 前言
在这篇教程中，我使用的主机名为server1.example.com，ip地址是192.168.0.100。这些设置可能与你想要的有所不同，所以你必须在适当的地方修改一下。


2 安装MySQL5
用下列命令安装MySQL：

yum install mysql mysql-server

然后我们为MySQL创建系统启动链接（这样的话，MySQL就会随着系统启动而启动），并启动MySQL服务器：

chkconfig –levels 235 mysqld on
/etc/init.d/mysqld start

运行

mysqladmin -u root password yourrootsqlpassword
mysqladmin -h server1.example.com -u root password yourrootsqlpassword

来为root用户设置一个密码（否则任何人都可以访问你的MySQL数据库！）

3 安装Apache2
Fedora默认有Apache2这个包，我们可以用下列命令安装它：

yum install httpd

现在配置下系统使得Apache能够随着系统启动而启动…

chkconfig –levels 235 httpd on

… 启动Apache:

/etc/init.d/httpd start

现在打开浏览器，访问http://192.168.0.100，你就应该能看到Apache2的预留页了：



在Fedora中Apache的默认文档路径在/var/www/html，配置文件是/etc/httpd/conf/httpd.conf。其余的配置文件存储在/etc/httpd/conf.d/。


4 安装PHP5

我们用下列命令安装PHP5和Apache PHP5模块：

yum install php

然后我们启动下Apache：

/etc/init.d/httpd restart


5 测试PHP5/获取PHP5安装后的详细信息

网站的默认文档路径是/var/www/html。我们现在在这个文件夹中创建一个小型PHP(info.php)文件，并在；浏览器中访问它。这个文件会显示关于PHP安装的大量的细节，例如PHP的版本。

vi /var/www/html/info.php

<?php 

phpinfo();

???>

现在我们在浏览器中访问这个文件(例如http://192.168.0.100/info.php)：




正如你所看到的一样，PHP5已经正常工作了，并且在Server API这一行中显示的Apache是以Apache2.0 Handler模式工作的。如果你向下翻页，你将会看到已经安装了PHP5的所有的模块。MySQL没有在这里列出来，也就意味着目前PHP5并不支持MySQL。

6 让PHP5支持MySQL
我们安装php-mysql这个包既可以使MySQL支持php了。在这里最好也安装其他的PHP5模块，这些模块也许你会在其他的应用中用到。你可以使用下列明星先搜索一下PHP5的模块：

yum search php

选取你需要的模块，并使用下列命令安装它们：

yum install php-mysql php-gd php-imap php-ldap php-odbc php-pear php-xml php-xmlrpc php-eaccelerator php-magickwand php-magpierss php-mapserver php-mbstring php-mcrypt php-mhash php-mssql php-shout php-snmp php-soap php-tidy

现在重启Apache2:

/etc/init.d/httpd restart

现在在浏览器中刷新http://192.168.0.100/info.php，并再次翻到模块部分。你就应该能在这里找到很多新模块，其中就包括了MySQL模块：



7 phpMyAdmin
phpMyAdmin是一款可以web化管理MySQL数据库的工具：

可以使用下列命令安装phpmyadmin：

yum install phpmyadmin

现在我们配置phpMyAdmin。我们改变Apache的配置文件让其只能通过本地访问（通过注销

#   order deny,allow

#   deny from all

#   allow from 127.0.0.1

#   allow from ::1

#

# This directory does not require access over HTTP – taken from the original

# phpMyAdmin upstream tarball

#



Order Deny,Allow

Deny from All

Allow from None



# This configuration prevents mod_security at phpMyAdmin directories from

# filtering SQL etc.  This may break your mod_security implementation.

#

#<ifmodule mod_security.c="">

#    

#        SecRuleInheritance Off

#    

#</ifmodule>

重启Apache:

/etc/init.d/httpd restart

然后,你就可以通过http://192.168.0.100/phpmyadmin/:访问phpMyAdmin了 ：



8 相关链接
Apache: http://httpd.apache.org/ 
PHP: http://www.php.net/ 
MySQL: http://www.mysql.com/ 
Fedora: http://fedoraproject.org/ 
phpMyAdmin: http://www.phpmyadmin.net/ 





</pre><img src ="http://www.cnitblog.com/guopingleee/aggbug/62791.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/guopingleee/" target="_blank">向左向右走</a> 2009-11-24 11:58 <a href="http://www.cnitblog.com/guopingleee/archive/2009/11/24/62791.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>linux fedora 11 flash安装</title><link>http://www.cnitblog.com/guopingleee/archive/2009/11/24/62787.html</link><dc:creator>向左向右走</dc:creator><author>向左向右走</author><pubDate>Tue, 24 Nov 2009 02:45:00 GMT</pubDate><guid>http://www.cnitblog.com/guopingleee/archive/2009/11/24/62787.html</guid><wfw:comment>http://www.cnitblog.com/guopingleee/comments/62787.html</wfw:comment><comments>http://www.cnitblog.com/guopingleee/archive/2009/11/24/62787.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/guopingleee/comments/commentRss/62787.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/guopingleee/services/trackbacks/62787.html</trackback:ping><description><![CDATA[
 到linux fedora 11下打开这个网址  http://get.adobe.com/flashplayer/

进入这个网站下有选项

.rm for linux 

然后按Agree and install now

这就可以有个下载包了，就这样下载
用命令是root管理员安装
用命令进入下载文件路径下
输入下命令：

#: rpm -ivh flash-plugin-10.0.32.18-release.i386.rpm

完成再进下一个命令：


  #：rpm -qpl flash-plugin-10.0.32.18-release.i386.rpm

程序进行中了
    /usr/lib/flash-plugin
    /usr/lib/flash-plugin/LICENSE
    /usr/lib/flash-plugin/README
    /usr/lib/flash-plugin/homecleanup
    /usr/lib/flash-plugin/libflashplayer.so
    /usr/lib/flash-plugin/setup
    /usr/share/doc/flash-plugin-10.0.32.18
    /usr/share/doc/flash-plugin-10.0.32.18/readme.txt



源地址：http://yangtai.blog.51cto.com/334569/197107




    重启，结果可以使用了。转载的资料<img src ="http://www.cnitblog.com/guopingleee/aggbug/62787.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/guopingleee/" target="_blank">向左向右走</a> 2009-11-24 10:45 <a href="http://www.cnitblog.com/guopingleee/archive/2009/11/24/62787.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>linux fedora 11 flash 安装说明</title><link>http://www.cnitblog.com/guopingleee/archive/2009/11/24/62786.html</link><dc:creator>向左向右走</dc:creator><author>向左向右走</author><pubDate>Tue, 24 Nov 2009 02:44:00 GMT</pubDate><guid>http://www.cnitblog.com/guopingleee/archive/2009/11/24/62786.html</guid><wfw:comment>http://www.cnitblog.com/guopingleee/comments/62786.html</wfw:comment><comments>http://www.cnitblog.com/guopingleee/archive/2009/11/24/62786.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/guopingleee/comments/commentRss/62786.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/guopingleee/services/trackbacks/62786.html</trackback:ping><description><![CDATA[ 到linux fedora 11下打开这个网址  http://get.adobe.com/flashplayer/

进入这个网站下有选项

.rm for linux 

然后按Agree and install now

这就可以有个下载包了，就这样下载
用命令是root管理员安装
用命令进入下载文件路径下
输入下命令：

#: rpm -ivh flash-plugin-10.0.32.18-release.i386.rpm

完成再进下一个命令：


  #：rpm -qpl flash-plugin-10.0.32.18-release.i386.rpm

程序进行中了
    /usr/lib/flash-plugin
    /usr/lib/flash-plugin/LICENSE
    /usr/lib/flash-plugin/README
    /usr/lib/flash-plugin/homecleanup
    /usr/lib/flash-plugin/libflashplayer.so
    /usr/lib/flash-plugin/setup
    /usr/share/doc/flash-plugin-10.0.32.18
    /usr/share/doc/flash-plugin-10.0.32.18/readme.txt

    重启，结果可以使用了。转载的资料<img src ="http://www.cnitblog.com/guopingleee/aggbug/62786.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/guopingleee/" target="_blank">向左向右走</a> 2009-11-24 10:44 <a href="http://www.cnitblog.com/guopingleee/archive/2009/11/24/62786.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++内联函数与宏定义</title><link>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54625.html</link><dc:creator>向左向右走</dc:creator><author>向左向右走</author><pubDate>Mon, 16 Feb 2009 14:42:00 GMT</pubDate><guid>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54625.html</guid><wfw:comment>http://www.cnitblog.com/guopingleee/comments/54625.html</wfw:comment><comments>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54625.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/guopingleee/comments/commentRss/54625.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/guopingleee/services/trackbacks/54625.html</trackback:ping><description><![CDATA[
		<table style="BORDER-COLLAPSE: collapse; WORD-WRAP: break-word" cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td align="middle" height="25">
										<font style="FONT-SIZE: 14pt" color="#02368d">
												<b>C++内联函数与宏定义</b>
										</font>
										<br />
								</td>
						</tr>
						<tr>
								<td bgcolor="#d2dee2" height="1">
								</td>
						</tr>
						<tr>
								<td bgcolor="#ffffff" height="1">
								</td>
						</tr>
						<tr>
								<td align="middle">
										<table style="BORDER-COLLAPSE: collapse; WORD-WRAP: break-word" cellspacing="0" cellpadding="0" width="100%" border="0">
												<tbody>
														<tr>
																<td width="100%">
																		<div id="art" style="MARGIN: 15px" width="100%">
																				<p>
																						<strong>用内联取代宏：</strong>
																				</p>
																				<p style="COLOR: rgb(255,1,2)">
																						<strong>1.内联可调试；</strong>
																				</p>
																				<p style="COLOR: rgb(255,1,2)">
																						<strong>2.可进行类型安全检查或自动类型转换；</strong>
																				</p>
																				<p style="COLOR: rgb(255,1,2)">
																						<strong>3.可访问成员变量。</strong>
																				</p>
																				<p>
																						<strong>
																								<span style="COLOR: rgb(255,1,2)">另外，定义在类声明中的成员函数自动转化为内联函数。</span>
																								<br />
																						</strong>
																				</p>
																				<p>
																						<strong>文章（一）</strong>
																				</p>
																				<p>内联函数与宏定义<br />　　在C中，常用预处理语句#define来代替一个函数定义。例如：<br />　　　　#define MAX(a，b) ((a)&gt;(b)?(a):(b))<br />　　该语句使得程序中每个出现MAX(a,b)函数调用的地方都被宏定义中后面的表达式((a)&gt;(b)?(a):(b))所替换。</p>
																				<p>　　宏定义语句的书写格式有过分的讲究， MAX与括号之间不能有空格，所有的参数都要<br />　　放在括号里。尽管如此，它还是有麻烦：<br />　　　　int a=1，b=0；<br />　　　　MAX(a++,b)； //a被增值2次<br />　　　　MAX(a++,b+10)； //a被增值1次<br />　　　　MAX(a,"Hello")； //错误地比较int和字符串，没有参数类型检查<br />　　　　MAX( )函数的求值会由于两个参数值的大小不同而产生不同的副作用。<br />　　　　MAX(a++,b)的值为2，同时a的值为3；<br />　　　　MAX(a++,b+10)的值为10，同时a的值为2。<br />　　如果是普通函数，则MAX(a,"HellO")会受到函数调用的检查，但此处不会因为两个参数类型不同而被编译拒之门外。幸运的是，通过一个内联函数可以得到所有宏的替换效能和 所有可预见的状态以及常规函数的类型检查：<br />　　　　inline int MAX(int a，int b)<br />　　　　{<br />　　　　　return a&gt;b?a:b；<br />　　　　}</p>
																				<p>1.内联函数与宏的区别：</p>
																				<p>      传统的宏定义函数可能会引起一些麻烦。</p>
																				<p>      ex：</p>
																				<p>           #define F(x) x+x</p>
																				<p>           void main(){int i=1;F(i++);}</p>
																				<p>            这里x将被加两次。</p>
																				<p>        内联函数被编译器自动的用函数的形势添加进代码，而不会出现这种情况。</p>
																				<p>        内联函数的使用提高了效率（省去了很多函数调用汇编代码如：call和ret等）。</p>
																				<p>2.内联函数的使用：</p>
																				<p>         所有在类的声明中定义的函数将被自动认为是内联函数。</p>
																				<p>        class A()</p>
																				<p>       {</p>
																				<p>             void c();// not a inline function;</p>
																				<p>            void d(){ print("d() is a inline function.");}</p>
																				<p>        }</p>
																				<p>        如果想将一个全局函数定义为内联函数可用，inline 关键字。</p>
																				<p>        inline a(){print("a() is a inline function.");}</p>
																				<p>注意：</p>
																				<p>      在内联函数中如果有复杂操作将不被内联。如：循环和递归调用。</p>
																				<p>总结：</p>
																				<p>      将简单短小的函数定义为内联函数将会提高效率。</p>
																				<p>
																						<strong>文章（二）</strong>
																				</p>
																				<p>8.5.1 用内联取代宏代码 <br />C++ 语言支持函数内联，其目的是为了提高函数的执行效率（速度）。 <br />在 C程序中，可以用宏代码提高执行效率。宏代码本身不是函数，但使用起来象函数。预处理器用复制宏代码的方式代替函数调用，省去了参数压栈、生成汇编语言的 CALL调用、返回参数、执行return等过程，从而提高了速度。使用宏代码最大的缺点是容易出错，预处理器在复制宏代码时常常产生意想不到的边际效应。例如 <br />#define MAX(a, b)       (a) &gt; (b) ? (a) : (b) <br />语句  <br />result = MAX(i, j) + 2 ; <br />将被预处理器解释为 <br />result = (i) &gt; (j) ? (i) : (j) + 2 ; <br />由于运算符‘+’比运算符‘:’的优先级高，所以上述语句并不等价于期望的 <br />result = ( (i) &gt; (j) ? (i) : (j) ) + 2 ; <br />如果把宏代码改写为 <br />#define MAX(a, b)       ( (a) &gt; (b) ? (a) : (b) ) <br />则可以解决由优先级引起的错误。但是即使使用修改后的宏代码也不是万无一失的，例如语句 <br />result = MAX(i++, j); <br />将被预处理器解释为 <br />result = (i++) &gt; (j) ? (i++) : (j); <br />对于C++ 而言，使用宏代码还有另一种缺点：无法操作类的私有数据成员。 </p>
																				<p>让我们看看C++ 的“函数内联”是如何工作的。对于任何内联函数，编译器在符号表里放入函数的声明（包括名字、参数类型、返回值类型）。如果编译器没有发现内联函数存在错误，那么该函数的代码也被放入符号表里。在调用一个内联函数时，编译器首先检查调用是否正确（进行类型安全检查，或者进行自动类型转换，当然对所有的函数都一样）。如果正确，内联函数的代码就会直接替换函数调用，于是省去了函数调用的开销。这个过程与预处理有显著的不同，因为预处理器不能进行类型安全检查，或者进行自动类型转换。假如内联函数是成员函数，对象的地址（this）会被放在合适的地方，这也是预处理器办不到的。 <br />C++ 语言的函数内联机制既具备宏代码的效率，又增加了安全性，而且可以自由操作类的数据成员。所以在C++ 程序中，应该用内联函数取代所有宏代码，“断言assert”恐怕是唯一的例外。assert是仅在Debug版本起作用的宏，它用于检查“不应该”发生的情况。为了不在程序的Debug版本和Release版本引起差别，assert不应该产生任何副作用。如果assert是函数，由于函数调用会引起内存、代码的变动，那么将导致Debug版本与Release版本存在差异。所以assert不是函数，而是宏。（参见6.5节“使用断言”）<br />8.5.2 内联函数的编程风格 <br />关键字inline必须与函数定义体放在一起才能使函数成为内联，仅将inline放在函数声明前面不起任何作用。如下风格的函数Foo不能成为内联函数： <br />inline void Foo(int x, int y);  // inline仅与函数声明放在一起 <br />void Foo(int x, int y) <br />{ <br />… <br />} <br />而如下风格的函数Foo则成为内联函数： <br />void Foo(int x, int y);  <br />inline void Foo(int x, int y) // inline与函数定义体放在一起 <br />{ <br />… <br />} <br />所以说，inline是一种“用于实现的关键字”，而不是一种“用于声明的关键字”。一般地，用户可以阅读函数的声明，但是看不到函数的定义。尽管在大多数教科书中内联函数的声明、定义体前面都加了inline关键字，但我认为inline不应该出现在函数的声明中。这个细节虽然不会影响函数的功能，但是体现了高质量C++/C程序设计风格的一个基本原则：声明与定义不可混为一谈，用户没有必要、也不应该知道函数是否需要内联。 <br />定义在类声明之中的成员函数将自动地成为内联函数，例如 <br />class A <br />{ <br />public: <br />void Foo(int x, int y) { … }  // 自动地成为内联函数 <br />} <br />将成员函数的定义体放在类声明之中虽然能带来书写上的方便，但不是一种良好的编程风格，上例应该改成： <br />// 头文件 <br />class A <br />{ <br />public: <br />void Foo(int x, int y)；  <br />} <br />// 定义文件 <br />inline void A::Foo(int x, int y) <br />{ <br />… <br />} </p>
																				<p>8.5.3 慎用内联 <br />内联能提高函数的执行效率，为什么不把所有的函数都定义成内联函数？ <br />如果所有的函数都是内联函数，还用得着“内联”这个关键字吗？ <br />内联是以代码膨胀（复制）为代价，仅仅省去了函数调用的开销，从而提高函数的执行效率。如果执行函数体内代码的时间，相比于函数调用的开销较大，那么效率的收获会很少。另一方面，每一处内联函数的调用都要复制代码，将使程序的总代码量增大，消耗更多的内存空间。以下情况不宜使用内联： <br />（1）如果函数体内的代码比较长，使用内联将导致内存消耗代价较高。 <br />（2）如果函数体内出现循环，那么执行函数体内代码的时间要比函数调用的开销大。 <br />类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为，如“偷偷地”执行了基类或成员对象的构造函数和析构函数。所以不要随便地将构造函数和析构函数的定义体放在类声明中。 <br />一个好的编译器将会根据函数的定义体，自动地取消不值得的内联（这进一步说明了inline不应该出现在函数的声明中）。 <br />8.6 一些心得体会 <br />C++ 语言中的重载、内联、缺省参数、隐式转换等机制展现了很多优点，但是这些优点的背后都隐藏着一些隐患。正如人们的饮食，少食和暴食都不可取，应当恰到好处。我们要辨证地看待C++的新机制，应该恰如其分地使用它们。虽然这会使我们编程时多费一些心思，少了一些痛快，但这才是编程的艺术。 </p>
																				<p>第9章 类的构造函数、析构函数与赋值函数 <br />构造函数、析构函数与赋值函数是每个类最基本的函数。它们太普通以致让人容易麻痹大意，其实这些貌似简单的函数就象没有顶盖的下水道那样危险。 <br />每个类只有一个析构函数和一个赋值函数，但可以有多个构造函数（包含一个拷贝构造函数，其它的称为普通构造函数）。对于任意一个类A，如果不想编写上述函数，C++编译器将自动为A产生四个缺省的函数，如 <br />A(void); // 缺省的无参数构造函数 <br />A(const A &amp;a); // 缺省的拷贝构造函数 <br />~A(void); // 缺省的析构函数 <br />A &amp; operate =(const A &amp;a); // 缺省的赋值函数 </p>
																				<p>这不禁让人疑惑，既然能自动生成函数，为什么还要程序员编写？ <br />原因如下： <br />（1）如果使用“缺省的无参数构造函数”和“缺省的析构函数”，等于放弃了自主“初始化”和“清除”的机会，C++发明人Stroustrup的好心好意白费了。 <br />（2）“缺省的拷贝构造函数”和“缺省的赋值函数”均采用“位拷贝”而非“值拷贝”的方式来实现，倘若类中含有指针变量，这两个函数注定将出错。 </p>
																				<p>对于那些没有吃够苦头的C++程序员，如果他说编写构造函数、析构函数与赋值函数很容易，可以不用动脑筋，表明他的认识还比较肤浅，水平有待于提高。 <br />本章以类String的设计与实现为例，深入阐述被很多教科书忽视了的道理。String的结构如下： <br />class String <br />{ <br />  public: <br />String(const char *str = NULL); // 普通构造函数 <br />String(const String &amp;other); // 拷贝构造函数 <br />~ String(void); // 析构函数 <br />String &amp; operate =(const String &amp;other); // 赋值函数 <br />  private: <br />char   *m_data; // 用于保存字符串 <br />};</p>
																		</div>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cnitblog.com/guopingleee/aggbug/54625.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/guopingleee/" target="_blank">向左向右走</a> 2009-02-16 22:42 <a href="http://www.cnitblog.com/guopingleee/archive/2009/02/16/54625.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内联函数与c++宏相比的优点有哪些？</title><link>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54624.html</link><dc:creator>向左向右走</dc:creator><author>向左向右走</author><pubDate>Mon, 16 Feb 2009 14:40:00 GMT</pubDate><guid>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54624.html</guid><wfw:comment>http://www.cnitblog.com/guopingleee/comments/54624.html</wfw:comment><comments>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54624.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/guopingleee/comments/commentRss/54624.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/guopingleee/services/trackbacks/54624.html</trackback:ping><description><![CDATA[
		<div class="bc0">
				<div class="p90">
						<div class="f14 B wr" id="question_title">
								<cq>内联函数与c++宏相比的优点有哪些？</cq>
						</div>
						<div class="wr" id="question_info">
								<span class="red">
										<img height="16" src="http://img.baidu.com/img/iknow/icn_point.gif" width="16" align="absMiddle" /> 悬赏分：0</span> - <span class="gray">解决时间：2009-1-7 00:05</span></div>
						<div class="f14 wr" id="question_content">
								<cd>越详细越好，谢谢大哥大姐啦</cd>
						</div>
						<div class="f14 wr" id="question_sup">
						</div>
				</div>
				<div class="gray wr" id="question_author" align="right">提问者： <a href="http://passport.baidu.com/?business&amp;aid=6&amp;un=loveshenxue#2" target="_blank">loveshenxue</a> - <a href="http://www.baidu.com/search/zhidao_help.html#n5" target="_blank">试用期 一级</a></div>
		</div>
		<div class="rg_4">
		</div>
		<div class="rg_5">
		</div>
		<div class="rg_1">
		</div>
		<div class="mb12 bai">
				<div class="rr_1">
				</div>
				<div class="rr_2">
				</div>
				<div class="rr_3">
				</div>
				<div class="rr">
						<div class="t1">
								<div class="ico">
										<div class="ibest">
										</div>
								</div>最佳答案</div>
						<div class="bc0" style="PADDING-RIGHT: 0pt; PADDING-LEFT: 0pt; PADDING-BOTTOM: 5px; PADDING-TOP: 5px">
								<div class="wr">
										<div class="f14 p90 pl10" id="best_answer_content">
												<ca>函数内联 <br />用内联取代宏代码 <br />---------------- <br />C++ 语言支持函数内联<font style="BACKGROUND-COLOR: #7fffd4">，其目的是为了提高函数的执行效率（速度）。</font><br /><font style="BACKGROUND-COLOR: #ff1493">在C程序中，可以用宏代码提高执行效率。宏代码本身不是函数，但使用起来象函数。</font><br />预处理器用复制宏代码的方式代替函数调用，省去了参数压栈、生成汇编语言的CALL调用、 <br />返回参数、执行return等过程，从而提高了速度。 <br /><br />使用宏代码最大的缺点是容易出错，预处理器在复制宏代码时常常产生意想不到的边际效应。 <br /><br />对于C++ 而言，使用宏代码还有另一种缺点：无法操作类的私有数据成员。 <br /><br />让我们看看C++ 的"函数内联"是如何工作的。 <br />对于任何内联函数，编译器在符号表里放入函数的声明（包括名字、参数类型、返回值类型）。 <br />如果编译器没有发现内联函数存在错误，那么该函数的代码也被放入符号表里。 <br />在调用一个内联函数时，编译器首先检查调用是否正确 <br /><font style="BACKGROUND-COLOR: #ffc0cb">（进行类型安全检查，或者进行自动类型转换，当然对所有的函数都一样）。 <br />如果正确，内联函数的代码就会直接替换函数调用，于是省去了函数调用的开销。</font><br /><br />这个过程与预处理有显著的不同，因为预处理器不能进行类型安全检查，或者进行自动类型转换。 <br />假如内联函数是成员函数，对象的地址（this）会被放在合适的地方，这也是预处理器办不到的。 <br /><br />C++ 语言的函数内联机制既具备宏代码的效率，又增加了安全性，而且可以自由操作类的数据成员。 <br />所以在C++ 程序中，应该用内联函数取代所有宏代码，"断言assert"恐怕是唯一的例外。 <br />assert是仅在Debug版本起作用的宏，它用于检查"不应该"发生的情况。 <br />为了不在程序的Debug版本和Release版本引起差别，assert不应该产生任何副作用。 <br />如果assert是函数，由于函数调用会引起内存、代码的变动，那么将导致Debug版本与Release版本存在差异。 <br />所以assert不是函数，而是宏。</ca>
										</div>
								</div>
						</div>
				</div>
		</div>
<img src ="http://www.cnitblog.com/guopingleee/aggbug/54624.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/guopingleee/" target="_blank">向左向右走</a> 2009-02-16 22:40 <a href="http://www.cnitblog.com/guopingleee/archive/2009/02/16/54624.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++堆、栈、自由存储区、全局/静态存储区和常量存储区</title><link>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54601.html</link><dc:creator>向左向右走</dc:creator><author>向左向右走</author><pubDate>Mon, 16 Feb 2009 03:25:00 GMT</pubDate><guid>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54601.html</guid><wfw:comment>http://www.cnitblog.com/guopingleee/comments/54601.html</wfw:comment><comments>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54601.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cnitblog.com/guopingleee/comments/commentRss/54601.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/guopingleee/services/trackbacks/54601.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="title" valign="bottom" align="middle" bgcolor="#f7fcff">
										<strong>C++堆、栈、自由存储区、全局/静态存储区和常量存储区</strong>
								</td>
						</tr>
						<tr>
								<td class="fbrq" align="middle" bgcolor="#f7fcff">发布日期：2007-8-18 7:56:13  点击:
<script src="/Click.asp?NewsID=0781807565551114"></script>
   <a href="http://forums.zxbc.cn/" target="_blank"><span class="color">进入论坛</span></a></td>
						</tr>
						<tr>
								<td class="comment" bgcolor="#f7fcff">    在C++中，内存分成5个区，他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。<br />  <font color="#ee82ee">  栈，就是那些由编译器在需要的时候分配，在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。<br /></font>    <font color="#006400">堆，就是那些由new分配的内存块，他们的释放编译器不去管，由我们的应用程序去控制，一般一个new就要对应一个delete。如果程序员没有释放掉，那么在程序结束后，操作系统会自动回收。<br /></font>    自由存储区，就是那些由malloc等分配的内存块，他和堆是十分相似的，不过它是用free来结束自己的生命的。<br />    全局/静态存储区，全局变量和静态变量被分配到同一块内存中，在以前的C语言中，全局变量又分为初始化的和未初始化的，在C++里面没有这个区分了，他们共同占用同一块内存区。<br />    常量存储区，这是一块比较特殊的存储区，他们里面存放的是常量，不允许修改（当然，你要通过非正当手段也可以修改，而且方法很多）<br /><strong>明确区分堆与栈<br /></strong>    在bbs上，堆与栈的区分问题，似乎是一个永恒的话题，由此可见，初学者对此往往是混淆不清的，所以我决定拿他第一个开刀。<br />    首先，我们举一个例子：<br />    void f() { int* p=new int[5]; } <br />    这条短短的一句话就包含了堆与栈，看到new，我们首先就应该想到，我们分配了一块堆内存，那么指针p呢？他分配的是一块栈内存，所以这句话的意思就是： 在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小，然后调用operator new分配内存，然后返回这块内存的首地址，放入栈中，他在VC6下的汇编代码如下：<br />    00401028   push        14h<br />    0040102A   call        operator new (00401060)<br />    0040102F   add         esp,4<br />    00401032   mov         dword ptr [ebp-8],eax<br />    00401035   mov         eax,dword ptr [ebp-8]<br />    00401038   mov         dword ptr [ebp-4],eax<br />    这里，我们为了简单并没有释放内存，那么该怎么去释放呢？是delete p么？澳，错了，应该是delete []p，这是为了告诉编译器：我删除的是一个数组，VC6就会根据相应的Cookie信息去进行释放内存的工作。<br />    好了，我们回到我们的主题：堆和栈究竟有什么区别？ <br />    主要的区别由以下几点：<br />    1、管理方式不同；<br />    2、空间大小不同；<br />    3、能否产生碎片不同；<br />    4、生长方向不同；<br />    5、分配方式不同；<br />    6、分配效率不同；<br />    管理方式：对于栈来讲，是由编译器自动管理，无需我们手工控制；对于堆来说，释放工作由程序员控制，容易产生memory leak。</td>
						</tr>
				</tbody>
		</table>空间大小：一般来讲在32位系统下，堆内存可以达到4G的空间，从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲，一般都是有一定的空间大小的，例如，在VC6下面，默认的栈空间大小是1M（好像是，记不清楚了）。当然，我们可以修改：    <br />    打开工程，依次操作菜单如下：Project-&gt;Setting-&gt;Link，在Category 中选中Output，然后在Reserve中设定堆栈的最大值和commit。<br />注意：reserve最小值为4Byte；commit是保留在虚拟内存的页文件里面，它设置的较大会使栈开辟较大的值，可能增加内存的开销和启动时间。<br />    碎片问题：对于堆来讲，频繁的new/delete势必会造成内存空间的不连续，从而造成大量的碎片，使程序效率降低。对于栈来讲，则不会存在这个问题， 因为栈是先进后出的队列，他们是如此的一一对应，以至于永远都不可能有一个内存块从栈中间弹出，在他弹出之前，在他上面的后进的栈内容已经被弹出，详细的 可以参考数据结构，这里我们就不再一一讨论了。<br />    生长方向：对于堆来讲，生长方向是向上的，也就是向着内存地址增加的方向；对于栈来讲，它的生长方向是向下的，是向着内存地址减小的方向增长。<br />    分配方式：堆都是动态分配的，没有静态分配的堆。栈有2种分配方式：静态分配和动态分配。静态分配是编译器完成的，比如局部变量的分配。动态分配由alloca函数进行分配，但是栈的动态分配和堆是不同的，他的动态分配是由编译器进行释放，无需我们手工实现。<br />    分配效率：栈是机器系统提供的数据结构，计算机会在底层对栈提供支持：分配专门的寄存器存放栈的地址，压栈出栈都有专门的指令执行，这就决定了栈的效率比 较高。堆则是C/C++函数库提供的，它的机制是很复杂的，例如为了分配一块内存，库函数会按照一定的算法（具体的算法可以参考数据结构/操作系统）在堆 内存中搜索可用的足够大小的空间，如果没有足够大小的空间（可能是由于内存碎片太多），就有可能调用系统功能去增加程序数据段的内存空间，这样就有机会分 到足够大小的内存，然后进行返回。显然，堆的效率比栈要低得多。<br />    从这里我们可以看到，堆和栈相比，由于大量new/delete的使用，容易造成大量的内存碎片；由于没有专门的系统支持，效率很低；由于可能引发用户态 和核心态的切换，内存的申请，代价变得更加昂贵。所以栈在程序中是应用最广泛的，就算是函数的调用也利用栈去完成，函数调用过程中的参数，返回地址， EBP和局部变量都采用栈的方式存放。所以，我们推荐大家尽量用栈，而不是用堆。<br />    虽然栈有如此众多的好处，但是由于和堆相比不是那么灵活，有时候分配大量的内存空间，还是用堆好一些。<br />    无论是堆还是栈，都要防止越界现象的发生（除非你是故意使其越界），因为越界的结果要么是程序崩溃，要么是摧毁程序的堆、栈结构，产生以想不到的结果,就 算是在你的程序运行过程中，没有发生上面的问题，你还是要小心，说不定什么时候就崩掉，那时候debug可是相当困难的：）<br />对了，还有一件事，如果有人把堆栈合起来说，那它的意思是栈，可不是堆，呵呵，清楚了？<br /><strong>static用来控制变量的存储方式和可见性<br /></strong>       函数内部定义的变量，在程序执行到它的定义处时，编译器为它在栈上分配空间，函数在栈上分配的空间在此函数执行结束时会释放掉，这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时，如何实现？ 最容易想到的方法是定义一个全局的变量，但定义为一个全局变量有许多缺点，最明显的缺点是破坏了此变量的访问范围（使得在此函数中定义的变量，不仅仅受此 函数控制）。 
<p>       需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部，对外不可见。</p><p>       static的内部机制：<br />       静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用，所以静态数据成员不能在任何函数内分配空间和初始化。<br />       这样，它的空间分配有三个可能的地方，一是作为类的外部接口的头文件，那里有类声明；二是类定义的内部实现，那里有类的成员函数定义；三是应用程序的main（）函数前的全局数据声明和定义处。<br />      静态数据成员要实际地分配空间，故不能在类的声明中定义（只能声明数据成员）。类声明只声明一个类的“尺寸和规格”，并不进行实际的内存分配，所以在类声 明中写成定义是错误的。它也不能在头文件中类声明的外部定义，因为那会造成在多个使用该类的源文件中，对其重复定义。<br />      static被引入以告知编译器，将变量存储在程序的静态存储区而非栈上空间，静态<br />数据成员按定义出现的先后顺序依次初始化，注意静态成员嵌套时，要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。</p><p>       static的优势：<br />       可以节省内存，因为它是所有对象所公有的，因此，对多个对象来说，静态数据成员只存储一处，供所有对象共用。静态数据成员的值对每个对象都是一样，但它的 值是可以更新的。只要对静态数据成员的值更新一次，保证所有对象存取更新后的相同的值，这样可以提高时间效率。</p><p>        引用静态数据成员时，采用如下格式：<br />         &lt;类名&gt;::&lt;静态成员名&gt;<br />    如果静态数据成员的访问权限允许的话(即public的成员)，可在程序中，按上述格式<br />来引用静态数据成员。</p><p>       PS:<br />      (1)类的静态成员函数是属于整个类而非类的对象，所以它没有this指针，这就导致<br />了它仅能访问类的静态数据和静态成员函数。<br />      (2)不能将静态成员函数定义为虚函数。<br />      (3)由于静态成员声明于类中，操作于其外，所以对其取地址操作，就多少有些特殊<br />，变量地址是指向其数据类型的指针 ，函数地址类型是一个“nonmember函数指针”。 </p><p></p><p>      (4)由于静态成员函数没有this指针，所以就差不多等同于nonmember函数，结果就<br />产生了一个意想不到的好处：成为一个callback函数，使得我们得以将C++和C-based X W<br />indow系统结合，同时也成功的应用于线程函数身上。<br />      (5)static并没有增加程序的时空开销，相反她还缩短了子类对父类静态成员的访问<br />时间，节省了子类的内存空间。<br />      (6)静态数据成员在&lt;定义或说明&gt;时前面加关键字static。<br />      (7)静态数据成员是静态存储的，所以必须对它进行初始化。<br />      (8)静态成员初始化与一般数据成员初始化不同:<br />      初始化在类体外进行，而前面不加static，以免与一般静态变量或对象相混淆；<br />      初始化时不加该成员的访问权限控制符private，public等；<br />           初始化时使用作用域运算符来标明它所属类；<br />           所以我们得出静态数据成员初始化的格式：<br />         &lt;数据类型&gt;&lt;类名&gt;::&lt;静态数据成员名&gt;=&lt;值&gt;<br />      (9)为了防止父类的影响，可以在子类定义一个与父类相同的静态变量，以屏蔽父类的影响。这里有一点需要注意：我们说静态成员为父类和子类共享，但我们有 重复定义了静态成员，这会不会引起错误呢？不会，我们的编译器采用了一种绝妙的手法：name-mangling 用以生成唯一的标志。<br /><br /></p><img src ="http://www.cnitblog.com/guopingleee/aggbug/54601.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/guopingleee/" target="_blank">向左向右走</a> 2009-02-16 11:25 <a href="http://www.cnitblog.com/guopingleee/archive/2009/02/16/54601.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> C++堆、栈、自由存储区、全局/静态存储区和常量存储区收藏</title><link>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54599.html</link><dc:creator>向左向右走</dc:creator><author>向左向右走</author><pubDate>Mon, 16 Feb 2009 03:23:00 GMT</pubDate><guid>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54599.html</guid><wfw:comment>http://www.cnitblog.com/guopingleee/comments/54599.html</wfw:comment><comments>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54599.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/guopingleee/comments/commentRss/54599.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/guopingleee/services/trackbacks/54599.html</trackback:ping><description><![CDATA[
		<p>一个由c/C++编译的程序占用的内存分为以下几个部分 <br />1、栈区（stack）— 由编译器自动分配释放 ，存放函数的参数值，局部变量的值等。其操作方式类似于数据结构中的栈。 <br />2、堆区（heap） — 一般由程序员分配释放， 若程序员不释放，程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事，分配方式倒是类似于链表，呵呵。 <br />3、全局区（静态区）（static）—，全局变量和静态变量的存储是放在一块的，初始化的全局变量和静态变量在一块区域， 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 <br />4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放 <br />5、程序代码区—存放函数体的二进制代码。</p>
		<p>
				<br />二、例子程序 <br />这是一个前辈写的，非常详细 <br />//main.cpp <br />int a = 0; 全局初始化区 <br />char *p1; 全局未初始化区 <br />main() <br />{ <br />int b; 栈 <br />char s[] = "abc"; 栈 <br />char *p2; 栈 <br />char *p3 = "123456"; 123456在常量区，p3在栈上。 <br />static int c =0； 全局（静态）初始化区 <br />p1 = (char *)malloc(10); <br />p2 = (char *)malloc(20); <br />分配得来得10和20字节的区域就在堆区。 <br />strcpy(p1, "123456"); 123456放在常量区，编译器可能会将它与p3所指向的"123456"优化成一个地方。 <br />}</p>
		<p>
				<br />二、堆和栈的理论知识 <br />2.1申请方式 <br />stack: <br />由系统自动分配。 例如，声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间 <br />heap: <br />需要程序员自己申请，并指明大小，在c中malloc函数 <br />如p1 = (char *)malloc(10); <br />在C++中用new运算符 <br />如p2 = (char *)malloc(10); <br />但是注意p1、p2本身是在栈中的。</p>
		<p>
				<br />2.2 <br />申请后系统的响应 <br />栈：只要栈的剩余空间大于所申请空间，系统将为程序提供内存，否则将报异常提示栈溢出。 <br />堆：首先应该知道操作系统有一个记录空闲内存地址的链表，当系统收到程序的申请时， <br />会遍历该链表，寻找第一个空间大于所申请空间的堆结点，然后将该结点从空闲结点链表中删除，并将该结点的空间分配给程序，另外，对于大多数系统，会在这块内存空间中的首地址处记录本次分配的大小，这样，代码中的delete语句才能正确的释放本内存空间。另外，由于找到的堆结点的大小不一定正好等于申请的大小，系统会自动的将多余的那部分重新放入空闲链表中。</p>
		<p>2.3申请大小的限制 <br />栈：在Windows下,栈是向低地址扩展的数据结构，是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的，在 WINDOWS下，栈的大小是2M（也有的说是1M，总之是一个编译时就确定的常数），如果申请的空间超过栈的剩余空间时，将提示overflow。因此，能从栈获得的空间较小。 <br />堆：堆是向高地址扩展的数据结构，是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的，自然是不连续的，而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见，堆获得的空间比较灵活，也比较大。</p>
		<p>
				<br />2.4申请效率的比较： <br />栈由系统自动分配，速度较快。但程序员是无法控制的。 <br />堆是由new分配的内存，一般速度比较慢，而且容易产生内存碎片,不过用起来最方便. <br />另外，在WINDOWS下，最好的方式是用VirtualAlloc分配内存，他不是在堆，也不是在栈是直接在进程的地址空间中保留一快内存，虽然用起来最不方便。但是速度快，也最灵活。</p>
		<p>2.5堆和栈中的存储内容 <br />栈： 在函数调用时，第一个进栈的是主函数中后的下一条指令（函数调用语句的下一条可执行语句）的地址，然后是函数的各个参数，在大多数的C编译器中，参数是由右往左入栈的，然后是函数中的局部变量。注意静态变量是不入栈的。 <br />当本次函数调用结束后，局部变量先出栈，然后是参数，最后栈顶指针指向最开始存的地址，也就是主函数中的下一条指令，程序由该点继续运行。 <br />堆：一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。</p>
		<p>2.6存取效率的比较</p>
		<p>char s1[] = "aaaaaaaaaaaaaaa"; <br />char *s2 = "bbbbbbbbbbbbbbbbb"; <br />aaaaaaaaaaa是在运行时刻赋值的； <br />而bbbbbbbbbbb是在编译时就确定的； <br />但是，在以后的存取中，在栈上的数组比指针所指向的字符串(例如堆)快。 <br />比如： <br />#include <br />void main() <br />{ <br />char a = 1; <br />char c[] = "1234567890"; <br />char *p ="1234567890"; <br />a = c[1]; <br />a = p[1]; <br />return; <br />} <br />对应的汇编代码 <br />10: a = c[1]; <br />00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh] <br />0040106A 88 4D FC mov byte ptr [ebp-4],cl <br />11: a = p[1]; <br />0040106D 8B 55 EC mov edx,dword ptr [ebp-14h] <br />00401070 8A 42 01 mov al,byte ptr [edx+1] <br />00401073 88 45 FC mov byte ptr [ebp-4],al <br />第一种在读取时直接就把字符串中的元素读到寄存器cl中，而第二种则要先把指针值读到edx中，在根据edx读取字符，显然慢了。</p>
		<p>
				<br />2.7小结： <br />堆和栈的区别可以用如下的比喻来看出： <br />使用栈就象我们去饭馆里吃饭，只管点菜（发出申请）、付钱、和吃（使用），吃饱了就走，不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作，他的好处是快捷，但是自由度小。 <br />使用堆就象是自己动手做喜欢吃的菜肴，比较麻烦，但是比较符合自己的口味，而且自由度大。</p>
		<p>1、内存分配方面：</p>
		<p>    堆：一般由程序员分配释放， 若程序员不释放，程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事，分配方式是类似于链表。可能用到的关键字如下：new、malloc、delete、free等等。</p>
		<p>    栈：由编译器(Compiler)自动分配释放，存放函数的参数值，局部变量的值等。其操作方式类似于数据结构中的栈。</p>
		<p>2、申请方式方面：</p>
		<p>    堆：需要程序员自己申请，并指明大小。在c中malloc函数如p1 = (char *)malloc(10)；在C++中用new运算符，但是注意p1、p2本身是在栈中的。因为他们还是可以认为是局部变量。</p>
		<p>    栈：由系统自动分配。 例如，声明在函数中一个局部变量 int b；系统自动在栈中为b开辟空间。</p>
		<p>3、系统响应方面：</p>
		<p>    堆：操作系统有一个记录空闲内存地址的链表，当系统收到程序的申请时，会遍历该链表，寻找第一个空间大于所申请空间的堆结点，然后将该结点从空闲结点链表中删除，并将该结点的空间分配给程序，另外，对于大多数系统，会在这块内存空间中的首地址处记录本次分配的大小，这样代码中的delete语句才能正确的释放本内存空间。另外由于找到的堆结点的大小不一定正好等于申请的大小，系统会自动的将多余的那部分重新放入空闲链表中。</p>
		<p>    栈：只要栈的剩余空间大于所申请空间，系统将为程序提供内存，否则将报异常提示栈溢出。</p>
		<p>4、大小限制方面：</p>
		<p>    堆：是向高地址扩展的数据结构，是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的，自然是不连续的，而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见，堆获得的空间比较灵活，也比较大。</p>
		<p>    栈：在Windows下, 栈是向低地址扩展的数据结构，是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的，在WINDOWS下，栈的大小是固定的（是一个编译时就确定的常数），如果申请的空间超过栈的剩余空间时，将提示overflow。因此，能从栈获得的空间较小。</p>
		<p>5、效率方面：</p>
		<p>    堆：是由new分配的内存，一般速度比较慢，而且容易产生内存碎片，不过用起来最方便，另外，在WINDOWS下，最好的方式是用VirtualAlloc分配内存，他不是在堆，也不是在栈是直接在进程的地址空间中保留一快内存，虽然用起来最不方便。但是速度快，也最灵活。</p>
		<p>    栈：由系统自动分配，速度较快。但程序员是无法控制的。</p>
		<p>6、存放内容方面：</p>
		<p>    堆：一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。</p>
		<p>    栈：在函数调用时第一个进栈的是主函数中后的下一条指令（函数调用语句的下一条可执行语句）的地址然后是函数的各个参数，在大多数的C编译器中，参数是由右往左入栈，然后是函数中的局部变量。 注意: 静态变量是不入栈的。当本次函数调用结束后，局部变量先出栈，然后是参数，最后栈顶指针指向最开始存的地址，也就是主函数中的下一条指令，程序由该点继续运行。</p>
		<p>7、存取效率方面：</p>
		<p>    堆：char *s1 = "Hellow Word"；是在编译时就确定的；</p>
		<p>    栈：char s1[] = "Hellow Word"； 是在运行时赋值的；用数组比用指针速度要快一些，因为指针在底层汇编中需要用edx寄存器中转一下，而数组在栈上直接读取。</p>
<img src ="http://www.cnitblog.com/guopingleee/aggbug/54599.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/guopingleee/" target="_blank">向左向右走</a> 2009-02-16 11:23 <a href="http://www.cnitblog.com/guopingleee/archive/2009/02/16/54599.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>常量函数、常量引用参数、常量引用返回值[C++] </title><link>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54598.html</link><dc:creator>向左向右走</dc:creator><author>向左向右走</author><pubDate>Mon, 16 Feb 2009 03:19:00 GMT</pubDate><guid>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54598.html</guid><wfw:comment>http://www.cnitblog.com/guopingleee/comments/54598.html</wfw:comment><comments>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54598.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/guopingleee/comments/commentRss/54598.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/guopingleee/services/trackbacks/54598.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 常量函数、常量引用参数、常量引用返回值[C++]																		1. 关于常量引用正像在C语言中使用指针一样，C++中通常使用引用 有一个函数... foo()并且这个函数返回一个引用...... &amp; foo()...., 一个指向位图(Bitmap)的引用 ...Bitmap &amp; foo().... 并且这个位图(bitmap)是常量con...&nbsp;&nbsp;<a href='http://www.cnitblog.com/guopingleee/archive/2009/02/16/54598.html'>阅读全文</a><img src ="http://www.cnitblog.com/guopingleee/aggbug/54598.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/guopingleee/" target="_blank">向左向右走</a> 2009-02-16 11:19 <a href="http://www.cnitblog.com/guopingleee/archive/2009/02/16/54598.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>值和传引用、传地址的区别是什么？</title><link>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54597.html</link><dc:creator>向左向右走</dc:creator><author>向左向右走</author><pubDate>Mon, 16 Feb 2009 03:18:00 GMT</pubDate><guid>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54597.html</guid><wfw:comment>http://www.cnitblog.com/guopingleee/comments/54597.html</wfw:comment><comments>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54597.html#Feedback</comments><slash:comments>15</slash:comments><wfw:commentRss>http://www.cnitblog.com/guopingleee/comments/commentRss/54597.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/guopingleee/services/trackbacks/54597.html</trackback:ping><description><![CDATA[
		<h1 class="ContentTitle">
				<strong>传值和传引用、传地址的区别是什么？ </strong>
		</h1>
		<h2 class="ContentAuthor">作者:dh20156 日期:2007-06-18</h2>
		<div class="Content-Info">
				<div class="InfoOther">字体大小: <a accesskey="1" href="javascript:SetFont('12px')">小</a><a accesskey="2" href="javascript:SetFont('14px')">中</a><a accesskey="3" href="javascript:SetFont('16px')">大</a></div>
				<div class="InfoAuthor">
						<img style="MARGIN: 0px 2px -6px 0px" alt="" src="http://www.v-ec.com/dh20156/images/weather/hn2_sunny.gif" />
						<img alt="" src="http://www.v-ec.com/dh20156/images/weather/hn2_t_sunny.gif" />
						<img style="MARGIN: 0px 2px -1px 0px" alt="" src="http://www.v-ec.com/dh20156/images/level3.gif" />
				</div>
		</div>
		<div class="Content-body" id="logPanel">
				<p>传值，   <br />  是把实参的值赋值给行参   <br />  那么对行参的修改，<font color="#ff0000">不会影响实参的值</font>   <br />    <br />  传地址   <br />  是传值的一种特殊方式，只是他传递的是地址，不是普通的如int   <br />  那么传地址以后，实参和行参都<font color="#ff0000">指向同一个对象</font>   <br />    <br />  传引用   <br />  真正的以地址的方式传递参数   <br />  传递以后，行参和实参<font color="#ff0000">都是同一个对象</font>，只是他们名字不同而已   <br />  对行参的修改将影响实参的值<br /><br />-----------------------------------------------------------------------------------<br /><br />觉得从函数调用的角度理解比较好   <br />    <br />  传值：   <br />  函数参数压栈的是参数的副本。   <br />  任何的修改是在副本上作用，没有作用在原来的变量上。   <br />    <br />  传指针：   <br />  压栈的是指针变量的副本。   <br />  当你对指针解指针操作时，其值是指向原来的那个变量，所以对原来变量操作。   <br />    <br />  传引用：   <br />  压栈的是引用的副本。由于引用是指向某个变量的，对引用的操作其实就是对他指向的变量的操作。（作用和传指针一样，只是引用少了解指针的草纸）  <br /><br />-----------------------------------------------------------------------------------<br />函数参数传递机制的基本理论   <br />  　　函数参数传递机制问题在本质上是调用函数（过程）和被调用函数（过程）在调用发生时进行通信的方法问题。基本的参数传递机制有两种：值传递和引用传递。以下讨论称调用其他函数的函数为主调函数，被调用的函数为被调函数。   <br />  　　值传递（passl-by-value）过程中，被调函数的形式参数作为被调函数的局部变量处理，即在堆栈中开辟了内存空间以存放由主调函数放进来的实参的值，从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行，不会影响主调函数的实参变量的值。   <br />  　　引用传递(pass-by-reference)过程中，被调函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间，但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址，即通过堆栈中存放的地址访问主调函数中的实参变量。正因为如此，被调函数对形参做的任何操作都影响了主调函数中的   <br />  实参变量。   <br /><br /><br />-----------------------------------------------------------------------------------<br /><br />仅讨论一下值传递和引用：   <br />  所谓值传递，就是说仅将对象的值传递给目标对象，就相当于copy；系统将为目标对象重新开辟一个完全相同的内存空间。   <br />  所谓引用，就是说将对象在内存中的地址传递给目标对象，就相当于使<font color="#ff0000">目标对象和原始对象对应同一个内存存储空间</font>。此时，如果对目标对象进行修改，内存中的数据也会改变。</p>
				<p>
						<strong>
								<font color="#000000">原文地址</font>
						</strong>
						<a href="http://topic.csdn.net/t/20051207/06/4442668.html" target="_blank">http://topic.csdn.net/t/20051207/06/4442668</a>
				</p>
		</div>
<img src ="http://www.cnitblog.com/guopingleee/aggbug/54597.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/guopingleee/" target="_blank">向左向右走</a> 2009-02-16 11:18 <a href="http://www.cnitblog.com/guopingleee/archive/2009/02/16/54597.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>]c++重点知识 </title><link>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54595.html</link><dc:creator>向左向右走</dc:creator><author>向左向右走</author><pubDate>Mon, 16 Feb 2009 02:52:00 GMT</pubDate><guid>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54595.html</guid><wfw:comment>http://www.cnitblog.com/guopingleee/comments/54595.html</wfw:comment><comments>http://www.cnitblog.com/guopingleee/archive/2009/02/16/54595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/guopingleee/comments/commentRss/54595.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/guopingleee/services/trackbacks/54595.html</trackback:ping><description><![CDATA[
		<font size="4">论坛: <a href="http://www.ieee.org.cn/list.asp?boardid=61&amp;page=2&amp;action">http://www.ieee.org.cn/list.asp?boardid=61&amp;page=2&amp;action</a>=<br /><br />看看了这总结的真不错, 在反复看看, 书要反复读, 再反复看, 看自己还有哪些遗漏处.<br /></font>
		<table class="luntan_font_title_2" cellspacing="0" cellpadding="0" width="96%" align="center" border="0">
				<tbody>
						<tr>
								<td width="80%">
										<font size="4">
												<b>]c++重点知识</b> 　　<span class="pt9_1"><font color="#ffffff">[阅读：
<script src="/blog/view_count.asp?id=1440442&amp;poster_userid=654318"></script>
 1208]</font></span></font>
								</td>
								<td align="right" width="20%">
										<font size="4">
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<table cellspacing="0" cellpadding="0" width="96%" align="center" border="0">
				<tbody>
						<tr>
								<td width="100%" colspan="4" height="20">
										<font size="4">
										</font>
								</td>
						</tr>
						<tr>
								<td class="luntan_font" width="100%" colspan="4">
										<p>
												<font size="4">C++知识点 <br />一、＃i nclude “filename.h”和＃i nclude filename.h&gt;的区别<br />＃i nclude “filename.h”是指编译器将从当前工作目录上开始查找此文件<br />＃i nclude filename.h&gt;是指编译器将从标准库目录中开始查找此文件</font>
										</p>
										<p>
												<font size="4">二、头文件的作用<br />加强安全检测<br />通过头文件可能方便地调用库功能，而不必关心其实现方式</font>
										</p>
										<p>
												<font size="4">三、* , &amp;修饰符的位置<br /><font color="#ff1493">对于*和&amp;修饰符，为了避免误解，最好将修饰符紧靠变量名</font></font>
										</p>
										<p>
												<font size="4">四、if语句<br />不要将布尔变量与任何值进行比较，那会很容易出错的。<br />整形变量必须要有类型相同的值进行比较<br /><font color="#ff1493">浮点变量最好少比点，就算要比也要有值进行限制</font><br /><font color="#006400">指针变量要和NULL进行比较，不要和布尔型和整形比较</font></font>
										</p>
										<p>
												<font size="4">五、const和#define的比较<br /><font color="#ff1493">const有数据类型，<br /></font><font color="#ffff00"><font color="#a52a2a">#define没有数据类型</font><br /></font><font color="#ee82ee">个别编译器中const可以进行调试，#define不可以进行调试</font><br />在类中定义常量有两种方式<br />1、 在类在声明常量，但不赋值，在构造函数初始化表中进行赋值；<br />2、 用枚举代替const常量。</font>
										</p>
										<p>
												<font size="4">六、C++函数中值的传递方式<br />有三种方式：值传递(Pass by value)、指针传递(Pass by pointer)、引用传递(Pass by reference)<br />void fun(char c) //pass by value<br />void fun(char *str) //pass by pointer<br /><font color="#ff1493">void fun(char &amp;str) //pass by reference</font><br />如果输入参数是以值传递的话，最好使用引用传递代替，因为引用传递省去了临时对象的构造和析构<br />函数的类型不能省略，就算没有也要加个void</font>
										</p>
										<p>
												<font size="4">七、<font color="#ff1493">函数体中的指针或引用常量不能被返回<br />Char *func(void)<br />{<br />char str[]=”Hello Word”;<br />//这个是不能被返回的，因为str是个指向栈内存的指针，不是一般的值，函数结束后会被注销掉<br /></font>return str; <br />}<br /><br />函数体内的指针变量并不会随着函数的消亡而自动释放<br /></font>
										</p>
										<p>
												<font size="4">例子: <br />char * fun(void)<br />{<br />    char    * st="hello ssssssssssssss             ";</font>
										</p>
										<p>
												<font size="4">    return st; <font color="#ff1493">//函数体内的指针变量并不会随着函数的消亡而自动释放<br /></font>}<br />void main() <br />{ <br />     char    *p3;<br />    p3 = fun()<br />    printf(p3);</font>
										</p>
										<p>
												<font size="4">} <br /><br /><br />八、一个内存拷贝函数的实现体<br />void *memcpy(void *pvTo,const void *pvFrom,size_t size)<br />{<br />assert((pvTo!=NULL)&amp;&amp;(pvFrom!=NULL));<br />byte *pbTo=(byte*)pvTo; //防止地址被改变<br />byte *pbFrom=(byte*)pvFrom;<br />while (size-- &gt;0)<br />pbTo++ = pbForm++;<br />return pvTo;<br />} </font>
										</p>
										<p>
												<font size="4">九、内存的分配方式<br />分配方式有三种，请记住，说不定那天去面试的时候就会有人问你这问题<br />1、<font color="#ff1493"> 静态存储区，是在程序编译时就已经分配好的，在整个运行期间都存在，如全局变量、常量。<br />2、 栈上分配，函数内的局部变量就是从这分配的，但分配的内存容易有限。<br />3、 堆上分配，也称动态分配，如我们用new,malloc分配内存，用delete,free来释放的内存。</font></font>
										</p>
										<p>
												<font size="4">十、内存分配的注意事项<br /><font color="#ff0000">用new或malloc分配内存时，必须要对此指针赋初值。<br />用delete 或free释放内存后，必须要将指针指向NULL<br /></font><font color="#ff1493">不能修改指向常量的指针数据</font></font>
										</p>
										<p>
												<font size="4">十一、内容复制与比较<br />//数组……<br />char a[]=”Hello Word!”;<br />char b[10];<br />strcpy(b,a);<br />if (strcmp(a,b)==0)<br />{}<br />//指针……<br />char a[]=”Hello Word!”;<br />char *p;<br />p=new char[strlen(a)+1];<br />strcpy(p,a);<br />if (strcmp(p,a)==0)<br />{}</font>
										</p>
										<p>
												<font size="4">十二、sizeof的问题<br />记住一点，C++无法知道指针所指对象的大小，指针的大小永远为4字节<br />char a[]=”Hello World!”<br />char *p=a;<br />count sizeof(a) end; //12字节<br />count sizeof(p) endl; //4字节<br />而且，在函数中，数组参数退化为指针，所以下面的内容永远输出为4<br />void fun(char a[1000])<br />{<br />count sizeof(a) endl; //输出4而不是1000<br />}</font>
										</p>
										<p>
												<font size="4">十三、关于指针<br />1、 指针创建时必须被初始化<br />2、 指针在free 或delete后必须置为NULL<br />3、 指针的长度都为4字节<br />４、释放内存时，如果是数组指针，必须要释放掉所有的内存，如<br />char *p=new char[100];<br />strcpy(p,”Hello World”);<br />delete []p; //注意前面的[]号<br />p=NULL;//置为NULL<br />５、数组指针的内容不能超过数组指针的最大容易。<br />如:<br />char *p=new char[5];<br />strcpy(p,”Hello World”); //报错 目标容易不够大<br />delete []p; //注意前面的［］号<br />p=NULL;</font>
										</p>
										<p>
												<font size="4">十四、关于malloc/free 和new /delete<br />l malloc/free 是C/C+的内存分配符，new /delete是C++的内存分配符。<br />l 注意：malloc/free是库函数，new/delete是运算符<br />l malloc/free不能执行构造函数与析构函数，而new/delete可以<br />l new/delete不能在C上运行，所以malloc/free不能被淘汰<br />l 两者都必须要成对使用<br />l C++中可以使用_set_new_hander函数来定义内存分配异常的处理</font>
										</p>
										<p>
												<font size="4">十五、Ｃ++的特性<br />Ｃ++新增加有重载(overload)，内联（inline），Const，Virtual四种机制<br />重载和内联：即可用于全局函数，也可用于类的成员函数；<br />Const和Virtual：只可用于类的成员函数；<br />重载：在同一类中，函数名相同的函数。由不同的参数决定调用那个函数。函数可要不可要Virtual关键字。和全局函数同名的函数<br />不叫重载。如果在类中调用同名的全局函数，必须用全局引用符号::引用。<br />覆盖是指派生类函数覆盖基类函数<br />函数名相同；<br />参数相同；<br />基类函数必须有Virtual关键字；<br />不同的范围(派生类和基类)。<br />隐藏是指派生类屏蔽了基类的同名函数相同<br />1、 函数名相同，但参数不同，此时不论基类有无Virtual关键字，基类函数将被隐藏。<br />2、 函数名相同，参数也相同，但基类无Virtual关键字(有就是覆盖)，基类函数将被隐藏。<br />内联：inline关键字必须与定义体放在一起，而不是单单放在声明中。<br />Const：const是constant的缩写，“恒定不变”的意思。被const修饰的东西都受到强制保护，可以预防意外的变动，能提高程序的<br />健壮性。<br />1、 参数做输入用的指针型参数，加上const可防止被意外改动。<br />2、 按值引用的用户类型做输入参数时，最好将按值传递的改为引用传递，并加上const关键字，目的是为了提高效率。数据类型为<br />内部类型的就没必要做这件事情；如：<br />将void Func(A a) 改为void Func(const A &amp;a)。<br />而void func(int a)就没必要改成void func(const int &amp;a);<br />3、 给返回值为指针类型的函数加上const，会使函数返回值不能被修改，赋给的变量也只能是const型变量。如：函<br />数const char*GetString(void); char *str=GetString()将会出错。而const char *str=GetString()将是正确的。<br />4、 Const成员函数是指此函数体内只能调用Const成员变量，提高程序的键壮性。如声明函数 int GetCount(void) const;此函数<br />体内就只<br />能调用Const成员变量。<br />Virtual：虚函数：派生类可以覆盖掉的函数，纯虚函数：只是个空函数，没有函数实现体；</font>
										</p>
										<p>
												<font size="4">十六、extern“C”有什么作用？<br />Extern “C”是由Ｃ＋＋提供的一个连接交换指定符号，用于告诉Ｃ＋＋这段代码是Ｃ函数。这是因为C++编译后库中函数名会变<br />得很长，与C生成的不一致，造成Ｃ＋＋不能直接调用C函数，加上extren “c”后，C++就能直接调用C函数了。<br />Extern “C”主要使用正规DLL函数的引用和导出 和 在C++包含C函数或C头文件时使用。使用时在前面加上extern “c” 关键字即<br />可。</font>
										</p>
										<p>
												<font size="4">十七、构造函数与析构函数<br />派生类的构造函数应在初始化表里调用基类的构造函数；<br />派生类和基类的析构函数应加Virtual关键字。<br />不要小看构造函数和析构函数，其实编起来还是不容易。<br />＃i nclude <iostream.h><br />using namespace std;<br />class Base<br />{<br />public: <br />virtual ~Base() { cout "~Base" endl ; }<br />};<br />class Derived : public Base<br />{<br />public: <br />virtual ~Derived() { cout "~Derived" endl ; }<br />};<br />void main(void)<br />{<br />Base * pB = new Derived; // upcast<br />delete pB;<br />cin.get();<br />}<br />输出结果为：<br />~Derived<br />~Base<br />如果析构函数不为虚，那么输出结果为<br />~Base</iostream.h></font>
										</p>
										<p>
												<font size="4">十八、#IFNDEF/#DEFINE/#ENDIF有什么作用<br />仿止该头文件被重复引用<br />一、＃i nclude “filename.h”和＃i nclude filename.h&gt;的区别<br />＃i nclude “filename.h”是指编译器将从当前工作目录上开始查找此文件<br />＃i nclude filename.h&gt;是指编译器将从标准库目录中开始查找此文件</font>
										</p>
										<p>
												<font size="4">二、头文件的作用<br />加强安全检测<br />通过头文件可能方便地调用库功能，而不必关心其实现方式</font>
										</p>
										<p>
												<font size="4">三、* , &amp;修饰符的位置<br />对于*和&amp;修饰符，为了避免误解，最好将修饰符紧靠变量名</font>
										</p>
										<p>
												<font size="4">四、if语句<br />不要将布尔变量与任何值进行比较，那会很容易出错的。<br />整形变量必须要有类型相同的值进行比较<br />浮点变量最好少比点，就算要比也要有值进行限制<br />指针变量要和NULL进行比较，不要和布尔型和整形比较</font>
										</p>
										<p>
												<font size="4">五、const和#define的比较<br />const有数据类型，#define没有数据类型<br />个别编译器中const可以进行调试，#define不可以进行调试<br />在类中定义常量有两种方式<br />1、 在类在声明常量，但不赋值，在构造函数初始化表中进行赋值；<br />2、 用枚举代替const常量。</font>
										</p>
										<p>
												<font size="4">六、C++函数中值的传递方式<br />有三种方式：值传递(Pass by value)、指针传递(Pass by pointer)、引用传递(Pass by reference)<br />void fun(char c) //pass by value<br />void fun(char *str) //pass by pointer<br />void fun(char &amp;str) //pass by reference<br />如果输入参数是以值传递的话，最好使用引用传递代替，因为引用传递省去了临时对象的构造和析构<br />函数的类型不能省略，就算没有也要加个void</font>
										</p>
										<p>
												<font size="4">七、函数体中的指针或引用常量不能被返回<br />Char *func(void)<br />{<br />char str[]=”Hello Word”;<br />//这个是不能被返回的，因为str是个指定变量，不是一般的值，函数结束后会被注销掉<br />return str; <br />}<br />函数体内的指针变量并不会随着函数的消亡而自动释放</font>
										</p>
										<p>
												<font size="4">八、一个内存拷贝函数的实现体<br />void *memcpy(void *pvTo,const void *pvFrom,size_t size)<br />{<br />assert((pvTo!=NULL)&amp;&amp;(pvFrom!=NULL));<br />byte *pbTo=(byte*)pvTo; //防止地址被改变<br />byte *pbFrom=(byte*)pvFrom;<br />while (size-- &gt;0)<br />pbTo++ = pbForm++;<br />return pvTo;<br />} </font>
										</p>
										<p>
												<font size="4">九、内存的分配方式<br />分配方式有三种，请记住，说不定那天去面试的时候就会有人问你这问题<br />1、 静态存储区，是在程序编译时就已经分配好的，在整个运行期间都存在，如全局变量、常量。<br />2、 栈上分配，函数内的局部变量就是从这分配的，但分配的内存容易有限。<br />3、 堆上分配，也称动态分配，如我们用new,malloc分配内存，用delete,free来释放的内存。</font>
										</p>
										<p>
												<font size="4">十、内存分配的注意事项<br />用new或malloc分配内存时，必须要对此指针赋初值。<br />用delete 或free释放内存后，必须要将指针指向NULL<br />不能修改指向常量的指针数据</font>
										</p>
										<p>
												<font size="4">十一、内容复制与比较<br />//数组……<br />char a[]=”Hello Word!”;<br />char b[10];<br />strcpy(b,a);<br />if (strcmp(a,b)==0)<br />{}<br />//指针……<br />char a[]=”Hello Word!”;<br />char *p;<br />p=new char[strlen(a)+1];<br />strcpy(p,a);<br />if (strcmp(p,a)==0)<br />{}</font>
										</p>
										<p>
												<font size="4">十二、sizeof的问题<br />记住一点，C++无法知道指针所指对象的大小，指针的大小永远为4字节<br />char a[]=”Hello World!”<br />char *p=a;<br />count sizeof(a) end; //12字节<br />count sizeof(p) endl; //4字节<br />而且，在函数中，数组参数退化为指针，所以下面的内容永远输出为4<br />void fun(char a[1000])<br />{<br />count sizeof(a) endl; //输出4而不是1000<br />}</font>
										</p>
										<p>
												<font size="4">十三、关于指针<br />1、 指针创建时必须被初始化<br />2、 指针在free 或delete后必须置为NULL<br />3、 指针的长度都为4字节<br />４、释放内存时，如果是数组指针，必须要释放掉所有的内存，如<br />char *p=new char[100];<br />strcpy(p,”Hello World”);<br />delete []p; //注意前面的［］号<br />p=NULL;<br />５、数组指针的内容不能超过数组指针的最大容易。<br />如:<br />char *p=new char[5];<br />strcpy(p,”Hello World”); //报错 目标容易不够大<br />delete []p; //注意前面的［］号<br />p=NULL;</font>
										</p>
										<p>
												<font size="4">十四、关于malloc/free 和new /delete<br />l malloc/free 是C/C+的内存分配符，new /delete是C++的内存分配符。<br />l 注意：malloc/free是库函数，new/delete是运算符<br />l malloc/free不能执行构造函数与析构函数，而new/delete可以<br />l new/delete不能在C上运行，所以malloc/free不能被淘汰<br />l 两者都必须要成对使用<br />l C++中可以使用_set_new_hander函数来定义内存分配异常的处理</font>
										</p>
										<p>
												<font size="4">十五、Ｃ++的特性<br />Ｃ++新增加有重载(overload)，内联（inline），Const，Virtual四种机制<br />重载和内联：即可用于全局函数，也可用于类的成员函数；<br />Const和Virtual：只可用于类的成员函数；<br />重载：在同一类中，函数名相同的函数。由不同的参数决定调用那个函数。函数可要不可要Virtual关键字。和全局函数同名的函数<br />不叫重载。如果在类中调用同名的全局函数，必须用全局引用符号::引用。<br />覆盖是指派生类函数覆盖基类函数<br />函数名相同；<br />参数相同；<br />基类函数必须有Virtual关键字；<br />不同的范围(派生类和基类)。<br />隐藏是指派生类屏蔽了基类的同名函数相同<br />1、 函数名相同，但参数不同，此时不论基类有无Virtual关键字，基类函数将被隐藏。<br />2、 函数名相同，参数也相同，但基类无Virtual关键字(有就是覆盖)，基类函数将被隐藏。<br />内联：inline关键字必须与定义体放在一起，而不是单单放在声明中。<br />Const：const是constant的缩写，“恒定不变”的意思。被const修饰的东西都受到强制保护，可以预防意外的变动，能提高程序的健壮性。<br />1、 参数做输入用的指针型参数，加上const可防止被意外改动。<br />2、 按值引用的用户类型做输入参数时，最好将按值传递的改为引用传递，并加上const关键字，目的是为了提高效率。数据类型为内部类型<br />的就没必要做这件事情；如：<br />将void Func(A a) 改为void Func(const A &amp;a)。<br />而void func(int a)就没必要改成void func(const int &amp;a);<br />3、 给返回值为指针类型的函数加上const，会使函数返回值不能被修改，赋给的变量也只能是const型变量。如：函<br />数const char*GetString(void); char *str=GetString()将会出错。而const char *str=GetString()将是正确的。<br />4、 Const成员函数是指此函数体内只能调用Const成员变量，提高程序的键壮性。如声明函数 int GetCount(void) const;此函数体内就只能<br />调用Const成员变量。<br />Virtual：虚函数：派生类可以覆盖掉的函数，纯虚函数：只是个空函数，没有函数实现体；</font>
										</p>
										<p>
												<font size="4">十六、extern“C”有什么作用？<br />Extern “C”是由Ｃ＋＋提供的一个连接交换指定符号，用于告诉Ｃ＋＋这段代码是Ｃ函数。这是因为C++编译后库中函数名会变得<br />很长，与C生成的不一致，造成Ｃ＋＋不能直接调用C函数，加上extren “c”后，C++就能直接调用C函数了。<br />Extern “C”主要使用正规DLL函数的引用和导出 和 在C++包含C函数或C头文件时使用。使用时在前面加上extern “c” 关键字即可。</font>
										</p>
										<p>
												<font size="4">十七、构造函数与析构函数<br />派生类的构造函数应在初始化表里调用基类的构造函数；<br />派生类和基类的析构函数应加Virtual关键字。<br />不要小看构造函数和析构函数，其实编起来还是不容易。<br />＃i nclude iostream.h&gt;<br />class Base<br />{<br />public: <br />virtual ~Base() { cout "~Base" endl ; }<br />};<br />class Derived : public Base<br />{<br />public: <br />virtual ~Derived() { cout "~Derived" endl ; }<br />};<br />void main(void)<br />{<br />Base * pB = new Derived; // upcast<br />delete pB;<br />}<br />输出结果为：<br />~Derived<br />~Base<br />如果析构函数不为虚，那么输出结果为<br />~Base</font>
										</p>
										<p>
												<font size="4">十八、#IFNDEF/#DEFINE/#ENDIF有什么作用<br />仿止该头文件被重复引用<br /></font>
										</p>
										<p>
												<font size="4">学习C++必须掌握的概念 <br />一、指针的概念<br />char str[] = “ABCDEFG”;<br />char *pc = str; //pc是指向string str的指针<br />short x = 33; 　<br />short *px = &amp;x; //px是指向short x的指针<br />cout *pc endl; //这条语句将打印字符‘A’<br />pc += 4; //指针向右移动4指向第5个字符<br />cout *pc endl; //这时这条语句将打印字符‘E’<br />pc--; //向左移动指针<br />cout *pc endl; //这时这条语句将打印字符‘D’<br />cout *px + 3 endl; //这条语句打印36因为=33+3<br />在 C 程序中,假设我们已定义了以下的几个变量及函数: int k, tem, *P1, *P2, a[5], f(), *P3(); 以下的设定<br />叙述(Assignment statements)中, 那些有语法上的错误? 并请说明其原因<br />1.P1 = &amp;k;<br />2.P2 = a;<br />3.P3 = f;<br />4.P1 = &amp;a[3];<br />5.P1 = P2;<br />答案:<br />(1) P1 = &amp;k; P1是指针变量, 因此P1表位址,而k表示一般变量,&amp;k表示取出k的位址,故正确.<br />(2) P2 = a; a是数组名称,此时可代表数组存放在内存中的起始位址,而P2为指针变量,故正确.<br />(3) P3 = f; f代表函数的名称,此时代表呼叫函数f,因此含有传回值,而P3为指针变量,故此式有错误.<br />(4) P1 = &amp;a[3];P1表指针变量,代表位址,而&amp;a[3]表取出索引(index)为3的数组元素的位址,故正确.<br />(5) P1 = P2; P1,P2皆为指针变量代表位址,此叙述是指将P2的位址指定给P1,故正确.</font>
										</p>
										<p>
												<font size="4">结构的概念<br />结构是一种类型，它的成员默认是public.<br />struct Student //定义一个结构Student用来存放学生的资料<br />{ <br />int id; //编号<br />char name[30]; //名字<br />}<br />Student s = {555, “Davis, Samuel”}; //初始化Student的实例s<br />cout s.id “ “ s.name endl; //这条将打印“ 555 Davis,Samuel”<br />类的概念我想大家都应该很清楚了，我就不废话了。<br />类的继承的概念<br />class base<br />{<br />private:<br />int a;<br />protected:<br />int b;<br />public:<br />int c;<br />};<br />class sub1:public base {…};<br />class sub2:private base{…};<br />说明在base,sub1,sub2中所能取用的data members各为何.并指出这些data members的access mode(private, protected或public).<br />Ans:<br />class data members access mode<br />base a private<br />b protected<br />c public<br />sub1<br />b protected<br />c public<br />sub2<br />b private<br />c private</font>
										</p>
										<p>
												<font size="4">虚函数和抽象类<br />多态 (polymorphism)<br />面向对象程设计的核心观念之一就是多态--它使一群类似的行为的同名称的方法, 但各对象可依适合自己所需的方式建构此同名动作的实行<br />细节, C++多态的关键在于所谓的虚函数这一类的函数。<br />虚函数(virtual function)<br />透过虚拟函数, 衍生类可重新定义基类的成员函数, 若想在C++程式中建立虚拟函数(然後才能实行多态), 只需利用virtual关键字声明函数即<br />可(如下所示)<br />virtual void Display();<br />虚函数的用处<br />针对共享相同基类的那些对象, 可有较一致的使用态度, 例如, 你可能定义一个名为Shape且带有一 个Draw虚拟成员函数的基类, 然后从它派<br />生了Circle类和Square类, 而且它们各自带有自己的Draw成员函数.从这些类派生建立的每个对象都可呼叫Draw成员函数; 但是编译程式可确<br />保各自应呼叫那个版本的Draw 函数.是基类的还是派生类的。<br />一个例子<br />重要观念: 指向父类的指针也可用来指向子类别<br />＃i nclude iostream.h&gt;<br />class BaseClass<br />{<br />public:<br />virtual void Display( ) { cout 100 "\n"; }<br />};<br />class DerivedClass: public BaseClass<br />{<br />public:<br />virtual void Display( ) { cout 200 "\n"; }<br />};<br />void Print(BaseClass* pbc)<br />{ pbc-&gt;Display( ); }<br />int main( )<br />{ BaseClass* pbc = new BaseClass;<br />DerivedClass* pdc = new DerivedClass;<br />Print(pbc);//显示 100<br />Print(pdc);//显示 200<br />return 0;<br />}<br />V-table (Virtual function table)<br />当C++程式呼叫非虚函数, 采用与C程式呼叫函数所用方式一样的静态绑定来呼叫函数. 但是C++程式 若是透过指向类别的指针来呼叫虚函数<br />时, 编译程式则采用所谓的晚期绑定(late binding)或静态绑定 (static binding)技术来呼叫函数.<br />而C++虚函数用虚函数表(virtual function table), 或称V-表来实作动态绑定, 所谓的V-表是一 个函数指针的阵列, 这是编译程序替每个<br />使用虚函数的类所建制的。<br />纯虚函数 (pure virtual function)<br />一个不仅可被重新定义, 而且必须被重新定义的成员函数就称为纯虚函数, 你只要指定函数一个零值 (更有效说法是一个空指针),就可将虚<br />成员函数转为纯虚成员函数,如以下所示<br />virtual void PrintData() = 0;<br />抽象类 (abstract class)<br />当一个类含有至少一个纯虚函数时, 此类就称为抽象类,而你无法以此类来衍生建立对象.</font>
										</p>
										<p>
												<font size="4">C++ template classes<br />一般的声明及使用 <br />class Collection<br />{ …<br />int A[10]; <br />}<br />Collection object; <br />模板的声明及使用<br />template class T&gt; //注意这里<br />class Collection<br />{ …<br />T A[10]; }// generic declaration<br />Collection int&gt; object; //注意这里<br />Collection char&gt; object; //注意这里 <br /></font>
										</p>
										<p>
												<font size="4">冒泡排序 <br />陀陀木修 发表于2005-5-22 12:23:00<br />1、排序方法<br />　将被排序的记录数组R[1..n]垂直排列，每个记录R[i]看作是重量为R[i].key的气泡。根据轻气泡不能在重气泡之下的原则，从下往<br />上扫描数组R：凡扫描到违反本原则的轻气泡，就使其向上"飘浮"。如此反复进行，直到最后任何两个气泡都是轻者在上，重者在下为止。<br />（1）初始<br />　 R[1..n]为无序区。<br />（2）第一趟扫描<br />　 从无序区底部向上依次比较相邻的两个气泡的重量，若发现轻者在下、重者在上，则交换二者的位置。即依次比较(R[n]，R[n-1])，(R[n-1]，R[n-2])，…，(R[2]，R[1])；对于每对气泡(R[j+1]，R[j])，若R[j+1].key 　第一趟扫描完毕时，"最轻"的气泡就飘浮到该区间的顶部，即关键字最小的记录被放在最高位置R[1]上。<br />（3）第二趟扫描<br />　 扫描R[2..n]。扫描完毕时，"次轻"的气泡飘浮到R[2]的位置上……<br />　最后，经过n-1 趟扫描可得到有序区R[1..n]<br />注意：<br />　 第i趟扫描时，R[1..i-1]和R[i..n]分别为当前的有序区和无序区。扫描仍是从无序区底部向上直至该区顶部。扫描完毕时，该区中最<br />轻气泡飘浮到顶部位置R[i]上，结果是R[1..i]变为新的有序区。<br />2、冒泡排序过程示例<br />　对关键字序列为49 38 65 97 76 13 27 49的文件进行冒泡排序的过程【参见动画演示】<br />3、排序算法<br />（1）分析<br />　因为每一趟排序都使有序区增加了一个气泡，在经过n-1趟排序之后，有序区中就有n-1个气泡，而无序区中气泡的重量总是大于等于<br />有序区中气泡的重量，所以整个冒泡排序过程至多需要进行n-1趟排序。<br />　若在某一趟排序中未发现气泡位置的交换，则说明待排序的无序区中所有气泡均满足轻者在上，重者在下的原则，因此，冒泡排序过程<br />可在此趟排序后终止。为此，在下面给出的算法中，引入一个布尔量exchange，在每趟排序开始前，先将其置为FALSE。若排序过程中发生了交换，则将其置为TRUE。各趟排序结束时检查exchange，若未曾发生过交换则终止算法，不再进行下一趟排序。<br />（2）具体算法<br />void BubbleSort(SeqList R)<br />{ //R（l..n)是待排序的文件，采用自下向上扫描，对R做冒泡排序<br />int i，j；<br />Boolean exchange； //交换标志<br />for(i=1;i exchange=FALSE； //本趟排序开始前，交换标志应为假<br />for(j=n-1;j&gt;=i；j--) //对当前无序区R[i..n]自下向上扫描<br />if(R[j+1].key R[0]=R[j+1]； //R[0]不是哨兵，仅做暂存单元<br />R[j+1]=R[j]；<br />R[j]=R[0]；<br />exchange=TRUE； //发生了交换，故将交换标志置为真<br />}<br />if(!exchange) //本趟排序未发生交换，提前终止算法<br />return；<br />} //endfor(外循环)<br />} //BubbleSort <br />4、算法分析<br />（1）算法的最好时间复杂度<br />　若文件的初始状态是正序的，一趟扫描即可完成排序。所需的关键字比较次数C和记录移动次数M均达到最小值：<br />Cmin=n-1<br />Mmin=0。<br />　冒泡排序最好的时间复杂度为O(n)。<br />（2）算法的最坏时间复杂度<br />　若初始文件是反序的，需要进行n-1趟排序。每趟排序要进行n-i次关键字的比较(1≤i≤n-1)，且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下，比较和移动次数均达到最大值：<br />Cmax=n(n-1)/2=O(n2)<br />Mmax=3n(n-1)/2=O(n2)<br />　冒泡排序的最坏时间复杂度为O(n2)。<br />（3）算法的平均时间复杂度为O(n2)<br />　虽然冒泡排序不一定要进行n-1趟，但由于它的记录移动次数较多，故平均时间性能比直接插入排序要差得多。<br />（4）算法稳定性<br />　冒泡排序是就地排序，且它是稳定的。<br />5、算法改进<br />　上述的冒泡排序还可做如下的改进：<br />(1)记住最后一次交换发生位置lastExchange的冒泡排序<br />　　在每趟扫描中，记住最后一次交换发生的位置lastExchange，（该位置之前的相邻记录均已有序）。下一趟排序开始时，R[1..lastExchange-1]是有序区，R[lastExchange..n]是无序区。这样，一趟排序可能使当前有序区扩充多个记录，从而减少排序的趟数。具体算法【参见习题】。<br />(2) 改变扫描方向的冒泡排序<br />①冒泡排序的不对称性<br />　　能一趟扫描完成排序的情况：<br />　只有最轻的气泡位于R[n]的位置，其余的气泡均已排好序，那么也只需一趟扫描就可以完成排序。<br />【例】对初始关键字序列12，18，42，44，45，67，94，10就仅需一趟扫描。<br />需要n-1趟扫描完成排序情况：<br />　 当只有最重的气泡位于R[1]的位置，其余的气泡均已排好序时，则仍需做n-1趟扫描才能完成排序。<br />【例】对初始关键字序列：94，10，12，18，42，44，45，67就需七趟扫描。<br /><br />②造成不对称性的原因<br />　　每趟扫描仅能使最重气泡"下沉"一个位置，因此使位于顶端的最重气泡下沉到底部时，需做n-1趟扫描。<br />③改进不对称性的方法<br />　在排序过程中交替改变扫描方向，可改进不对称性。具体算法【参见习题】。 <br /><br />C++，这个词在中国大陆的程序员圈子中通常被读做“C加加”，而西方的程序员通常读做“see plus plus”， 它是一种被使用的非常广泛的计算机编程语言。C++是一种静态数据类型检查的，支持多重编程范式的通用程序设计语言。它支持过程序程序设计、数据抽象、面向对象程序设计、泛型程序设计等多种程序设计风格。<br />布贾尼•斯特劳斯特卢普（Bjarne Stroustrup）博士在20世纪80年代发明并实现了C++（最初这种语言被称作“C with Classes”）。一开始C++是作为C语言的增强版出现的，从给C语言增加类开始，不断的增加新特性。虚函数、运算符重载、多重继承、模板、异常、RTTI、名字空间逐渐被加入标准。1998年国际标准组织（ISO）颁布了C++程序设计语言的国际标准ISO/IEC 14882-1998。遗憾的是，由于C++语言过于复杂，以及他经历了长年的演变，直到现在（2004年）只有少数几个完全符合这个标准的编译器出现。<br />另外，就目前学习C++而言，可以认为他是一门独立的语言；他并不依赖C语言，我们可以完全不学C语言，而直接学习C++。根据《C++编程思想》（Thinking in C++）一书所评述的，C++与C的效率往往相差在正负5%之间。所以有人认为在大多数场合C++ 完全可以取代C语言。<br />C++语言发展大概可以分为三个阶段：第一阶段从80年代到1995年。这一阶段C++语言基本上是传统类型上的面向对象语言，并且凭借着接<br />近C语言的效率，在工业界使用的开发语言中占据了相当大份额；第二阶段从1995年到2000年，这一阶段由于STL和后来的Boost等程序库的出<br />现，泛型程序设计在C++中占据了越来越多的比重性。当然，同时由于Java、C#等语言的出现和硬件价格的大规模下降，C++开始逐渐退出用户<br />级程序的开发领域，转向系统级别的程序开发；第三阶段从2000年至今，由于以Loki、MPL等程序库为代表的产生式编程和模板元编程的出<br />现，C++出现了发展历史上又一个新的高峰，这些新技术的出现以及和原有技术的融合，使C++已经成为当今主流程序设计语言中最庞大，最<br />复杂的一员。<br /><br />何为算法？ <br />陀陀木修 发表于2005-5-22 12:09:00<br />不论您在您的生活或工作中是否已经注意到，算法的直接或隐含的存在已经日益增多。算法是软件运算部分功能的基础，它存在于嵌入或<br />非嵌入的系统中间，默默地做着底层的事情。有些计算的功能是显而易见的，因此在编程的过程中算法并不显得很重要，不需要单独去考虑它，例如控制单一的开关，或单一的视窗。而越来越多与物理世界相关的复杂运算，人们并不直接地了解如何去算；那么在编程的过程中就需要对于这些算法进行开发；例如，如何最有效地压缩音乐信号数据，诸如通行的MP3算法；或者手机里面的GSM编解码算法。 <br />计算机硬件的发展的速度之快，在其存储量与运算速度方面都早已超过了人类大脑。但是，却因为大大缺少足够的算法，使人们尚做不出<br />能够充分使用这些硬件的软件，以至于巨大的计算机还模拟不出一个简单蚂蚁的功能。模拟人类就更加遥远，即使是模拟人类的某个单一功能，如，语音对话。 <br />那些已经相对成熟并经常使用的算法，就已经被固化在软件模块里面，甚至半导体芯片之中；可以方便地直接使用而无须重新开发。越是<br />尚未成熟标准化的领域，算法越需要直接去开发，例如语音识别的算法。更有人类与日俱增的观察世界和控制世界的欲望，了解自身、相互沟<br />通、以及提高生活的舒适程度的愿望。而这些新的愿望在刚出现的时候，往往还没有已经固化的算法可供选用，这样就不断产生出对新的算法<br />研发的需求。当然也存在由于商业的考虑而需要‘重新发明车轮’的情况。 <br />任何算法以及软件都是要在一定的硬件系统中运行。一个完整的计算机或嵌入电子装置的功能，都是软、硬件结合的结果。因此系统结构<br />的合理性和算法同样很重要。但是，我们工作室的侧重面是对算法的探讨、研发和设计、实现。对于系统我们仅仅是去优化地选择使用，并不<br />花主要的精力去设计。在一切情况下，对于算法的需求包括未知算法本身的研发，以及已知算法在具体系统中的实现。 <br /><br /><br /></font>
										</p>
										<p>
												<font size="4">可以运用分而治之方法来解决排序问题，该问题是将n 个元素排成非递减顺序。分而治之方法通常用以下的步骤来进行排序算法：若n 为1，算法终止；否则，将这一元素集合分割成两个或更多个子集合，对每一个子集合分别排序，然后将排好序的子集合归并为一个集合。 <br />假设仅将n 个元素的集合分成两个子集合。现在需要确定如何进行子集合的划分。一种可能性就是把前面n- 1个元素放到第一个子集中（称为A），最后一个元素放到第二个子集里（称为B）。按照这种方式对A递归地进行排序。由于B仅含一个元素，所以它已经排序完毕，在A排完序后，只需要用程序2 - 1 0中的函数i n s e r t将A和B合并起来。把这种排序算法与I n s e r t i o n S o r t（见程序2 - 1 5）进行比较，可以发现这种排序算法实际上就是插入排序的递归算法。该算法的复杂性为O (n 2 )。把n 个元素划分成两个子集合的另一种方法是将含有最大值的元素放入B，剩下的放入A中。然后A被递归排序。为了合并排序后的A和B，只需要将B添加到A中即可。假如用函数M a x（见程序1 - 3 1）来找出最大元素，这种排序算法实际上就是S e l e c t i o n S o r t（见程序2 - 7）的递归算法。 <br />假如用冒泡过程（见程序2 - 8）来寻找最大元素并把它移到最右边的位置，这种排序算法就是B u b b l e S o r t（见程序2 - 9）的递归算法。这两种递归排序算法的复杂性均为(n2 )。若一旦发现A已经被排好序就终止对A进行递归分割，则算法的复杂性为O(n2 )（见例2 - 1 6和2 - 1 7）。 <br />上述分割方案将n 个元素分成两个极不平衡的集合A和B。A有n- 1个元素，而B仅含一个元素。下面来看一看采用平衡分割法会发生什么情况： A集合中含有n/k 个元素，B中包含其余的元素。递归地使用分而治之方法对A和B进行排序。然后采用一个被称之为归并（ m e rg e）的过程，将已排好序的A和B合并成一个集合。 <br />例2-5 考虑8个元素，值分别为[ 1 0，4，6，3，8，2，5，7 ]。如果选定k = 2，则[ 1 0 , 4 , 6 , 3 ]和[ 8 , 2 , 5 , 7 ]将被分别独立地排序。结果分别为[ 3 , 4 , 6 , 1 0 ]和[ 2 , 5 , 7 , 8 ]。从两个序列的头部开始归并这两个已排序的序列。元素2比3更小，被移到结果序列；3与5进行比较，3被移入结果序列；4与5比较，4被放入结果序列；5和6比较，.。如果选择k= 4，则序列[ 1 0 , 4 ]和[ 6 , 3 , 8 , 2 , 5 , 7 ]将被排序。排序结果分别为[ 4 , 1 0 ]和[ 2 , 3 , 5 , 6&amp;n </font>
										</p>
										<p>
												<font size="4">
												</font>
										</p>
										<p>
												<font size="4">文章来源：CSDN</font>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cnitblog.com/guopingleee/aggbug/54595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/guopingleee/" target="_blank">向左向右走</a> 2009-02-16 10:52 <a href="http://www.cnitblog.com/guopingleee/archive/2009/02/16/54595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>