<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Programming Life with Music &#187; JackalDire</title>
	<atom:link href="http://jackaldire.com/author/admin/feed/" rel="self" type="application/rss+xml" />
	<link>http://jackaldire.com</link>
	<description>JackalDire &#039;s Blog</description>
	<lastBuildDate>Tue, 13 Jul 2010 08:29:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/><atom:link rel="hub" href="http://superfeedr.com/hubbub"/>		<item>
		<title>Windows下实现EXE的自删除与自修改</title>
		<link>http://jackaldire.com/201004/exe-self-delete-and-self-modify/</link>
		<comments>http://jackaldire.com/201004/exe-self-delete-and-self-modify/#comments</comments>
		<pubDate>Sun, 25 Apr 2010 04:21:17 +0000</pubDate>
		<dc:creator>JackalDire</dc:creator>
				<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://jackaldire.com/?p=97</guid>
		<description><![CDATA[押尾コータロー &#8211; Merry Christmas, Mr. Lawrence from Starting Point 先介绍一下这首背景音乐吧，老早就听过，前几天才发现出处：是“Merry Christmas Mr. Lawrence”这部电影（断臂片）的主题曲，也是坂本龙一配乐的处女作。这个版本是押尾光太郎的指弹吉他版。 自从开始实习就没有更新过blog了，加上软工、数据库、图形学乱七八糟的实验，有点忙不过来了。 本来一直在想以后做Linux相关的开发，周围认识的很多学长都走上了这条路，开始实习后却事与愿违搞起了Linux开发。其实说实话一直也不知道自己的兴趣点在哪里，工作了一个月后感觉可能还是桌面和互联网更适合自己，对于系统开发、运维这样的工作，干长时间可能会受不了&#8230;&#8230;纠结啊 前两天和朋友聊到windows下一个程序如何删除自己，正好以前和同学讨论过这个问题，写出来凑个数。 其实真正的删除自己肯定是做不到的，至少用户态不行。windows下只要一个文件被某个进程打开就不能被删掉（Linux下可以删除任何打开的文件，只要有权限，而且一般不会影响程序的执行，因为文件系统会等到所有的打开的fd都释放后会才回收inode和data）,所以一个windows进程在运行的时候是肯定不可以删除自己的可执行文件的，只能想一些旁门左道了。 Solution 方法其实很简单，就是在程序结束前开另一个进程去删自己，但是要求是自己删自己，所以只能借助系统utils。这时候就需要bat脚本来帮忙了。在CMD下删除一个文件很容易，一条del命令就搞定了，但是需要保证执行脚本的时候原进程已经结束运行了，一般来说用一条延时命令walk around“ping 127.0.0.1 -n 2”，2为秒数，然后用“&#038;”连接del命令删除文件 ping 127.0.0.1 -n 2 &#62;nul &#38;&#38; del path/to/your/file.exe 更为保险的做法是在bat里用tasklist命令查看进程，循环直到找不到当前进程位置 原来的和同学讨论的是一个程序如何自己修改自己，做到单文件自动更新，实际上和自己删除自己是一个问题。无非就是先生成一个自身的副本，修改副本，再程序结束后用bat脚本覆盖自己就ok了，源代码如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [...]]]></description>
			<content:encoded><![CDATA[<p><embed src="http://www.blogcastone.net/audio/player.swf?soundFile=http%3A%2F%2Fstorage.live.com%2Fitems%2F9151E070FED682BB%21180%3Ffilename%3D12%2520-%2520Merry%2520Christmas%2520Mr.Lawrence.mp3&#038;playerID=10&#038;bg=0xf8f8f8&#038;leftbg=0xeeeeee&#038;lefticon=0x666666&#038;rightbg=0xcccccc&#038;rightbghover=0x999999&#038;righticon=0x666666&#038;righticonhover=0xffffff&#038;text=0x666666&#038;slider=0x666666&#038;track=0xFFFFFF&#038;border=0x666666&#038;loader=0x9FFFB8&#038;loop=no&#038;autostart=no" type="application/x-shockwave-flash" wmode="transparent" height="40" width="290"></embed><br />
押尾コータロー &#8211; Merry Christmas, Mr. Lawrence from <em>Starting Point</em></p>
<p>先介绍一下这首背景音乐吧，老早就听过，前几天才发现出处：是“Merry Christmas Mr. Lawrence”这部电影（断臂片）的主题曲，也是坂本龙一配乐的处女作。这个版本是押尾光太郎的指弹吉他版。</p>
<p>自从开始实习就没有更新过blog了，加上软工、数据库、图形学乱七八糟的实验，有点忙不过来了。</p>
<p>本来一直在想以后做Linux相关的开发，周围认识的很多学长都走上了这条路，开始实习后却事与愿违搞起了Linux开发。其实说实话一直也不知道自己的兴趣点在哪里，工作了一个月后感觉可能还是桌面和互联网更适合自己，对于系统开发、运维这样的工作，干长时间可能会受不了&#8230;&#8230;纠结啊</p>
<p>前两天和朋友聊到windows下一个程序如何删除自己，正好以前和同学讨论过这个问题，写出来凑个数。<br />
<span id="more-97"></span><br />
其实真正的删除自己肯定是做不到的，至少用户态不行。windows下只要一个文件被某个进程打开就不能被删掉（Linux下可以删除任何打开的文件，只要有权限，而且一般不会影响程序的执行，因为文件系统会等到所有的打开的fd都释放后会才回收inode和data）,所以一个windows进程在运行的时候是肯定不可以删除自己的可执行文件的，只能想一些旁门左道了。</p>
<h2>Solution</h2>
<p>方法其实很简单，就是在程序结束前开另一个进程去删自己，但是要求是自己删自己，所以只能借助系统utils。这时候就需要bat脚本来帮忙了。在CMD下删除一个文件很容易，一条del命令就搞定了，但是需要保证执行脚本的时候原进程已经结束运行了，一般来说用一条延时命令walk around“ping 127.0.0.1 -n 2”，2为秒数，然后用“&#038;”连接del命令删除文件</p>

<div class="wp_syntax"><div class="code"><pre class="bat" style="font-family:monospace;">ping 127.0.0.1 -n 2 &gt;nul &amp;&amp; del path/to/your/file.exe</pre></div></div>

<p>更为保险的做法是在bat里用tasklist命令查看进程，循环直到找不到当前进程位置</p>
<p>原来的和同学讨论的是一个程序如何自己修改自己，做到单文件自动更新，实际上和自己删除自己是一个问题。无非就是先生成一个自身的副本，修改副本，再程序结束后用bat脚本覆盖自己就ok了，源代码如下</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;windows.h&gt;</span>
<span style="color: #339933;">#include &lt;stdio.h&gt;</span>
&nbsp;
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span> argv<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">char</span> self<span style="color: #009900;">&#91;</span>_MAX_PATH<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>  
    <span style="color: #993333;">char</span> swap<span style="color: #009900;">&#91;</span>_MAX_PATH<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// get the full path of myself</span>
    GetModuleFileName<span style="color: #009900;">&#40;</span>NULL<span style="color: #339933;">,</span> self<span style="color: #339933;">,</span> _MAX_PATH<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// copy myself to a temp file for modify </span>
    strcpy<span style="color: #009900;">&#40;</span>swap<span style="color: #339933;">,</span> self<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    strcat<span style="color: #009900;">&#40;</span>swap<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;.tmp&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// add .tmp postfix. better to use tempnam()</span>
    CopyFile<span style="color: #009900;">&#40;</span>self<span style="color: #339933;">,</span> swap<span style="color: #339933;">,</span> FALSE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
&nbsp;
    FILE <span style="color: #339933;">*</span> fp <span style="color: #339933;">=</span> fopen<span style="color: #009900;">&#40;</span>swap<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;ab&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// pending whatever you want to the exe</span>
    fwrite<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;Hack is not good, but i love it.&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">32</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> fp<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    fclose<span style="color: #009900;">&#40;</span>fp<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// &quot;ping&quot; is used for delay to wait the main process terminated.</span>
    <span style="color: #666666; font-style: italic;">// &quot;move /Y src dst&quot; : overide whtout warnning</span>
    <span style="color: #666666; font-style: italic;">// quotation marks are needed for paths which contain blank.</span>
    <span style="color: #993333;">char</span> bat<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #339933;">*</span>_MAX_PATH <span style="color: #339933;">+</span> <span style="color: #0000dd;">30</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #ff0000;">&quot;cmd /c ping 127.0.0.1 -n 2 &gt;nul &amp;&amp; move /Y <span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span><span style="color: #339933;">;</span>
    strcat<span style="color: #009900;">&#40;</span>bat<span style="color: #339933;">,</span> swap<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    strcat<span style="color: #009900;">&#40;</span>bat<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    strcat<span style="color: #009900;">&#40;</span>bat<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot; <span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    strcat<span style="color: #009900;">&#40;</span>bat<span style="color: #339933;">,</span> self<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    strcat<span style="color: #009900;">&#40;</span>bat<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>  <span style="color: #666666; font-style: italic;">// bat += &quot;path\to\swap&quot; &quot;path\to\self&quot; </span>
&nbsp;
    WinExec<span style="color: #009900;">&#40;</span>bat<span style="color: #339933;">,</span> SW_HIDE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Exec the bat script with window hiden</span>
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>C库函数和win32 API混用，看着挺别扭，本来写的时候还想尝试一下匈牙利，被恶心到以后还是放弃了，还好用到的API都参数比较简单，自从大一的时候看到一个win32 API调用占了半屏后，对win32 API就深为恐惧，再加上满屏幕的大写，读起来简直就是噩梦&#8230;</p>
<h2>Improvement</h2>
<p>用ping命令延时只是一个walk around，在系统负载很重的情况下，2秒程序也未必退出了，所以应该寻找一个方法确定一个exe是否在运行。小研究了一下bat，发现通过tasklist命令和find命令可以搞定：</p>

<div class="wp_syntax"><div class="code"><pre class="bat" style="font-family:monospace;">:loop
tasklist /NH | find /i &quot;xxx.exe&quot;
if %ERRORLEVEL% equ 1 (
goto loop
) else (
del path\to\your\file\xxx.exe
)
exit</pre></div></div>

<p>ERRORLEVEL变量是上一条命令的返回值，不停的在进程列表里寻找xxx.exe直到找不到为止。</p>
<p>顺便bless一下灾区的同胞们还有但愿今天可以拿到工资&#8230;.</p>

	<h4>Related Post</h4>
	<ul class="st-related-posts">
	<li>No Related Post</li>
	</ul>

]]></content:encoded>
			<wfw:commentRss>http://jackaldire.com/201004/exe-self-delete-and-self-modify/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://storage.live.com/items/9151E070FED682BB!180?filename=12%20-%20Merry%20Christmas%20Mr.Lawrence.mp3" length="7025792" type="audio/mpeg" />
		</item>
		<item>
		<title>自己动手写Linux Shell（三） —— 支持IO重定向</title>
		<link>http://jackaldire.com/201001/write-your-own-shell-3-io-redirection/</link>
		<comments>http://jackaldire.com/201001/write-your-own-shell-3-io-redirection/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 14:57:56 +0000</pubDate>
		<dc:creator>JackalDire</dc:creator>
				<category><![CDATA[Linux与开源]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Shell]]></category>

		<guid isPermaLink="false">http://jackaldire.com/?p=86</guid>
		<description><![CDATA[1.IO重定向功能分析 IO重定向也是Shell的基本功能之一，这篇文章比较全面地介绍了Linux Shell的IO重定向功能。总结一下，IO重定向的大致格式是这样： cmd &#91;src &#124; &#38;&#93; &#40;&#62; &#124; &#60; &#124; &#62;&#62; &#41; &#40;&#38; num&#124;-&#41; &#124; dst 貌似写得有点复杂（我不是故意的）。解释一下，整个重定向语句由三部分组成： 第一部分（[src&#124;&#038;]）：src代表被重定向的文件描述符，一般是0（stdin）、1（stdout）和2（stderr），此外还可以是‘＆’，代表2和3，也就是把stdout和stderr同时重定向。这一部分通常是省略的，‘>’和‘>>’隐含了0，‘ &#124; < &#124; >>）：三种操作符。‘’将src的输出重定向到目标文件（若文件不存在则创建，否则现有文件被截断(truncation)）；‘>>’将src的输出附加到（pending）目标文件尾部（若文件不存在则创建）。 第三部分（ (&#038; num&#124;-) &#124; dst ）：第三部分有两种形式，最常见的就是一个文件名，代表重定向的目标。此外还可以是&#8217;&#038;'加一个数字，代表将src重定向到数字代表的文件描述符上。另外‘&#038;’后还可以接‘-’，代表关闭src。比如： $ cmd 2&#62;&#38;1 将标准错误重定向到标准输出 $ cmd 1&#62;&#38;- 关闭标准输出 $ cmd 0&#60;&#38;- 关闭标准输入 2.IO重定向功能实现 Linux的IO重定向实际上是通过dup函数和close函数配合实现。close关闭一个文件描述符，而dup复制一个文件描述符，并且新产生的文件描述符是当前可用文件描述符的最小值。 通过先将要重定向的fd关闭，在将重定向的目标文件的描述符dup就实现了重定向（因为012三个描述符默认都是打开的，关闭任何一个后其都将成为当前可用的最小文件描述符）。 为了支持重定向命令的分析，实现里新添加了一个结构，记录了每个重定向的必须信息，然后在子进程fork以后根据记录信息进行重定向操作。 测试的时候发现了一个有趣的问题。比如： $ ls &#62;f1 &#62;f2 $ cat &#62;f1 &#62;f2 这两条命令在bash里的结果是后面的重定向覆盖了前面的重定向，这和我的实现是一样的，也是最简单的。而在zsh里，第一条命令的结果是f1 [...]]]></description>
			<content:encoded><![CDATA[<p><embed src="http://www.blogcastone.net/audio/player.swf?soundFile=http%3A%2F%2Fstorage.live.com%2Fitems%2F9151E070FED682BB%21167%3Ffilename%3D11%2520A%2520WINTER%2520STORY.mp3&#038;playerID=10&#038;bg=0xf8f8f8&#038;leftbg=0xeeeeee&#038;lefticon=0x666666&#038;rightbg=0xcccccc&#038;rightbghover=0x999999&#038;righticon=0x666666&#038;righticonhover=0xffffff&#038;text=0x666666&#038;slider=0x666666&#038;track=0xFFFFFF&#038;border=0x666666&#038;loader=0x9FFFB8&#038;loop=no&#038;autostart=no" type="application/x-shockwave-flash" wmode="transparent" height="40" width="290"></embed></p>
<h2>1.IO重定向功能分析</h2>
<p>IO重定向也是Shell的基本功能之一，<a href="http://www.ibm.com/developerworks/cn/linux/l-iotips/">这篇文章</a>比较全面地介绍了Linux Shell的IO重定向功能。总结一下，IO重定向的大致格式是这样：</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">cmd  <span style="color: #7a0874; font-weight: bold;">&#91;</span>src <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #000000; font-weight: bold;">&amp;</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>     <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #000000; font-weight: bold;">&lt;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #000000; font-weight: bold;">&gt;&gt;</span> <span style="color: #7a0874; font-weight: bold;">&#41;</span>      <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000; font-weight: bold;">&amp;</span> num<span style="color: #000000; font-weight: bold;">|</span>-<span style="color: #7a0874; font-weight: bold;">&#41;</span>  <span style="color: #000000; font-weight: bold;">|</span> dst</pre></div></div>

<p>貌似写得有点复杂（我不是故意的）。解释一下，整个重定向语句由三部分组成：</p>
<p><span id="more-86"></span></p>
<p>第一部分（[src|&#038;]）：src代表被重定向的文件描述符，一般是0（stdin）、1（stdout）和2（stderr），此外还可以是‘＆’，代表2和3，也就是把stdout和stderr同时重定向。这一部分通常是省略的，‘>’和‘>>’隐含了0，‘<’隐含了1，也就是说</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ cmd <span style="color: #000000; font-weight: bold;">&lt;</span><span style="color: #c20cb9; font-weight: bold;">file</span> 等价于
$ cmd <span style="color: #000000;">0</span><span style="color: #000000; font-weight: bold;">&lt;</span><span style="color: #c20cb9; font-weight: bold;">file</span>
$ cmd <span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #c20cb9; font-weight: bold;">file</span> 等价于
$ cmd <span style="color: #000000;">1</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #c20cb9; font-weight: bold;">file</span></pre></div></div>

<p>第二部分（> | < | >>）：三种操作符。‘<’将src的输入重定向到目标文件；‘>’将src的输出重定向到目标文件（若文件不存在则创建，否则现有文件被截断(truncation)）；‘>>’将src的输出附加到（pending）目标文件尾部（若文件不存在则创建）。</p>
<p>第三部分（ (&#038; num|-)  | dst ）：第三部分有两种形式，最常见的就是一个文件名，代表重定向的目标。此外还可以是&#8217;&#038;'加一个数字，代表将src重定向到数字代表的文件描述符上。另外‘&#038;’后还可以接‘-’，代表关闭src。比如：</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ cmd <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">1</span>     将标准错误重定向到标准输出
$ cmd <span style="color: #000000;">1</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span>-      关闭标准输出
$ cmd <span style="color: #000000;">0</span><span style="color: #000000; font-weight: bold;">&lt;&amp;</span>-      关闭标准输入</pre></div></div>

</p>
<h2>2.IO重定向功能实现</h2>
<p>Linux的IO重定向实际上是通过dup函数和close函数配合实现。close关闭一个文件描述符，而dup复制一个文件描述符，并且新产生的文件描述符是当前可用文件描述符的最小值。</p>
<p>通过先将要重定向的fd关闭，在将重定向的目标文件的描述符dup就实现了重定向（因为012三个描述符默认都是打开的，关闭任何一个后其都将成为当前可用的最小文件描述符）。</p>
<p>为了支持重定向命令的分析，实现里新添加了一个结构，记录了每个重定向的必须信息，然后在子进程fork以后根据记录信息进行重定向操作。</p>
<p>测试的时候发现了一个有趣的问题。比如：</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">ls</span> <span style="color: #000000; font-weight: bold;">&gt;</span>f1 <span style="color: #000000; font-weight: bold;">&gt;</span>f2
$ <span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #000000; font-weight: bold;">&gt;</span>f1 <span style="color: #000000; font-weight: bold;">&gt;</span>f2</pre></div></div>

<p>这两条命令在bash里的结果是后面的重定向覆盖了前面的重定向，这和我的实现是一样的，也是最简单的。而在zsh里，第一条命令的结果是f1 f2文件有相同的内容，也就是标准输出同时被重定向到f1和f2两个文件里了；第二条命令的效果等同于先把f1、f2两个文件现连接起来再重定向到cat的输入。这是相当神奇的，到现在也没找到实现方法，看来得找时间研究一下zsh的代码了。</p>
<p>其实实现重定向最麻烦的地方是命令分析，也就是字符串处理。parse_command函数俨然已经100行了，两个switch-case加无数个if-else组成的大自动机，不加注释恐怕就是write-only了（感觉加了注释还是write-only）&#8230;</p>
<p>打开重定向文件那里有一点问题，一大堆flags或来或去，最傻的是忘了给创建的文件设置mode，结果只能用root权限查看&#8230;</p>
<p><strong>源代码 : <a href='http://jackaldire.com/wordpress/wp-content/uploads/2010/01/jdsh_v3.h'>jdsh_v3.h</a> <a href='http://jackaldire.com/wordpress/wp-content/uploads/2010/01/jdsh_v3.c'>jdsh_v3.c</a>（为了让乱七八糟的代码稍微可读一点，单独分了个头文件出来）</strong></p>
<p>剩下的任务就是管道了，有必要把代码好好整理一下了。</p>

	<h4>Related Post</h4>
	<ul class="st-related-posts">
	<li><a href="http://jackaldire.com/201001/write-your-own-shell-2-background-task/" title="自己动手写Linux Shell（二） —— 支持后台执行 (2010年01月31日)">自己动手写Linux Shell（二） —— 支持后台执行</a> (2)</li>
	<li><a href="http://jackaldire.com/201001/write-your-own-shell-1-a-simple-command-interpreter/" title="自己动手写Linux Shell（一） —— 简单的命令解释器 (2010年01月29日)">自己动手写Linux Shell（一） —— 简单的命令解释器</a> (2)</li>
	<li><a href="http://jackaldire.com/200905/linux-and-i/" title="我和Linux (2009年05月14日)">我和Linux</a> (0)</li>
	<li><a href="http://jackaldire.com/200906/archlinux-tor-config/" title="在Archlinux上的安装Tor (2009年06月8日)">在Archlinux上的安装Tor</a> (6)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://jackaldire.com/201001/write-your-own-shell-3-io-redirection/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>自己动手写Linux Shell（二） —— 支持后台执行</title>
		<link>http://jackaldire.com/201001/write-your-own-shell-2-background-task/</link>
		<comments>http://jackaldire.com/201001/write-your-own-shell-2-background-task/#comments</comments>
		<pubDate>Sat, 30 Jan 2010 18:09:53 +0000</pubDate>
		<dc:creator>JackalDire</dc:creator>
				<category><![CDATA[Linux与开源]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Shell]]></category>

		<guid isPermaLink="false">http://jackaldire.com/?p=82</guid>
		<description><![CDATA[在写完一个最简单的命令解释器以后，我给自己的shell起了个名字——jdsh（JackalDire Shell）。 本来以为加入后台执行不是什么难事，但是认真想了一下要处理好一个字符‘＆’不是一般的麻烦，各种问题接踵而至，于是决定先找点轻松的活干。 1.加入shell内建命令 每个shell都有自己的内建命令，最常见的有“cd”、“pwd”、“exit”等等。没有“cd“的shell是没法干活的。 其实很简单，标准的做法建个hash表把所有内建命令加进去，parse command以后先查一下表就行了，然后可以通过像Linux Syscall的实现方法一样，用一个字符串连接宏（##）找到对应的处理函数。但是由于只准备写寥寥几个命令，偷懒直接 if else if了（= =!）。 2.打印命令提示符Prompt 每个命令行shell都有命令提示符，告诉用户现在可以敲命令。大多数的linux shell的prompt是可以定制的。我采用了bash的默认格式“[username@hostname cwd]$ ”。实现prompt里的cwd（current working directory）时候发现了一个问题：基本上所有linux shell里都用了&#8217;~'代替$HOME。于是做个个字符串替换，使得home文件夹在显示的时候都显示为&#8217;~'（命令里的路径还不支持&#8217;~'） 3.处理SIGINT、SIGQUIT和SIGTSTP信号 SIGINT信号对应按下ctrl+c，shell对该信号的处理方式是（观察zsh/bash得到，没有查文档）：若shell当前没有前台任务，则输入一个空行，放弃当前正在输入的命令；若当前有前台任务，则SIGINT信号由前台程序捕捉。 SIGQUIT信号对应按下ctrl+\，shell对该信号的处理方式是（观察zsh/bash得到，没有查文档）：若shell当前没有前台任务，则忽略该信号，放弃当前正在输入的命令；若当前有前台任务，则SIGQUIT信号由前台程序捕捉。 SIGQUIT信号对应按下ctrl+z，shell对该信号的处理方式是（观察zsh/bash得到，没有查文档）：若shell当前没有前台任务，则忽略该信号，放弃当前正在输入的命令；若当前有前台任务，则SIGQUIT信号由前台程序捕捉。 PS:对这APUE里的信号表看了一遍，好像没有其他要特殊处理的信号了。 其实很好处理，用signal函数或者sigaction都可以（偷懒就用signal了）。在shell的主进程里改变SIGINT的信号处理函数、忽略SIGQUIT和SIGTSPT信号就可以。 有一个问题需要注意：必须在fork的子进程里恢复对这几个信号的默认处理方式。因为fork产生子进程和父进程有相同的信号处理函数signal handler。解决方法就是fork以后在子进程里手动恢复修改过的信号。另一种方法是不用fork，改用clone系统调用，通过clone flags里的CLONE_SIGHAND参数使得复制出来的进程不保留父进程的信号处理函数。 回到主题上&#8230;.. 4.后台运行程序 其实单纯的实现后台运行很简单，把前面程序里的wait去掉使shell主进程不等待子进程结束就OK了。问题在于，shell是通过一个&#8217;&#038;'字符决定后台执行，如何才能从命令里提取出这个代表后台执行的&#8217;&#038;'字符？ 看起来似乎一个字符串查找就能解决，其实并非如此：如果这&#8217;&#038;'是在一个路径名里呢(Linux中只有一个字符不能做文件名：&#8217;/')。看一下别的shell很快就会找到解决方法：转义字符。如果想把有特殊含义的字符当作一个普通字符处理，那么就要在前面加上转移字符&#8217;\'（比如空格、&#8217;\'、&#8217;&#038;'、&#8217;~'、&#8217;-'等等）。 要支持转移字符，我原来用strsep实现的优美的parse command函数就得全部扔掉重写。没办法，换成了fgetc和丑陋的switch case。 有了转义字符，就可以处理含有特殊字符的文件名了^ ^ 另外，我观察到bash和zsh在后台程序运行结束后都会显示一条提示信息显示pid和命令，于是我也想把这个功能加进去。思路很简单，就是改变SIGCHLD信号的handler，捕捉到SIGCHLD后输出进程信息就可以了。默认SIGCHLD信号是通过wait和waitpid函数捕捉。signal能改变SIGCHLD信号的处理函数，但是无法获得足够的信息（pid、退出代码等），而sigaction支持复杂的信号处理函数，通过向信号处理函数传递siginfo结构，提供更充足的信息（还是sigaction强大）。 差不多就这样了&#8230;代码量翻了一倍，直接贴出来有点恐怖，所以扔到附件了～（BUG很多，就不一一列举了，sign～） 源代码：jdsh_v2.c Related Post 自己动手写Linux Shell（三） —— 支持IO重定向 (1) 自己动手写Linux Shell（一） —— 简单的命令解释器 (2) 我和Linux (0) [...]]]></description>
			<content:encoded><![CDATA[<p>在写完一个最简单的命令解释器以后，我给自己的shell起了个名字——jdsh（JackalDire Shell）。</p>
<p>本来以为加入后台执行不是什么难事，但是认真想了一下要处理好一个字符‘＆’不是一般的麻烦，各种问题接踵而至，于是决定先找点轻松的活干。</p>
<h2>1.加入shell内建命令</h2>
<p><span id="more-82"></span></p>
<p>每个shell都有自己的内建命令，最常见的有“cd”、“pwd”、“exit”等等。没有“cd“的shell是没法干活的。</p>
<p>其实很简单，标准的做法建个hash表把所有内建命令加进去，parse command以后先查一下表就行了，然后可以通过像Linux Syscall的实现方法一样，用一个字符串连接宏（##）找到对应的处理函数。但是由于只准备写寥寥几个命令，偷懒直接 if else if了（= =!）。</p>
<h2>2.打印命令提示符Prompt</h2>
<p>每个命令行shell都有命令提示符，告诉用户现在可以敲命令。大多数的linux shell的prompt是可以定制的。我采用了bash的默认格式“[username@hostname cwd]$ ”。实现prompt里的cwd（current working directory）时候发现了一个问题：基本上所有linux shell里都用了&#8217;~'代替$HOME。于是做个个字符串替换，使得home文件夹在显示的时候都显示为&#8217;~'（命令里的路径还不支持&#8217;~'）</p>
<h2>3.处理SIGINT、SIGQUIT和SIGTSTP信号</h2>
<p>SIGINT信号对应按下ctrl+c，shell对该信号的处理方式是（观察zsh/bash得到，没有查文档）：若shell当前没有前台任务，则输入一个空行，放弃当前正在输入的命令；若当前有前台任务，则SIGINT信号由前台程序捕捉。</p>
<p>SIGQUIT信号对应按下ctrl+\，shell对该信号的处理方式是（观察zsh/bash得到，没有查文档）：若shell当前没有前台任务，则忽略该信号，放弃当前正在输入的命令；若当前有前台任务，则SIGQUIT信号由前台程序捕捉。</p>
<p>SIGQUIT信号对应按下ctrl+z，shell对该信号的处理方式是（观察zsh/bash得到，没有查文档）：若shell当前没有前台任务，则忽略该信号，放弃当前正在输入的命令；若当前有前台任务，则SIGQUIT信号由前台程序捕捉。<br />
PS:对这APUE里的信号表看了一遍，好像没有其他要特殊处理的信号了。</p>
<p>其实很好处理，用signal函数或者sigaction都可以（偷懒就用signal了）。在shell的主进程里改变SIGINT的信号处理函数、忽略SIGQUIT和SIGTSPT信号就可以。</p>
<p>有一个问题需要注意：必须在fork的子进程里恢复对这几个信号的默认处理方式。因为fork产生子进程和父进程有相同的信号处理函数signal handler。解决方法就是fork以后在子进程里手动恢复修改过的信号。另一种方法是不用fork，改用clone系统调用，通过clone flags里的CLONE_SIGHAND参数使得复制出来的进程不保留父进程的信号处理函数。</p>
</p>
<p>回到主题上&#8230;..</p>
<h2>4.后台运行程序</h2>
<p>其实单纯的实现后台运行很简单，把前面程序里的wait去掉使shell主进程不等待子进程结束就OK了。问题在于，shell是通过一个&#8217;&#038;'字符决定后台执行，如何才能从命令里提取出这个代表后台执行的&#8217;&#038;'字符？</p>
<p>看起来似乎一个字符串查找就能解决，其实并非如此：如果这&#8217;&#038;'是在一个路径名里呢(Linux中只有一个字符不能做文件名：&#8217;/')。看一下别的shell很快就会找到解决方法：<strong>转义字符</strong>。如果想把有特殊含义的字符当作一个普通字符处理，那么就要在前面加上转移字符&#8217;\'（比如空格、&#8217;\'、&#8217;&#038;'、&#8217;~'、&#8217;-'等等）。</p>
<p>要支持转移字符，我原来用strsep实现的优美的parse command函数就得全部扔掉重写。没办法，换成了fgetc和丑陋的switch case。</p>
<p>有了转义字符，就可以处理含有特殊字符的文件名了^ ^</p>
<p>另外，我观察到bash和zsh在后台程序运行结束后都会显示一条提示信息显示pid和命令，于是我也想把这个功能加进去。思路很简单，就是改变SIGCHLD信号的handler，捕捉到SIGCHLD后输出进程信息就可以了。默认SIGCHLD信号是通过wait和waitpid函数捕捉。signal能改变SIGCHLD信号的处理函数，但是无法获得足够的信息（pid、退出代码等），而sigaction支持复杂的信号处理函数，通过向信号处理函数传递siginfo结构，提供更充足的信息（还是sigaction强大）。</p>
<p>差不多就这样了&#8230;代码量翻了一倍，直接贴出来有点恐怖，所以扔到附件了～（BUG很多，就不一一列举了，sign～）</p>
<p>源代码：<a href='http://jackaldire.com/wordpress/wp-content/uploads/2010/01/jdsh_v21.c'>jdsh_v2.c</a></p>

	<h4>Related Post</h4>
	<ul class="st-related-posts">
	<li><a href="http://jackaldire.com/201001/write-your-own-shell-3-io-redirection/" title="自己动手写Linux Shell（三） —— 支持IO重定向 (2010年01月31日)">自己动手写Linux Shell（三） —— 支持IO重定向</a> (1)</li>
	<li><a href="http://jackaldire.com/201001/write-your-own-shell-1-a-simple-command-interpreter/" title="自己动手写Linux Shell（一） —— 简单的命令解释器 (2010年01月29日)">自己动手写Linux Shell（一） —— 简单的命令解释器</a> (2)</li>
	<li><a href="http://jackaldire.com/200905/linux-and-i/" title="我和Linux (2009年05月14日)">我和Linux</a> (0)</li>
	<li><a href="http://jackaldire.com/200906/archlinux-tor-config/" title="在Archlinux上的安装Tor (2009年06月8日)">在Archlinux上的安装Tor</a> (6)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://jackaldire.com/201001/write-your-own-shell-2-background-task/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>自己动手写Linux Shell（一） —— 简单的命令解释器</title>
		<link>http://jackaldire.com/201001/write-your-own-shell-1-a-simple-command-interpreter/</link>
		<comments>http://jackaldire.com/201001/write-your-own-shell-1-a-simple-command-interpreter/#comments</comments>
		<pubDate>Fri, 29 Jan 2010 10:32:37 +0000</pubDate>
		<dc:creator>JackalDire</dc:creator>
				<category><![CDATA[Linux与开源]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Shell]]></category>

		<guid isPermaLink="false">http://jackaldire.com/?p=80</guid>
		<description><![CDATA[Like The Wind &#8212; S.E.N.S 寒假在做Linux Kernel Project这本书上的习题，第二章的练习是写一个简单的shell，看了一下要求觉得这个练习很有价值，涉及到很多Linux C Programming的知识，所以准备认真地做一下。 最终的目标如下: 命令解释执行 支持后台执行(&#038;) 支持输入输出重定向(, >>) 支持管道IPC 内建命令cd, pwd, exit等 可见写一个shell并不是一件简单的事，从简单的一步一步做起吧，手头有APUE，一边做一边查。 一个简单的命令解释器 命令解释执行是shell最基本的功能，实现的方法很简单：从标准输入流中读入命令，然后exec一下就行了。但是还有很多琐碎的地方需要处理： 1.命令行参数传递 首先需要将输入的命令字符串按空格打断（strsep实在是太方便了），然后将打断的字符串构建成一个char*数组，通过execv的第二个参数传递给程序。 注：man exec可以得到关于exec函数族的详细说明。需要说明的是execlp和execvp会在PATH环境变量中的目录搜索可执行程序，而其他的exec函数族函数不会，如果不使用这两个函数，则需要自己编写代码搜索PATH环境变量。 2.使用fork建立子进程 直接在当前进程里exec的话，exec执行的程序结束后，整个程序也就结束了，因为exec直接将原来的进程上下文替换。所以需要fork一个新进程来执行命令，而父进程阻塞直到子进程结束后继续执行，这个可以通过wait函数实现。 3.处理命令的返回值 大多数的shell在命令程序返回非零值（异常退出）会打印出其返回值。而子进程的返回值可以在父进程里通过wait函数的第一个参数得到。然后通过一组宏可以方便地确定子进程的返回状态。这部分内容在APUE里有详细说明（8.6节），下面代码里的pr_exit函数基本上就是从APUE上抄过来的。 4.检查各个函数的返回值 Linux C Programming的一个原则就是在所有可能fail的地方加入检查代码。绝大多数C库函数和Linux系统函数都以负数返回值表示出错，并且通过C库的全局变量errno可以获得错误号，从而得到错误原因，并输出到标准错误流。由于整个过程动作固定，就用一个CHKERR宏来完成了。 下面是源代码 CODE BELOW ARE UNDER GPLV3 LISENCE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 [...]]]></description>
			<content:encoded><![CDATA[<p><embed src="http://www.blogcastone.net/audio/player.swf?soundFile=http%3A%2F%2Fstorage.live.com%2Fitems%2F9151E070FED682BB%21175%3Ffilename%3D4.Like%2520the%2520Wind%2520%7E%2520Guitar%2520Version%2520.mp3&#038;playerID=10&#038;bg=0xf8f8f8&#038;leftbg=0xeeeeee&#038;lefticon=0x666666&#038;rightbg=0xcccccc&#038;rightbghover=0x999999&#038;righticon=0x666666&#038;righticonhover=0xffffff&#038;text=0x666666&#038;slider=0x666666&#038;track=0xFFFFFF&#038;border=0x666666&#038;loader=0x9FFFB8&#038;loop=no&#038;autostart=no" type="application/x-shockwave-flash" wmode="transparent" height="40" width="290"></embed></p>
<div> Like The Wind &#8212; S.E.N.S </div>
<p></p>
<p>寒假在做Linux Kernel Project这本书上的习题，第二章的练习是写一个简单的shell，看了一下要求觉得这个练习很有价值，涉及到很多Linux C Programming的知识，所以准备认真地做一下。</p>
<ol><strong>最终的目标如下:</strong></p>
<li>命令解释执行</li>
<li>支持后台执行(&#038;)</li>
<li>支持输入输出重定向(<, >, >>)</li>
<li>支持管道IPC</li>
<li>内建命令cd, pwd, exit等</li>
</ol>
<p>可见写一个shell并不是一件简单的事，从简单的一步一步做起吧，手头有APUE，一边做一边查。</p>
<p><span id="more-80"></span></p>
<h2>一个简单的命令解释器</h2>
<p>命令解释执行是shell最基本的功能，实现的方法很简单：从标准输入流中读入命令，然后exec一下就行了。但是还有很多琐碎的地方需要处理：</p>
<h3>1.命令行参数传递</h3>
<p>首先需要将输入的命令字符串按空格打断（strsep实在是太方便了），然后将打断的字符串构建成一个char*数组，通过execv的第二个参数传递给程序。</p>
<p>注：man exec可以得到关于exec函数族的详细说明。需要说明的是execlp和execvp会在PATH环境变量中的目录搜索可执行程序，而其他的exec函数族函数不会，如果不使用这两个函数，则需要自己编写代码搜索PATH环境变量。</p>
<h3>2.使用fork建立子进程</h3>
<p>直接在当前进程里exec的话，exec执行的程序结束后，整个程序也就结束了，因为exec直接将原来的进程上下文替换。所以需要fork一个新进程来执行命令，而父进程阻塞直到子进程结束后继续执行，这个可以通过wait函数实现。</p>
<h3>3.处理命令的返回值</h3>
<p>大多数的shell在命令程序返回非零值（异常退出）会打印出其返回值。而子进程的返回值可以在父进程里通过wait函数的第一个参数得到。然后通过一组宏可以方便地确定子进程的返回状态。这部分内容在APUE里有详细说明（8.6节），下面代码里的pr_exit函数基本上就是从APUE上抄过来的。</p>
<h3>4.检查各个函数的返回值</h3>
<p>Linux C Programming的一个原则就是在所有可能fail的地方加入检查代码。绝大多数C库函数和Linux系统函数都以负数返回值表示出错，并且通过C库的全局变量errno可以获得错误号，从而得到错误原因，并输出到标准错误流。由于整个过程动作固定，就用一个CHKERR宏来完成了。
<p>下面是源代码</p>
<p><strong>CODE BELOW ARE UNDER <a href="http://www.gnu.org/licenses/gpl-3.0-standalone.html">GPLV3 LISENCE</a></strong></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
</pre></td><td class="code"><pre class="c" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">/* By JackalDire, Jan 29 2010 
 * Tested on Linux Kernel 2.6.32, gcc 4.4.3 */</span>
<span style="color: #339933;">#include &lt;unistd.h&gt;</span>
<span style="color: #339933;">#include &lt;sys/wait.h&gt;</span>
&nbsp;
<span style="color: #339933;">#include &lt;stdio.h&gt;</span>
<span style="color: #339933;">#include &lt;stdlib.h&gt;</span>
<span style="color: #339933;">#include &lt;string.h&gt;</span>
<span style="color: #339933;">#include &lt;errno.h&gt;</span>
&nbsp;
<span style="color: #339933;">#define LINE_MAX 8192</span>
<span style="color: #339933;">#define ARG_MAX 1024</span>
<span style="color: #339933;">#define ARG_NR_MAX 32</span>
&nbsp;
<span style="color: #339933;">#define CHKERR(ret, msg) if (ret &lt; 0) {\
        fprintf(stderr, &quot;ERROR : \&quot;%s\&quot;, %s\n&quot;, \
                msg, strerror(errno)); \
        exit(-1);   \
    } </span>
&nbsp;
<span style="color: #993333;">char</span> <span style="color: #339933;">*</span> args<span style="color: #009900;">&#91;</span>ARG_NR_MAX <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">extern</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span> environ<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">char</span> line<span style="color: #009900;">&#91;</span>LINE_MAX <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">void</span> parse_command<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span> cmd<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">char</span> <span style="color: #339933;">*</span> res<span style="color: #339933;">;</span>
    size_t cnt <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #808080; font-style: italic;">/* tokenize the command string by space */</span>
    <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>res <span style="color: #339933;">=</span> strsep<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>cmd<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot; &quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> NULL<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        args<span style="color: #009900;">&#91;</span>cnt<span style="color: #339933;">++</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> strdup<span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    args<span style="color: #009900;">&#91;</span>cnt<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">void</span> pr_exit<span style="color: #009900;">&#40;</span><span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span> name<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> status<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>WIFEXITED<span style="color: #009900;">&#40;</span>status<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">// exit normally</span>
        <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">else</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>WIFSIGNALED<span style="color: #009900;">&#40;</span>status<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        fprintf<span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%s exit abnormally, signal %d caught%s.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span>
                name<span style="color: #339933;">,</span> WTERMSIG<span style="color: #009900;">&#40;</span>status<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
<span style="color: #339933;">#ifdef WCOREDUMP</span>
            WCOREDUMP<span style="color: #009900;">&#40;</span>status<span style="color: #009900;">&#41;</span> <span style="color: #339933;">?</span> <span style="color: #ff0000;">&quot; (core file generated)&quot;</span> <span style="color: #339933;">:</span> <span style="color: #ff0000;">&quot;&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #339933;">#else</span>
            <span style="color: #ff0000;">&quot;&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #339933;">#endif</span>
    <span style="color: #b1b100;">else</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>WIFSTOPPED<span style="color: #009900;">&#40;</span>status<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        fprintf<span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;child stopped, signal %d caught.&quot;</span><span style="color: #339933;">,</span>
                WSTOPSIG<span style="color: #009900;">&#40;</span>status<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span> argv<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">char</span> c<span style="color: #339933;">;</span>
    size_t idx<span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> r<span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> status<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        idx <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
        bzero<span style="color: #009900;">&#40;</span>line<span style="color: #339933;">,</span> LINE_MAX <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        c <span style="color: #339933;">=</span> fgetc<span style="color: #009900;">&#40;</span>stdin<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>c <span style="color: #339933;">&amp;&amp;</span> c <span style="color: #339933;">!=</span> <span style="color: #ff0000;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            line<span style="color: #009900;">&#91;</span>idx<span style="color: #339933;">++</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> c<span style="color: #339933;">;</span>
            c <span style="color: #339933;">=</span> fgetc<span style="color: #009900;">&#40;</span>stdin<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        parse_command<span style="color: #009900;">&#40;</span>line<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        r <span style="color: #339933;">=</span> fork<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
        CHKERR<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;fork&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>r <span style="color: #339933;">==</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            r <span style="color: #339933;">=</span> execvp<span style="color: #009900;">&#40;</span>args<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> args<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #666666; font-style: italic;">//printf(&quot;ret : %d\n&quot;, r);</span>
            CHKERR<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> args<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
            wait<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>status<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            pr_exit<span style="color: #009900;">&#40;</span>args<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> status<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>一个简单的命令解释器就这样完成了，下面的工作就是添加后台执行功能，休息一会^ ^</p>

	<h4>Related Post</h4>
	<ul class="st-related-posts">
	<li><a href="http://jackaldire.com/201001/write-your-own-shell-2-background-task/" title="自己动手写Linux Shell（二） —— 支持后台执行 (2010年01月31日)">自己动手写Linux Shell（二） —— 支持后台执行</a> (2)</li>
	<li><a href="http://jackaldire.com/201001/write-your-own-shell-3-io-redirection/" title="自己动手写Linux Shell（三） —— 支持IO重定向 (2010年01月31日)">自己动手写Linux Shell（三） —— 支持IO重定向</a> (1)</li>
	<li><a href="http://jackaldire.com/200905/linux-and-i/" title="我和Linux (2009年05月14日)">我和Linux</a> (0)</li>
	<li><a href="http://jackaldire.com/200906/archlinux-tor-config/" title="在Archlinux上的安装Tor (2009年06月8日)">在Archlinux上的安装Tor</a> (6)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://jackaldire.com/201001/write-your-own-shell-1-a-simple-command-interpreter/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
<enclosure url="http://www.86comic.com/music/song/2007/9/14/86comic0914131614181.mp3" length="293170" type="audio/mpeg" />
		</item>
		<item>
		<title>[消遣]Love Functions</title>
		<link>http://jackaldire.com/201001/love-function/</link>
		<comments>http://jackaldire.com/201001/love-function/#comments</comments>
		<pubDate>Wed, 13 Jan 2010 13:51:46 +0000</pubDate>
		<dc:creator>JackalDire</dc:creator>
				<category><![CDATA[未分类]]></category>
		<category><![CDATA[fun]]></category>

		<guid isPermaLink="false">http://jackaldire.com/?p=79</guid>
		<description><![CDATA[Version 1 (ZZ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 result love&#40;boy, girl&#41; &#123; if &#40; boy.有房&#40;&#41; [...]]]></description>
			<content:encoded><![CDATA[<h2>Version 1 (ZZ)</h2>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;">result love<span style="color: #008000;">&#40;</span>boy, girl<span style="color: #008000;">&#41;</span> 
<span style="color: #008000;">&#123;</span> 
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span> boy.有房<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> and boy.有车<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
        boy.<span style="color: #007788;">set</span><span style="color: #008000;">&#40;</span>nothing<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
        <span style="color: #0000ff;">return</span> girl.嫁给<span style="color: #008000;">&#40;</span>boy<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
    <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>girl.愿意等<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
        <span style="color: #0000ff;">while</span><span style="color: #008000;">&#40;</span> <span style="color: #000040;">!</span> <span style="color: #008000;">&#40;</span>boy.赚钱 ＞ <span style="color:#800080;">1e6</span> and girl.感情 ＞ <span style="color: #0000dd;">8</span> <span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
            <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span>day<span style="color: #000080;">=</span><span style="color: #0000dd;">1</span><span style="color: #008080;">;</span> day ＜<span style="color: #000080;">=</span><span style="color: #0000dd;">365</span><span style="color: #008080;">;</span> day<span style="color: #000040;">++</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
                <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span> day <span style="color: #000080;">==</span> 情人节 <span style="color: #008000;">&#41;</span> 
                    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span> boy.<span style="color: #007788;">givegirl</span><span style="color: #008000;">&#40;</span>玫瑰<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#41;</span> girl.感情<span style="color: #000040;">++</span><span style="color: #008080;">;</span> 
                    <span style="color: #0000ff;">else</span> girl.感情<span style="color: #000040;">--</span><span style="color: #008080;">;</span> 
                <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span> day <span style="color: #000080;">==</span> girl.生日<span style="color: #008000;">&#41;</span> 
                    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span> boy.<span style="color: #007788;">givegirl</span><span style="color: #008000;">&#40;</span>玫瑰<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#41;</span> 
                        girl.感情<span style="color: #000040;">++</span><span style="color: #008080;">;</span> 
                <span style="color: #0000ff;">else</span> girl.感情<span style="color: #000040;">--</span><span style="color: #008080;">;</span> 
                boy.拼命赚钱<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
                <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span> girl.耐心 <span style="color: #000080;">==</span> <span style="color: #0000dd;">0</span> <span style="color: #000040;">&amp;&amp;</span> girl.有其它追求者<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
                    girl.<span style="color: #0000ff;">goto</span><span style="color: #008000;">&#40;</span>nother_boy<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
                    boy.郁闷中<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
                    boy.天天到BYR灌水<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
                    <span style="color: #0000ff;">return</span> 没有结果<span style="color: #008080;">;</span> 
                <span style="color: #008000;">&#125;</span> 
            <span style="color: #008000;">&#125;</span> 
        <span style="color: #008000;">&#125;</span>
        <span style="color: #0000ff;">try</span> 
        <span style="color: #008000;">&#123;</span> 
            girl.要男友买房<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
            girl.要男友买车<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
            girl.每天逛专卖店<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
            <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span> boy.有房<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">&amp;&amp;</span> boy.有车<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
                girl.去澳洲旅游<span style="color: #008000;">&#40;</span>boy<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
                girl.到英国威斯敏斯结婚<span style="color: #008000;">&#40;</span>boy<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
                girl.嫁给<span style="color: #008000;">&#40;</span>boy<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
                boy.没日没夜挣钱<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
            <span style="color: #008000;">&#125;</span> 
        <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">catch</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
            girl.<span style="color: #007788;">byebye</span><span style="color: #008000;">&#40;</span>boy<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
            boy.郁闷中<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
            boy.天天到天涯灌水<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
            <span style="color: #0000ff;">return</span> girl.<span style="color: #007788;">broadcast</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;这个男人真小气&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
        <span style="color: #008000;">&#125;</span> 
        <span style="color: #0000ff;">return</span> girl.每天逛专卖店<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
    <span style="color: #008000;">&#125;</span> 
    <span style="color: #0000ff;">return</span> girl.<span style="color: #0000ff;">goto</span><span style="color: #008000;">&#40;</span>another_boy<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p><span id="more-79"></span></p>
<h2>Version 2 (By wks)</h2>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">void</span> love<span style="color: #008000;">&#40;</span>Man <span style="color: #000040;">&amp;</span>m, Woman <span style="color: #000040;">&amp;</span>w<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
     <span style="color: #0000ff;">try</span> <span style="color: #008000;">&#123;</span> 
         <span style="color: #0000ff;">while</span><span style="color: #008000;">&#40;</span>w.<span style="color: #007788;">isFuckable</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
         doSomething<span style="color: #008000;">&#40;</span>things<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">rand</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #000040;">%</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>things<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #000040;">/</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>things<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
         wait<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
        <span style="color: #008000;">&#125;</span> 
    <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">catch</span> <span style="color: #008000;">&#40;</span>CanWaitNoLongerException e<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
    <span style="color: #008000;">&#125;</span> 
    m.<span style="color: #007788;">fuck</span><span style="color: #008000;">&#40;</span>w<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<h2>Version 3 (By me)</h2>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">void</span> Man<span style="color: #008080;">::</span><span style="color: #007788;">love</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
    <span style="color: #0000ff;">try</span> <span style="color: #008000;">&#123;</span> 
        <span style="color: #0000ff;">while</span><span style="color: #008000;">&#40;</span>m.<span style="color: #007788;">alive</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">&amp;&amp;</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>m.<span style="color: #007788;">hasHouse</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">||</span> <span style="color: #000040;">!</span>m.<span style="color: #007788;">hasCar</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
            m.<span style="color: #007788;">makeMoney</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>  <span style="color: #666666;">// good luck if this is not a infinite loop... </span>
        <span style="color: #008000;">&#125;</span> 
        Woman w <span style="color: #000040;">*</span><span style="color: #008080;">;</span> 
        <span style="color: #0000ff;">while</span><span style="color: #008000;">&#40;</span>w <span style="color: #000080;">=</span> findMM<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>  <span style="color: #666666;">// good luck if this do not block forever... </span>
        <span style="color: #008000;">&#123;</span> 
            <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>w<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>isLove<span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span><span style="color: #0000dd;">this</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">&amp;&amp;</span> w<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>getParents<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">isLike</span><span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span><span style="color: #0000dd;">this</span><span style="color: #008000;">&#41;</span> 
                <span style="color: #000040;">&amp;&amp;</span> w<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>getParents<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">getParents</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">isLike</span><span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span><span style="color: #0000dd;">this</span><span style="color: #008000;">&#41;</span> 
                <span style="color: #000040;">&amp;&amp;</span> ...<span style="color: #008000;">&#41;</span>    
                marry<span style="color: #008000;">&#40;</span>w<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
            <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">continue</span><span style="color: #008080;">;</span> 
        <span style="color: #008000;">&#125;</span> 
    <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">catch</span> <span style="color: #008000;">&#40;</span>房子又涨价了Exception  <span style="color: #000040;">&amp;</span> e<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
        letItBe<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
    <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">catch</span> <span style="color: #008000;">&#40;</span>遇到宋思明了Exception  <span style="color: #000040;">&amp;</span> e<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>  
        letItBe<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
    <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">catch</span> <span style="color: #008000;">&#40;</span>被炒鱿鱼了Exception <span style="color: #000040;">&amp;</span> e<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
        letItBe<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
    <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">catch</span> <span style="color: #008000;">&#40;</span>家命难违Exception <span style="color: #000040;">&amp;</span> e<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> 
        letItBe<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
    ...... 
    <span style="color: #008000;">&#125;</span> finally <span style="color: #008000;">&#123;</span> 
        mayGodSaveMe<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
    <span style="color: #008000;">&#125;</span> 
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>


	<h4>Related Post</h4>
	<ul class="st-related-posts">
	<li>No Related Post</li>
	</ul>

]]></content:encoded>
			<wfw:commentRss>http://jackaldire.com/201001/love-function/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[C++]一个由C-Style类型转换引发的血案</title>
		<link>http://jackaldire.com/201001/c-style-cast-issues/</link>
		<comments>http://jackaldire.com/201001/c-style-cast-issues/#comments</comments>
		<pubDate>Mon, 11 Jan 2010 13:13:21 +0000</pubDate>
		<dc:creator>JackalDire</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[C++]]></category>

		<guid isPermaLink="false">http://jackaldire.com/?p=78</guid>
		<description><![CDATA[没事搜了一下自己域名，无意间发现老早提交的open directory申请居然通过了&#8230;想到一个多月没写东西，大惭&#8230; 为了尽快阻止这个连续N天没有日志的记录，先找一篇凑数&#8230; 先上开胃小菜 Appetizer 有人在byr论坛C++版上问了这样一道C++面试题： class A &#123; public: void fun&#40;&#41; &#123; &#125; &#125;; &#160; class B: public A &#123; public: virtual void fun&#40;&#41; &#123; &#125; &#125;; &#160; class C: public B &#123; public: void fun&#40;&#41;&#123;&#125; &#125;; &#160; class D: virtual public A &#123; public: void fun&#40;&#41;&#123;&#125; &#125;; &#160; int main&#40;void&#41; &#123; void *p; [...]]]></description>
			<content:encoded><![CDATA[<p>没事搜了一下自己域名，无意间发现老早提交的<a href="http://www.dmoz.org/World/Chinese_Simplified/%E8%AE%A1%E7%AE%97%E6%9C%BA/%E4%BA%92%E8%81%94%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E8%B5%84%E6%BA%90/%E5%8D%9A%E5%AE%A2/%E6%8A%80%E6%9C%AF/">open directory</a>申请居然通过了&#8230;想到一个多月没写东西，大惭&#8230;</p>
<p>为了尽快阻止这个连续N天没有日志的记录，先找一篇凑数&#8230;</p>
<h2>先上开胃小菜 Appetizer</h2>
<p>有人在<a href="http://forum.byr.edu.cn/wForum/disparticle.php?boardName=CPP&#038;ID=34447&#038;pos=49&#038;page=1">byr论坛C++版</a>上问了这样一道C++面试题：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">class</span> A <span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">public</span><span style="color: #008080;">:</span> <span style="color: #0000ff;">void</span> fun<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>    <span style="color: #008000;">&#123;</span>    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">class</span> B<span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> A <span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">public</span><span style="color: #008080;">:</span> <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> fun<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">class</span> C<span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> B <span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">public</span><span style="color: #008080;">:</span> <span style="color: #0000ff;">void</span> fun<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span><span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">class</span> D<span style="color: #008080;">:</span> <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">public</span> A <span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">void</span> fun<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span><span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span>  <span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>p<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>A<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span><span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>fun<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>C<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span><span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>fun<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// why fault here?</span>
    <span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>D<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span><span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>fun<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>为什么在((C*)NULL)->fun()这句挂了呢？</p>
<p><span id="more-78"></span><br />
原因很简单：B的fun是虚函数, 而C继承B, 所以通过C对象指针调用fun的时候触发基类virtual方法的多态特性, 需要查通过vptr查询虚表, 但是对NULL强制类型转换并不会设置vptr（vptr的设置是在构造函数中完成的），编译器就把地址0（NULL）中的内容当vptr，一解引用就segment fault了。</p>
<p>其实一开始看((A*)NULL)->fun();这句也觉得别扭，没有构造对象就直接调用非static的成员方法，居然还没有运行错误。想了一想，实际上在编译期，编译器都会通过一个<a href="http://en.wikipedia.org/wiki/Name_mangling">name mangling机制</a>将类的成员函数转换成一个具有唯一名字的非成员函数。程序开始运行时，成员函数和非成员函数一样都被载入到内存。所以只要在调用的成员函数不用到需要由类构造函数构造的成分（比如成员变量和vptr），这种通过指针调用成员函数就不会出错。</p>
<p>其实这个问题并不复杂，但是jmpesp老兄在回帖中写了一道更恶心的题目。</p>
<h2>主菜来了 Main Dishes</h2>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">class</span> A <span style="color: #008000;">&#123;</span>  
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>  
    <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> fun<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">float</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;A&quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span>  
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>  
&nbsp;
<span style="color: #0000ff;">class</span> B <span style="color: #008000;">&#123;</span>  
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>  
    <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> fun<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;B&quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span>  
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>  
&nbsp;
<span style="color: #0000ff;">class</span> C<span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> B, <span style="color: #0000ff;">public</span> A <span style="color: #008000;">&#123;</span>  
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>  
    <span style="color: #0000ff;">void</span> fun<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">float</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;C float&quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">void</span> fun<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #008000;">&#41;</span>   <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;C int&quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span> 
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>       
    C<span style="color: #000040;">*</span> p <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> C<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>B<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span>A<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>p<span style="color: #008000;">&#41;</span><span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>fun<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">delete</span> p<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>问该段代码的输出是什么？</p>
<p>自己编译运行了一下输出是：C float&#8230;</p>
<p>首先输出C是确定的，因为无论怎么转型， p都是指向一个C对象，而A、B中的fun都是虚函数，所以调用的肯定是C类方法。输出float看起来比较诡异，原因肯定在这个(B*)(A*)c-style转型上。</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">     <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #008000;">&#40;</span>A<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>p <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
     <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #008000;">&#40;</span>B<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>p <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
     <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #008000;">&#40;</span>B<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span>A<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>p <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span></pre></div></div>

<p>上面的代码得到以下输出：<br />
00382E30<br />
00382E34<br />
00382E30</p>
<p>可见(B*)(A*)p和(A*)p是相同的。</p>
<p>分析如下：</p>
<p>C继承了A和B，所以一个C对象里包含了一个A对象和B对象。由上面的输出知道(A*)p使得p偏移到了C对象中的A对象，是个static_cast。 接下来(B*)再对指向A对象的p进行转型，这时候问题就出现了，B对象并不包含A对象，编译器也不知道p指向的A对象实际上是包含在一个C对象里，所以 (B*)这次转换，只是改变了p的静态类型，并没有改变p指向的位置，是个reinterpret_cast也就是说p还是指向一个A对象。所以通过p调用fun(1)的时候，查的是A的虚表，先查到virtual void A::fun(float)，再到void C::fun(float)</p>
<p>这个问题的关键就在(B*)(A*)p这两个C-Style的函数式转型(functional cast)上:<br />
(A*)p是从派生类C到基类A的转换，有可能是个向从派生类到基类的static_cast，也有可能是个简单的reinterpret_cast, 从运行结果上看(A*)是个static_cast，而由(A*)到(B*)的转换不可能是static_cast（static_cast (static_cast(p)))是编译不过的），所以只能是reinterpret_cast</p>
<p>这里又出现了一个问题，为什么(A*)p是个static_cast而不是reinterpret_cast？至少这与我的直觉不服，在ISO C++标准5.4节找到如下定义(见图):</p>
<p>也就是说一个C-style的强制类型转换如果可以解释成多个列表里的C++ style转型，取在列表里位置最前面的一个。static_cast在reinterpret_cast前，所以得到了下面的结果：</p>
<p style="text-align: center;"><strong>(B*)(A*)p 等价于 reinterpret_cast(static_cast(p))</strong></p>
<h2><strong>由这道题目说明（Conclusion）：</strong></h2>
<ol>
<li><strong>千万不要用C-style对对象指针进行转型，请用C++-style的static_cast、reinterpret_cast和dynamic_cast，以免造成意料之外的错误。</strong></li>
<li><strong>C++标准是个好东西，它胜过任何技术手册，一旦对语言特性有困惑，查标准是最好的解决方法。</strong></li>
</ol>

	<h4>Related Post</h4>
	<ul class="st-related-posts">
	<li><a href="http://jackaldire.com/200906/cost-of-class-inherit/" title="类继承的开销 ——《Inside the C++ Object Model》笔记二 (2009年06月20日)">类继承的开销 ——《Inside the C++ Object Model》笔记二</a> (0)</li>
	<li><a href="http://jackaldire.com/200905/note-constructor/" title="构造函数 ——《Inside the C++ Object Model》笔记一 (2009年05月15日)">构造函数 ——《Inside the C++ Object Model》笔记一</a> (0)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://jackaldire.com/201001/c-style-cast-issues/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>[一道面试题]含有*的字符串匹配问题</title>
		<link>http://jackaldire.com/200911/string-matching-with-wildcard/</link>
		<comments>http://jackaldire.com/200911/string-matching-with-wildcard/#comments</comments>
		<pubDate>Wed, 25 Nov 2009 01:13:43 +0000</pubDate>
		<dc:creator>JackalDire</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[算法]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://jackaldire.com/?p=76</guid>
		<description><![CDATA[Question 字符串1：只含有英文字母 字符串2：含有英文字母和*，其中符号*表示匹配任意字符0或者多次，即正则表达式里面的含义。 现在给定这样的两个串，要求判断是否匹配？ bool isMatch ( const char *str1, const char *str2) 例如：str1 = &#8220;hello&#8221;, str2 = &#8220;he*o&#8221;，则二者匹配，返回true,str1 = &#8220;hello&#8221;, str2 = &#8220;he*l&#8221;，则不匹配，返回false。 Solution 关键是如何处理*，首先想到的就是回溯，在纸上画了一下得到如下算法 设输入是两个字符串 s, t, 其中t可能包含* 1.当*t不是*的时候, 就像普通的串匹配一样, 移动s和t 2.当*t是*的时候, 假设*t后面第一个不是*的字符是x, 若x是null, 直接匹配成功, 否则在s中找到当前位置后所有字符x的位置, 这时候问题转化成了t中x后的串和s中当前位置以后所有以x为开始的串的匹配问题, 递归调用即可, 其中任意一个匹配成功, 则原串匹配成功, 若都没有匹配成功则匹配失败. 3.当*s和*t其中一个是null时 跳出循环, 若此时 *t == &#8216;*&#8217;, 则++t 知道 t != &#8216;*&#8217;, 这时若 [...]]]></description>
			<content:encoded><![CDATA[<h2>Question</h2>
<p>字符串1：只含有英文字母<br />
字符串2：含有英文字母和*，其中符号*表示匹配任意字符0或者多次，即正则表达式里面的含义。</p>
<p>现在给定这样的两个串，要求判断是否匹配？<br />
bool isMatch ( const char *str1, const char *str2)</p>
<p>例如：str1 = &#8220;hello&#8221;, str2 = &#8220;he*o&#8221;，则二者匹配，返回true,str1 = &#8220;hello&#8221;, str2 = &#8220;he*l&#8221;，则不匹配，返回false。</p>
<p><span id="more-76"></span></p>
<h2>Solution</h2>
<p>关键是如何处理*，首先想到的就是回溯，在纸上画了一下得到如下算法</p>
<p>设输入是两个字符串 s, t, 其中t可能包含* <.p><br />
1.当*t不是*的时候, 就像普通的串匹配一样, 移动s和t <br />
2.当*t是*的时候,  假设*t后面第一个不是*的字符是x,  若x是null, 直接匹配成功,  否则在s中找到当前位置后所有字符x的位置, 这时候问题转化成了t中x后的串和s中当前位置以后所有以x为开始的串的匹配问题, 递归调用即可, 其中任意一个匹配成功, 则原串匹配成功, 若都没有匹配成功则匹配失败.</p>
<p>3.当*s和*t其中一个是null时 跳出循环, 若此时 *t  == &#8216;*&#8217;, 则++t 知道 t != &#8216;*&#8217;,  这时若 *t == 0 则代表匹配成功, 否则匹配失败。</p>
<p>代码如下:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;cstring&gt;</span>
<span style="color: #339900;">#include &lt;iostream&gt;</span>
&nbsp;
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">bool</span> is_match<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> s, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> t<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>s <span style="color: #000040;">&amp;&amp;</span> <span style="color: #000040;">*</span>t<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>t <span style="color: #000040;">!</span><span style="color: #000080;">=</span> <span style="color: #FF0000;">'*'</span> <span style="color: #000040;">&amp;&amp;</span> <span style="color: #000040;">*</span>s <span style="color: #000080;">==</span> <span style="color: #000040;">*</span>t<span style="color: #008000;">&#41;</span>
            <span style="color: #000040;">++</span>s, <span style="color: #000040;">++</span>t<span style="color: #008080;">;</span>
        <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>t <span style="color: #000040;">!</span><span style="color: #000080;">=</span> <span style="color: #FF0000;">'*'</span> <span style="color: #000040;">&amp;&amp;</span> <span style="color: #000040;">*</span>s <span style="color: #000040;">!</span><span style="color: #000080;">=</span> <span style="color: #000040;">*</span>t<span style="color: #008000;">&#41;</span>
            <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>t <span style="color: #000080;">==</span> <span style="color: #FF0000;">'*'</span><span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            <span style="color: #0000ff;">do</span> <span style="color: #000040;">++</span>t<span style="color: #008080;">;</span> <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>t <span style="color: #000080;">==</span> <span style="color: #FF0000;">'*'</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
            <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>t <span style="color: #000080;">==</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span><span style="color: #008080;">;</span>
            <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span> <span style="color: #008080;">;</span> <span style="color: #000040;">*</span>s<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>s<span style="color: #008000;">&#41;</span>
                <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>s <span style="color: #000080;">==</span> <span style="color: #000040;">*</span>t <span style="color: #000040;">&amp;&amp;</span> is_match<span style="color: #008000;">&#40;</span>s<span style="color: #000040;">+</span><span style="color: #0000dd;">1</span>, t<span style="color: #000040;">+</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
                    <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span><span style="color: #008080;">;</span>
            <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>t <span style="color: #000080;">==</span> <span style="color: #FF0000;">'*'</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">++</span>t<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>s <span style="color: #000080;">==</span> <span style="color: #000040;">*</span>t<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> argc, <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> argv<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>is_match<span style="color: #008000;">&#40;</span>argv<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span>, argv<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
        <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;match&quot;</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">else</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;not match&quot;</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<h2>改进</h2>
<p>上面的暴力算法如果遇到“aaaaaaaaaaaaaaaa”，“a*a*a*a*a*a*a*a*a*a*a*a”这样的输入，会达到2^n的复杂度，是无法接受的。注意到，递归搜索是有很多重复的状态，自然就想到了记忆化搜索，时间空间复杂度均为O(n^2)，代码如下：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;iostream&gt;</span>
<span style="color: #339900;">#include &lt;cstring&gt;</span>
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> MAX_LEN <span style="color: #000080;">=</span> <span style="color: #0000dd;">1024</span><span style="color: #008080;">;</span>
<span style="color: #0000ff;">int</span> dp<span style="color: #008000;">&#91;</span>MAX_LEN<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#91;</span>MAX_LEN<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">bool</span> is_match<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> p, <span style="color: #0000ff;">int</span> q, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> s, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> t<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>dp<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#91;</span>q<span style="color: #008000;">&#93;</span> <span style="color: #000080;">&gt;=</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">return</span> dp<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#91;</span>q<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">int</span> <span style="color: #000040;">&amp;</span>ans <span style="color: #000080;">=</span> dp<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#91;</span>q<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>s<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span> <span style="color: #000040;">&amp;&amp;</span> <span style="color: #000040;">!</span>t<span style="color: #008000;">&#91;</span>q<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        ans <span style="color: #000080;">=</span> <span style="color: #0000ff;">true</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>s<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span> <span style="color: #000040;">||</span> <span style="color: #000040;">!</span>t<span style="color: #008000;">&#91;</span>q<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>t<span style="color: #008000;">&#91;</span>q<span style="color: #008000;">&#93;</span> <span style="color: #000080;">==</span> <span style="color: #FF0000;">'*'</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
            ans <span style="color: #000080;">=</span> is_match<span style="color: #008000;">&#40;</span>p, q <span style="color: #000040;">+</span> <span style="color: #0000dd;">1</span>, s, t<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>t<span style="color: #008000;">&#91;</span>q<span style="color: #008000;">&#93;</span> <span style="color: #000080;">==</span> <span style="color: #FF0000;">'*'</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
            ans <span style="color: #000080;">=</span> is_match<span style="color: #008000;">&#40;</span>p <span style="color: #000040;">+</span> <span style="color: #0000dd;">1</span>, q, s, t<span style="color: #008000;">&#41;</span>
                <span style="color: #000040;">||</span> is_match<span style="color: #008000;">&#40;</span>p, q <span style="color: #000040;">+</span> <span style="color: #0000dd;">1</span>, s, t<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>s<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span> <span style="color: #000080;">==</span> t<span style="color: #008000;">&#91;</span>q<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
            ans <span style="color: #000080;">=</span> is_match<span style="color: #008000;">&#40;</span>p <span style="color: #000040;">+</span> <span style="color: #0000dd;">1</span>, q <span style="color: #000040;">+</span> <span style="color: #0000dd;">1</span>, s, t<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">return</span> ans<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">bool</span> is_match<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> s, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> t<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000dd;">memset</span><span style="color: #008000;">&#40;</span>dp, <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span>, <span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>dp<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> is_match<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, s, t<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>  
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> argc, <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> argv<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>is_match<span style="color: #008000;">&#40;</span>argv<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span>, argv<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
        <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;match&quot;</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">else</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;not match&quot;</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>


	<h4>Related Post</h4>
	<ul class="st-related-posts">
	<li><a href="http://jackaldire.com/200908/quick-sort-analysis/" title="快速排序详细分析 (2009年08月27日)">快速排序详细分析</a> (4)</li>
	<li><a href="http://jackaldire.com/200908/reverse-token/" title="[备忘]倒置字符串中的单词 (2009年08月18日)">[备忘]倒置字符串中的单词</a> (0)</li>
	<li><a href="http://jackaldire.com/200905/smart-way-to-solve-fibonacci/" title="Fibonacci数的巧妙求法 (2009年05月6日)">Fibonacci数的巧妙求法</a> (2)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://jackaldire.com/200911/string-matching-with-wildcard/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>快速排序详细分析</title>
		<link>http://jackaldire.com/200908/quick-sort-analysis/</link>
		<comments>http://jackaldire.com/200908/quick-sort-analysis/#comments</comments>
		<pubDate>Thu, 27 Aug 2009 09:15:37 +0000</pubDate>
		<dc:creator>JackalDire</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://jackaldire.com/?p=73</guid>
		<description><![CDATA[快速排序详细分析 注：REF[n]为参考资料，列于文章结尾。 看了编程珠玑Programming Perls第11章关于快速排序的讨论，发现自己长年用库函数，已经忘了快排怎么写。于是整理下思路和资料，把至今所了解的快排的方方面面记录与此。 纲要 算法描述 时间复杂度分析 具体实现细节 划分 选取枢纽元 固定位置 随机选取 三数取中 分割 单向扫描 双向扫描 Hoare的双向扫描 改进的双向扫描 双向扫描的其他问题 分治 尾递归 参考文献 一、算法描述（Algorithm Description） 快速排序由C.A.R.Hoare于1962年提出，算法相当简单精炼，基本策略是随机分治。 首先选取一个枢纽元（pivot），然后将数据划分成左右两部分，左边的大于（或等于）枢纽元，右边的小于(或等于枢纽元)，最后递归处理左右两部分。 分治算法一般分成三个部分：分解、解决以及合并。快排是就地排序，所以就不需要合并了。只需要划分（partition）和解决（递归）两个步骤。因为划分的结果决定递归的位置，所以Partition是整个算法的核心。 对数组S排序的形式化的描述如下（REF[1]）: 如果S中的元素个数是0或1，则返回 取S中任意一元素v，称之为枢纽元 将S-{v}（S中其余元素），划分成两个不相交的集合：S1={x∈S-{v}&#124;x=v} 返回{quicksort(S1) , v , quicksort(S2)} 二、时间复杂度分析（Time Complexity） 快速排序最佳运行时间O(nlogn)，最坏运行时间Ｏ(N^2)，随机化以后期望运行时间O(nlogn)，关于这些任何一本算法数据结构书上都有证明，就不写在这了，一下两点很重要： 选取枢纽元的不同, 决定了快排算法时间复杂度的数量级； 划分方法的划分方法总是O(n), 所以其具体实现的不同只影响算法时间复杂度的系数。 所以诉时间复杂度的分析都是围绕枢纽元的位置展开讨论的。 三、具体实现细节（Details of Implementaion） 1、划分(Partirion) 为了方便讨论，将Partition从QuickSort函数里提出来，就像算法导论里一样。实际实现时我更倾向于合并在一起，就一个函数，减少了函数调用次数。（REF[2]） 1 2 3 4 5 6 [...]]]></description>
			<content:encoded><![CDATA[<p>快速排序详细分析</p>
<p>注：REF[n]为参考资料，列于文章结尾。</p>
<p>看了编程珠玑Programming Perls第11章关于快速排序的讨论，发现自己长年用库函数，已经忘了快排怎么写。于是整理下思路和资料，把至今所了解的快排的方方面面记录与此。</p>
<p><span id="more-73"></span></p>
<h2>纲要</h2>
<ol>
<li>算法描述</li>
<li>时间复杂度分析</li>
<li>具体实现细节</li>
<ol style="border:0px">
<li>划分</li>
<ol style="border:0px">
<li>选取枢纽元</li>
<ol style="border:0px">
<li>固定位置</li>
<li>随机选取</li>
<li>三数取中</li>
</ol>
<li>分割</li>
<ol style="border:0px">
<li>单向扫描</li>
<li>双向扫描</li>
<li>Hoare的双向扫描</li>
<li>改进的双向扫描</li>
<li>双向扫描的其他问题</li>
</ol>
</ol>
<li>分治</li>
<ol  style="border:0px">
<li>尾递归</li>
</ol>
</ol>
<li>参考文献</li>
</ol>
<h2>一、算法描述（Algorithm Description）</h2>
<p>快速排序由C.A.R.Hoare于1962年提出，算法相当简单精炼，基本策略是随机分治。<br />
首先选取一个枢纽元（pivot），然后将数据划分成左右两部分，左边的大于（或等于）枢纽元，右边的小于(或等于枢纽元)，最后递归处理左右两部分。<br />
分治算法一般分成三个部分：分解、解决以及合并。快排是就地排序，所以就不需要合并了。只需要划分（partition）和解决（递归）两个步骤。因为划分的结果决定递归的位置，所以Partition是整个算法的核心。</p>
<p>对数组S排序的形式化的描述如下（REF[1]）:</p>
<ol>
<li>如果S中的元素个数是0或1，则返回</li>
<li>取S中任意一元素v，称之为枢纽元</li>
<li>将S-{v}（S中其余元素），划分成两个不相交的集合：S1={x∈S-{v}|x<=v} 和 S2={x∈S-{v}|x>=v}</li>
<li>返回{quicksort(S1) , v , quicksort(S2)}</li>
</ol>
<h2>二、时间复杂度分析（Time Complexity）</h2>
<p>快速排序最佳运行时间O(nlogn)，最坏运行时间Ｏ(N^2)，随机化以后期望运行时间O(nlogn)，关于这些任何一本算法数据结构书上都有证明，就不写在这了，一下两点很重要：</p>
<ol>
<li>选取枢纽元的不同, 决定了快排算法时间复杂度的数量级；</li>
<li>划分方法的划分方法总是O(n), 所以其具体实现的不同只影响算法时间复杂度的系数。</li>
</ol>
<p>所以诉时间复杂度的分析都是围绕枢纽元的位置展开讨论的。</p>
<h2>三、具体实现细节（Details of Implementaion）</h2>
<h3>1、划分(Partirion)</h3>
<p>为了方便讨论，将Partition从QuickSort函数里提出来，就像算法导论里一样。实际实现时我更倾向于合并在一起，就一个函数，减少了函数调用次数。（REF[2]）</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">void</span> QuickSort<span style="color: #008000;">&#40;</span>T A<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> p, <span style="color: #0000ff;">int</span> q<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>p <span style="color: #000080;">&lt;</span> q<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">int</span> q <span style="color: #000080;">=</span> Partition<span style="color: #008000;">&#40;</span>A, p, q<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        QuickSort<span style="color: #008000;">&#40;</span>A, p, q<span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        QuickSort<span style="color: #008000;">&#40;</span>A, q<span style="color: #000040;">+</span><span style="color: #0000dd;">1</span>, r<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>划分又分成两个步骤：<b>选取枢纽元</b>和<b>按枢纽元将数组分成左右两部分</b></p>
<h4>a.选取枢纽元（Pivot Selection）</h4>
<h5>固定位置</h5>
<p>同样是为了方便，将选取枢纽元单独提出来成一个函数：select_pivot(T A[], int p, int q)，该函数从A[p...q]中选取一个枢纽元并返回，且枢纽元放置在左端（A[p]的位置）。</p>
<p>对于完全随机的数据，枢纽元的选取不是很重要，往往直接取左端的元素作为枢纽元。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> select_pivot<span style="color: #008000;">&#40;</span>T A<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> p, <span style="color: #0000ff;">int</span> q<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span> A<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>但是实际应用中，数据往往是部分有序的，如果仍用两端的元素最为枢纽元，则会产生很不好的划分，使算法退化成O(n^2)。所以要采用一些手段避免这种情况，我知道的有“随机选取法”和“三数取中法”。</p>
<h5>随机选取</h5>
<p>顾名思义就是从A[p...q]中随机选择一个枢纽元，这个用库函数可以很容易实现</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> select_pivot_random<span style="color: #008000;">&#40;</span>T A<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> p, <span style="color: #0000ff;">int</span> q<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> randInt<span style="color: #008000;">&#40;</span>p, q<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    swap<span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span>, A<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> A<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>其中randInt(p, q)随机返回[p, q]中的一个数，C/C++里可由stdlib.h中的rand函数模拟。</p>
<h5>三数取中</h5>
<p>即取三个元素的中间数作为枢纽元，一般是取左端、右断和中间三个数，也可以随机选取。（REF[1]）</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> select_pivot_median3<span style="color: #008000;">&#40;</span>T A<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> p, <span style="color: #0000ff;">int</span> q<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span> m <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>p <span style="color: #000040;">+</span> q<span style="color: #008000;">&#41;</span><span style="color: #000040;">/</span><span style="color: #0000dd;">2</span><span style="color: #008080;">;</span>
    <span style="color: #ff0000; font-style: italic;">/* swap to ensure A[m] &lt;= A[p] &lt;= A[q] */</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span> <span style="color: #000080;">&lt;</span> A<span style="color: #008000;">&#91;</span>m<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> swap<span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span>, A<span style="color: #008000;">&#91;</span>m<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>q<span style="color: #008000;">&#93;</span> <span style="color: #000080;">&lt;</span> A<span style="color: #008000;">&#91;</span>m<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> swap<span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>q<span style="color: #008000;">&#93;</span>, A<span style="color: #008000;">&#91;</span>m<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>q<span style="color: #008000;">&#93;</span> <span style="color: #000080;">&lt;</span> A<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> swap<span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>q<span style="color: #008000;">&#93;</span>, A<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> A<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<h4>b.按枢纽元将数组分成左右两部分</h4>
<p>虽然说分割方法只影响算法时间复杂度的系数，但是一个好系数也是比较重要的。这也就是为什么实际应用中宁愿选择可能退化成O(n^2)的快速排序，也不用稳定的堆排序（堆排序交换次数太多，导致系数很大）。</p>
<p>常见的分割方法有三种：</p>
<h5>单向扫描</h5>
<p>单向扫描代码非常简单，只有短短的几行，思路也比较清晰。该算法由N.Lomuto提出，算法导论上也采用了这种算法。对于数组A[p...q]，该算法用一个循环扫描整个区间，并维护一个标志m，使得循环不变量（loop invariant）A[p＋1...m] < A[p] &#038;&#038; A[m+1, i-1] >= x[l]始终成立。（REF[2],REF[3]）</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> partition<span style="color: #008000;">&#40;</span>T A<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> p, <span style="color: #0000ff;">int</span> q<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span> x <span style="color: #000080;">=</span> select_pivot<span style="color: #008000;">&#40;</span>A, p, q<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> m <span style="color: #000080;">=</span> p, j<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> j <span style="color: #000080;">=</span> p<span style="color: #000040;">+</span><span style="color: #0000dd;">1</span><span style="color: #008080;">;</span> j <span style="color: #000080;">&lt;=</span> q<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>j<span style="color: #008000;">&#41;</span>
        <span style="color: #ff0000; font-style: italic;">/* invariant : A[p＋1...m] &lt; A[p] &amp;&amp; A[m+1, i-1] &gt;= x[q] */</span>
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>j<span style="color: #008000;">&#93;</span> <span style="color: #000080;">&lt;=</span> x<span style="color: #008000;">&#41;</span>
            swap<span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span><span style="color: #000040;">++</span>m<span style="color: #008000;">&#93;</span>, A<span style="color: #008000;">&#91;</span>j<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> 
    swap<span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span>, A<span style="color: #008000;">&#91;</span>m<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
    <span style="color: #ff0000; font-style: italic;">/* A[p...m-1] &lt; A[m] &lt;= A[m+1...u] */</span>
    <span style="color: #0000ff;">return</span> m<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>顺便废话几句，在看国外的书的时候，发现老外在分析和测试算法尤其是循环时，非常重视不变量（invariant）的使用。确立一个不变量，在循环开始之前和结束之后检查这个不变量，是一个很好的保持算法正确性的手段。</p>
<p>事实上第一种算法需要的交换次数比较多，而且如果采用选取左端元素作为枢纽元的方法，该算法在输入数组中元素全部相同时退化成O(n^2)。第二种方法可以避免这个问题。</p>
<h5>双向扫描</h5>
<p>双向扫描用两个标志i、j，分别初始化成数组的两端。主循环里嵌套两个内循环：第一个内循环i从左向右移过小于枢纽元的元素，遇到大元素时停止；第二个循环j从右向左移过大于枢纽元的元素，遇到小元素时停止。然后主循环检查i、j是否相交并交换A[i]、A[j]。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> partition<span style="color: #008000;">&#40;</span>T A<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> p, <span style="color: #0000ff;">int</span> q<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span> x <span style="color: #000080;">=</span> select_pivot<span style="color: #008000;">&#40;</span>A, p, q<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> p, j <span style="color: #000080;">=</span> q <span style="color: #000040;">+</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span> <span style="color: #008080;">;</span> <span style="color: #008080;">;</span> <span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">do</span> <span style="color: #000040;">++</span>i<span style="color: #008080;">;</span> <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span>i <span style="color: #000080;">&lt;=</span> q <span style="color: #000040;">&amp;&amp;</span> A<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span> <span style="color: #000080;">&lt;</span> x<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">do</span> <span style="color: #000040;">--</span>j<span style="color: #008080;">;</span> <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>j<span style="color: #008000;">&#93;</span> <span style="color: #000080;">&gt;</span> x<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>i <span style="color: #000080;">&gt;</span> j<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span>
        swap<span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span>, A<span style="color: #008000;">&#91;</span>j<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    swap<span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>p<span style="color: #008000;">&#93;</span>, A<span style="color: #008000;">&#91;</span>j<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> j<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>双向扫描可以正常处理所有元素相同的情况，而且交换次数比单向扫描要少。</p>
<h5>Hoare的双向扫描</h5>
<p>这种方法是Hoare在62年最初提出快速排序采用的方法，与前面的双向扫描基本相同，但是更难理解，手算了几组数据才搞明白：（REF[2]）</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> partition<span style="color: #008000;">&#40;</span>T A<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> p, <span style="color: #0000ff;">int</span> q<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span> x <span style="color: #000080;">=</span> select_pivot<span style="color: #008000;">&#40;</span>A, p, q<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> p <span style="color: #000040;">-</span> <span style="color: #0000dd;">1</span>, j <span style="color: #000080;">=</span> q <span style="color: #000040;">+</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span> <span style="color: #008080;">;</span> <span style="color: #008080;">;</span> <span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">do</span> <span style="color: #000040;">--</span>j<span style="color: #008080;">;</span> <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>j<span style="color: #008000;">&#93;</span> <span style="color: #000080;">&gt;</span> x<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">do</span> <span style="color: #000040;">++</span>i<span style="color: #008080;">;</span> <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span> <span style="color: #000080;">&lt;</span> x<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>i <span style="color: #000080;">&lt;</span> j<span style="color: #008000;">&#41;</span> swap<span style="color: #008000;">&#40;</span>A<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span>, A<span style="color: #008000;">&#91;</span>j<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span>
        <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">return</span> j<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>需要注意的是，返回值j并不是枢纽元的位置，但是仍然保证了A[p..j] <= A[j+1...q]。这种方法在效率上于双向扫描差别甚微，只是代码相对更为紧凑，并且用A[p]做哨兵元素减少了内层循环的一个if测试。</p>
<p>http://www.see2say.com/channel/music/player.aspx?v_album_id=9804</p>
<h5>改进的双向扫描</h5>
<p>枢纽元保存在一个临时变量中，这样左端的位置可视为空闲。j从右向左扫描，直到A[j]小于等于枢纽元,检查i、j是否相交并将A[j]赋给空闲位置A[i],这时A[j]变成空闲位置；i从左向右扫描，直到A[i]大于等于枢纽元,检查i、j是否相交并将A[i]赋给空闲位置A[j]，然后A[i]变成空闲位置。重复上述过程，最后直到i、j相交跳出循环。最后把枢纽元放到空闲位置上。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> partition<span style="color: #008000;">&#40;</span>T A<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> p, <span style="color: #0000ff;">int</span> q<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span> x <span style="color: #000080;">=</span> select_pivot<span style="color: #008000;">&#40;</span>A, p, q<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> p, j <span style="color: #000080;">=</span> q<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span> <span style="color: #008080;">;</span> <span style="color: #008080;">;</span> <span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span>i <span style="color: #000080;">&lt;</span> j <span style="color: #000040;">&amp;&amp;</span> A<span style="color: #008000;">&#91;</span>j<span style="color: #008000;">&#93;</span> <span style="color: #000080;">&gt;</span> x<span style="color: #008000;">&#41;</span> <span style="color: #000040;">--</span>j<span style="color: #008080;">;</span>
        A<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> A<span style="color: #008000;">&#91;</span>j<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span>i <span style="color: #000080;">&lt;</span> j <span style="color: #000040;">&amp;&amp;</span> A<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span> <span style="color: #000080;">&lt;</span> x<span style="color: #008000;">&#41;</span> <span style="color: #000040;">++</span>i<span style="color: #008080;">;</span>
        A<span style="color: #008000;">&#91;</span>j<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> A<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    A<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> x<span style="color: #008080;">;</span>  <span style="color: #666666;">// i == j</span>
    <span style="color: #0000ff;">return</span> i<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>这种类似迭代的方法，每次只需一次赋值，减少了内存读写次数，而前面几种的方法一次交换需要三次赋值操作。由于没有哨兵元素，不得不在内层循环里判断i、j是否相交，实际上反而增加了很多内存读取操作。但是由于循环计数器往往被放在寄存器了，而如果待排数组很大，访问其元素会频繁的cache miss，所以用计数器的访问次数换取待排数组的访存是值得的。</p>
<h5>关于双向扫描的几个问题</h5>
<p>1.内层循环中的while测试是用“严格大于/小于”还是&#8221;大于等于/小于等于&#8221;。</p>
<p>一般的想法是用大于等于/小于等于，忽略与枢纽元相同的元素，这样可以减少不必要的交换，因为这些元素无论放在哪一边都是一样的。但是如果遇到所有元素都一样的情况，这种方法每次都会产生最坏的划分，也就是一边1个元素，令一边n－1个元素，使得时间复杂度变成O(N^2)。而如果用严格大于/小于，虽然两边指针每此只挪动1位，但是它们会在正中间相遇，产生一个最好的划分，时间复杂度为log(2,n)。</p>
<p>另一个因素是，如果将枢纽元放在数组两端，用严格大于/小于就可以将枢纽元作为一个哨兵元素，从而减少内层循环的一个测试。<br />
由以上两点，内层循环中的while测试一般用“严格大于/小于”。</p>
<p>2.对于小数组特殊处理</p>
<p>按照上面的方法，递归会持续到分区只有一个元素。而事实上，当分割到一定大小后，继续分割的效率比插入排序要差。由统计方法得到的数值是50左右(REF[3])，也有采用20的（REF[1]）, 这样原先的QuickSort就可以写成这样</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">void</span> QuickSort<span style="color: #008000;">&#40;</span>T A<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> p, <span style="color: #0000ff;">int</span> q<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>q <span style="color: #000040;">-</span> p <span style="color: #000080;">&gt;</span> cutoff<span style="color: #008000;">&#41;</span> <span style="color: #666666;">//cutoff is constant </span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">int</span> q <span style="color: #000080;">=</span> Partition<span style="color: #008000;">&#40;</span>A, p, q<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        QuickSort<span style="color: #008000;">&#40;</span>A, p, q<span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        QuickSort<span style="color: #008000;">&#40;</span>A, q<span style="color: #000040;">+</span><span style="color: #0000dd;">1</span>, r<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">else</span>
        InsertionSort<span style="color: #008000;">&#40;</span>T A<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, p, q<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//user insertion sort for small arrays</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<h2>二、分治</h2>
<p>分治这里看起来没什么可说的，就是一枢纽元为中心，左右递归，实际上也有一些技巧。</p>
<h3>1.尾递归（Tail recursion）</h3>
<p>快排算法和大多数分治排序算法一样，都有两次递归调用。但是快排与归并排序不同，归并的递归则在函数一开始， 快排的递归在函数尾部，这就使得快排代码可以实施尾递归优化。第一次递归以后，变量p就没有用处了， 也就是说第二次递归可以用迭代控制结构代替。虽然这种优化一般是有编译器实施，但是也可以人为的模拟：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">void</span> QuickSort<span style="color: #008000;">&#40;</span>T A<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> p, <span style="color: #0000ff;">int</span> q<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span>p <span style="color: #000080;">&lt;</span> q<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">int</span> m <span style="color: #000080;">=</span> Partition<span style="color: #008000;">&#40;</span>A, p, q<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        QuickSort<span style="color: #008000;">&#40;</span>A, p, m<span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        p <span style="color: #000080;">=</span> m <span style="color: #000040;">+</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>采用这种方法可以缩减堆栈深度，由原来的O(n)缩减为O(logn)。</p>
<h2>三、参考文献：</h2>
<li>[1]Mark Allen Weiss. <em>Data Structures and Algorithms Analysis in C++</em>. Pearson Education, Third Edition, 2006.</li>
<li>[2]Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein. <em>Introduction to Algorithms</em>. MIT Press, 2001, Second Edtion, 2001.</li>
<li>[3]Jon Bently. <em>Programming Pearls</em>. Addison Wesley, Second Edition, 2000.</li>

	<h4>Related Post</h4>
	<ul class="st-related-posts">
	<li><a href="http://jackaldire.com/200908/reverse-token/" title="[备忘]倒置字符串中的单词 (2009年08月18日)">[备忘]倒置字符串中的单词</a> (0)</li>
	<li><a href="http://jackaldire.com/200911/string-matching-with-wildcard/" title="[一道面试题]含有*的字符串匹配问题 (2009年11月25日)">[一道面试题]含有*的字符串匹配问题</a> (5)</li>
	<li><a href="http://jackaldire.com/200905/smart-way-to-solve-fibonacci/" title="Fibonacci数的巧妙求法 (2009年05月6日)">Fibonacci数的巧妙求法</a> (2)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://jackaldire.com/200908/quick-sort-analysis/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>[备忘]倒置字符串中的单词</title>
		<link>http://jackaldire.com/200908/reverse-token/</link>
		<comments>http://jackaldire.com/200908/reverse-token/#comments</comments>
		<pubDate>Tue, 18 Aug 2009 14:24:08 +0000</pubDate>
		<dc:creator>JackalDire</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[备忘]]></category>
		<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://jackaldire.com/?p=70</guid>
		<description><![CDATA[输入：一个字符串，单词用某个特定符号分割（比如空格） 输出：一个字符串，单词顺序和原串相反 看到倒置，一般的做法是用栈，要么自己建个数组、要么STL，或者递归用程序栈。 优雅的递归 void reverse_token&#40;&#41; &#123; char str&#91;MAX&#93; = &#123;0&#125;; if &#40;scanf&#40;&#34;%[^#]&#34;, str&#41; != EOF&#41; &#123; //利用scanf的正则式特性 getchar&#40;&#41;; reverse_token&#40;&#41;; printf&#40;&#34;%s &#34;, str&#41;; &#125; &#125; STL list void reverse_token&#40;&#41; &#123; char tmp&#91;MAX&#93;; list&#60;string&#62; stack; while &#40;cin.getline&#40;tmp, MAX, '#'&#41;&#41; stack.push_front&#40;string&#40;tmp&#41;&#41;; copy&#40;stack.begin&#40;&#41;, stack.end&#40;&#41;, ostream_iterator&#60;string&#62;&#40;cout,&#34; &#34;&#41;&#41;; &#125; 如果是处理字符串, 而不是stdin, 可以改用sscanf()或者STL的范型算法find, 更标准的做法是strtok()。想到了javascript里的String().split(&#8216;x&#8217;)，直接返回一个分割后的数组，相当的方便。 Related Post 快速排序详细分析 (4) [一道面试题]含有*的字符串匹配问题 (5) Fibonacci数的巧妙求法 [...]]]></description>
			<content:encoded><![CDATA[<p>输入：一个字符串，单词用某个特定符号分割（比如空格）<br />
输出：一个字符串，单词顺序和原串相反</p>
<p>看到倒置，一般的做法是用栈，要么自己建个数组、要么STL，或者递归用程序栈。</p>
<h2>优雅的递归</h2>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span> reverse_token<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #993333;">char</span> str<span style="color: #009900;">&#91;</span>MAX<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>scanf<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%[^#]&quot;</span><span style="color: #339933;">,</span> str<span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> EOF<span style="color: #009900;">&#41;</span>  <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">//利用scanf的正则式特性</span>
      getchar<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      reverse_token<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%s &quot;</span><span style="color: #339933;">,</span> str<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span> 
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><span id="more-70"></span></p>
<h2>STL list</h2>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span> reverse_token<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">char</span> tmp<span style="color: #009900;">&#91;</span>MAX<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    list<span style="color: #339933;">&lt;</span>string<span style="color: #339933;">&gt;</span> stack<span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>cin.<span style="color: #202020;">getline</span><span style="color: #009900;">&#40;</span>tmp<span style="color: #339933;">,</span> MAX<span style="color: #339933;">,</span> <span style="color: #ff0000;">'#'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> stack.<span style="color: #202020;">push_front</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">string</span><span style="color: #009900;">&#40;</span>tmp<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    copy<span style="color: #009900;">&#40;</span>stack.<span style="color: #202020;">begin</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> stack.<span style="color: #202020;">end</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> ostream_iterator<span style="color: #339933;">&lt;</span>string<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #000066;">cout</span><span style="color: #339933;">,</span><span style="color: #ff0000;">&quot; &quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>
如果是处理字符串, 而不是stdin, 可以改用sscanf()或者STL的范型算法find, 更标准的做法是strtok()。想到了javascript里的String().split(&#8216;x&#8217;)，直接返回一个分割后的数组，相当的方便。</p>

	<h4>Related Post</h4>
	<ul class="st-related-posts">
	<li><a href="http://jackaldire.com/200908/quick-sort-analysis/" title="快速排序详细分析 (2009年08月27日)">快速排序详细分析</a> (4)</li>
	<li><a href="http://jackaldire.com/200911/string-matching-with-wildcard/" title="[一道面试题]含有*的字符串匹配问题 (2009年11月25日)">[一道面试题]含有*的字符串匹配问题</a> (5)</li>
	<li><a href="http://jackaldire.com/200905/smart-way-to-solve-fibonacci/" title="Fibonacci数的巧妙求法 (2009年05月6日)">Fibonacci数的巧妙求法</a> (2)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://jackaldire.com/200908/reverse-token/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>类型转换－无处不在的陷阱</title>
		<link>http://jackaldire.com/200907/a-trap-in-type-cast/</link>
		<comments>http://jackaldire.com/200907/a-trap-in-type-cast/#comments</comments>
		<pubDate>Sun, 05 Jul 2009 13:17:07 +0000</pubDate>
		<dc:creator>JackalDire</dc:creator>
				<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://jackaldire.com/?p=64</guid>
		<description><![CDATA[今天在论坛上看有laphon同学的一个问题，觉得这个问题很有意思。 原帖地址 问题援引如下: 做一个小程序的时候发现的。代码如下，使用的编译器为DEV-C++ 4.9.9.2。 如果先要求输入a,再要求输入b,那么a的值无论输入多少(少于255)输出都会是0； 反过来，如果先要求输入b，再要求输入a，那么就会正常。 这是为什么呢？请教达人解释。 #include #include &#160; int main&#40;int argc,char **argv&#41; &#123; unsigned char a,b; scanf&#40;&#34;%d&#34;,&#38;a&#41;; scanf&#40;&#34;%d&#34;,&#38;b&#41;; printf&#40;&#34;a=%d,b=%d\n&#34;,a,b&#41;; scanf&#40;&#34;%d&#34;,&#38;b&#41;; scanf&#40;&#34;%d&#34;,&#38;a&#41;; printf&#40;&#34;a=%d,b=%d\n&#34;,a,b&#41;; system&#40;&#34;pause&#34;&#41;; &#125; devcpp用的是gcc编译器，自己用gcc试了一下，果然是这样。为什么出现这种问题呢？开gdb调试，信息如下： main &#40;argc=1, argv=0xbfbaf3e4&#41; at a.c:7 7 scanf&#40;&#34;%d&#34;,&#38;a&#41;; &#40;gdb&#41; n 1 8 scanf&#40;&#34;%d&#34;,&#38;b&#41;; &#40;gdb&#41; p a $1 = 1 '\001' &#40;gdb&#41; n 2 9 printf&#40;&#34;a=%d,b=%d\n&#34;,a,b&#41;; &#40;gdb&#41; p a [...]]]></description>
			<content:encoded><![CDATA[<p>今天在论坛上看有laphon同学的一个问题，觉得这个问题很有意思。<br />
<a href="http://forum.byr.edu.cn/wForum/disparticle.php?boardName=CPP&#038;ID=25858&#038;pos=5">原帖地址</a><br />
问题援引如下:</p>
<blockquote><p>做一个小程序的时候发现的。代码如下，使用的编译器为DEV-C++ 4.9.9.2。<br />
如果先要求输入a,再要求输入b,那么a的值无论输入多少(少于255)输出都会是0；<br />
反过来，如果先要求输入b，再要求输入a，那么就会正常。<br />
这是为什么呢？请教达人解释。</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include</span>
<span style="color: #339933;">#include</span>
&nbsp;
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span><span style="color: #993333;">char</span> <span style="color: #339933;">**</span>argv<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span> a<span style="color: #339933;">,</span>b<span style="color: #339933;">;</span>
    scanf<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d&quot;</span><span style="color: #339933;">,&amp;</span>a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    scanf<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d&quot;</span><span style="color: #339933;">,&amp;</span>b<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;a=%d,b=%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span>a<span style="color: #339933;">,</span>b<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    scanf<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d&quot;</span><span style="color: #339933;">,&amp;</span>b<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    scanf<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d&quot;</span><span style="color: #339933;">,&amp;</span>a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;a=%d,b=%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span>a<span style="color: #339933;">,</span>b<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    system<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;pause&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

</blockquote>
<p><span id="more-64"></span><br />
devcpp用的是gcc编译器，自己用gcc试了一下，果然是这样。为什么出现这种问题呢？开gdb调试，信息如下：</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">main <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">argc</span>=<span style="color: #000000;">1</span>, <span style="color: #007800;">argv</span>=0xbfbaf3e4<span style="color: #7a0874; font-weight: bold;">&#41;</span> at a.c:<span style="color: #000000;">7</span>
<span style="color: #000000;">7</span>           scanf<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;%d&quot;</span>,<span style="color: #000000; font-weight: bold;">&amp;</span>a<span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> n
<span style="color: #000000;">1</span>
<span style="color: #000000;">8</span>           scanf<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;%d&quot;</span>,<span style="color: #000000; font-weight: bold;">&amp;</span>b<span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> p a
$<span style="color: #000000;">1</span> = <span style="color: #000000;">1</span> <span style="color: #ff0000;">'\001'</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> n
<span style="color: #000000;">2</span>
<span style="color: #000000;">9</span>           <span style="color: #7a0874; font-weight: bold;">printf</span><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;a=%d,b=%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>,a,b<span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> p a
$<span style="color: #000000;">2</span> = <span style="color: #000000;">0</span> <span style="color: #ff0000;">'\0'</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> p b
$<span style="color: #000000;">3</span> = <span style="color: #000000;">2</span> <span style="color: #ff0000;">'\002'</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

<p>从第12行可以看出，在第一次scanf读入b后，a的值被清0了，这样原因就好分析了。用%d读b的时候，实际上把b转型成了int，即<strong>scanf(&#8220;%d&#8221;,&#038;b)实际上等于 int * p = &#038;b;  *p = 2</strong> ，因为scanf接受的参数是指针。问题明显了，int4个字节，char1个字节，scanf实际上向内存里写了4个字节，高地址的3个字节为0，把a的1个字节和前面的参数区的2个字节给覆盖了。</p>
<p>如果声明顺序反过来，b在高地址，就不会把a覆盖，覆盖掉的是栈头部的参数区的3个字节。</p>
<p>但是无论那种方法，都是危险的，都会造成数据丢失。gcc 在开启 -Wall 开关后会给出警告</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"> warning<span style="color: #339933;">:</span> format ‘<span style="color: #339933;">%</span>d’ expects type ‘<span style="color: #993333;">int</span> <span style="color: #339933;">*</span>’<span style="color: #339933;">,</span> but argument <span style="color: #0000dd;">2</span> has type ‘<span style="color: #993333;">char</span> <span style="color: #339933;">*</span>’</pre></div></div>

<p>（这个warning应该是针对c标准库函数设计的）。</p>
<p>这种转型实际上C++其实是不允许的。比如</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">char</span> a<span style="color: #008080;">;</span> <span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span> p <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>a<span style="color: #008080;">;</span></pre></div></div>

<p>编译器(g++)会毫不客气的给出一个error：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">error<span style="color: #339933;">:</span> cannot convert ‘<span style="color: #993333;">char</span><span style="color: #339933;">*</span>’ to ‘<span style="color: #993333;">int</span><span style="color: #339933;">*</span>’ in initialization</pre></div></div>

<p>但是实际上那段“问题代码”仍然可以编译通过。为什么呢？查看了stdio.h，scanf函数的原型如下：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">extern</span> <span style="color: #993333;">int</span> scanf <span style="color: #009900;">&#40;</span>__const <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>__restrict __format<span style="color: #339933;">,</span> ...<span style="color: #009900;">&#41;</span></pre></div></div>

<p>printf最后一个参数&#8221;&#8230;&#8221;是一个变长参数，传参时实际传了一个void*进去，真正的类型分析和转型动在printf函数定义内的va_arg宏完成。所以编译器在分析这个函数调用时是无法知到真正的参数类型的。而scanf定义部分早被编译成了2进制lib。所以这段代码在c++中也可以编译通过。</p>
<p>另外有人说Intel C编译器没有这个问题，自己试了一下vc也没这个问题，这令我很费解。个人觉得这个问题似乎很难避免，因为这种用变长参数列表传递的参数，参数类型完全由前面的format string决定，可惜搞不到源码，就没法深究了。</p>

	<h4>Related Post</h4>
	<ul class="st-related-posts">
	<li>No Related Post</li>
	</ul>

]]></content:encoded>
			<wfw:commentRss>http://jackaldire.com/200907/a-trap-in-type-cast/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
