﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>博客园-zjz</title><link>http://www.cnblogs.com/zjz/</link><description>.net一些學習資料和文檔！</description><language>zh-cn</language><lastBuildDate>Wed, 19 Nov 2008 06:05:06 GMT</lastBuildDate><pubDate>Wed, 19 Nov 2008 06:05:06 GMT</pubDate><ttl>60</ttl><item><title>makefile</title><link>http://www.cnblogs.com/zjz/archive/2008/01/14/1038440.html</link><dc:creator>.net技術</dc:creator><author>.net技術</author><pubDate>Mon, 14 Jan 2008 08:06:00 GMT</pubDate><guid>http://www.cnblogs.com/zjz/archive/2008/01/14/1038440.html</guid><wfw:comment>http://www.cnblogs.com/zjz/comments/1038440.html</wfw:comment><comments>http://www.cnblogs.com/zjz/archive/2008/01/14/1038440.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zjz/comments/commentRss/1038440.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zjz/services/trackbacks/1038440.html</trackback:ping><description><![CDATA[<P>一.生成库文件<BR>cat test.h<BR>#ifndef __TEST_H__<BR>#define __TEST_H__<BR>#include &lt;string.h&gt;</P>
<P>char CmdStr[200][200];</P>
<P>class TEST<BR>{<BR>&nbsp;&nbsp;&nbsp; public:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TEST();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual ~TEST();<BR>&nbsp;&nbsp;&nbsp; public:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SplitBufByChar( char *buf1, char ch, char tc,int stno);<BR>};<BR>#endif<BR>cat&nbsp; test.cpp<BR>#include "test.h"</P>
<P>TEST::TEST()<BR>{<BR>&nbsp; for(int i=0;i&lt;200;i++)<BR>&nbsp; {<BR>&nbsp;&nbsp;&nbsp; CmdStr[i][0]='\0';<BR>&nbsp; }<BR>&nbsp;&nbsp;&nbsp; <BR>}<BR>TEST::~TEST()<BR>{<BR>&nbsp; for(int i=0;i&lt;200;++i)<BR>&nbsp; {<BR>&nbsp;&nbsp;&nbsp; CmdStr[i][0]='\0';<BR>&nbsp; }<BR>}</P>
<P>int TEST::SplitBufByChar( char *buf1, char ch, char tc,int stno)<BR>{<BR>&nbsp; char *ss0, *ss1;<BR>&nbsp; int&nbsp; i,j;<BR>&nbsp; char T[200][500];</P>
<P>&nbsp; ss0 = buf1; i = 0;<BR>&nbsp; while ( (ss1=strchr( ss0, ch )) != NULL )&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp; *ss1 = 0; strcpy( T[stno+i], ss0 );<BR>&nbsp;&nbsp;&nbsp;&nbsp; i++; ss0= ss1+1; *ss1= ch;<BR>&nbsp; }</P>
<P>&nbsp; if ( tc=='C' ) for (j=stno;j&lt;stno+i;j++) strcpy(CmdStr[j],T[j]);<BR>&nbsp; return( i );<BR>}<BR>cat makefile<BR>DEST=libtest.a <BR>OBJS=test.o<BR>CC= g++<BR>CPPFLAGS = -O2 -Wall<BR>SHAREFLAGS = -shared -fPIC<BR>INCLUDES = -I.</P>
<P>$(DEST) : $(OBJS)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(CC) $(SHAREFLAGS) $(INCLUDES) $(CPPFLAGS) -o $@ $^</P>
<P>test.o : test.cpp test.h<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(CC) $(INCLUDES) $(CPPFLAGS) -c $&lt; -o $@<BR><BR><BR>二.使用动态库<BR>cat protest.cpp<BR>#include "test.h"<BR>#include &lt;string&gt;<BR>#include &lt;vector&gt;</P>
<P>using namespace std;</P>
<P><BR>typedef struct{<BR>&nbsp;&nbsp;&nbsp; int id;<BR>&nbsp;&nbsp;&nbsp; string name;<BR>}STUDENT;</P>
<P>typedef std::vector &lt;STUDENT&gt; STRSET;</P>
<P>//extern char CmdStr[200][200];</P>
<P>&nbsp;</P>
<P>int main()<BR>{<BR>&nbsp;char sc[200];</P>
<P><BR>&nbsp;TEST test1;<BR>&nbsp;STUDENT stdt1,stdt2,stdt3;<BR>&nbsp;</P>
<P>&nbsp;STRSET settest;<BR>&nbsp;stdt1.id=200;<BR>&nbsp;stdt1.name="GPRS100~SMS-03-17~新GPRS100元套餐办理~";<BR>&nbsp;stdt2.id=100;<BR>&nbsp;stdt2.name="GPRS200~SMS-03-18~新GPRS100元套餐办理~";<BR>&nbsp;stdt3.id=300;<BR>&nbsp;stdt3.name="GPRS300~SMS-03-19~新GPRS100元套餐办理~";</P>
<P><BR>&nbsp;settest.push_back(stdt1);<BR>&nbsp;settest.push_back(stdt2);<BR>&nbsp;settest.push_back(stdt3);</P>
<P>&nbsp;for(std::vector &lt;STUDENT&gt;::iterator it=settest.begin();it !=settest.end();it++)<BR>&nbsp;{<BR>&nbsp; sprintf(sc,"%s",((STUDENT)*it).name.c_str());<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#ff0000>test1.SplitBufByChar(sc,'~','C',1);</FONT></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //test1.~TEST();<BR>&nbsp; printf("cmdstr[1]:%s\n",CmdStr[1]);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("cmdstr[2]:%s\n",CmdStr[2]);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("cmdstr[3]:%s\n",CmdStr[3]);<BR>&nbsp;}</P>
<P>&nbsp;return 0;</P>
<P>}<BR><BR>cat makefile<BR>DEST=protest<BR>OBJS=protest.o<BR>CC= g++<BR>CPPFLAGS = -O2 -Wall<BR>INCLUDES = -I. -I../libtest/<BR>LIBS =-L../libtest/ -ltest</P>
<P>$(DEST) : $(OBJS)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(CC) $(INCLUDES) $(LIBS) $(CPPFLAGS) -o $@ $^</P>
<P>protest.o : protest.cpp<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(CC) $(INCLUDES) $(CPPFLAGS) -c $&lt; -o $@</P><img src ="http://www.cnblogs.com/zjz/aggbug/1038440.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43606/" target="_blank">[新闻]李彦宏首次表态竞价排名问题:有错能改善莫大焉</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>c语言难点</title><link>http://www.cnblogs.com/zjz/archive/2006/09/21/510722.html</link><dc:creator>.net技術</dc:creator><author>.net技術</author><pubDate>Thu, 21 Sep 2006 05:58:00 GMT</pubDate><guid>http://www.cnblogs.com/zjz/archive/2006/09/21/510722.html</guid><wfw:comment>http://www.cnblogs.com/zjz/comments/510722.html</wfw:comment><comments>http://www.cnblogs.com/zjz/archive/2006/09/21/510722.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zjz/comments/commentRss/510722.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zjz/services/trackbacks/510722.html</trackback:ping><description><![CDATA[<P><FONT color=#000000><FONT size=1><STRONG>数组：</STRONG> </FONT></FONT></P>
<P><FONT color=#000000 size=1>分为一维数组和多维数组，其存储方式画为表格的话就会一目了然，其实就是把相同类型的变量有序的放在一起。因此，在处理比较多的数据时（这也是大多数的情况）数组的应用范围是非常广的。</FONT></P>
<P><FONT color=#000000 size=1>具体的实际应用不便举例，而且绝大多数是与指针相结合的，笔者个人认为学习数组在 更大程度上是为学习指针做一个铺垫。作为基础的基础要明白几种基本操作：即数组赋值、打印、排序（冒泡排序法和选择排序法）、查找。这些都不可避免的用到 循环，如果觉得反应不过来，可以先一点点的把循环展开，就会越来越熟悉，以后自己编写一个功能的时候就会先找出内在规律，较好的运用了。另外数组做参数 时，一维的[]里可以是空的，二维的第一个[]里可以是空的但是第二个[]中必须规定大小。</FONT></P>
<TABLE class=code width="100%" border=0>
<TBODY>
<TR>
<TD bgColor=#e0e0e0><FONT color=#000000 size=1>冒泡法排序函数： <BR>void bubble(int a[],int n) <BR>{ <BR>int i,j,k; <BR>for(i=1,i&lt;n;i++) <BR>&nbsp;&nbsp;&nbsp;for(j=0;j&lt;n-i;j++) <BR>&nbsp;&nbsp;&nbsp;if(a[j]&gt;a[j+1]) <BR>&nbsp;&nbsp;&nbsp; { <BR>&nbsp; &nbsp; k=a[j]; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a[j]=a[j+1]; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a[j+1]=k; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <BR>} <BR><BR>选择法排序函数： <BR>void sort(int a[],int n) <BR>{ <BR>int i,j,k,t; <BR>for(i=0,i&lt;n-1;i++) <BR>&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;k=i; <BR>&nbsp;&nbsp;&nbsp;for(j=i+1;j&lt;n;j++) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(a[k]&lt;a[j]) k=j; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(k!=i) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t=a[i]; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a[i]=a[k]; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a[k]=t; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <BR>&nbsp;&nbsp;&nbsp;} <BR>} <BR><BR>折半查找函数（原数组有序）： <BR>void search(int a[],int n,int x) <BR>{ <BR>int left=0,right=n-1,mid,flag=0; <BR>while((flag==0)&amp;&amp;(left&lt;=right)) <BR>&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;mid=(left+right)/2; <BR>&nbsp;&nbsp;&nbsp;if(x==a[mid]) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("%d%d",x,mid); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flag =1; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if(x&lt;a[mid]) right=mid-1; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else left=mid+1; <BR>&nbsp;&nbsp;&nbsp;} <BR>} </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000 size=1>相关常用的算法还有<STRONG>判断回文，求阶乘，Fibanacci数列，任意进制转换，杨辉三角形计算</STRONG>等等<STRONG>。</STRONG> </FONT></P>
<P><FONT color=#000000><FONT size=1><STRONG>字符串：</STRONG> </FONT></FONT></P>
<P><FONT color=#000000 size=1>字符串其实就是一个数组（指针），在scanf的输入列中是不需要在前面加 “&amp;”符号的，因为字符数组名本身即代表地址。值得注意的是字符串末尾的‘\0’，如果没有的话，字符串很有可能会不正常的打印。另外就是字符串 的定义和赋值问题了，笔者有一次的比较综合的上机作业就是字符串打印老是乱码，上上下下找了一圈问题，最后发现是因为</FONT></P>
<TABLE class=code width="100%" bgColor=#e0e0e0 border=0>
<TBODY>
<TR>
<TD><FONT color=#000000 size=1>char *name; </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000 size=1>而不是</FONT></P>
<TABLE class=code width="100%" bgColor=#e0e0e0 border=0>
<TBODY>
<TR>
<TD><FONT color=#000000 size=1>char name[10]; </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000 size=1>前者没有说明指向哪儿，更没有确定大小，导致了乱码的错误，印象挺深刻的。 </FONT></P>
<P><FONT color=#000000 size=1>另外，字符串的赋值也是需要注意的，如果是用字符指针的话，既可以定义的时候赋初值，即</FONT></P>
<TABLE class=code width="100%">
<TBODY>
<TR>
<TD class=text bgColor=#e0e0e0><FONT color=#000000 size=1>char *a="Abcdefg"; </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000 size=1>也可以在赋值语句中赋值，即</FONT></P>
<TABLE class=code width="100%" bgColor=#e0e0e0 border=0>
<TBODY>
<TR>
<TD><FONT color=#000000 size=1>char *a; <BR>a="Abcdefg"; </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000 size=1>但如果是用字符数组的话，就只能在定义时整体赋初值，即char a[5]={"abcd"};而不能在赋值语句中整体赋值。 </FONT></P>
<P><FONT color=#000000 size=1>常用字符串函数列表如下，要会自己实现：</FONT></P>
<TABLE cellSpacing=1 width="100%" bgColor=#000000 border=0>
<TBODY>
<TR>
<TD class=text width="21%" bgColor=#cccccc><FONT color=#000000><FONT size=1><STRONG>函数作用</STRONG> </FONT></FONT></TD>
<TD class=text width="30%" bgColor=#cccccc><FONT color=#000000><FONT size=1><STRONG>函数调用形式</STRONG> </FONT></FONT></TD>
<TD class=text width="49%" bgColor=#cccccc><FONT color=#000000><FONT size=1><STRONG>备注</STRONG> </FONT></FONT></TD></TR>
<TR>
<TD class=text bgColor=#ffffff><FONT color=#000000 size=1>字符串拷贝函数</FONT></TD>
<TD class=text bgColor=#ffffff><FONT color=#000000 size=1>strcpy(char*,char *)</FONT></TD>
<TD class=text bgColor=#ffffff><FONT color=#000000 size=1>后者拷贝到前者</FONT></TD></TR>
<TR>
<TD class=text bgColor=#e0e0e0><FONT color=#000000 size=1>字符串追加函数</FONT></TD>
<TD class=text bgColor=#e0e0e0><FONT color=#000000 size=1>strcat(char*,char *)</FONT></TD>
<TD class=text bgColor=#e0e0e0><FONT color=#000000 size=1>后者追加到前者后，返回前者，因此前者空间要足够大</FONT></TD></TR>
<TR>
<TD class=text bgColor=#ffffff><FONT color=#000000 size=1>字符串比较函数</FONT></TD>
<TD class=text bgColor=#ffffff><FONT color=#000000 size=1>strcmp(char*,char *)</FONT></TD>
<TD class=text bgColor=#ffffff><FONT color=#000000 size=1>前者等于、小于、大于后者时，返回0、正值、负值。注意，不是比较长度，是比较字符ASCII码的大小，可用于按姓名字母排序等。</FONT></TD></TR>
<TR>
<TD class=text bgColor=#e0e0e0><FONT color=#000000 size=1>字符串长度</FONT></TD>
<TD class=text bgColor=#e0e0e0><FONT color=#000000 size=1>strlen(char *)</FONT></TD>
<TD class=text bgColor=#e0e0e0><FONT color=#000000 size=1>返回字符串的长度，不包括'\0'.转义字符算一个字符。</FONT></TD></TR>
<TR>
<TD class=text bgColor=#ffffff><FONT color=#000000 size=1>字符串型-&gt;整型</FONT></TD>
<TD class=text bgColor=#ffffff colSpan=2><FONT color=#000000 size=1>atoi(char *)</FONT></TD></TR>
<TR>
<TD class=text bgColor=#e0e0e0 rowSpan=2><FONT color=#000000 size=1>整型-&gt;字符串型</FONT></TD>
<TD class=text bgColor=#e0e0e0><FONT color=#000000 size=1>itoa(int,char *,int)</FONT></TD>
<TD class=text bgColor=#e0e0e0><FONT color=#000000 size=1>做课设时挺有用的</FONT></TD></TR>
<TR>
<TD class=text bgColor=#e0e0e0><FONT color=#000000 size=1>sprintf(char *,格式化输入）</FONT></TD>
<TD class=text bgColor=#e0e0e0><FONT color=#000000 size=1>赋给字符串，而不打印出来。课设时用也比较方便</FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000><FONT size=1><STRONG>注：</STRONG>对字符串是不允许做==或！=的运算的，只能用字符串比较函数 </FONT></FONT></P>
<P><FONT color=#000000><FONT size=1><STRONG>指针：</STRONG> </FONT></FONT></P>
<P><FONT color=#000000 size=1>指针可以说是C语言中最关键的地方了，其实这个“指针”的名字对于这个概念的理解 是十分形象的。首先要知道，指针变量的值（即指针变量中存放的值）是指针（即地址）。指针变量定义形式中：基本类型 *指针变量名 中的“*”代表的是这是一个指向该基本类型的指针变量，而不是内容的意思。在以后使用的时候，如*ptr=a时，“*”才表示ptr所指向的地址里放的内 容是a。</FONT></P>
<P><FONT color=#000000 size=1>指针比较典型又简单的一应用例子是两数互换，看下面的程序，</FONT></P>
<TABLE class=code width="100%" bgColor=#e0e0e0 border=0>
<TBODY>
<TR>
<TD><FONT color=#000000 size=1>swap(int c,int d) <BR>{ <BR>int t; <BR>t=c; <BR>c=d; <BR>d=t; <BR>} <BR>main() <BR>{ <BR>int a=2,b=3; <BR>swap(a,b); <BR>printf(“%d,%d”,a,b); <BR>} </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000 size=1>这是不能实现a和b的数值互换的，实际上只是形参在这个函数中换来换去，对实参没什么影响。现在，用指针类型的数据做为参数的话，更改如下：</FONT></P>
<TABLE class=code width="100%" bgColor=#e0e0e0 border=0>
<TBODY>
<TR>
<TD><FONT color=#000000 size=1>swap(#3333FF *p1,int *p2) <BR>{ <BR>int t; <BR>t=*p1; <BR>*p1=*p2; <BR>*p2=t; <BR>} <BR>main() <BR>{ <BR>int a=2,b=3; <BR>int *ptr1,*ptr2; <BR>ptr1=&amp;a; <BR>ptr2=&amp;b; <BR>swap(prt1,ptr2); <BR>printf(“%d,%d”,a,b); <BR>} </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000 size=1>这样在swap中就把p1,p2 的内容给换了，即把a，b的值互换了。</FONT></P>
<P><FONT color=#000000 size=1>指针可以执行<STRONG>增、减运算</STRONG>，结合++运算符的法则，我们可以看到: </FONT></P>
<TABLE cellSpacing=1 cellPadding=0 width="100%" bgColor=#000000 border=0>
<TBODY>
<TR class=text bgColor=#cccccc>
<TD width="6%" bgColor=#e0e0e0><FONT color=#000000><FONT size=1><STRONG>*++s</STRONG> </FONT></FONT></TD>
<TD width="94%" bgColor=#ffffff>
<P><FONT color=#000000 size=1>取指针变量加1以后的内容</FONT></P></TD></TR>
<TR class=text bgColor=#cccccc>
<TD bgColor=#e0e0e0><FONT color=#000000><FONT size=1><STRONG>*s++</STRONG> </FONT></FONT></TD>
<TD bgColor=#ffffff><FONT color=#000000 size=1>取指针变量所指内容后s再加1</FONT></TD></TR>
<TR class=text bgColor=#cccccc>
<TD bgColor=#e0e0e0><FONT color=#000000><FONT size=1><STRONG>(*s)++</STRONG> </FONT></FONT></TD>
<TD bgColor=#ffffff><FONT color=#000000 size=1>指针变量指的内容加1</FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000><FONT size=1><STRONG>指针和数组</STRONG>实际上几乎是一样的，数组名可以看成是一个常量指针，一维数组中ptr=&amp;b[0]则下面的表示法是等价的： </FONT></FONT></P>
<P><STRONG><FONT color=#000000 size=1>a[3]等价于*(a+3) <BR>ptr[3]等价于*(ptr+3) </FONT></STRONG></P>
<P><FONT color=#000000 size=1>下面看一个用指针来自己实现atoi（字符串型-&gt;整型）函数：</FONT></P>
<TABLE class=code width="100%" bgColor=#e0e0e0 border=0>
<TBODY>
<TR>
<TD><FONT color=#000000 size=1>int atoi(char *s) <BR>{ <BR>int sign=1,m=0; <BR>if(*s=='+'||*s=='-') /*判断是否有符号*/ <BR>sign=(*s++=='+')?1:-1; /*用到三目运算符*/ <BR>while(*s!='\0') /*对每一个字符进行操作*/ <BR>&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;m=m*10+(*s-'0'); <BR>&nbsp;&nbsp;&nbsp;s++; /*指向下一个字符*/ <BR>&nbsp;&nbsp;&nbsp;} <BR>return m*sign; <BR>} </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000 size=1>指向多维数组的指针变量也是一个比较广泛的运用。例如数组a[3][4]，a代表的实际是整个二维数组的首地址，即第0行的首地址，也就是一个指针变量。而a+1就不是简单的在数值上加上1了，它代表的不是a[0][1]，而是第1行的首地址，&amp;a[1][0]。</FONT></P>
<P><FONT color=#000000 size=1>指针变量常用的用途还有把指针作为参数传递给其他函数，即<STRONG>指向函数的指针</STRONG>。 <BR>看下面的几行代码： </FONT></P>
<TABLE class=code width="100%" bgColor=#e0e0e0 border=0>
<TBODY>
<TR>
<TD><FONT color=#000000 size=1>void Input(ST *); <BR>void Output(ST *); <BR>void Bubble(ST *); <BR>void Find(ST *); <BR>void Failure(ST *); <BR>/*函数声明：这五个函数都是以一个指向ST型（事先定义过）结构的指针变量作为参数，无返回值。*/ <BR><BR>void (*process[5])(ST *)={Input,Output,Bubble,Find,Failure}; <BR>/*process被调用时提供5种功能不同的函数共选择(指向函数的指针数组）*/ <BR><BR>printf("\nChoose:\n?"); <BR>scanf("%d",&amp;choice); <BR>if(choice&gt;=0&amp;&amp;choice&lt;=4) <BR>(*process[choice])(a); /*调用相应的函数实现不同功能*;/ </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000 size=1>总之，指针的应用是非常灵活和广泛的，不是三言两语能说完的，上面几个小例子只是个引子，实际编程中，会逐渐发现运用指针所能带来的便利和高效率。 </FONT></P>
<P><FONT color=#000000><FONT size=1><STRONG>文件：</STRONG> </FONT></FONT></P>
<TABLE class=unnamed1 cellSpacing=1 cellPadding=0 width="100%" bgColor=#000000 border=0><!--DWLayoutTable-->
<TBODY>
<TR bgColor=#cccccc>
<TD class=text width="40%"><FONT color=#000000><FONT size=1><STRONG>函数调用形式</STRONG> </FONT></FONT></TD>
<TD class=text><FONT color=#000000><FONT size=1><STRONG>说明</STRONG> </FONT></FONT></TD></TR>
<TR bgColor=#ffffff>
<TD class=text><FONT color=#000000 size=1>fopen("路径","打开方式")</FONT></TD>
<TD class=text><FONT color=#000000 size=1>打开文件</FONT></TD></TR>
<TR bgColor=#e0e0e0>
<TD class=text><FONT color=#000000 size=1>fclose(FILE *)</FONT></TD>
<TD class=text><FONT color=#000000 size=1>防止之后被误用</FONT></TD></TR>
<TR bgColor=#ffffff>
<TD class=text><FONT color=#000000 size=1>fgetc(FILE *)</FONT></TD>
<TD class=text><FONT color=#000000 size=1>从文件中读取一个字符</FONT></TD></TR>
<TR bgColor=#e0e0e0>
<TD class=text><FONT color=#000000 size=1>fputc(ch,FILE *)</FONT></TD>
<TD class=text><FONT color=#000000 size=1>把ch代表的字符写入这个文件里</FONT></TD></TR>
<TR bgColor=#ffffff>
<TD class=text><FONT color=#000000 size=1>fgets(FILE *)</FONT></TD>
<TD class=text><FONT color=#000000 size=1>从文件中读取一行</FONT></TD></TR>
<TR bgColor=#e0e0e0>
<TD class=text><FONT color=#000000 size=1>fputs(FILE *)</FONT></TD>
<TD class=text><FONT color=#000000 size=1>把一行写入文件中</FONT></TD></TR>
<TR bgColor=#ffffff>
<TD class=text><FONT color=#000000 size=1>fprintf(FILE *,"格式字符串",输出表列）</FONT></TD>
<TD class=text><FONT color=#000000 size=1>把数据写入文件</FONT></TD></TR>
<TR bgColor=#e0e0e0>
<TD class=text><FONT color=#000000 size=1>fscanf(FILE *,"格式字符串",输入表列）</FONT></TD>
<TD class=text><FONT color=#000000 size=1>从文件中读取</FONT></TD></TR>
<TR bgColor=#ffffff>
<TD class=text><FONT color=#000000 size=1>fwrite（地址，sizeof（），n，FILE *）</FONT></TD>
<TD class=text><FONT color=#000000 size=1>把地址中n个sizeof大的数据写入文件里</FONT></TD></TR>
<TR bgColor=#e0e0e0>
<TD class=text><FONT color=#000000 size=1>fread（地址，sizeof（），n，FILE *）</FONT></TD>
<TD class=text><FONT color=#000000 size=1>把文件中n个sizeof大的数据读到地址里</FONT></TD></TR>
<TR bgColor=#ffffff>
<TD class=text><FONT color=#000000 size=1>rewind（FILE *）</FONT></TD>
<TD class=text><FONT color=#000000 size=1>把文件指针拨回到文件头</FONT></TD></TR>
<TR bgColor=#e0e0e0>
<TD class=text><FONT color=#000000 size=1>fseek（FILE *，x，0/1/2）</FONT></TD>
<TD class=text><FONT color=#000000 size=1>移动文件指针。第二个参数是位移量，0代表从头移，1代表从当前位置移，2代表从文件尾移。</FONT></TD></TR>
<TR bgColor=#ffffff>
<TD class=text><FONT color=#000000 size=1>feof(FILE *)</FONT></TD>
<TD class=text><FONT color=#000000 size=1>判断是否到了文件末尾</FONT></TD></TR></TBODY></TABLE><BR>
<TABLE cellSpacing=1 cellPadding=0 width="100%" bgColor=#000000 border=0><!--DWLayoutTable-->
<TBODY>
<TR bgColor=#e0e0e0>
<TD class=text width="22%"><FONT color=#000000><FONT size=1><STRONG>文件打开方式</STRONG> </FONT></FONT></TD>
<TD class=text width="78%"><FONT color=#000000><FONT size=1><STRONG>说明</STRONG> </FONT></FONT></TD></TR>
<TR bgColor=#ffffff>
<TD class=text><FONT color=#000000><FONT size=1><STRONG>r</STRONG> </FONT></FONT></TD>
<TD class=text><FONT color=#000000 size=1>打开只能读的文件</FONT></TD></TR>
<TR bgColor=#ffffff>
<TD class=text><FONT color=#000000><FONT size=1><STRONG>w</STRONG> </FONT></FONT></TD>
<TD class=text><FONT color=#000000 size=1>建立供写入的文件，如果已存在就抹去原有数据</FONT></TD></TR>
<TR bgColor=#ffffff>
<TD class=text><FONT color=#000000><FONT size=1><STRONG>a</STRONG> </FONT></FONT></TD>
<TD class=text><FONT color=#000000 size=1>打开或建立一个把数据追加到文件尾的文件</FONT></TD></TR>
<TR bgColor=#ffffff>
<TD class=text><FONT color=#000000><FONT size=1><STRONG>r+</STRONG> </FONT></FONT></TD>
<TD class=text><FONT color=#000000 size=1>打开用于更新数据的文件</FONT></TD></TR>
<TR bgColor=#ffffff>
<TD class=text><FONT color=#000000><FONT size=1><STRONG>w+</STRONG> </FONT></FONT></TD>
<TD class=text><FONT color=#000000 size=1>建立用于更新数据的文件，如果已存在就抹去原有数据</FONT></TD></TR>
<TR bgColor=#ffffff>
<TD class=text><FONT color=#000000><FONT size=1><STRONG>a+</STRONG> </FONT></FONT></TD>
<TD class=text><FONT color=#000000 size=1>打开或建立用于更新数据的文件，数据追加到文件尾</FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000><FONT size=1><STRONG>注：</STRONG>以上用于文本文件的操作，如果是二进制文件就在上述字母后加“b”。 </FONT></FONT></P>
<P><FONT color=#000000 size=1>我们用文件最大的目的就是能让数据保存下来。因此在要用文件中数据的时候，就是要 把数据读到一个结构（一般保存数据多用结构，便于管理）中去，再对结构进行操作即可。例如，文件aa.data中存储的是30个学生的成绩等信息，要遍历 这些信息，对其进行成绩输出、排序、查找等工作时，我们就把这些信息先读入到一个结构数组中，再对这个数组进行操作。如下例：</FONT></P>
<TABLE class=code width="100%" border=0>
<TBODY>
<TR>
<TD bgColor=#e0e0e0><FONT color=#000000 size=1>#include&lt;stdio.h&gt; <BR>#include&lt;stdlib.h&gt; <BR>#define N 30 </FONT>
<P><FONT color=#000000 size=1>typedef struct student /*定义储存学生成绩信息的数组*/ <BR>{ <BR>char *name; <BR>int chinese; <BR>int maths; <BR>int phy; <BR>int total; <BR>}ST; </FONT></P>
<P><FONT color=#000000 size=1>main() <BR>{ <BR>ST a[N]; /*存储N个学生信息的数组*/ <BR>FILE *fp; <BR>void (*process[3])(ST *)={Output,Bubble,Find}; /*实现相关功能的三个函数*/ <BR>int choice,i=0; <BR>Show(); <BR>printf("\nChoose:\n?"); <BR>scanf("%d",&amp;choice); <BR>while(choice&gt;=0&amp;&amp;choice&lt;=2) <BR>&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;fp=fopen("aa.dat","rb"); <BR>&nbsp;&nbsp;&nbsp;for(i=0;i&lt;N;i++) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fread(&amp;a[i],sizeof(ST),1,fp); /*把文件中储存的信息逐个读到数组中去*/ <BR>&nbsp;&nbsp;&nbsp;fclose(fp); <BR>&nbsp;&nbsp;&nbsp;(*process[choice])(a); /*前面提到的指向函数的指针，选择操作*/ <BR>&nbsp;&nbsp;&nbsp;printf("\n"); <BR>&nbsp;&nbsp;&nbsp;Show(); <BR>&nbsp;&nbsp;&nbsp;printf("\n?"); <BR>&nbsp;&nbsp;&nbsp;scanf("%d",&amp;choice); <BR>&nbsp;&nbsp;&nbsp;} <BR>} </FONT></P>
<P><FONT color=#000000 size=1>void Show() <BR>{ <BR>printf("\n****Choices:****\n0.Display the data form\n1.Bubble it according to the total score\n2.Search\n3.Quit!\n"); <BR>} </FONT></P>
<P><FONT color=#000000 size=1>void Output(ST *a) /*将文件中存储的信息逐个输出*/ <BR>{ <BR>int i,t=0; <BR>printf("Name Chinese Maths Physics Total\n"); <BR>for(i=0;i&lt;N;i++) <BR>&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;t=a[i].chinese+a[i].maths+a[i].phy; <BR>&nbsp;&nbsp;&nbsp;a[i].total=t; <BR>&nbsp;&nbsp;&nbsp;printf("%4s%8d%8d%8d%8d\n",a[i].name,a[i].chinese,a[i].maths,a[i].phy,a[i].total); <BR>&nbsp;&nbsp;&nbsp;} <BR>} </FONT></P>
<P><FONT color=#000000 size=1>void Bubble(ST *a) /*对数组进行排序，并输出结果*/ <BR>{ <BR>int i,pass; <BR>ST m; <BR>for(pass=0;pass&lt;N-1;pass++) <BR>&nbsp;&nbsp;&nbsp;for(i=0;i&lt;N-1;i++) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(a[i].total&lt;a[i+1].total) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m=a[i]; /*结构互换*/ <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a[i]=a[i+1]; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a[i+1]=m; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <BR>Output(a); <BR>} </FONT></P>
<P><FONT color=#000000 size=1>void Find(ST *a) <BR>{ <BR>int i,t=1; <BR>char m[20]; <BR>printf("\nEnter the name you want:"); <BR>scanf("%s",m); <BR>for(i=0;i&lt;N;i++) <BR>&nbsp;&nbsp;&nbsp;if(!strcmp(m,a[i].name)) /*根据姓名匹配情况输出查找结果*/ <BR>&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;printf("\nThe result is:\n%s, Chinese:%d, Maths:%d, &nbsp;&nbsp;&nbsp;&nbsp;Physics:%d,Total:%d\n",m,a[i].chinese,a[i].maths,a[i].phy,a[i].total); <BR>&nbsp;&nbsp;&nbsp;t=0; <BR>&nbsp;&nbsp;&nbsp;} <BR>if(t) <BR>&nbsp;&nbsp;&nbsp;printf("\nThe name is not in the list!\n"); <BR>} </FONT></P></TD></TR></TBODY></TABLE>
<P><FONT color=#000000><FONT size=1><STRONG>链表：</STRONG> <BR>链表是C语言中另外一个难点。牵扯到结点、动态分配空间等等。用结构作为链表的结点是非常适合的，例如： </FONT></FONT></P>
<TABLE class=code cellSpacing=4 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD bgColor=#e0e0e0><FONT color=#000000 size=1>struct node <BR>{ <BR>int data; <BR>struct node *next; <BR>}; </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000 size=1>其中next是指向自身所在结构类型的指针，这样就可以把一个个结点相连，构成链表。</FONT></P>
<P><FONT color=#000000 size=1>链表结构的一大优势就是动态分配存储，不会像数组一样必须在定义时确定大小，造成不必要的浪费。用malloc和free函数即可实现开辟和释放存储单元。其中，malloc的参数多用sizeof运算符计算得到。</FONT></P>
<P><FONT color=#000000 size=1>链表的基本操作有：<STRONG>正、反向建立链表；输出链表；删除链表中结点；在链表中插入结点</STRONG>等等，都是要熟练掌握的，初学者通过<STRONG>画图</STRONG>的方式能比较形象地理解建立、插入等实现的过程。 </FONT></P>
<TABLE class=code width="100%" border=0>
<TBODY>
<TR>
<TD bgColor=#e0e0e0><FONT color=#000000 size=1>typedef struct node <BR>{ <BR>char data; <BR>struct node *next; <BR>}NODE; /*结点*/ <BR><BR>正向建立链表： <BR>NODE *create() <BR>{ <BR>char ch='a'; <BR>NODE *p,*h=NULL,*q=NULL; <BR>while(ch&lt;'z') <BR>&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;p=(NODE *)malloc(sizeof(NODE)); /*强制类型转换为指针*/ <BR>&nbsp;&nbsp;&nbsp;p-&gt;data=ch; <BR>&nbsp;&nbsp;&nbsp;if(h==NULL) h=p; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else q-&gt;next=p; <BR>&nbsp;&nbsp;&nbsp;ch++; <BR>&nbsp;&nbsp;&nbsp;q=p; <BR>&nbsp;&nbsp;&nbsp;} <BR>q-&gt;next=NULL; /*链表结束*/ <BR>return h; <BR>} </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000><FONT size=1></FONT></FONT>&nbsp;</P>
<P><FONT color=#000000 size=1>逆向建立：</FONT></P>
<TABLE class=code width="100%" border=0>
<TBODY>
<TR>
<TD bgColor=#e0e0e0><FONT color=#000000 size=1>NODE *create() <BR>{ <BR>char ch='a'; <BR>NODE *p,*h=NULL; <BR>while(ch&lt;='z') <BR>&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;p=(NODE *)malloc(sizeof(NODE)); <BR>&nbsp;&nbsp;&nbsp;p-&gt;data=ch; <BR>&nbsp;&nbsp;&nbsp;p-&gt;next=h; /*不断地把head往前挪*/ <BR>&nbsp;&nbsp;&nbsp;h=p; <BR>&nbsp;&nbsp;&nbsp;ch++; <BR>&nbsp;&nbsp;&nbsp;} <BR>return h; <BR>} </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000><FONT size=1></FONT></FONT>&nbsp;</P>
<P><FONT color=#000000 size=1>用递归实现链表逆序输出：</FONT></P>
<TABLE class=code width="100%" border=0>
<TBODY>
<TR>
<TD bgColor=#e0e0e0><FONT color=#000000 size=1>void output(NODE *h) <BR>{ <BR>if(h!=NULL) <BR>&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;output(h-&gt;next); <BR>&nbsp;&nbsp;&nbsp;printf("%c",h-&gt;data); <BR>&nbsp;&nbsp;&nbsp;} <BR>} </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000 size=1>插入结点（已有升序的链表）：</FONT></P>
<TABLE class=code width="100%" border=0>
<TBODY>
<TR>
<TD bgColor=#e0e0e0><FONT color=#000000 size=1>NODE *insert(NODE *h,int x) <BR>{ <BR>NODE *new,*front,*current=h; <BR>while(current!=NULL&amp;&amp;(current-&gt;data&lt;x)) /*查找插入的位置*/ <BR>&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;front=current; <BR>&nbsp;&nbsp;&nbsp;current=current-&gt;next; <BR>&nbsp;&nbsp;&nbsp;} <BR>new=(NODE *)malloc(sizeof(NODE)); <BR>new-&gt;data=x; <BR>new-&gt;next=current; <BR>if(current==h) /*判断是否是要插在表头*/ <BR>&nbsp;&nbsp;&nbsp;h=new; <BR>else front-&gt;next=new; <BR>return h; <BR>} </FONT></TD></TR></TBODY></TABLE>
<P><FONT color=#000000><FONT size=1></FONT></FONT>&nbsp;</P>
<P><FONT color=#000000 size=1>删除结点：</FONT></P><FONT color=#000000 size=1>NODE *delete(NODE *h,int x) <BR>{ <BR>NODE *q,*p=h; <BR>while(p!=NULL&amp;&amp;(p-&gt;data!=x)) <BR>&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;q=p; <BR>&nbsp;&nbsp;&nbsp;p=p-&gt;next; <BR>&nbsp;&nbsp;&nbsp;} <BR>if(p-&gt;data==x) /*找到了要删的结点*/ <BR>&nbsp;&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;&nbsp;if(p==h) /*判断是否要删表头*/ <BR>&nbsp;&nbsp;&nbsp;h=h-&gt;next; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else q-&gt;next=p-&gt;next; <BR>&nbsp;&nbsp;&nbsp;free(p); /*释放掉已删掉的结点*/ <BR>&nbsp;&nbsp;&nbsp;} <BR>return h; <BR>}</FONT><BR><img src ="http://www.cnblogs.com/zjz/aggbug/510722.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43605/" target="_blank">[新闻]杨致远发表博客解释辞职原因</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>线程同步(转)</title><link>http://www.cnblogs.com/zjz/archive/2006/09/20/509688.html</link><dc:creator>.net技術</dc:creator><author>.net技術</author><pubDate>Wed, 20 Sep 2006 07:36:00 GMT</pubDate><guid>http://www.cnblogs.com/zjz/archive/2006/09/20/509688.html</guid><wfw:comment>http://www.cnblogs.com/zjz/comments/509688.html</wfw:comment><comments>http://www.cnblogs.com/zjz/archive/2006/09/20/509688.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zjz/comments/commentRss/509688.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zjz/services/trackbacks/509688.html</trackback:ping><description><![CDATA[<TABLE cellSpacing=0 cellPadding=0 width=504 align=center border=0>
<TBODY>
<TR>
<TD class=big vAlign=top colSpan=2><FONT color=#565656><FONT size=2><BR>　　<B>使线程同步</B><BR><BR>　　在程序中使用多线程时，一般很少有多个线程能在其生命期内进行完全独立的操作。更多的情况是一些线程进行某些处理操作，而其他的线程必须对其处理结果进行了解。正常情况下对这种处理结果的了解应当在其处理任务完成后进行。<BR><BR>　　如果不采取适当的措施，其他线程往往会在线程处理任务结束前就去访问处理结果，这就很有可能得到有关处理结果的错误了解。例如，多个线程同时访问同一个全局变量，如果都是读取操作，则不会出现问题。如果一个线程负责改变此变量的值，而其他线程负责同时读取变量内容，则不能保证读取到的数据是经过写线程修改后的。<BR><BR>　　为了确保读线程读取到的是经过修改的变量，就必须在向变量写入数据时禁止其他线程对其的任何访问，直至赋值过程结束后再解除对其他线程的访问限制。象这种保证线程能了解其他线程任务处理结束后的处理结果而采取的保护措施即为线程同步。<BR><BR>　　线程同步是一个非常大的话题，包括方方面面的内容。从大的方面讲，线程的同步可分用户模式的线程同步和内核对象的线程同步两大类。用户模式中线程的同步方法主要有原子访问和临界区等方法。其特点是同步速度特别快，适合于对线程运行速度有严格要求的场合。<BR><BR>　　内核对象的线程同步则主要由事件、等待定时器、信号量以及信号灯等内核对象构成。由于这种同步机制使用了内核对象，使用时必须将线程从用户模式切换到内核模式，而这种转换一般要耗费近千个CPU周期，因此同步速度较慢，但在适用性上却要远优于用户模式的线程同步方式。<BR></FONT>
<DIV><SPAN class=f14><FONT size=2>　　<B>临界区</B><BR><BR>　　临界区（Critical Section）是一段独占对某些共享资源访问的代码，在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区，那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起，并一直持续到进入临界区的线程离开。临界区在被释放后，其他线程可以继续抢占，并以此达到用原子方式操作共享资源的目的。<BR><BR>　　临界区在使用时以CRITICAL_SECTION结构对象保护共享资源，并分别用EnterCriticalSection（）和LeaveCriticalSection（）函数去标识和释放一个临界区。所用到的CRITICAL_SECTION结构对象必须经过InitializeCriticalSection（）的初始化后才能使用，而且必须确保所有线程中的任何试图访问此共享资源的代码都处在此临界区的保护之下。否则临界区将不会起到应有的作用，共享资源依然有被破坏的可能。<BR><BR><IMG onerror="this.src='http://www.yesky.com/image20010518/110093.jpg';" hspace=3 src="http://www.yesky.com/image20010518/110093.jpg" onload="var image=new Image();image.src=this.src;if(image.width>0 &amp;&amp; image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" align=center vspace=1 border=1><BR>图1 使用临界区保持线程同步<BR><BR>　　下面通过一段代码展示了临界区在保护多线程访问的共享资源中的作用。通过两个线程来分别对全局变量g_cArray[10]进行写入操作，用临界区结构对象g_cs来保持线程的同步，并在开启线程前对其进行初始化。为了使实验效果更加明显，体现出临界区的作用，在线程函数对共享资源g_cArray[10]的写入时，以Sleep（）函数延迟1毫秒，使其他线程同其抢占CPU的可能性增大。如果不使用临界区对其进行保护，则共享资源数据将被破坏（参见图1（a）所示计算结果），而使用临界区对线程保持同步后则可以得到正确的结果（参见图1（b）所示计算结果）。代码实现清单附下：<BR><BR></FONT>
<P></P>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>// 临界区结构对象<BR>CRITICAL_SECTION g_cs;<BR>// 共享资源 <BR>char g_cArray[10];<BR>UINT ThreadProc10(LPVOID pParam)<BR>{<BR>　// 进入临界区<BR>　EnterCriticalSection(&amp;g_cs);<BR>　// 对共享资源进行写入操作<BR>　for (int i = 0; i &lt; 10; i++)<BR>　{<BR>　　g_cArray[i] = 'a';<BR>　　Sleep(1);<BR>　}<BR>　// 离开临界区<BR>　LeaveCriticalSection(&amp;g_cs);<BR>　return 0;<BR>}<BR>UINT ThreadProc11(LPVOID pParam)<BR>{<BR>　// 进入临界区<BR>　EnterCriticalSection(&amp;g_cs);<BR>　// 对共享资源进行写入操作<BR>　for (int i = 0; i &lt; 10; i++)<BR>　{<BR>　　g_cArray[10 - i - 1] = 'b';<BR>　　Sleep(1);<BR>　}<BR>　// 离开临界区<BR>　LeaveCriticalSection(&amp;g_cs);<BR>　return 0;<BR>}<BR>……<BR>void CSample08View::OnCriticalSection() <BR>{<BR>　// 初始化临界区<BR>　InitializeCriticalSection(&amp;g_cs);<BR>　// 启动线程<BR>　AfxBeginThread(ThreadProc10, NULL);<BR>　AfxBeginThread(ThreadProc11, NULL);<BR>　// 等待计算完毕<BR>　Sleep(300);<BR>　// 报告计算结果<BR>　CString sResult = CString(g_cArray);<BR>　AfxMessageBox(sResult);<BR>}</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　在使用临界区时，一般不允许其运行时间过长，只要进入临界区的线程还没有离开，其他所有试图进入此临界区的线程都会被挂起而进入到等待状态，并会在一定程度上影响。程序的运行性能。尤其需要注意的是不要将等待用户输入或是其他一些外界干预的操作包含到临界区。如果进入了临界区却一直没有释放，同样也会引起其他线程的长时间等待。换句话说，在执行了EnterCriticalSection（）语句进入临界区后无论发生什么，必须确保与之匹配的LeaveCriticalSection（）都能够被执行到。可以通过添加结构化异常处理代码来确保LeaveCriticalSection（）语句的执行。虽然临界区同步速度很快，但却只能用来同步本进程内的线程，而不可用来同步多个进程中的线程。<BR><BR>　　MFC为临界区提供有一个CCriticalSection类，使用该类进行线程同步处理是非常简单的，只需在线程函数中用CCriticalSection类成员函数Lock（）和UnLock（）标定出被保护代码片段即可。对于上述代码，可通过CCriticalSection类将其改写如下：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>// MFC临界区类对象<BR>CCriticalSection g_clsCriticalSection;<BR>// 共享资源 <BR>char g_cArray[10];<BR>UINT ThreadProc20(LPVOID pParam)<BR>{<BR>　// 进入临界区<BR>　g_clsCriticalSection.Lock();<BR>　// 对共享资源进行写入操作<BR>　for (int i = 0; i &lt; 10; i++)<BR>　{<BR>　　g_cArray[i] = 'a';<BR>　　Sleep(1);<BR>　}<BR>　// 离开临界区<BR>　g_clsCriticalSection.Unlock();<BR>　return 0;<BR>}<BR>UINT ThreadProc21(LPVOID pParam)<BR>{<BR>　// 进入临界区<BR>　g_clsCriticalSection.Lock();<BR>　// 对共享资源进行写入操作<BR>　for (int i = 0; i &lt; 10; i++)<BR>　{<BR>　　g_cArray[10 - i - 1] = 'b';<BR>　　Sleep(1);<BR>　}<BR>　// 离开临界区<BR>　g_clsCriticalSection.Unlock();<BR>　return 0;<BR>}<BR>……<BR>void CSample08View::OnCriticalSectionMfc() <BR>{<BR>　// 启动线程<BR>　AfxBeginThread(ThreadProc20, NULL);<BR>　AfxBeginThread(ThreadProc21, NULL);<BR>　// 等待计算完毕<BR>　Sleep(300);<BR>　// 报告计算结果<BR>　CString sResult = CString(g_cArray);<BR>　AfxMessageBox(sResult);<BR>}</FONT></TD></TR></TBODY></TABLE></SPAN></DIV><SPAN class=f14><FONT size=2>　　<B>管理事件内核对象</B><BR><BR>　　在前面讲述线程通信时曾使用过事件内核对象来进行线程间的通信，除此之外，事件内核对象也可以通过通知操作的方式来保持线程的同步。对于前面那段使用临界区保持线程同步的代码可用事件对象的线程同步方法改写如下：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>// 事件句柄<BR>HANDLE hEvent = NULL;<BR>// 共享资源 <BR>char g_cArray[10];<BR>……<BR>UINT ThreadProc12(LPVOID pParam)<BR>{<BR>　// 等待事件置位<BR>　WaitForSingleObject(hEvent, INFINITE);<BR>　// 对共享资源进行写入操作<BR>　for (int i = 0; i &lt; 10; i++)<BR>　{<BR>　　g_cArray[i] = 'a';<BR>　　Sleep(1);<BR>　}<BR>　// 处理完成后即将事件对象置位<BR>　SetEvent(hEvent);<BR>　return 0;<BR>}<BR>UINT ThreadProc13(LPVOID pParam)<BR>{<BR>　// 等待事件置位<BR>　WaitForSingleObject(hEvent, INFINITE);<BR>　// 对共享资源进行写入操作<BR>　for (int i = 0; i &lt; 10; i++)<BR>　{<BR>　　g_cArray[10 - i - 1] = 'b';<BR>　　Sleep(1);<BR>　}<BR>　// 处理完成后即将事件对象置位<BR>　SetEvent(hEvent);<BR>　return 0;<BR>}<BR>……<BR>void CSample08View::OnEvent() <BR>{<BR>　// 创建事件<BR>　hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);<BR>　// 事件置位<BR>　SetEvent(hEvent);<BR>　// 启动线程<BR>　AfxBeginThread(ThreadProc12, NULL);<BR>　AfxBeginThread(ThreadProc13, NULL);<BR>　// 等待计算完毕<BR>　Sleep(300);<BR>　// 报告计算结果<BR>　CString sResult = CString(g_cArray);<BR>　AfxMessageBox(sResult);<BR>}</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　在创建线程前，首先创建一个可以自动复位的事件内核对象hEvent，而线程函数则通过WaitForSingleObject（）等待函数无限等待hEvent的置位，只有在事件置位时WaitForSingleObject（）才会返回，被保护的代码将得以执行。对于以自动复位方式创建的事件对象，在其置位后一被WaitForSingleObject（）等待到就会立即复位，也就是说在执行ThreadProc12（）中的受保护代码时，事件对象已经是复位状态的，这时即使有ThreadProc13（）对CPU的抢占，也会由于WaitForSingleObject（）没有hEvent的置位而不能继续执行，也就没有可能破坏受保护的共享资源。在ThreadProc12（）中的处理完成后可以通过SetEvent（）对hEvent的置位而允许ThreadProc13（）对共享资源g_cArray的处理。这里SetEvent（）所起的作用可以看作是对某项特定任务完成的通知。<BR><BR>　　使用临界区只能同步同一进程中的线程，而使用事件内核对象则可以对进程外的线程进行同步，其前提是得到对此事件对象的访问权。可以通过OpenEvent（）函数获取得到，其函数原型为：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>HANDLE OpenEvent(<BR>　DWORD dwDesiredAccess, // 访问标志<BR>　BOOL bInheritHandle, // 继承标志<BR>　LPCTSTR lpName // 指向事件对象名的指针<BR>);</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　如果事件对象已创建（在创建事件时需要指定事件名），函数将返回指定事件的句柄。对于那些在创建事件时没有指定事件名的事件内核对象，可以通过使用内核对象的继承性或是调用DuplicateHandle（）函数来调用CreateEvent（）以获得对指定事件对象的访问权。在获取到访问权后所进行的同步操作与在同一个进程中所进行的线程同步操作是一样的。<BR><BR>　　如果需要在一个线程中等待多个事件，则用WaitForMultipleObjects（）来等待。WaitForMultipleObjects（）与WaitForSingleObject（）类似，同时监视位于句柄数组中的所有句柄。这些被监视对象的句柄享有平等的优先权，任何一个句柄都不可能比其他句柄具有更高的优先权。WaitForMultipleObjects（）的函数原型为：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>DWORD WaitForMultipleObjects(<BR>　DWORD nCount, // 等待句柄数<BR>　CONST HANDLE *lpHandles, // 句柄数组首地址<BR>　BOOL fWaitAll, // 等待标志<BR>　DWORD dwMilliseconds // 等待时间间隔<BR>);</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　参数nCount指定了要等待的内核对象的数目，存放这些内核对象的数组由lpHandles来指向。fWaitAll对指定的这nCount个内核对象的两种等待方式进行了指定，为TRUE时当所有对象都被通知时函数才会返回，为FALSE则只要其中任何一个得到通知就可以返回。dwMilliseconds在这里的作用与在WaitForSingleObject（）中的作用是完全一致的。如果等待超时，函数将返回WAIT_TIMEOUT。如果返回WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1中的某个值，则说明所有指定对象的状态均为已通知状态（当fWaitAll为TRUE时）或是用以减去WAIT_OBJECT_0而得到发生通知的对象的索引（当fWaitAll为FALSE时）。如果返回值在WAIT_ABANDONED_0与WAIT_ABANDONED_0+nCount-1之间，则表示所有指定对象的状态均为已通知，且其中至少有一个对象是被丢弃的互斥对象（当fWaitAll为TRUE时），或是用以减去WAIT_OBJECT_0表示一个等待正常结束的互斥对象的索引（当fWaitAll为FALSE时）。 下面给出的代码主要展示了对WaitForMultipleObjects（）函数的使用。通过对两个事件内核对象的等待来控制线程任务的执行与中途退出：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>// 存放事件句柄的数组<BR>HANDLE hEvents[2];<BR>UINT ThreadProc14(LPVOID pParam)<BR>{ <BR>　// 等待开启事件<BR>　DWORD dwRet1 = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);<BR>　// 如果开启事件到达则线程开始执行任务<BR>　if (dwRet1 == WAIT_OBJECT_0)<BR>　{<BR>　　AfxMessageBox("线程开始工作!");<BR>　　while (true)<BR>　　{<BR>　　　for (int i = 0; i &lt; 10000; i++);<BR>　　　// 在任务处理过程中等待结束事件 <BR>　　　DWORD dwRet2 = WaitForMultipleObjects(2, hEvents, FALSE, 0);<BR>　　　// 如果结束事件置位则立即终止任务的执行<BR>　　　if (dwRet2 == WAIT_OBJECT_0 + 1)<BR>　　　　break;<BR>　　}<BR>　}<BR>　AfxMessageBox("线程退出!");<BR>　return 0;<BR>}<BR>……<BR>void CSample08View::OnStartEvent() <BR>{<BR>　// 创建线程<BR>　for (int i = 0; i &lt; 2; i++)<BR>　　hEvents[i] = CreateEvent(NULL, FALSE, FALSE, NULL);<BR>　　// 开启线程<BR>　　AfxBeginThread(ThreadProc14, NULL);<BR>　　// 设置事件0(开启事件)<BR>　　SetEvent(hEvents[0]);<BR>}<BR>void CSample08View::OnEndevent() <BR>{<BR>　// 设置事件1(结束事件)<BR>　SetEvent(hEvents[1]);<BR>}</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　MFC为事件相关处理也提供了一个CEvent类，共包含有除构造函数外的4个成员函数PulseEvent（）、ResetEvent（）、SetEvent（）和UnLock（）。在功能上分别相当与Win32 API的PulseEvent（）、ResetEvent（）、SetEvent（）和CloseHandle（）等函数。而构造函数则履行了原CreateEvent（）函数创建事件对象的职责，其函数原型为：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>CEvent(BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　按照此缺省设置将创建一个自动复位、初始状态为复位状态的没有名字的事件对象。封装后的CEvent类使用起来更加方便，图2即展示了CEvent类对A、B两线程的同步过程：<BR><BR><IMG onerror="this.src='http://www.yesky.com/image20010518/110094.jpg';" hspace=3 src="http://www.yesky.com/image20010518/110094.jpg" onload="var image=new Image();image.src=this.src;if(image.width>0 &amp;&amp; image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" align=center vspace=1 border=1><BR>图2 CEvent类对线程的同步过程示意<BR><BR>　　B线程在执行到CEvent类成员函数Lock（）时将会发生阻塞，而A线程此时则可以在没有B线程干扰的情况下对共享资源进行处理，并在处理完成后通过成员函数SetEvent（）向B发出事件，使其被释放，得以对A先前已处理完毕的共享资源进行操作。可见，使用CEvent类对线程的同步方法与通过API函数进行线程同步的处理方法是基本一致的。前面的API处理代码可用CEvent类将其改写为：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>// MFC事件类对象<BR>CEvent g_clsEvent;<BR>UINT ThreadProc22(LPVOID pParam)<BR>{<BR>　// 对共享资源进行写入操作<BR>　for (int i = 0; i &lt; 10; i++)<BR>　{<BR>　　g_cArray[i] = 'a';<BR>　　Sleep(1);<BR>　}<BR>　// 事件置位<BR>　g_clsEvent.SetEvent();<BR>　return 0;<BR>}<BR>UINT ThreadProc23(LPVOID pParam)<BR>{<BR>　// 等待事件<BR>　g_clsEvent.Lock();<BR>　// 对共享资源进行写入操作<BR>　for (int i = 0; i &lt; 10; i++)<BR>　{<BR>　　g_cArray[10 - i - 1] = 'b';<BR>　　Sleep(1);<BR>　}<BR>　return 0;<BR>}<BR>……<BR>void CSample08View::OnEventMfc() <BR>{<BR>　// 启动线程<BR>　AfxBeginThread(ThreadProc22, NULL);<BR>　AfxBeginThread(ThreadProc23, NULL);<BR>　// 等待计算完毕<BR>　Sleep(300);<BR>　// 报告计算结果<BR>　CString sResult = CString(g_cArray);<BR>　AfxMessageBox(sResult);<BR>}</FONT></TD></TR></TBODY></TABLE></SPAN><SPAN class=f14><FONT size=2>　　<B>信号量内核对象</B><BR><BR>　　信号量（Semaphore）内核对象对线程的同步方式与前面几种方法不同，它允许多个线程在同一时刻访问同一资源，但是需要限制在同一时刻访问此资源的最大线程数目。在用CreateSemaphore（）创建信号量时即要同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数，每增加一个线程对共享资源的访问，当前可用资源计数就会减1，只要当前可用资源计数是大于0的，就可以发出信号量信号。但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最大数目，不能在允许其他线程的进入，此时的信号量信号将无法发出。线程在处理完共享资源后，应在离开的同时通过ReleaseSemaphore（）函数将当前可用资源计数加1。在任何时候当前可用资源计数决不可能大于最大资源计数。<BR><BR><IMG onerror="this.src='http://www.yesky.com/image20010518/110095.jpg';" hspace=3 src="http://www.yesky.com/image20010518/110095.jpg" onload="var image=new Image();image.src=this.src;if(image.width>0 &amp;&amp; image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" align=center vspace=1 border=1><BR>图3 使用信号量对象控制资源<BR><BR>　　下面结合图例3来演示信号量对象对资源的控制。在图3中，以箭头和白色箭头表示共享资源所允许的最大资源计数和当前可用资源计数。初始如图（a）所示，最大资源计数和当前可用资源计数均为4，此后每增加一个对资源进行访问的线程（用黑色箭头表示）当前资源计数就会相应减1，图（b）即表示的在3个线程对共享资源进行访问时的状态。当进入线程数达到4个时，将如图（c）所示，此时已达到最大资源计数，而当前可用资源计数也已减到0，其他线程无法对共享资源进行访问。在当前占有资源的线程处理完毕而退出后，将会释放出空间，图（d）已有两个线程退出对资源的占有，当前可用计数为2，可以再允许2个线程进入到对资源的处理。可以看出，信号量是通过计数来对线程访问资源进行控制的，而实际上信号量确实也被称作Dijkstra计数器。<BR><BR>　　使用信号量内核对象进行线程同步主要会用到CreateSemaphore（）、OpenSemaphore（）、ReleaseSemaphore（）、WaitForSingleObject（）和WaitForMultipleObjects（）等函数。其中，CreateSemaphore（）用来创建一个信号量内核对象，其函数原型为：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>HANDLE CreateSemaphore(<BR>　LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // 安全属性指针<BR>　LONG lInitialCount, // 初始计数<BR>　LONG lMaximumCount, // 最大计数<BR>　LPCTSTR lpName // 对象名指针<BR>); </FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　参数lMaximumCount是一个有符号32位值，定义了允许的最大资源计数，最大取值不能超过4294967295。lpName参数可以为创建的信号量定义一个名字，由于其创建的是一个内核对象，因此在其他进程中可以通过该名字而得到此信号量。OpenSemaphore（）函数即可用来根据信号量名打开在其他进程中创建的信号量，函数原型如下：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>HANDLE OpenSemaphore(<BR>　DWORD dwDesiredAccess, // 访问标志<BR>　BOOL bInheritHandle, // 继承标志<BR>　LPCTSTR lpName // 信号量名<BR>);</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　在线程离开对共享资源的处理时，必须通过ReleaseSemaphore（）来增加当前可用资源计数。否则将会出现当前正在处理共享资源的实际线程数并没有达到要限制的数值，而其他线程却因为当前可用资源计数为0而仍无法进入的情况。ReleaseSemaphore（）的函数原型为：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>BOOL ReleaseSemaphore(<BR>　HANDLE hSemaphore, // 信号量句柄<BR>　LONG lReleaseCount, // 计数递增数量<BR>　LPLONG lpPreviousCount // 先前计数<BR>);</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　该函数将lReleaseCount中的值添加给信号量的当前资源计数，一般将lReleaseCount设置为1，如果需要也可以设置其他的值。WaitForSingleObject（）和WaitForMultipleObjects（）主要用在试图进入共享资源的线程函数入口处，主要用来判断信号量的当前可用资源计数是否允许本线程的进入。只有在当前可用资源计数值大于0时，被监视的信号量内核对象才会得到通知。<BR><BR>　　信号量的使用特点使其更适用于对Socket（套接字）程序中线程的同步。例如，网络上的HTTP服务器要对同一时间内访问同一页面的用户数加以限制，这时可以为没一个用户对服务器的页面请求设置一个线程，而页面则是待保护的共享资源，通过使用信号量对线程的同步作用可以确保在任一时刻无论有多少用户对某一页面进行访问，只有不大于设定的最大用户数目的线程能够进行访问，而其他的访问企图则被挂起，只有在有用户退出对此页面的访问后才有可能进入。下面给出的示例代码即展示了类似的处理过程：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>// 信号量对象句柄<BR>HANDLE hSemaphore;<BR>UINT ThreadProc15(LPVOID pParam)<BR>{ <BR>　// 试图进入信号量关口<BR>　WaitForSingleObject(hSemaphore, INFINITE);<BR>　// 线程任务处理<BR>　AfxMessageBox("线程一正在执行!");<BR>　// 释放信号量计数<BR>　ReleaseSemaphore(hSemaphore, 1, NULL);<BR>　return 0;<BR>}<BR>UINT ThreadProc16(LPVOID pParam)<BR>{ <BR>　// 试图进入信号量关口<BR>　WaitForSingleObject(hSemaphore, INFINITE);<BR>　// 线程任务处理<BR>　AfxMessageBox("线程二正在执行!");<BR>　// 释放信号量计数<BR>　ReleaseSemaphore(hSemaphore, 1, NULL);<BR>　return 0;<BR>}<BR>UINT ThreadProc17(LPVOID pParam)<BR>{ <BR>　// 试图进入信号量关口<BR>　WaitForSingleObject(hSemaphore, INFINITE);<BR>　// 线程任务处理<BR>　AfxMessageBox("线程三正在执行!");<BR>　// 释放信号量计数<BR>　ReleaseSemaphore(hSemaphore, 1, NULL);<BR>　return 0;<BR>}<BR>……<BR>void CSample08View::OnSemaphore() <BR>{<BR>　// 创建信号量对象<BR>　hSemaphore = CreateSemaphore(NULL, 2, 2, NULL);<BR>　// 开启线程<BR>　AfxBeginThread(ThreadProc15, NULL);<BR>　AfxBeginThread(ThreadProc16, NULL);<BR>　AfxBeginThread(ThreadProc17, NULL);<BR>}</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2><IMG onerror="this.src='http://www.yesky.com/image20010518/110096.jpg';" hspace=3 src="http://www.yesky.com/image20010518/110096.jpg" onload="var image=new Image();image.src=this.src;if(image.width>0 &amp;&amp; image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" align=center vspace=1 border=1><BR>图4 开始进入的两个线程<BR><BR><IMG onerror="this.src='http://www.yesky.com/image20010518/110097.jpg';" hspace=3 src="http://www.yesky.com/image20010518/110097.jpg" onload="var image=new Image();image.src=this.src;if(image.width>0 &amp;&amp; image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" align=center vspace=1 border=1><BR>图5 线程二退出后线程三才得以进入<BR><BR>　　上述代码在开启线程前首先创建了一个初始计数和最大资源计数均为2的信号量对象hSemaphore。即在同一时刻只允许2个线程进入由hSemaphore保护的共享资源。随后开启的三个线程均试图访问此共享资源，在前两个线程试图访问共享资源时，由于hSemaphore的当前可用资源计数分别为2和1，此时的hSemaphore是可以得到通知的，也就是说位于线程入口处的WaitForSingleObject（）将立即返回，而在前两个线程进入到保护区域后，hSemaphore的当前资源计数减少到0，hSemaphore将不再得到通知，WaitForSingleObject（）将线程挂起。直到此前进入到保护区的线程退出后才能得以进入。图4和图5为上述代脉的运行结果。从实验结果可以看出，信号量始终保持了同一时刻不超过2个线程的进入。<BR><BR>　　在MFC中，通过CSemaphore类对信号量作了表述。该类只具有一个构造函数，可以构造一个信号量对象，并对初始资源计数、最大资源计数、对象名和安全属性等进行初始化，其原型如下：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>CSemaphore( LONG lInitialCount = 1, LONG lMaxCount = 1, LPCTSTR pstrName = NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL );</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　在构造了CSemaphore类对象后，任何一个访问受保护共享资源的线程都必须通过CSemaphore从父类CSyncObject类继承得到的Lock（）和UnLock（）成员函数来访问或释放CSemaphore对象。与前面介绍的几种通过MFC类保持线程同步的方法类似，通过CSemaphore类也可以将前面的线程同步代码进行改写，这两种使用信号量的线程同步方法无论是在实现原理上还是从实现结果上都是完全一致的。下面给出经MFC改写后的信号量线程同步代码：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>// MFC信号量类对象<BR>CSemaphore g_clsSemaphore(2, 2);<BR>UINT ThreadProc24(LPVOID pParam)<BR>{ <BR>　// 试图进入信号量关口<BR>　g_clsSemaphore.Lock();<BR>　// 线程任务处理<BR>　AfxMessageBox("线程一正在执行!");<BR>　// 释放信号量计数<BR>　g_clsSemaphore.Unlock();<BR>　return 0;<BR>}<BR>UINT ThreadProc25(LPVOID pParam)<BR>{<BR>　// 试图进入信号量关口<BR>　g_clsSemaphore.Lock();<BR>　// 线程任务处理<BR>　AfxMessageBox("线程二正在执行!");<BR>　// 释放信号量计数<BR>　g_clsSemaphore.Unlock();<BR>　return 0;<BR>}<BR>UINT ThreadProc26(LPVOID pParam)<BR>{<BR>　// 试图进入信号量关口<BR>　g_clsSemaphore.Lock();<BR>　// 线程任务处理<BR>　AfxMessageBox("线程三正在执行!");<BR>　// 释放信号量计数<BR>　g_clsSemaphore.Unlock();<BR>　return 0;<BR>}<BR>……<BR>void CSample08View::OnSemaphoreMfc() <BR>{<BR>　// 开启线程<BR>　AfxBeginThread(ThreadProc24, NULL);<BR>　AfxBeginThread(ThreadProc25, NULL);<BR>　AfxBeginThread(ThreadProc26, NULL);<BR>}</FONT></TD></TR></TBODY></TABLE></SPAN><SPAN class=f14><FONT size=2>　　<B>互斥内核对象</B><BR><BR>　　互斥（Mutex）是一种用途非常广泛的内核对象。能够保证多个线程对同一共享资源的互斥访问。同临界区有些类似，只有拥有互斥对象的线程才具有访问资源的权限，由于互斥对象只有一个，因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出，以便其他线程在获得后得以访问资源。与其他几种内核对象不同，互斥对象在操作系统中拥有特殊代码，并由操作系统来管理，操作系统甚至还允许其进行一些其他内核对象所不能进行的非常规操作。为便于理解，可参照图6给出的互斥内核对象的工作模型：<BR><BR><IMG onerror="this.src='http://www.yesky.com/image20010518/110098.jpg';" hspace=3 src="http://www.yesky.com/image20010518/110098.jpg" onload="var image=new Image();image.src=this.src;if(image.width>0 &amp;&amp; image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" align=center vspace=1 border=1><BR>图6 使用互斥内核对象对共享资源的保护<BR><BR>　　图（a）中的箭头为要访问资源（矩形框）的线程，但只有第二个线程拥有互斥对象（黑点）并得以进入到共享资源，而其他线程则会被排斥在外（如图（b）所示）。当此线程处理完共享资源并准备离开此区域时将把其所拥有的互斥对象交出（如图（c）所示），其他任何一个试图访问此资源的线程都有机会得到此互斥对象。<BR><BR>　　以互斥内核对象来保持线程同步可能用到的函数主要有CreateMutex（）、OpenMutex（）、ReleaseMutex（）、WaitForSingleObject（）和WaitForMultipleObjects（）等。在使用互斥对象前，首先要通过CreateMutex（）或OpenMutex（）创建或打开一个互斥对象。CreateMutex（）函数原型为：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>HANDLE CreateMutex(<BR>　LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全属性指针<BR>　BOOL bInitialOwner, // 初始拥有者<BR>　LPCTSTR lpName // 互斥对象名<BR>);</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　参数bInitialOwner主要用来控制互斥对象的初始状态。一般多将其设置为FALSE，以表明互斥对象在创建时并没有为任何线程所占有。如果在创建互斥对象时指定了对象名，那么可以在本进程其他地方或是在其他进程通过OpenMutex（）函数得到此互斥对象的句柄。OpenMutex（）函数原型为：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>HANDLE OpenMutex(<BR>　DWORD dwDesiredAccess, // 访问标志<BR>　BOOL bInheritHandle, // 继承标志<BR>　LPCTSTR lpName // 互斥对象名<BR>); </FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　当目前对资源具有访问权的线程不再需要访问此资源而要离开时，必须通过ReleaseMutex（）函数来释放其拥有的互斥对象，其函数原型为：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>BOOL ReleaseMutex(HANDLE hMutex);</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　其唯一的参数hMutex为待释放的互斥对象句柄。至于WaitForSingleObject（）和WaitForMultipleObjects（）等待函数在互斥对象保持线程同步中所起的作用与在其他内核对象中的作用是基本一致的，也是等待互斥内核对象的通知。但是这里需要特别指出的是：在互斥对象通知引起调用等待函数返回时，等待函数的返回值不再是通常的WAIT_OBJECT_0（对于WaitForSingleObject（）函数）或是在WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1之间的一个值（对于WaitForMultipleObjects（）函数），而是将返回一个WAIT_ABANDONED_0（对于WaitForSingleObject（）函数）或是在WAIT_ABANDONED_0到WAIT_ABANDONED_0+nCount-1之间的一个值（对于WaitForMultipleObjects（）函数）。以此来表明线程正在等待的互斥对象由另外一个线程所拥有，而此线程却在使用完共享资源前就已经终止。除此之外，使用互斥对象的方法在等待线程的可调度性上同使用其他几种内核对象的方法也有所不同，其他内核对象在没有得到通知时，受调用等待函数的作用，线程将会挂起，同时失去可调度性，而使用互斥的方法却可以在等待的同时仍具有可调度性，这也正是互斥对象所能完成的非常规操作之一。<BR><BR>　　在编写程序时，互斥对象多用在对那些为多个线程所访问的内存块的保护上，可以确保任何线程在处理此内存块时都对其拥有可靠的独占访问权。下面给出的示例代码即通过互斥内核对象hMutex对共享内存快g_cArray[]进行线程的独占访问保护。下面给出实现代码清单：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>// 互斥对象<BR>HANDLE hMutex = NULL;<BR>char g_cArray[10];<BR>UINT ThreadProc18(LPVOID pParam)<BR>{<BR>　// 等待互斥对象通知<BR>　WaitForSingleObject(hMutex, INFINITE);<BR>　// 对共享资源进行写入操作<BR>　for (int i = 0; i &lt; 10; i++)<BR>　{<BR>　　g_cArray[i] = 'a';<BR>　　Sleep(1);<BR>　}<BR>　// 释放互斥对象<BR>　ReleaseMutex(hMutex);<BR>　return 0;<BR>}<BR>UINT ThreadProc19(LPVOID pParam)<BR>{<BR>　// 等待互斥对象通知<BR>　WaitForSingleObject(hMutex, INFINITE);<BR>　// 对共享资源进行写入操作<BR>　for (int i = 0; i &lt; 10; i++)<BR>　{<BR>　　g_cArray[10 - i - 1] = 'b';<BR>　　Sleep(1);<BR>　}<BR>　// 释放互斥对象<BR>　ReleaseMutex(hMutex);<BR>　return 0;<BR>}<BR>……<BR>void CSample08View::OnMutex() <BR>{<BR>　// 创建互斥对象<BR>　hMutex = CreateMutex(NULL, FALSE, NULL);<BR>　// 启动线程<BR>　AfxBeginThread(ThreadProc18, NULL);<BR>　AfxBeginThread(ThreadProc19, NULL);<BR>　// 等待计算完毕<BR>　Sleep(300);<BR>　// 报告计算结果<BR>　CString sResult = CString(g_cArray);<BR>　AfxMessageBox(sResult);<BR>} </FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　互斥对象在MFC中通过CMutex类进行表述。使用CMutex类的方法非常简单，在构造CMutex类对象的同时可以指明待查询的互斥对象的名字，在构造函数返回后即可访问此互斥变量。CMutex类也是只含有构造函数这唯一的成员函数，当完成对互斥对象保护资源的访问后，可通过调用从父类CSyncObject继承的UnLock（）函数完成对互斥对象的释放。CMutex类构造函数原型为：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　该类的适用范围和实现原理与API方式创建的互斥内核对象是完全类似的，但要简洁的多，下面给出就是对前面的示例代码经CMutex类改写后的程序实现清单：<BR><BR></FONT>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD><FONT size=2>// MFC互斥类对象<BR>CMutex g_clsMutex(FALSE, NULL);<BR>UINT ThreadProc27(LPVOID pParam)<BR>{<BR>　// 等待互斥对象通知<BR>　g_clsMutex.Lock();<BR>　// 对共享资源进行写入操作<BR>　for (int i = 0; i &lt; 10; i++)<BR>　{<BR>　　g_cArray[i] = 'a';<BR>　　Sleep(1);<BR>　}<BR>　// 释放互斥对象<BR>　g_clsMutex.Unlock();<BR>　return 0;<BR>}<BR>UINT ThreadProc28(LPVOID pParam)<BR>{<BR>　// 等待互斥对象通知<BR>　g_clsMutex.Lock();<BR>　// 对共享资源进行写入操作<BR>　for (int i = 0; i &lt; 10; i++)<BR>　{<BR>　　g_cArray[10 - i - 1] = 'b';<BR>　　Sleep(1);<BR>　}<BR>　// 释放互斥对象<BR>　g_clsMutex.Unlock();<BR>　return 0;<BR>}<BR>……<BR>void CSample08View::OnMutexMfc() <BR>{<BR>　// 启动线程<BR>　AfxBeginThread(ThreadProc27, NULL);<BR>　AfxBeginThread(ThreadProc28, NULL);<BR>　// 等待计算完毕<BR>　Sleep(300);<BR>　// 报告计算结果<BR>　CString sResult = CString(g_cArray);<BR>　AfxMessageBox(sResult);<BR>}</FONT></TD></TR></TBODY></TABLE><BR><FONT size=2>　　<B>小结</B><BR><BR>　　线程的使用使程序处理更够更加灵活，而这种灵活同样也会带来各种不确定性的可能。尤其是在多个线程对同一公共变量进行访问时。虽然未使用线程同步的程序代码在逻辑上或许没有什么问题，但为了确保程序的正确、可靠运行，必须在适当的场合采取线程同步措施。<BR></FONT></SPAN></FONT></TD></TR>
<TR>
<TD colSpan=2>&nbsp;</TD></TR></TBODY></TABLE><img src ="http://www.cnblogs.com/zjz/aggbug/509688.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43604/" target="_blank">[新闻]微软公布免费安全软件计划</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>stl学习(转帖2)</title><link>http://www.cnblogs.com/zjz/archive/2006/09/18/507304.html</link><dc:creator>.net技術</dc:creator><author>.net技術</author><pubDate>Mon, 18 Sep 2006 04:16:00 GMT</pubDate><guid>http://www.cnblogs.com/zjz/archive/2006/09/18/507304.html</guid><wfw:comment>http://www.cnblogs.com/zjz/comments/507304.html</wfw:comment><comments>http://www.cnblogs.com/zjz/archive/2006/09/18/507304.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zjz/comments/commentRss/507304.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zjz/services/trackbacks/507304.html</trackback:ping><description><![CDATA[<H2 class=diaryTitle>STL学习系列之三：操作list容器- -</H2><B>Tag</B>： <A href="http://tag.bokee.com/SearchTag.b?span=1&amp;wd=c%2B%2B" target=_blank><FONT color=#002c99>c++</FONT></A> &nbsp;&nbsp; <A href="http://tag.bokee.com/SearchTag.b?span=1&amp;wd=STL" target=_blank><FONT color=#002c99>STL</FONT></A> &nbsp;&nbsp; <A href="http://tag.bokee.com/SearchTag.b?span=1&amp;wd=list" target=_blank><FONT color=#002c99>list</FONT></A> &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<P>
<P>学习完了STL系列之二，自己写了个程序练手！程序采用的还是系列之二文章的架构。学习了STL之一和之二，对于STL的基本原理算有个个基本的了解。其实关于这几种容器，以前也都接触过，不过是在java上，当时学习时也是囫囵吞枣！现在感觉那真是学习之大忌，还是一步一个脚印为好。速度可以放慢点，那要扎实！</P>
<P>注意：程序在vc6下调试通过，对于不清楚如何在vc下运行STL者，可以读STL系列之一。</P>
<P>//TjuAiLab<BR>//Author:zhangbufeng<BR>//Time:2005.8.23 22:00<BR>#include &lt;string&gt;<BR>#include &lt;list&gt;<BR>#include &lt;iostream&gt;<BR>#include &lt;algorithm&gt;<BR>using namespace std;</P>
<P>PrintString(const string&amp; StringToPrint);<BR>const string NameCode("Bufeng");<BR>class IsBufeng<BR>{<BR>public:<BR>&nbsp;bool operator()(string &amp;StringName)<BR>&nbsp;{<BR>&nbsp;&nbsp;return StringName.substr(0,6)==NameCode;<BR>&nbsp;}<BR>};<BR>void main(void)<BR>{<BR>&nbsp;//定义一个list<BR>&nbsp;list&lt;string&gt;AIStudentName;<BR>&nbsp;list&lt;string&gt;TargetAIStudentName;<BR>&nbsp;list&lt;string&gt;::iterator AIStudentNameIterator;<BR>&nbsp;//使用的list的成员函数push_back和puch_front插入元素到list中,使用成员函数insert任意插入<BR>&nbsp;&nbsp;&nbsp; AIStudentName.push_back("BufengZhang");<BR>&nbsp;AIStudentName.push_back("YangZhang");<BR>&nbsp;AIStudentName.push_back("KunHuang");<BR>&nbsp;AIStudentName.push_front("ChengLuo");<BR>&nbsp;AIStudentName.push_front("YonghuoYang");<BR>&nbsp;AIStudentName.push_front("XiaoyuanCui");<BR>&nbsp;AIStudentName.insert(AIStudentName.end(),"KefeiGong");<BR>&nbsp;TargetAIStudentName.push_back("BufengZhang");<BR>&nbsp;TargetAIStudentName.push_back("YangZhang");<BR>&nbsp;//使用list的成员函数empty判断list是否为空，size来返回成员个数<BR>&nbsp;if(AIStudentName.empty())<BR>&nbsp;{<BR>&nbsp;&nbsp;cout&lt;&lt;"AIStudentName的成员为空"&lt;&lt;endl;<BR>&nbsp;}<BR>&nbsp;else<BR>&nbsp;{<BR>&nbsp;&nbsp;cout&lt;&lt;"AIStudentName的成员个数为"&lt;&lt;AIStudentName.size()&lt;&lt;endl;<BR>&nbsp;}<BR>&nbsp;//使用for循环和迭代器处理list的元素<BR>&nbsp;cout&lt;&lt;"AIStudentName的成员如下(使用for循环和迭代器："&lt;&lt;endl;<BR>&nbsp;for(AIStudentNameIterator=AIStudentName.begin();AIStudentNameIterator!=AIStudentName.end();<BR>&nbsp;&nbsp;&nbsp;&nbsp; AIStudentNameIterator++)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;cout&lt;&lt;*AIStudentNameIterator&lt;&lt;endl;<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp; //使用STL的通用算法for_each来处理list中的元素<BR>&nbsp;cout&lt;&lt;"AIStudentName的成员如下(使用STL的通用算法for_each："&lt;&lt;endl;<BR>&nbsp;for_each(AIStudentName.begin(),AIStudentName.end(),PrintString);<BR>&nbsp;//学习使用STL的通用算法count和count_if<BR>&nbsp;int NumberofStudent=0;<BR>&nbsp;NumberofStudent=count (AIStudentName.begin(),AIStudentName.end(),"BufengZhang");<BR>&nbsp;cout&lt;&lt;"TjuAIlab中有"&lt;&lt;NumberofStudent&lt;&lt;"个BufengZhang"&lt;&lt;endl;<BR>&nbsp;NumberofStudent=count_if(AIStudentName.begin(),AIStudentName.end(),IsBufeng());<BR>&nbsp;cout&lt;&lt;"TjuAIlab中有"&lt;&lt;NumberofStudent&lt;&lt;"个BufengZhang"&lt;&lt;endl;<BR>&nbsp;&nbsp;&nbsp; //使用STL通用算法find()在list中查找对象<BR>&nbsp;AIStudentNameIterator=find(AIStudentName.begin(),AIStudentName.end(),"BufengZhang");<BR>&nbsp;if(AIStudentNameIterator==AIStudentName.end())<BR>&nbsp;&nbsp;cout&lt;&lt;"AIStudentName中没有BufengZhang"&lt;&lt;endl;<BR>&nbsp;else<BR>&nbsp;&nbsp;cout&lt;&lt;"在AIStudentName中可以找到BufengZhang"&lt;&lt;endl;<BR>&nbsp;//使用STL通用算法find_if在list中查找对象<BR>&nbsp;AIStudentNameIterator=find_if(AIStudentName.begin(),AIStudentName.end(),IsBufeng());<BR>&nbsp;if(AIStudentNameIterator==AIStudentName.end())<BR>&nbsp;&nbsp;cout&lt;&lt;"AIStudentName中没有BufengZhang"&lt;&lt;endl;<BR>&nbsp;else<BR>&nbsp;&nbsp;cout&lt;&lt;"在AIStudentName中可以找到BufengZhang"&lt;&lt;endl;<BR>&nbsp;//使用STL通用算法search在list中找一个序列<BR>&nbsp;&nbsp;&nbsp; AIStudentNameIterator = search(AIStudentName.begin(),AIStudentName.end(),TargetAIStudentName.begin(),TargetAIStudentName.end());<BR>&nbsp;&nbsp;&nbsp; if(AIStudentNameIterator==AIStudentName.end())<BR>&nbsp;&nbsp;cout&lt;&lt;"AIStudentName中没有找到BufengZhang And YangZhang"&lt;&lt;endl;<BR>&nbsp;else<BR>&nbsp;&nbsp;cout&lt;&lt;"在AIStudentName中可以找到BufengZhang And YangZhang"&lt;&lt;endl;<BR>&nbsp;//使用list的成员函数sort()排序一个list<BR>&nbsp;AIStudentName.sort();<BR>&nbsp;cout&lt;&lt;"排序如下："&lt;&lt;endl;<BR>&nbsp;for_each(AIStudentName.begin(),AIStudentName.end(),PrintString);<BR>&nbsp;//使用list的成员函数删除元素(pop_front,pop_back,erase(),remove())<BR>&nbsp;&nbsp;&nbsp; AIStudentName.pop_front();<BR>&nbsp;AIStudentName.pop_back();<BR>&nbsp;AIStudentName.erase(AIStudentName.begin());<BR>&nbsp;AIStudentName.remove("XiaoyuanCui");<BR>&nbsp;cout&lt;&lt;"剩余成员如下："&lt;&lt;endl;<BR>&nbsp;for_each(AIStudentName.begin(),AIStudentName.end(),PrintString);<BR>&nbsp;//使用STL通用算法remove()从list中删除元素<BR>&nbsp;&nbsp;&nbsp; AIStudentNameIterator=remove(AIStudentName.begin(),AIStudentName.end(),"YangZhang");<BR>&nbsp;cout&lt;&lt;"remove后剩余成员如下:"&lt;&lt;endl;<BR>&nbsp;for_each(AIStudentName.begin(),AIStudentNameIterator,PrintString);</P>
<P>}<BR>PrintString(const string&amp; StringToPrint)<BR>{<BR>&nbsp;cout&lt;&lt;StringToPrint&lt;&lt;endl;<BR>}</P><BR><BR>
<H2 class=diaryTitle>STL学习系列之四：STL学习小结（转贴）- -</H2><B>Tag</B>： <A href="http://tag.bokee.com/SearchTag.b?span=1&amp;wd=c%2B%2B" target=_blank><FONT color=#002c99>c++</FONT></A> &nbsp;&nbsp; <A href="http://tag.bokee.com/SearchTag.b?span=1&amp;wd=vc" target=_blank><FONT color=#002c99>vc</FONT></A> &nbsp;&nbsp; <A href="http://tag.bokee.com/SearchTag.b?span=1&amp;wd=STL" target=_blank><FONT color=#002c99>STL</FONT></A> &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<P>
<DIV class=postTitle>zhe</DIV>
<DIV class=postText>
<TABLE height="100%" cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD style="PADDING-RIGHT: 10px" width=74><IMG height=80 alt="" src="http://www.frontfree.net/articles/pages/0000000844/title.gif" width=60 border=1></TD>
<TD vAlign=top width="100%">
<TABLE height="100%" cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=artitle vAlign=top colSpan=2>STL学习小结</TD></TR>
<TR class=text vAlign=top>
<TD align=left>原创：桑英硕 </TD>
<TD class=text vAlign=top align=right>2004年6月26日 </TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD class=arcontent colSpan=3><BR>
<STYLE type=text/css></STYLE>

<DIV class=Section1>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">提供了类型安全、高效而易用特性的STL无疑是最值得C++程序员骄傲的部分。每一个C＋＋程序员都应该好好学习STL：).&nbsp;&nbsp;&nbsp;</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">STL（Standard Template Library 标准模板库）是C＋＋标准库的一个重要组成部分，它由Stepanov and Lee等人最先开发，它是与C＋＋几乎同时开始开发的；一开始STL选择了Ada作为实现语言，但Ada有点不争气，最后他们选择了C＋＋，一个原因了，C＋＋中已经有了模板。在后来，STL又被添加进了C＋＋库。1996年，惠普公司又免费公开了STL，为STL的推广做了很大的贡献。</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">STL大体上包括container（容器）、algorithm（算法）和iterator（迭代器），容器和算法通过迭代器可以进行无缝连接。&nbsp;&nbsp;</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">STL体现了<SPAN class=GramE>范</SPAN>型编程的思想，它具有高度的可重用性，高性能，高移植性。程序员不用思考具体实现过程，只要能够熟练的应用就OK了。（有兴趣研究具体实现的，可以看侯捷老师编著的《STL源码剖析》）这样他们就可以把精力放在程序开发的别的方面。</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">我非常佩服创造STL的那些计算机和数学精英。因为他们做了一件非常辛苦的事情―<SPAN class=GramE>――</SPAN>抽象概念。而STL就是通过把容器抽象为统一的接口，算法利用这个接口，通过迭代器来操纵容器。因为接口不变，实现的容器可以随意更改。这样，就为编程、调试和扩展提供了便利。也许有一天，我们生产软件的时候也可以想DIY一台PC一样简单，只要拿来相应的实现模块，通过简单的拼装和调试就可以创造一个软件。这是多么令人兴奋的一件事^_^.不过，到时候，可能会有很多程序员失业了。呵呵，毕竟编写<SPAN class=GramE>类库不</SPAN>需要很多的人员。</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">虽然STL不是面向对象的，但，我想，每个人都会为它的创造力和高性能而感到兴奋和折服。</SPAN></P>
<P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><STRONG>一、容器&nbsp; </STRONG><BR>作为STL的最主要组成部分－－容器，分为向量（vector），双端队列(deque)，表(list)，队列（queue），堆栈(stack)，集合(set)，多重集合(multiset)，映射(map)，多重映射(multimap)。</SPAN></P>
<TABLE class=MsoTableGrid cellSpacing=0 cellPadding=0 width=500 border=1>
<TBODY>
<TR>
<TD class=Normal vAlign=top width=119 bgColor=#008000>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">容器<SPAN lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></P></TD>
<TD class=Normal vAlign=top width=324 bgColor=#008000>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">特性</SPAN></P></TD>
<TD class=Normal vAlign=top width=147 bgColor=#008000>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">所在头文件</SPAN></P></TD></TR>
<TR>
<TD class=Normal vAlign=top width=119 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">向量vector</SPAN></P></TD>
<TD class=Normal vAlign=top width=324 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">可以用常数时间访问和修改任意元素，在序列尾部进行插入和删除时，具有常数时间复杂度，对任意项的插入和删除就有的时间复杂度与到末尾的距离成正比，尤其对向量头的添加和删除的代价是惊人的高的</SPAN></P></TD>
<TD class=Normal vAlign=top width=147 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;vector&gt;</SPAN></P></TD></TR>
<TR>
<TD class=Normal vAlign=top width=119 bgColor=#a6a6a6>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">双端队列deque</SPAN></P></TD>
<TD class=Normal vAlign=top width=324 bgColor=#a6a6a6>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">基本上与向量相同，唯一的不同是，其在序列头部插入和删除操作也具有常量时间复杂度</SPAN></P></TD>
<TD class=Normal vAlign=top width=147 bgColor=#a6a6a6>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;deque&gt;</SPAN></P></TD></TR>
<TR>
<TD class=Normal vAlign=top width=119 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">表<SPAN lang=EN-US>list</SPAN></SPAN></P></TD>
<TD class=Normal vAlign=top width=324 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">对任意元素的访问与对两端的距离成正比，但对某个位置上插入和删除一个项的花费为常数时间。</SPAN></P></TD>
<TD class=Normal vAlign=top width=147 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;list&gt;</SPAN></P></TD></TR>
<TR>
<TD class=Normal vAlign=top width=119 bgColor=#a6a6a6>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">队列queue</SPAN></P></TD>
<TD class=Normal vAlign=top width=324 bgColor=#a6a6a6>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">插入只可以在尾部进行，删除、检索和修改只允许从头部进行。按照先进先出的原则。</SPAN></P></TD>
<TD class=Normal vAlign=top width=147 bgColor=#a6a6a6>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;queue&gt;</SPAN></P></TD></TR>
<TR>
<TD class=Normal vAlign=top width=119 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">堆栈stack</SPAN></P></TD>
<TD class=Normal vAlign=top width=324 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">堆栈是项的有限序列，并满足序列中被删除、检索和修改的<SPAN class=GramE>项只能</SPAN>是最近插入序列的项。即按照后进先出的原则</SPAN></P></TD>
<TD class=Normal vAlign=top width=147 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;stack&gt;</SPAN></P></TD></TR>
<TR>
<TD class=Normal vAlign=top width=119 bgColor=#a6a6a6>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">集合set</SPAN></P></TD>
<TD class=Normal vAlign=top width=324 bgColor=#a6a6a6>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体">由节点组成的红黑树，每个节点都包含着一个元素，节点之间以某种作用于元素对的谓词排列，没有两个不同的元素能够拥有相同的次序，具有快速查找的功能。但是它是以牺牲插入车删除操作的效率为代价的</SPAN></P></TD>
<TD class=Normal vAlign=top width=147 bgColor=#a6a6a6>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;set&gt;</SPAN></P></TD></TR>
<TR>
<TD class=Normal vAlign=top width=119 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">多重集合multiset</SPAN></P></TD>
<TD class=Normal vAlign=top width=324 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">和集合基本相同，但可以支持重复元素具有快速查找能力</SPAN></P></TD>
<TD class=Normal vAlign=top width=147 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;set&gt;</SPAN></P></TD></TR>
<TR>
<TD class=Normal vAlign=top width=119 bgColor=#a6a6a6>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">映射map</SPAN></P></TD>
<TD class=Normal vAlign=top width=324 bgColor=#a6a6a6>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">由{键，值}对组成的集合，以某种作用<SPAN class=GramE>于键对上</SPAN>的谓词排列。具有快速查找能力</SPAN></P></TD>
<TD class=Normal vAlign=top width=147 bgColor=#a6a6a6>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;map&gt;</SPAN></P></TD></TR>
<TR>
<TD class=Normal vAlign=top width=119 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">多重集合multimap</SPAN></P></TD>
<TD class=Normal vAlign=top width=324 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">比起映射，一个<SPAN class=GramE>键可以</SPAN>对应多了值。具有快速查找能力</SPAN></P></TD>
<TD class=Normal vAlign=top width=147 bgColor=#f3f3f3>
<P class=5 style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;map&gt;</SPAN></P></TD></TR></TBODY></TABLE>
<P style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">考虑到不同的实际需要，更主要的是效率的需要，我们可以选择不同的容器来实现我们的程序，以此达到我们提高性能的目的。这也是用好STL的一个难点，但这也是关键。</SPAN></P>
<P style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><STRONG>二、算法</STRONG></SPAN><BR><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">算法部分主要由头文件&lt;algorithm&gt;，&lt;numeric&gt;和&lt;functional&gt;组成。&lt;algorithm&gt;是所有STL头文件中最大的一个，它是由一大堆模版函数组成的，可以认为每个函数在很大程度上都是独立的，其中常用到的功能范围涉及到比较、交换、查找、遍历操作、复制、修改、移除、反转、排序、合并等等。&lt;numeric&gt;体积很小，只包括几个在序列上面进行简单数学运算的模板函数，包括加法和乘法在序列上的一些操作。&lt;functional&gt;中则定义了一些模板类，用以声明函数对象。</SPAN></P>
<P style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">STL的算法也是非常优秀的，它们大部分都是类属的，基本上都用到了C＋＋的模板来实现，这</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">样，很多相似的函数就不用自己写了，只要用函数模板就OK了。</SPAN></P>
<P style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">我们使用算法的时候，要针对不同的容器，比如：对集合的查找，最好不要用通用函数find（<SPAN class=GramE>）</SPAN>，它对集合使用的时候，性能非常的差，最好用集合自带的find（<SPAN class=GramE>）</SPAN>函数，它针对了集合进行了优化，性能非常的高。</SPAN></P>
<P style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><STRONG>三、迭代器</STRONG></SPAN><BR><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">它的具体实现在&lt;itertator&gt; 中，我们完全可以不管迭代器类是怎么实现的，大多数的时候，把它理解为指针是没有问题的（指针是迭代器的一个特例，它也属于迭代器），但是，决不能完全这么做。</SPAN></P>
<TABLE class=5 cellSpacing=0 cellPadding=0 width=500 border=1>
<TBODY>
<TR>
<TD class=Normal vAlign=top bgColor=#008000 colSpan=3>
<P class=5><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">迭代<SPAN class=GramE>器功能</SPAN></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">（<SPAN lang=EN-US>Abilities Of <SPAN class=SpellE>Iterator</SPAN> <SPAN class=SpellE>Gategories</SPAN>）</SPAN></SPAN></P></TD></TR>
<TR>
<TD class=Normal vAlign=top width=129 bgColor=#b3b3b3>
<P class=5><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">输入迭代器</SPAN></P>
<P class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">Input <SPAN class=SpellE>iterator</SPAN></SPAN></P></TD>
<TD class=Normal vAlign=top width=179 bgColor=#d9d9d9>
<P class=5><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">向前读</SPAN></P>
<P class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">Reads forward</SPAN></P></TD>
<TD class=Normal vAlign=top width=184 bgColor=#f3f3f3>
<P><SPAN class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">istream</SPAN></SPAN></P></TD></TR>
<TR>
<TD class=Normal vAlign=top width=129 bgColor=#b3b3b3>
<P class=5><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">输出迭代器</SPAN></P>
<P class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">Output <SPAN class=SpellE>iterator</SPAN></SPAN></P></TD>
<TD class=Normal vAlign=top width=179 bgColor=#d9d9d9>
<P class=5><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">向前写</SPAN></P>
<P class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">Writes forward</SPAN></P></TD>
<TD class=Normal vAlign=top width=184 bgColor=#f3f3f3>
<P><SPAN class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">ostream,inserter</SPAN></SPAN></P></TD></TR>
<TR>
<TD class=Normal vAlign=top width=129 bgColor=#b3b3b3>
<P class=5><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">前向迭代器</SPAN></P>
<P class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">Forward <SPAN class=SpellE>iterator</SPAN></SPAN></P></TD>
<TD class=Normal vAlign=top width=179 bgColor=#d9d9d9>
<P class=5><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">向前读写</SPAN></P>
<P class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">Read and Writes forward</SPAN></P></TD>
<TD class=Normal vAlign=top width=184 bgColor=#f3f3f3>&nbsp; </TD></TR>
<TR>
<TD class=Normal vAlign=top width=129 bgColor=#b3b3b3>
<P class=5><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">双向迭代器</SPAN></P>
<P class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">Bidirectional <SPAN class=SpellE>iterator</SPAN></SPAN></P></TD>
<TD class=Normal vAlign=top width=179 bgColor=#d9d9d9>
<P class=5><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">向前向后读写</SPAN></P>
<P class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">Read and Writes forward and</SPAN></P>
<P><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">backward</SPAN></P></TD>
<TD class=Normal vAlign=top width=184 bgColor=#f3f3f3>
<P><SPAN class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">list,set,multiset,map,mul</SPAN></SPAN></P>
<P><SPAN class=SpellE><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">timap</SPAN></SPAN></P></TD></TR>
<TR>
<TD class=Normal vAlign=top width=129 bgColor=#b3b3b3>
<P class=5><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">随机迭代器</SPAN></P>
<P class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">Random access <SPAN class=SpellE>iterator</SPAN></SPAN></P></TD>
<TD class=Normal vAlign=top width=179 bgColor=#d9d9d9>
<P class=5><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">随机读写</SPAN></P>
<P class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">Read and Write with random</SPAN></P>
<P class=5><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">access</SPAN></P></TD>
<TD class=Normal vAlign=top width=184 bgColor=#f3f3f3>
<P><SPAN class=SpellE><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">vector,deque,array,string</SPAN></SPAN></P></TD></TR></TBODY></TABLE>
<P><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><B>由此可见，指针和迭代<SPAN class=GramE>器还是</SPAN>有很大差别的。和指针最接近的就是随机访问迭代器。</B>下面是一个我编写的小例子：功能是分别对数组，向量，表，多重集合进行插入操作，对每个容器插入100万个随机整数；</SPAN></P>
<TABLE width=500 bgColor=#e0e0e0 border=0>
<TBODY>
<TR>
<TD class=5>
<P><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>#include</FONT></SPAN><FONT size=2><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;<SPAN class=SpellE>iostream</SPAN>&gt;<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">#include</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;<SPAN class=SpellE>iterator</SPAN>&gt;<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">#include</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;vector&gt;<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">#include</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;list&gt;<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">#include</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;set&gt;<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">#include</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;<SPAN class=SpellE>time.h</SPAN>&gt;<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">#include</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;<SPAN class=SpellE>conio.h</SPAN>&gt;<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">#include</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;algorithm&gt;<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">using</SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"> namespace</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"> std;<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">template</SPAN><SPAN class=GramE><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;</SPAN></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">typename</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"> T&gt;<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">void</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"> <SPAN class=SpellE>arrayInsert</SPAN>(T*<SPAN class=SpellE>a,T</SPAN>*<SPAN class=SpellE>s,</SPAN><SPAN class=blue>long</SPAN> size)&nbsp;&nbsp;&nbsp; <SPAN class=green>//向数组插入数据</SPAN><BR>{<BR></SPAN><SPAN class=green lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; //for(long i=0;i&lt;10;i++)&nbsp; // //好像数组支持不到100万，我们就算10万的<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; //最后在把把结果乘以10吧，<BR>&nbsp;&nbsp; //{</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><BR></SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN class=blue>for</SPAN><SPAN class=GramE>(</SPAN><SPAN class=blue>long</SPAN> <SPAN class=black>k=0</SPAN>;k&lt;<SPAN class=SpellE>size;k</SPAN>++)<BR><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN class=GramE>a[</SPAN>k]=s[k];&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;<SPAN class=green>&nbsp; //}</SPAN><BR>}<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">template</SPAN><SPAN class=GramE><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;</SPAN></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">typename</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"> T&gt;<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">void</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"> <SPAN class=SpellE>vectorInsert</SPAN>( vector&lt;T&gt; *<SPAN class=SpellE>v,T</SPAN>*<SPAN class=SpellE>s,</SPAN><SPAN class=blue>long</SPAN> size)&nbsp;&nbsp;&nbsp;&nbsp; <SPAN class=green>//向向量插入数据</SPAN><BR>{<BR></SPAN>&nbsp;&nbsp; <SPAN class=blue>for</SPAN><SPAN class=GramE>(</SPAN><SPAN class=blue>int</SPAN> <SPAN class=SpellE>i</SPAN><SPAN class=black>=0;i&lt;10</SPAN>;i++)<BR><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; {<BR></SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN class=blue>for</SPAN><SPAN class=GramE>(</SPAN><SPAN class=blue>long</SPAN> k<SPAN class=black>=0</SPAN>;k&lt;<SPAN class=SpellE>size;k</SPAN>++)<BR><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN class=GramE>v</SPAN>-&gt;<SPAN class=SpellE>push_back</SPAN>(s[k]); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp; }<BR>}<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">template</SPAN><SPAN class=GramE><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;</SPAN></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">typename</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"> T&gt;<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">void</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"> <SPAN class=SpellE>listInsert</SPAN>(list&lt;T&gt;*<SPAN class=SpellE>l,T</SPAN>*<SPAN class=SpellE>s,</SPAN><SPAN class=blue>long</SPAN> size)&nbsp;&nbsp;<SPAN class=green> //向表插入数据</SPAN><BR>{<BR></SPAN>&nbsp;&nbsp; <SPAN class=blue>for</SPAN><SPAN class=GramE>(</SPAN><SPAN class=blue>int</SPAN> <SPAN class=SpellE>i</SPAN><SPAN class=black>=0;i&lt;10;</SPAN>i++)<BR><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; {<BR></SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN class=blue>for</SPAN><SPAN class=GramE>(</SPAN><SPAN class=blue>long</SPAN> <SPAN class=black>k=0;k</SPAN>&lt;<SPAN class=SpellE>size;k</SPAN>++)<BR><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN class=GramE>l</SPAN>-&gt;<SPAN class=SpellE>push_back</SPAN>(s[k]);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <BR>&nbsp;&nbsp; }<BR>}<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">template</SPAN><SPAN class=GramE><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&lt;</SPAN></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">class</SPAN><SPAN class=red lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"> </SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">T&gt;<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">void</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"> <SPAN class=SpellE>multisetInsert</SPAN>(<SPAN class=SpellE>multiset</SPAN>&lt;T&gt;*s1,T*<SPAN class=SpellE>s,</SPAN><SPAN class=blue>long</SPAN> size)&nbsp;&nbsp; <SPAN class=green>//向多重集合插入数据</SPAN><BR>{<BR></SPAN>&nbsp;&nbsp; <SPAN class=blue>for</SPAN><SPAN class=GramE>(</SPAN><SPAN class=blue>int</SPAN> <SPAN class=SpellE>i</SPAN><SPAN class=black>=0;i&lt;10</SPAN>;i++)<BR><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; {<BR></SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN class=blue>for</SPAN><SPAN class=GramE>(</SPAN><SPAN class=blue>long</SPAN> k<SPAN class=black>=0</SPAN>;k&lt;<SPAN class=SpellE>size;k</SPAN>++)<BR><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s1-&gt;insert(s[k]);&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp; }<BR>}<BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">int</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">* <SPAN class=SpellE>genIntData</SPAN>(<SPAN class=blue>long</SPAN> size)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class=green> //生成随机数</SPAN><BR></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">{<BR></SPAN>&nbsp;&nbsp; <SPAN class=blue>int</SPAN>* data=<SPAN class=blue>new</SPAN> <SPAN class=blue>int</SPAN>[size];<BR>&nbsp;&nbsp; <SPAN class=GramE>generate(</SPAN>&amp;data<SPAN class=black>[0]</SPAN>,&amp;data[size],rand);<BR><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; <SPAN class=blue>return</SPAN> data;</SPAN></FONT></P>
<P><FONT size=2><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">}&nbsp;&nbsp; <BR></SPAN><SPAN class=blue lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">int</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"> main(<SPAN class=blue>void</SPAN>)<BR>{<BR></SPAN>&nbsp;&nbsp; <SPAN class=blue>const long </SPAN>size=<SPAN class=black>100000</SPAN>;<BR>&nbsp;&nbsp; <SPAN class=blue>int</SPAN>* s_data,array1[size];<BR>&nbsp;&nbsp; <SPAN class=blue>double </SPAN><SPAN class=SpellE>begin,end</SPAN>;<BR><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; <SPAN class=SpellE>s_data</SPAN>=<SPAN class=SpellE><SPAN class=GramE>genIntData</SPAN></SPAN><SPAN class=GramE>(</SPAN>size);<BR></SPAN>&nbsp;&nbsp; <SPAN class=GramE><FONT color=#000000>vector&lt;</FONT></SPAN><SPAN class=blue>int</SPAN><FONT color=#000000>&gt;</FONT></FONT> <FONT color=#000000 size=2>vector1</FONT><FONT size=2>;<BR>&nbsp;&nbsp; <SPAN class=GramE>list&lt;</SPAN><SPAN class=blue>int</SPAN>&gt; list1;<BR>&nbsp;&nbsp; <SPAN class=SpellE><SPAN class=GramE>multiset</SPAN></SPAN><SPAN class=GramE>&lt;</SPAN><SPAN class=blue>int</SPAN>&gt; multiset1;<BR><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; <SPAN class=GramE>clock(</SPAN>);<BR>&nbsp;&nbsp; <SPAN class=SpellE><SPAN class=GramE>cout</SPAN></SPAN>&lt;&lt;"?"&lt;&lt;<SPAN class=SpellE>endl</SPAN></SPAN></FONT></P>
<P><FONT size=2><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN class=SpellE>&nbsp;//开始计算数组插入时间&nbsp;</SPAN></SPAN></FONT></P>
<P><FONT size=2><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN class=SpellE>&nbsp; </SPAN></SPAN></FONT><FONT size=2><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN class=SpellE>getch();</SPAN></SPAN></FONT><FONT size=2><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><BR></SPAN>&nbsp;&nbsp; <SPAN class=GramE>begin</SPAN>=(<SPAN class=blue>double</SPAN>)clock()/CLK_TCK;<BR>&nbsp;&nbsp; <SPAN class=SpellE><SPAN class=GramE>arrayInsert</SPAN></SPAN><SPAN class=GramE>&lt;</SPAN><SPAN class=blue>int</SPAN>&gt;(array1,s_data,size);<BR>&nbsp;&nbsp; <SPAN class=GramE>end</SPAN>=(<SPAN class=blue>double</SPAN>)clock()/CLK_TCK;<BR><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; <SPAN class=SpellE><SPAN class=GramE>cout</SPAN></SPAN>&lt;&lt;"??"&lt;<SPAN class=GramE>&lt;(</SPAN>end-begin)&lt;&lt;<SPAN class=SpellE>endl</SPAN>;</SPAN></FONT></P>
<P><FONT size=2><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; //开始计算向量插入时间<BR>&nbsp;&nbsp; <SPAN class=SpellE><SPAN class=GramE>getch</SPAN></SPAN><SPAN class=GramE>(</SPAN>);<BR></SPAN>&nbsp;&nbsp; <SPAN class=GramE>begin</SPAN>=(<SPAN class=blue>double</SPAN>)clock()/CLK_TCK;<BR><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; <SPAN class=SpellE><SPAN class=GramE>vectorInsert</SPAN></SPAN><SPAN class=GramE>&lt;</SPAN><SPAN class=blue>int</SPAN>&gt;(&amp;vector1,s_data,size);<BR>&nbsp;&nbsp; <SPAN class=GramE>end</SPAN>=(<SPAN class=blue>double</SPAN>)clock()/CLK_TCK;<BR>&nbsp;&nbsp; <SPAN class=SpellE><SPAN class=GramE>cout</SPAN></SPAN>&lt;&lt;"??"&lt;<SPAN class=GramE>&lt;(</SPAN>end-begin)&lt;&lt;<SPAN class=SpellE>endl</SPAN>;</SPAN></FONT></P>
<P><FONT size=2><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp;//开始计算list插入时间<BR>&nbsp;&nbsp;&nbsp;</SPAN></FONT><FONT size=2><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;</SPAN></FONT><FONT size=2><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN class=SpellE><SPAN class=GramE>getch</SPAN></SPAN><SPAN class=GramE>(</SPAN>);<BR>&nbsp;&nbsp; <SPAN class=GramE>begin</SPAN>=(<SPAN class=blue>double</SPAN>)clock()/CLK_TCK;<BR>&nbsp;&nbsp; <SPAN class=SpellE><SPAN class=GramE>listInsert</SPAN></SPAN><SPAN class=GramE>&lt;</SPAN><SPAN class=blue>int</SPAN>&gt;(&amp;list1,s_data,size);<BR>&nbsp;&nbsp; <SPAN class=GramE>end</SPAN>=(<SPAN class=blue>double</SPAN>)clock()/CLK_TCK;<BR>&nbsp;&nbsp; <SPAN class=SpellE><SPAN class=GramE>cout</SPAN></SPAN>&lt;&lt;"??"&lt;<SPAN class=GramE>&lt;(</SPAN>end-begin)&lt;&lt;<SPAN class=SpellE>endl</SPAN>;</SPAN></FONT></P>
<P><FONT size=2><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp;//开始计算multiset插入时间<BR></SPAN></FONT><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; <SPAN class=SpellE><SPAN class=GramE>getch</SPAN></SPAN><SPAN class=GramE>(</SPAN>);<BR></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; <SPAN class=GramE>begin</SPAN>=(<SPAN class=blue>double</SPAN>)clock()/CLK_TCK;<BR></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; <SPAN class=SpellE><SPAN class=GramE>multisetInsert</SPAN></SPAN><SPAN class=GramE>&lt;</SPAN><SPAN class=blue>int</SPAN>&gt;(&amp;multiset1,s_data,size);<BR></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; <SPAN class=GramE>end</SPAN>=(<SPAN class=blue>double</SPAN>)clock()/CLK_TCK;<BR></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; <SPAN class=SpellE><SPAN class=GramE>cout</SPAN></SPAN>&lt;&lt;"??"&lt;<SPAN class=GramE>&lt;(</SPAN>end-begin)&lt;&lt;<SPAN class=SpellE>endl</SPAN>;</SPAN></P>
<P><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN class=SpellE><SPAN class=GramE>getch</SPAN></SPAN><SPAN class=GramE>(</SPAN>);<BR></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; <SPAN class=GramE>free(</SPAN><SPAN class=SpellE>s_data</SPAN>);<BR></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">&nbsp;&nbsp; <SPAN class=GramE>retur</SPAN><SPAN class=black>n 0;</SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">}</SPAN></P></TD></TR></TBODY></TABLE>
<P>&nbsp;</P>
<P style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><IMG height=300 alt="" src="http://www.frontfree.net/articles/pages/0000000844/image001.jpg" width=500></SPAN></P>
<P style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">这个程序清晰的表明这几种容器在插入速度之间的差别，当然，每种容器不是万能的，不能一好百好。比如说，多集在查找方面的优势是其他序列容器不可比拟的。<SPAN lang=EN-US>&nbsp; 还有，最好不要试图超越STL，因为：</SPAN></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"> <BR>1、STL实现使用的是最佳算法。它是几乎完美的。 <BR>2、STL实现的设计者通常是相应领域的专家。 <BR>3、各领域的专家致力于提供灵活的、强大和高效的库。这是他们的首要的任务。对于，我们这些其余的人，开发可重用的容器和算法顶多只算第二个目标。我们的首要任务是交付紧扣主题的应用程序。大多数情况下，我们没有时间和专门的技术去和那些专家相比。</SPAN></P>
<P style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">但是，超越STL不是不可能的。但是一般情况下，你只能靠牺牲可移植性来提高性能，这对于很多情况来说是很不好的。为了，超越STL，我们要付出非常大的努力。而且，最好我们知道一些STL专家们不知道的东西，尔后我们可以有针对性的进行优化，否则，我们的努力完全有可能白费。 </SPAN></P>
<P style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">面对这样一个优秀的库，并且它是免费的。我们C++程序员没有理由拒绝它，甚至去自己开发一个库。</SPAN></P></DIV></TD></TR></TBODY></TABLE><BR></DIV><img src ="http://www.cnblogs.com/zjz/aggbug/507304.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43603/" target="_blank">[新闻]《时代》：杨致远被Google玩弄于股掌之间？</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>stl 学习(转帖)</title><link>http://www.cnblogs.com/zjz/archive/2006/09/18/507299.html</link><dc:creator>.net技術</dc:creator><author>.net技術</author><pubDate>Mon, 18 Sep 2006 04:11:00 GMT</pubDate><guid>http://www.cnblogs.com/zjz/archive/2006/09/18/507299.html</guid><wfw:comment>http://www.cnblogs.com/zjz/comments/507299.html</wfw:comment><comments>http://www.cnblogs.com/zjz/archive/2006/09/18/507299.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zjz/comments/commentRss/507299.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zjz/services/trackbacks/507299.html</trackback:ping><description><![CDATA[摘要: C++ STL轻松导学　名称C++ STL轻松导学　作者晨光（Morning）　简介本教程介绍有关学习C++ STL的预备知识和STL的相关背景知识，适合想对STL做大致了解的初学者。　声明本教程版权为晨光（Morning）所有，未经允许，请勿复制、传播，谢谢。　目录1 初识STL：解答一些疑问 1.1 一个最关心的问题：什么是STL 1.2 追根溯源：STL的历史 1.3 千丝万缕的联系 1.3&nbsp;&nbsp;<a href='http://www.cnblogs.com/zjz/archive/2006/09/18/507299.html'>阅读全文</a><img src ="http://www.cnblogs.com/zjz/aggbug/507299.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43603/" target="_blank">[新闻]《时代》：杨致远被Google玩弄于股掌之间？</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>visual C++ 6.0开发工具与调试</title><link>http://www.cnblogs.com/zjz/archive/2006/09/12/502411.html</link><dc:creator>.net技術</dc:creator><author>.net技術</author><pubDate>Tue, 12 Sep 2006 11:24:00 GMT</pubDate><guid>http://www.cnblogs.com/zjz/archive/2006/09/12/502411.html</guid><wfw:comment>http://www.cnblogs.com/zjz/comments/502411.html</wfw:comment><comments>http://www.cnblogs.com/zjz/archive/2006/09/12/502411.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zjz/comments/commentRss/502411.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zjz/services/trackbacks/502411.html</trackback:ping><description><![CDATA[摘要: 《visual C++ 6.0开发工具与调试》1、 如何快速地规范代码缩进格式选中所需要规范的代码，按shift+F82、 如何在Release状态下进行调试Project－&gt;Setting＝&gt;ProjectSetting对话框，选择Release状态。C/C++标签中的Category选General，Optimizations选Disable(Debug)，Debut info选P&nbsp;&nbsp;<a href='http://www.cnblogs.com/zjz/archive/2006/09/12/502411.html'>阅读全文</a><img src ="http://www.cnblogs.com/zjz/aggbug/502411.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43602/" target="_blank">[新闻]Mozilla即将结束对FireFox 2的支持</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>vc动态装载动态库</title><link>http://www.cnblogs.com/zjz/archive/2006/08/11/474174.html</link><dc:creator>.net技術</dc:creator><author>.net技術</author><pubDate>Fri, 11 Aug 2006 04:56:00 GMT</pubDate><guid>http://www.cnblogs.com/zjz/archive/2006/08/11/474174.html</guid><wfw:comment>http://www.cnblogs.com/zjz/comments/474174.html</wfw:comment><comments>http://www.cnblogs.com/zjz/archive/2006/08/11/474174.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/zjz/comments/commentRss/474174.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/zjz/services/trackbacks/474174.html</trackback:ping><description><![CDATA[<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">&nbsp;1</SPAN>&nbsp;<SPAN style="COLOR: #000000">HMODULE&nbsp;hScanGMdll;<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;2</SPAN>&nbsp;<SPAN style="COLOR: #000000"></SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;(WINAPI&nbsp;</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">pScanGMdll)(</SPAN><SPAN style="COLOR: #0000ff">long</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #0000ff">long</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #0000ff">long</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #0000ff">long</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #0000ff">long</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #0000ff">long</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #0000ff">long</SPAN><SPAN style="COLOR: #000000">);<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;3</SPAN>&nbsp;<SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;4</SPAN>&nbsp;<SPAN style="COLOR: #000000"></SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;CTy_serverView::OnPlanarscanCard()&nbsp;<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;5</SPAN>&nbsp;<SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;6</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;TODO:&nbsp;Add&nbsp;your&nbsp;command&nbsp;handler&nbsp;code&nbsp;here<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;7</SPAN>&nbsp;<SPAN style="COLOR: #008000"></SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;::DeleteFile(".\\decode.out");</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;8</SPAN>&nbsp;<SPAN style="COLOR: #008000"></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(LoadGM())<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;9</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<BR></SPAN><SPAN style="COLOR: #008080">10</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(pScanGMdll(</SPAN><SPAN style="COLOR: #000000">300</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #000000">200</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #000000">80</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #000000">20</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">)&nbsp;</SPAN><SPAN style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">)<BR></SPAN><SPAN style="COLOR: #008080">11</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR></SPAN><SPAN style="COLOR: #008080">12</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pScanGMdll&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;NULL;<BR></SPAN><SPAN style="COLOR: #008080">13</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FreeLibrary(hScanGMdll);<BR></SPAN><SPAN style="COLOR: #008080">14</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">解析卡号失败!</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);<BR></SPAN><SPAN style="COLOR: #008080">15</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">;<BR></SPAN><SPAN style="COLOR: #008080">16</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR></SPAN><SPAN style="COLOR: #008080">17</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">18</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR></SPAN><SPAN style="COLOR: #008080">19</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pScanGMdll&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;NULL;<BR></SPAN><SPAN style="COLOR: #008080">20</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FreeLibrary(hScanGMdll);<BR></SPAN><SPAN style="COLOR: #008080">21</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;**Line&nbsp;=pFile.ReadLines(".\\decode.out");</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #008080">22</SPAN>&nbsp;<SPAN style="COLOR: #008000"></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">char</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">**</SPAN><SPAN style="COLOR: #000000">Line&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;read_file_lines(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">.\\decode.out</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000">);&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">读出一行数据&nbsp;,二维空间</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #008080">23</SPAN>&nbsp;<SPAN style="COLOR: #008000"></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">24</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CTy_serverView::strCard&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;Line[</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">];&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">第一行字符&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #008080">25</SPAN>&nbsp;<SPAN style="COLOR: #008000"></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CTy_serverView::strCard&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;CTy_serverView::strCard.Mid(</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">,&nbsp;</SPAN><SPAN style="COLOR: #000000">10</SPAN><SPAN style="COLOR: #000000">);&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">从1开始10个数据</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #008080">26</SPAN>&nbsp;<SPAN style="COLOR: #008000"></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strfreev(Line);&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">释放二维空间</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #008080">27</SPAN>&nbsp;<SPAN style="COLOR: #008000"></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">28</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(CTy_serverView::strCard&nbsp;</SPAN><SPAN style="COLOR: #000000">!=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">""</SPAN><SPAN style="COLOR: #000000">)<BR></SPAN><SPAN style="COLOR: #008080">29</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BrushCardPro();<BR></SPAN><SPAN style="COLOR: #008080">30</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR></SPAN><SPAN style="COLOR: #008080">31</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<BR></SPAN><SPAN style="COLOR: #008080">32</SPAN>&nbsp;<SPAN style="COLOR: #000000">}<BR></SPAN><SPAN style="COLOR: #008080">33</SPAN>&nbsp;<SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">34</SPAN>&nbsp;<SPAN style="COLOR: #000000">BOOL&nbsp;CTy_serverView::LoadGM()<BR></SPAN><SPAN style="COLOR: #008080">35</SPAN>&nbsp;<SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">36</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;::CoInitialize(NULL);<BR></SPAN><SPAN style="COLOR: #008080">37</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;hScanGMdll&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;LoadLibrary(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">FS531GM.dll</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);<BR></SPAN><SPAN style="COLOR: #008080">38</SPAN>&nbsp;<SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">39</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">(hScanGMdll&nbsp;</SPAN><SPAN style="COLOR: #000000">==</SPAN><SPAN style="COLOR: #000000">&nbsp;NULL)<BR></SPAN><SPAN style="COLOR: #008080">40</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<BR></SPAN><SPAN style="COLOR: #008080">41</SPAN>&nbsp;<SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(</SPAN><SPAN sty