﻿<?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>C++博客-The sky is the limit to what man can do.-文章分类-C++常见知识点</title><link>http://www.cppblog.com/ZhangShiyu/category/18192.html</link><description>心态决定一切</description><language>zh-cn</language><lastBuildDate>Mon, 19 Dec 2011 13:38:27 GMT</lastBuildDate><pubDate>Mon, 19 Dec 2011 13:38:27 GMT</pubDate><ttl>60</ttl><item><title>C排序总结---转载</title><link>http://www.cppblog.com/ZhangShiyu/articles/162168.html</link><dc:creator>ZhangShiyu</dc:creator><author>ZhangShiyu</author><pubDate>Thu, 15 Dec 2011 06:38:00 GMT</pubDate><guid>http://www.cppblog.com/ZhangShiyu/articles/162168.html</guid><wfw:comment>http://www.cppblog.com/ZhangShiyu/comments/162168.html</wfw:comment><comments>http://www.cppblog.com/ZhangShiyu/articles/162168.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ZhangShiyu/comments/commentRss/162168.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ZhangShiyu/services/trackbacks/162168.html</trackback:ping><description><![CDATA[一、<font color="#0000ff">插入排序(Insertion Sort)</font><br />1. 基本思想：<br />每次将一个待排序的数据元素，插入到前面已经排好序的数列中的适当位置，使数列依然有序；直到待排序数据元素全部插入完为止。<br />2. 排序过程：　 <br />【示例】：<br />[初始关键字] [49] 38 65 97 76 13 27 49<br />J=2(38) [38 49] 65 97 76 13 27 49<br />J=3(65) [38 49 65] 97 76 13 27 49<br />J=4(97) [38 49 65 97] 76 13 27 49<br />J=5(76) [38 49 65 76 97] 13 27 49<br />J=6(13) [13 38 49 65 76 97] 27 49<br />J=7(27) [13 27 38 49 65 76 97] 49<br />J=8(49) [13 27 38 49 49 65 76 97] 
<p>&nbsp;</p>
<p><br />Procedure InsertSort(Var R : FileType);<br />//对R[1..N]按递增序进行插入排序, R[0]是监视哨//<br />Begin<br />for I := 2 To N Do //依次插入R[2],...,R[n]//<br />begin<br />R[0] := R[I]; J := I - 1;<br />While R[0] &lt; R[J] Do //查找R[I]的插入位置//<br />begin<br />R[J 1] := R[J]; //将大于R[I]的元素后移//<br />J := J - 1<br />end<br />R[J 1] := R[0] ; //插入R[I] //<br />end<br />End; //InsertSort //</p>
<p><br />二、<font color="#0000ff">选择排序</font><br />1. 基本思想：<br />每一趟从待排序的数据元素中选出最小（或最大）的一个元素，顺序放在已排好序的数列的最后，直到全部待排序的数据元素排完。<br />2. 排序过程：<br />【示例】：<br />初始关键字 [49 38 65 97 76 13 27 49]<br />第一趟排序后 13 ［38 65 97 76 49 27 49]<br />第二趟排序后 13 27 ［65 97 76 49 38 49]<br />第三趟排序后 13 27 38 [97 76 49 65 49]<br />第四趟排序后 13 27 38 49 [49 97 65 76]<br />第五趟排序后 13 27 38 49 49 [97 97 76]<br />第六趟排序后 13 27 38 49 49 76 [76 97]<br />第七趟排序后 13 27 38 49 49 76 76 [ 97]<br />最后排序结果 13 27 38 49 49 76 76 97</p>
<p>Procedure SelectSort(Var R : FileType); //对R[1..N]进行直接选择排序 //<br />Begin<br />for I := 1 To N - 1 Do //做N - 1趟选择排序//<br />begin<br />K := I;<br />For J := I 1 To N Do //在当前无序区R[I..N]中选最小的元素R[K]//<br />begin<br />If R[J] &lt; R[K] Then K := J<br />end;<br />If K &lt;&gt; I Then //交换R[I]和R[K] //<br />begin Temp := R[I]; R[I] := R[K]; R[K] := Temp; end;<br />end<br />End; //SelectSort //</p>
<p><br />三、<font color="#0000ff">冒泡排序(BubbleSort)</font><br />1. 基本思想：<br />两两比较待排序数据元素的大小，发现两个数据元素的次序相反时即进行交换，直到没有反序的数据元素为止。<br />2. 排序过程：<br />设想被排序的数组R［1..N］垂直竖立，将每个数据元素看作有重量的气泡，根据轻气泡不能在重气泡之下的原则，从下往上扫描数组R，凡扫描到违反本原则的轻气泡，就使其向上"漂浮"，如此反复进行，直至最后任何两个气泡都是轻者在上，重者在下为止。<br />【示例】：<br />49 13 13 13 13 13 13 13 <br />38 49 27 27 27 27 27 27<br />65 38 49 38 38 38 38 38<br />97 65 38 49 49 49 49 49<br />76 97 65 49 49 49 49 49<br />13 76 97 65 65 65 65 65<br />27 27 76 97 76 76 76 76<br />49 49 49 76 97 97 97 97 </p>
<p>Procedure BubbleSort(Var R : FileType) //从下往上扫描的起泡排序//<br />Begin<br />For I := 1 To N-1 Do //做N-1趟排序//<br />begin<br />NoSwap := True; //置未排序的标志//<br />For J := N - 1 DownTo 1 Do //从底部往上扫描//<br />begin<br />If R[J 1]&lt; R[J] Then //交换元素//<br />begin<br />Temp := R[J 1]; R[J 1 := R[J]; R[J] := Temp;<br />NoSwap := False<br />end;<br />end;<br />If NoSwap Then Return//本趟排序中未发生交换，则终止算法//<br />end<br />End; //BubbleSort//</p>
<p>四、<font color="#0000ff">快速排序（Quick Sort）</font><br />1. 基本思想：<br />在当前无序区R[1..H]中任取一个数据元素作为比较的"基准"(不妨记为X)，用此基准将当前无序区划分为左右两个较小的无序区：R[1..I- 1]和R[I 1..H]，且左边的无序子区中数据元素均小于等于基准元素，右边的无序子区中数据元素均大于等于基准元素，而基准X则位于最终排序的位置上，即R [1..I-1]&#8804;X.Key&#8804;R[I 1..H](1&#8804;I&#8804;H)，当R[1..I-1]和R[I 1..H]均非空时，分别对它们进行上述的划分过程，直至所有无序子区中的数据元素均已排序为止。<br />2. 排序过程：<br />【示例】：<br />初始关键字 [49 38 65 97 76 13 27 49］<br />第一次交换后 ［27 38 65 97 76 13 49 49］ <br />第二次交换后 ［27 38 49 97 76 13 65 49］ <br />J向左扫描，位置不变，第三次交换后 ［27 38 13 97 76 49 65 49］ <br />I向右扫描，位置不变，第四次交换后 ［27 38 13 49 76 97 65 49］<br />J向左扫描 ［27 38 13 49 76 97 65 49］<br />（一次划分过程） </p>
<p>初始关键字 ［49 38 65 97 76 13 27 49］<br />一趟排序之后 ［27 38 13］ 49 ［76 97 65 49］ <br />二趟排序之后 ［13］ 27 ［38］ 49 ［49 65］76 ［97］<br />三趟排序之后 13 27 38 49 49 ［65］76 97<br />最后的排序结果 13 27 38 49 49 65 76 97 <br />各趟排序之后的状态</p>
<p>Procedure Parttion(Var R : FileType; L, H : Integer; Var I : Integer);<br />//对无序区R[1,H]做划分，I给以出本次划分后已被定位的基准元素的位置 //<br />Begin<br />I := 1; J := H; X := R[I] ;//初始化，X为基准//<br />Repeat<br />While (R[J] &gt;= X) And (I &lt; J) Do<br />begin<br />J := J - 1 //从右向左扫描，查找第1个小于 X的元素//<br />If I &lt; J Then //已找到R[J] 〈X//<br />begin<br />R[I] := R[J]; //相当于交换R[I]和R[J]//<br />I := I 1<br />end;<br />While (R[I] &lt;= X) And (I &lt; J) Do<br />I := I 1 //从左向右扫描，查找第1个大于 X的元素///<br /></p>
<p>&nbsp;</p>
<p>end;<br />If I &lt; J Then //已找到R[I] &gt; X //<br />begin R[J] := R[I]; //相当于交换R[I]和R[J]//<br />J := J - 1<br />end<br />Until I = J;<br />R[I] := X //基准X已被最终定位//<br />End; //Parttion // </p>
<p>&nbsp;</p>
<p>Procedure QuickSort(Var R :FileType; S,T: Integer); //对R[S..T]快速排序//<br />Begin<br />If S &lt; T Then //当R[S..T]为空或只有一个元素是无需排序//<br />begin<br />Partion(R, S, T, I); //对R[S..T]做划分//<br />QuickSort(R, S, I-1);//递归处理左区间R[S,I-1]//<br />QuickSort(R, I 1,T);//递归处理右区间R[I 1..T] //<br />end;<br />End; //QuickSort//</p>
<p><br />五、<font color="#0000ff">堆排序(Heap Sort)</font><br />1. 基本思想：<br />堆排序是一树形选择排序，在排序过程中，将R[1..N]看成是一颗完全二叉树的顺序存储结构，利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择最小的元素。<br />2. 堆的定义: N个元素的序列K1,K2,K3,...,Kn.称为堆，当且仅当该序列满足特性：<br />Ki&#8804;K2i Ki &#8804;K2i 1(1&#8804; I&#8804; [N/2])</p>
<p>堆实质上是满足如下性质的完全二叉树：树中任一非叶子结点的关键字均大于等于其孩子结点的关键字。例如序列10,15,56,25,30,70就是 一个堆，它对应的完全二叉树如上图所示。这种堆中根结点（称为堆顶）的关键字最小，我们把它称为小根堆。反之，若完全二叉树中任一非叶子结点的关键字均大 于等于其孩子的关键字，则称之为大根堆。<br />3. 排序过程：<br />堆排序正是利用小根堆（或大根堆）来选取当前无序区中关键字小（或最大）的记录实现排序的。我们不妨利用大根堆来排序。每一趟排序的基本操作是：将当前无 序区调整为一个大根堆，选取关键字最大的堆顶记录，将它和无序区中的最后一个记录交换。这样，正好和直接选择排序相反，有序区是在原记录区的尾部形成并逐 步向前扩大到整个记录区。<br />【示例】：对关键字序列42，13，91，23，24，16，05，88建堆 <br /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Procedure Sift(Var R :FileType; I, M : Integer);<br />//在数组R[I..M]中调用R[I]，使得以它为完全二叉树构成堆。事先已知其左、右子树(2I 1 &lt;=M时)均是堆//<br />Begin<br />X := R[I]; J := 2*I; //若J &lt;=M, R[J]是R[I]的左孩子//<br />While J &lt;= M Do //若当前被调整结点R[I]有左孩子R[J]//<br />begin<br />If (J &lt; M) And R[J].Key &lt; R[J 1].Key Then<br />J := J 1 //令J指向关键字较大的右孩子//<br />//J指向R[I]的左、右孩子中关键字较大者//<br />If X.Key &lt; R[J].Key Then //孩子结点关键字较大//<br />begin<br />R[I] := R[J]; //将R[J]换到双亲位置上//<br />I := J ; J := 2*I //继续以R[J]为当前被调整结点往下层调整//<br />end;<br />Else<br />Exit//调整完毕，退出循环//<br />end<br />R[I] := X;//将最初被调整的结点放入正确位置//<br />End;//Sift//</p>
<p>Procedure HeapSort(Var R : FileType); //对R[1..N]进行堆排序//<br />Begin<br />For I := N Div Downto 1 Do //建立初始堆//<br />Sift(R, I , N)<br />For I := N Downto 2 do //进行N-1趟排序//<br />begin<br />T := R[1]; R[1] := R[I]; R[I] := T;//将当前堆顶记录和堆中最后一个记录交换//<br />Sift(R, 1, I-1) //将R[1..I-1]重成堆//<br />end<br />End; //HeapSort//</p>
<p><br />六、几种排序算法的比较和选择 <br />1. 选取排序方法需要考虑的因素：<br />(1) 待排序的元素数目n；<br />(2) 元素本身信息量的大小；<br />(3) 关键字的结构及其分布情况；<br />(4) 语言工具的条件，辅助空间的大小等。<br />2. 小结：<br />(1) 若n较小(n &lt;= 50)，则可以采用直接插入排序或直接选择排序。由于直接插入排序所需的记录移动操作较直接选择排序多，因而当记录本身信息量较大时，用直接选择排序较好。<br />(2) 若文件的初始状态已按关键字基本有序，则选用直接插入或冒泡排序为宜。<br />(3) 若n较大，则应采用时间复杂度为O(nlog2n)的排序方法：快速排序、堆排序或归并排序。 快速排序是目前基于比较的内部排序法中被认为是最好的方法。<br />(4) 在基于比较排序方法中，每次比较两个关键字的大小之后，仅仅出现两种可能的转移，因此可以用一棵二叉树来描述比较判定过程，由此可以证明：当文件的n个关键字随机分布时，任何借助于"比较"的排序算法，至少需要O(nlog2n)的时间。<br />(5) 当记录本身信息量较大时，为避免耗费大量时间移动记录，可以用链表作为存储结构。</p><img src ="http://www.cppblog.com/ZhangShiyu/aggbug/162168.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ZhangShiyu/" target="_blank">ZhangShiyu</a> 2011-12-15 14:38 <a href="http://www.cppblog.com/ZhangShiyu/articles/162168.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>const用法详解---转载</title><link>http://www.cppblog.com/ZhangShiyu/articles/162166.html</link><dc:creator>ZhangShiyu</dc:creator><author>ZhangShiyu</author><pubDate>Thu, 15 Dec 2011 05:56:00 GMT</pubDate><guid>http://www.cppblog.com/ZhangShiyu/articles/162166.html</guid><wfw:comment>http://www.cppblog.com/ZhangShiyu/comments/162166.html</wfw:comment><comments>http://www.cppblog.com/ZhangShiyu/articles/162166.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ZhangShiyu/comments/commentRss/162166.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ZhangShiyu/services/trackbacks/162166.html</trackback:ping><description><![CDATA[<span style="font-family: 宋体; font-size: 9pt; mso-bidi-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" lang="EN-US">
<table class="mtxt" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td id="body" csdnid="body">
<div class="msgfont">面向对象是C++的重要特性.&nbsp; <br />但是c++在c的基础上新增加的几点优化也是很耀眼的<br />就const直接可以取代c中的#define<br />以下几点很重要,学不好后果也也很严重<br /><br />const<br />1. 限定符声明变量只能被读<br />&nbsp; const int i=5;<br />&nbsp; int j=0;<br />&nbsp; ...<br />&nbsp; i=j; //非法，导致编译错误<br />&nbsp; j=i; //合法<br />2. 必须初始化<br />&nbsp; const int i=5; //合法<br />&nbsp; const int j; //非法，导致编译错误<br />3. 在另一连接文件中引用const常量<br />&nbsp; extern const int i; //合法<br />&nbsp; extern const int j=10; //非法，常量不可以被再次赋值<br />4. 便于进行类型检查<br />&nbsp; 用const方法可以使编译器对处理内容有更多了解。<br />&nbsp; #define I=10<br />&nbsp; const long &amp;i=10; /*dapingguo提醒：由于编译器的优化，使<br />&nbsp; 得在const long i=10; 时i不被分配内存，而是已10直接代入<br />&nbsp; 以后的引用中，以致在以后的代码中没有错误，为达到说教效<br />&nbsp; 果，特别地用&amp;i明确地给出了i的内存分配。不过一旦你关闭所<br />&nbsp; 有优化措施，即使const long i=10;也会引起后面的编译错误。*/<br />&nbsp; char h=I; //没有错<br />&nbsp; char h=i; //编译警告，可能由于数的截短带来错误赋值。<br />5. 可以避免不必要的内存分配<br />&nbsp; #define STRING "abcdefghijklmn\n"<br />&nbsp; const char string[]="abcdefghijklm\n";<br />&nbsp; ...<br />&nbsp; printf(STRING); //为STRING分配了第一次内存<br />&nbsp; printf(string); //为string一次分配了内存，以后不再分配<br />&nbsp; ...<br />&nbsp; printf(STRING); //为STRING分配了第二次内存<br />&nbsp; printf(string);<br />&nbsp; ...&nbsp; <br />&nbsp; 由于const定义常量从汇编的角度来看，只是给出了对应的内存地址，<br />&nbsp; 而不是象#define一样给出的是立即数，所以，const定义的常量在<br />&nbsp; 程序运行过程中只有一份拷贝，而#define定义的常量在内存中有<br />&nbsp; 若干个拷贝。<br />6. 可以通过函数对常量进行初始化<br />&nbsp; int value();&nbsp; <br />&nbsp; const int i=value();<br />&nbsp; dapingguo说：假定对ROM编写程序时，由于目标代码的不可改写，<br />&nbsp; 本语句将会无效，不过可以变通一下：<br />&nbsp; const int &amp;i=value();<br />&nbsp; 只要令i的地址处于ROM之外，即可实现：i通过函数初始化，而其<br />&nbsp; 值有不会被修改。<br />7. 是不是const的常量值一定不可以被修改呢？<br />&nbsp; 观察以下一段代码：<br />&nbsp; const int i=0;<br />&nbsp; int *p=(int*)&amp;i;<br />&nbsp; p=100;<br />&nbsp; 通过强制类型转换，将地址赋给变量，再作修改即可以改变const常量值。<br />8. 请分清数值常量和指针常量，以下声明颇为玩味：<br />&nbsp; int ii=0;<br />&nbsp; const int i=0; //i是常量，i的值不会被修改<br />&nbsp; const int *p1i=&amp;i; //指针p1i所指内容是常量，可以不初始化<br />&nbsp; int * const p2i=&amp;ii; //指针p2i是常量，所指内容可修改<br />&nbsp; const int * const p3i=&amp;i; //指针p3i是常量，所指内容也是常量<br />&nbsp; p1i=&amp;ii; //合法<br />&nbsp; *p2i=100; //合法&nbsp; <br />关于C++中的const关键字的用法非常灵活，而使用const将大大改善程序的健壮性，参考了康建东兄的const使用详解一文，对其中进行了一些补充，写下了本文。<br /><br /><br /><br />1. const常量，如const int max = 100; &nbsp; <br />优点：const常量有数据类型，而宏常量没有数据类型。编译器可以对前者进行类型安全检查，而对后者只进行字符替换，没有类型安全检查，并且在字符替换时可能会产生意料不到的错误（边际效应）<br /><br />2. const 修饰类的数据成员。如：<br />class A<br /><br />{<br /><br />&nbsp; const int size;<br /><br />&nbsp; &#8230;&nbsp; <br /><br />}<br /><br />const数据成员只在某个对象生存期内是常量，而对于整个类而言却是可变的。因为类可以创建多个对象，不同的对象其const数据成员的值可以不同。所以不能在类声明中初始化const数据成员，因为类的对象未被创建时，编译器不知道const 数据成员的值是什么。如<br /><br />class A<br /><br />{<br /><br />const int size = 100; //错误<br /><br />int array[size]; //错误，未知的size<br /><br />}<br /><br />const数据成员的初始化只能在类的构造函数的初始化表中进行。要想建立在整个类中都恒定的常量，应该用类中的枚举常量来实现。如<br /><br />class A<br /><br />{&#8230;<br /><br />enum {size1=100, size2 = 200 };<br /><br />int array1[size1];<br /><br />int array2[size2];&nbsp; <br /><br />}<br /><br />枚举常量不会占用对象的存储空间，他们在编译时被全部求值。但是枚举常量的隐含数据类型是整数，其最大值有限，且不能表示浮点数。<br /><br />3. const修饰指针的情况，见下式：<br /><br />int b = 500;&nbsp; <br />const int* a = &amp; [1]&nbsp; <br />int const *a = &amp; [2]&nbsp; <br />int* const a = &amp; [3]&nbsp; <br />const int* const a = &amp; [4]&nbsp; <br />如果你能区分出上述四种情况，那么，恭喜你，你已经迈出了可喜的一步。不知道，也没关系，我们可以参考《Effective c++》Item21上的做法，如果const位于星号的左侧，则const就是用来修饰指针所指向的变量，即指针指向为常量；如果const位于星号的右侧，const就是修饰指针本身，即指针本身是常量。因此，[1]和[2]的情况相同，都是指针所指向的内容为常量（const放在变量声明符的位置无关），这种情况下不允许对内容进行更改操作，如不能*a = 3 ；[3]为指针本身是常量，而指针所指向的内容不是常量，这种情况下不能对指针本身进行更改操作，如a++是错误的；[4]为指针本身和指向的内容均为常量。&nbsp; <br /><br />4. const的初始化&nbsp; <br />先看一下const变量初始化的情况&nbsp; <br />1) 非指针const常量初始化的情况：A b;&nbsp; <br />const A a = b;&nbsp; <br />2) 指针const常量初始化的情况：<br /><br />A* d = new A();&nbsp; <br />const A* c = d;&nbsp; <br />或者：const A* c = new A();&nbsp; <br />3）引用const常量初始化的情况：&nbsp; <br />A f;&nbsp; <br />const A&amp; e = f; // 这样作e只能访问声明为const的函数，而不能访问一 &nbsp; <br /><br />般的成员函数；&nbsp; <br />&nbsp; [思考1]： 以下的这种赋值方法正确吗？&nbsp; <br />&nbsp; const A* c=new A();&nbsp; <br />&nbsp; A* e = c;&nbsp; <br />&nbsp; [思考2]： 以下的这种赋值方法正确吗？&nbsp; <br />&nbsp; A* const c = new A();&nbsp; <br />&nbsp; A* b = c;<br /><br />5. 另外const 的一些强大的功能在于它在函数声明中的应用。在一个函数声明中，const 可以修饰函数的返回值，或某个参数；对于成员函数，还可以修饰是整个函数。有如下几种情况，以下会逐渐的说明用法：A&amp; operator=(const A&amp; a);&nbsp; <br />void fun0(const A* a );&nbsp; <br />void fun1( ) const; // fun1( ) 为类成员函数&nbsp; <br />const A fun2( );<br /><br />1） 修饰参数的const，如 void fun0(const A* a ); void fun1(const A&amp; a);&nbsp; <br />调用函数的时候，用相应的变量初始化const常量，则在函数体中，按照const所修饰的部分进行常量化，如形参为const A* a，则不能对传递进来的指针的内容进行改变，保护了原指针所指向的内容；如形参为const A&amp; a，则不能对传递进来的引用对象进行改变，保护了原对象的属性。&nbsp; <br />[注意]：参数const通常用于参数为指针或引用的情况，且只能修饰输入参数;若输入参数采用&#8220;值传递&#8221;方式，由于函数将自动产生临时变量用于复制该参数，该参数本就不需要保护，所以不用const修饰。<br /><br />[总结]对于非内部数据类型的输入参数，因该将&#8220;值传递&#8221;的方式改为&#8220;const引用传递&#8221;，目的是为了提高效率。例如，将void Func(A a)改为void Func(const A &amp;a)<br /><br />&nbsp; 对于内部数据类型的输入参数，不要将&#8220;值传递&#8221;的方式改为&#8220;const引用传递&#8221;。否则既达不到提高效率的目的，又降低了函数的可理解性。例如void Func(int x)不应该改为void Func(const int &amp;x)<br /><br />2） 修饰返回值的const，如const A fun2( ); const A* fun3( );&nbsp; <br />这样声明了返回值后，const按照"修饰原则"进行修饰，起到相应的保护作用。const Rational operator*(const Rational&amp; lhs, const Rational&amp; rhs)&nbsp; <br />{&nbsp; <br />return Rational(lhs.numerator() * rhs.numerator(),&nbsp; <br />lhs.denominator() * rhs.denominator());&nbsp; <br />}&nbsp; <br />返回值用const修饰可以防止允许这样的操作发生:Rational a,b;&nbsp; <br />Radional c;&nbsp; <br />(a*b) = c;&nbsp; <br />一般用const修饰返回值为对象本身（非引用和指针）的情况多用于二目操作符重载函数并产生新对象的时候。&nbsp; <br />[总结]<br /><br />1. 一般情况下，函数的返回值为某个对象时，如果将其声明为const时，多用于操作符的重载。通常，不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。原因如下：如果返回值为某个对象为const（const A test = A 实例）或某个对象的引用为const（const A&amp; test = A实例） ，则返回值具有const属性，则返回实例只能访问类A中的公有（保护）数据成员和const成员函数，并且不允许对其进行赋值操作，这在一般情况下很少用到。&nbsp; <br /><br />2. 如果给采用&#8220;指针传递&#8221;方式的函数返回值加const修饰，那么函数返回值（即指针）的内容不能被修改，该返回值只能被赋给加const 修饰的同类型指针。如：<br /><br />const char * GetString(void);<br /><br />如下语句将出现编译错误：<br /><br />char *str=GetString();<br /><br />正确的用法是：<br /><br />const char *str=GetString();<br /><br />3. 函数返回值采用&#8220;引用传递&#8221;的场合不多，这种方式一般只出现在类的赙值函数中，目的是为了实现链式表达。如：<br /><br />class A<br /><br />{&#8230;<br /><br />A &amp;operate = (const A &amp;other); //负值函数<br /><br />}<br />A a,b,c; //a,b,c为A的对象<br /><br />&#8230;<br /><br />a=b=c; //正常<br /><br />(a=b)=c; //不正常，但是合法<br /><br />若负值函数的返回值加const修饰，那么该返回值的内容不允许修改，上例中a=b=c依然正确。(a=b)=c就不正确了。<br />[思考3]： 这样定义赋值操作符重载函数可以吗？&nbsp; <br />const A&amp; operator=(const A&amp; a);<br /><br />6. 类成员函数中const的使用&nbsp; <br />一般放在函数体后，形如：void fun() const;&nbsp; <br />任何不会修改数据成员的函数都因该声明为const类型。如果在编写const成员函数时，不慎修改了数据成员，或者调用了其他非const成员函数，编译器将报错，这大大提高了程序的健壮性。如：<br /><br />class Stack<br /><br />{<br /><br />public:<br /><br />&nbsp; void Push(int elem);<br /><br />&nbsp; int Pop(void);<br /><br />&nbsp; int GetCount(void) const; //const 成员函数<br /><br />private:&nbsp; <br /><br />&nbsp; int m_num;<br /><br />&nbsp; int m_data[100];<br /><br />};<br /><br />int Stack::GetCount(void) const<br /><br />{<br /><br />&nbsp; ++m_num; //编译错误，企图修改数据成员m_num<br /><br />&nbsp; Pop(); //编译错误，企图调用非const函数<br /><br />&nbsp; Return m_num;<br /><br />}<br /><br />7. 使用const的一些建议&nbsp; <br />1 要大胆的使用const，这将给你带来无尽的益处，但前提是你必须搞清楚原委；&nbsp; <br />2 要避免最一般的赋值操作错误，如将const变量赋值，具体可见思考题；&nbsp; <br />3 在参数中使用const应该使用引用或指针，而不是一般的对象实例，原因同上；&nbsp; <br />4 const在成员函数中的三种用法（参数、返回值、函数）要很好的使用；&nbsp; <br />5 不要轻易的将函数的返回值类型定为const;&nbsp; <br />6除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;&nbsp; <br />[思考题答案]&nbsp; <br />1 这种方法不正确，因为声明指针的目的是为了对其指向的内容进行改变，而声明的指针e指向的是一个常量，所以不正确；&nbsp; <br />2 这种方法正确，因为声明指针所指向的内容可变；&nbsp; <br />3 这种做法不正确；&nbsp; <br />在const A::operator=(const A&amp; a)中，参数列表中的const的用法正确，而当这样连续赋值的时侯，问题就出现了：&nbsp; <br />A a,b,c:&nbsp; <br />(a=b)=c;&nbsp; <br />因为a.operator=(b)的返回值是对a的const引用，不能再将c赋值给const常量。<br /></div></td></tr></tbody></table></span><img src ="http://www.cppblog.com/ZhangShiyu/aggbug/162166.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ZhangShiyu/" target="_blank">ZhangShiyu</a> 2011-12-15 13:56 <a href="http://www.cppblog.com/ZhangShiyu/articles/162166.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入理解C/C++函数指针---转</title><link>http://www.cppblog.com/ZhangShiyu/articles/161607.html</link><dc:creator>ZhangShiyu</dc:creator><author>ZhangShiyu</author><pubDate>Tue, 06 Dec 2011 12:16:00 GMT</pubDate><guid>http://www.cppblog.com/ZhangShiyu/articles/161607.html</guid><wfw:comment>http://www.cppblog.com/ZhangShiyu/comments/161607.html</wfw:comment><comments>http://www.cppblog.com/ZhangShiyu/articles/161607.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ZhangShiyu/comments/commentRss/161607.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ZhangShiyu/services/trackbacks/161607.html</trackback:ping><description><![CDATA[<div id="msgcns!68C21584AD4BB2C!120">
<div><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 笔者在开发某软件过程中遇到这样一个问题，前级模块传给我二进制数据，输入参数为 char* buffer和 int length，buffer是数据的首地址，length表示这批数据的长度。数据的特点是：长度不定，类型不定，由第一个字节（buffer[0]）标识该数据的类型，共有256（28 ）种可能性。我的任务是必须对每一种可能出现的数据类型都要作处理，并且我的模块包含若干个函数，在每个函数里面都要作类似的处理。若按通常做法，会写出如下代码：<br /><br />void MyFuntion( char* buffer, int length )<br />{<br />　　　　__int8 nStreamType = buffer[0];<br /><br />　　　　switch( nStreamType )<br />　　　　{<br />　　　　　　　case 0:<br />　　　　　　　　　　　function1();<br />　　　　　　　　　　　break;<br />　　　　　　　case 1:<br />　　　　　　　......<br />　　　　　　　case 255:<br />　　　　　　　　　　　function255();<br />　　　　　　　　　　　break;<br />　　　　　}<br />}</span> </div>
<div></div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span>如果按照这种方法写下去，那么在我的每一个函数里面，都必须作如此多的判断，写出的代码肯定很长，并且每一次处理，都要作许多次判断之后才找到正确的处理函数，代码的执行效率也不高。针对上述问题，我想到了用函数指针数组的方法解决这个问题。<br /><br />　　函数指针的概念，在潭浩强先生的C语言程序设计这本经典的教程中提及过，在大多数情况下我们使用不到，也忽略了它的存在。函数名实际上也是一种指针，指向函数的入口地址，但它又不同于普通的如int*、double*指针，看下面的例子来理解函数指针的概念：<br />int funtion( int x, int y );<br />void main ( void )<br />{<br />&nbsp;　　　int (*fun) ( int x, int y );<br />&nbsp;　　　int a = 10, b = 20;<br />&nbsp;　　　function( a, b );<br />&nbsp;　　　fun = function;<br />&nbsp;　　　（*fun）( a, b );<br />&nbsp;　　　　&#8230;&#8230;<br />}<br />　　语句1定义了一个函数function，其输入为两个整型数，返回也为一个整型数（输入参数和返回值可为其它任何数据类型）；语句3定义了一个函数指针，<font color="#ff0000"><strong>与int*或double*定义指针不同的是，函数指针的定义必须同时指出输入参数，表明这是一个函数指针，并且*fun也必须用一对括号括起来</strong></font>；语句6将函数指针赋值为funtion，前提条件是*fun和function的输入参数和返回值必须保持一致。语句5直接调用函数function（），语句7是调用函数指针，二者等效。<br /><br />　　当然从上述例子看不出函数指针的优点，目的主要是想引出函数指针数组的概念。我们从上面例子可以得知，既然函数名可以通过函数指针加以保存，那们也一定能定义一个数组保存若干个函数名，这就是函数指针数组。正确使用函数指针数组的前提条件是，这若干个需要通过函数指针数组保存的函数必须有相同的输入、输出值。</span><br /><span></span></div>
<div><span>这样，我工作中所面临的问题可以解决如下：<br /><br />首先定义256个处理函数(及其实现)。<br /><br />void funtion0( void );<br />&#8230;&#8230;<br />void funtion255(void );<br /><br />其次定义函数指针数组，并给数组赋值。<br />void (*fun[256])(void);<br /><br />fun[0] = function0;<br />&#8230;&#8230;<br />fun[255] = function();<br />最后，MyFunction()函数可以修改如下：<br /><br />void MyFuntion( char* buffer, int length )<br />{<br />　　　　__int8 nStreamType = buffer[0];<br />　　　　（*fun[nStreamType]）();<br />}<br /><br />　　只要2行代码，就完成了256条case语句要做的事，减少了编写代码时工作量，将nStreamType作为数组下标，直接调用函数指针，从代码执行效率上来说，也比case语句高。假如多个函数中均要作如此处理，函数指针数组更能体现出它的优势。</span></div>
<h4 style="margin-bottom: 0px" id="subjcns!68C21584AD4BB2C!119" class="TextColor1"><span><font color="#ff0000">函数指针与typedef</font></span></h4>
<div id="msgcns!68C21584AD4BB2C!119">
<div>
<div><span>关于C++中函数指针的使用(包含对typedef用法的讨论)<br /><strong><font size="4">（一）简单的函数指针的应用。</font></strong><br /><font color="#00ff00">//形式1：返回类型(*函数名)(参数表)</font><br /><strong>char (*pFun)(int);<br />char glFun(int a){ return;}<br />void main()<br />{<br />&nbsp;&nbsp;&nbsp; pFun = glFun;<br />&nbsp;&nbsp;&nbsp; (*pFun)(2);<br />}</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;第一行定义了一个指针变量pFun。首先我们根据前面提到的&#8220;形式1&#8221;认识到它是一个指向某种函数的指针，这种函数参数是一个int型，返回值是char类型。只有第一句我们还无法使用这个指针，因为我们还未对它进行赋值。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; 第二行定义了一个函数glFun()。该函数正好是一个以int为参数返回char的函数。<font color="#ff0000"><strong>我们要从指针的层次上理解函数&#8212;&#8212;函数的函数名实际上就是一个指针，函数名指向该函数的代码在内存中的首地址。<br /></strong></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 然后就是可爱的main()函数了，它的第一句您应该看得懂了&#8212;&#8212;它将函数glFun的地址赋值给变量pFun。main()函数的第二句中&#8220;*pFun&#8221;显然是取pFun所指向地址的内容，当然也就是取出了函数glFun()的内容，然后给定参数为2。<br /><font size="4"><strong>（二）使用typedef更直观更方便。</strong></font><br /><font color="#00ff00">//形式2：typedef 返回类型(*新类型)(参数表)</font><br /><strong>typedef char (*PTRFUN)(int);<br />PTRFUN pFun;<br />char glFun(int a){ return;}<br />void main()<br />{<br />&nbsp;&nbsp;&nbsp; pFun = glFun;<br />&nbsp;&nbsp;&nbsp; (*pFun)(2);<br />}</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef的功能是定义新的类型。第一句就是定义了一种PTRFUN的类型，并定义这种类型为指向某种函数的指针，这种函数以一个int为参数并返回char类型。后面就可以像使用int,char一样使用PTRFUN了。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第二行的代码便使用这个新类型定义了变量pFun，此时就可以像使用形式1一样使用这个变量了。<br /><strong><font size="4">（三）在C++类中使用函数指针。</font></strong><br /><font style="background-color: rgb(0,0,0)" color="#00ff00"><font style="background-color: rgb(255,255,255)">//形式3：typedef 返回类型(类名::*新类型)(参数表)</font> <font style="background-color: rgb(255,255,255)"><br /></font></font><strong>class CA<br />{<br />&nbsp;public:<br />&nbsp;&nbsp;&nbsp; char lcFun(int a){ return; }<br />};<br />CA ca;<br />typedef char (CA::*PTRFUN)(int);<br />PTRFUN pFun;<br />void main()<br />{<br />&nbsp;&nbsp;&nbsp; pFun = CA::lcFun;<br />&nbsp;&nbsp;&nbsp; ca.(*pFun)(2);<br />}</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这里，指针的定义与使用都加上了&#8220;类限制&#8221;或&#8220;对象&#8221;，用来指明指针指向的函数是哪个类的,这里的类对象也可以是使用new得到的。比如：<br /><strong>CA *pca = new CA;<br />pca-&gt;(*pFun)(2);<br />delete pca;</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而且这个类对象指针可以是类内部成员变量，你甚至可以使用this指针。比如：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类CA有成员变量PTRFUN m_pfun;<br /><strong>void CA::lcFun2()<br />{&nbsp;<br />&nbsp;&nbsp; (this-&gt;*m_pFun)(2);<br />}</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一句话，使用类成员函数指针必须有&#8220;-&gt;*&#8221;或&#8220;.*&#8221;的调用。</span></div>
<div>&nbsp;</div>
<div><span><font color="#000000">在调用动态库时，习惯用typedef重新定义动态库函数中的函数地址（函数指针），如在动态库（test.dll）中有如下函数：</font></span> 
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp; DoCase(int, long);</font></span></p>
<p><span><font color="#000000">则，在调用动态库是有两种方法：</font></span></p>
<p><span><font color="#000000">&nbsp; 1.&nbsp; 先声明一个与动态库中类型一致的指针函数变量：</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*DOCASE)(int ,long);//</font><font color="#339966">用于指向动态库中的DoCase函数地址</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HINSTANCE gLibMyDLL = NULL;</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gLibMyDLL = LoadLibrary("test.dll");</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(gLibMyDLL != NULL)</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //得到函数地址</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOCASE = (int(*)(int,long))GetProcAddress(gLibMyDLL, "DoCase");</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //调用函数</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int s = DOCASE(1,1000);</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;2.用typedef定义一个指针函数：typedef (*DOCASE)(int ,long);</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HINSTANCE gLibMyDLL = NULL;</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOCASE _docase;</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gLibMyDLL = LoadLibrary("test.dll");</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(gLibMyDLL != NULL)</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _docase = (DOCASE)GetProcAddress(gLibMyDll, "DoCase");</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //调用函数</font></span></p>
<p><span><font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int s=_docase(1,1000);</font></span></p></div></div></div></div><img src ="http://www.cppblog.com/ZhangShiyu/aggbug/161607.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ZhangShiyu/" target="_blank">ZhangShiyu</a> 2011-12-06 20:16 <a href="http://www.cppblog.com/ZhangShiyu/articles/161607.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符数组名与字符串指针变量名的区别 ---转</title><link>http://www.cppblog.com/ZhangShiyu/articles/161357.html</link><dc:creator>ZhangShiyu</dc:creator><author>ZhangShiyu</author><pubDate>Sat, 03 Dec 2011 07:31:00 GMT</pubDate><guid>http://www.cppblog.com/ZhangShiyu/articles/161357.html</guid><wfw:comment>http://www.cppblog.com/ZhangShiyu/comments/161357.html</wfw:comment><comments>http://www.cppblog.com/ZhangShiyu/articles/161357.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ZhangShiyu/comments/commentRss/161357.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ZhangShiyu/services/trackbacks/161357.html</trackback:ping><description><![CDATA[<p style="text-indent: 2em">&nbsp;</p>
<p><strong><span style="font-size: 16px">教学目的：</span></strong><span style="font-size: 16px">&nbsp;掌握使用字符串指针引用字符串的方法。掌握字符串指针作函数参数的方法。</span></p>
<p><strong><span style="font-size: 16px">教学重点：</span></strong><span style="font-size: 16px">&nbsp;通过字符串指针引用字符串。</span></p>
<p><strong><span style="font-size: 16px">教学难点：</span></strong><span style="font-size: 16px">&nbsp;字符数组名与字符串指针变量名的区别。</span></p>
<p><strong><span style="font-size: 16px">授课内容：</span></strong></p>
<p><span style="font-size: 16px">一、字符串指针变量的说明和使用</span></p>
<p><span style="font-size: 16px">字符串指针变量的定义说明与指向字符变量的指针变量说明是相同的。只能按对指针变量的赋值不同来区别。</span></p>
<p><span style="font-size: 16px">对指向字符变量的指针变量应赋予该字符变量的地址。如： char c,*p=&amp;c;表示p是一个指向字符变量c的指针变量。而： char *s="C Language";则表示s是一个指向字符串的指针变量。把字符串的首地址赋予s。</span></p>
<p><span style="font-size: 16px">请看下面一例。main(){</span><br /><span style="font-size: 16px">char *ps;</span><br /><span style="font-size: 16px">ps="C Language";</span><br /><span style="font-size: 16px">printf("%s",ps);</span><br /><span style="font-size: 16px">}</span><br /><span style="font-size: 16px">运行结果为：</span><br /><span style="font-size: 16px">C Language</span></p>
<p><span style="font-size: 16px">上例中，首先定义ps是一个字符指针变量， 然后把字符串的首</span><br /><span style="font-size: 16px">地址赋予ps(应写出整个字符串，以便编译系统把该串装入连续的一</span><br /><span style="font-size: 16px">块内存单元)，并把首地址送入ps。程序中的： char *ps;</span><br /><span style="font-size: 16px">ps="C Language";等效于： char *ps="C Language";</span><br /><span style="font-size: 16px">输出字符串中n个字符后的所有字符。</span></p>
<p><span style="font-size: 16px">二、字符指针变量的运算</span></p>
<p><span style="font-size: 16px">main(){</span><br /><span style="font-size: 16px">char *ps="this is a book";</span><br /><span style="font-size: 16px">int n=10;</span><br /><span style="font-size: 16px">ps=ps+n;</span><br /><span style="font-size: 16px">printf("%s\n",ps);</span><br /><span style="font-size: 16px">}</span><br /><span style="font-size: 16px">运行结果为：</span><br /><span style="font-size: 16px">book</span></p>
<p><span style="font-size: 16px">在程序中对ps初始化时，即把字符串首地址赋予ps，当ps= ps</span><br /><span style="font-size: 16px">+10之后，ps指向字符&#8220;b&#8221;，因此输出为"book"。</span></p>
<p><span style="font-size: 16px">main(){</span><br /><span style="font-size: 16px">char st[20],*ps;</span><br /><span style="font-size: 16px">int i;</span><br /><span style="font-size: 16px">printf("input a string:\n");</span><br /><span style="font-size: 16px">ps=st;</span><br /><span style="font-size: 16px">scanf("%s",ps);</span><br /><span style="font-size: 16px">for(i=0;ps[i]!='\0';i++)</span><br /><span style="font-size: 16px">if(ps[i]=='k'){</span><br /><span style="font-size: 16px">printf("there is a 'k' in the string\n");</span><br /><span style="font-size: 16px">break;</span><br /><span style="font-size: 16px">}</span><br /><span style="font-size: 16px">if(ps[i]=='\0') printf("There is no 'k' in the string\n");</span><br /><span style="font-size: 16px">}</span><br /><span style="font-size: 16px">本例是在输入的字符串中查找有无&#8216;k&#8217;字符。</span></p>
<p><span style="font-size: 16px">三、字符串指针作为函数参数的使用。</span></p>
<p><span style="font-size: 16px">要求把一个 字符串的内容复制到另一个字符串中，并且不能使用strcpy函数。函</span><br /><span style="font-size: 16px">数cprstr的形参为两个字符指针变量。pss指向源字符串，pds指向目标字符串。表达式： (*pds=*pss)!=`\0'</span></p>
<p><br /><span style="font-size: 16px">cpystr(char *pss,char *pds){</span><br /><span style="font-size: 16px">while((*pds=*pss)!='\0'){</span><br /><span style="font-size: 16px">pds++;</span><br /><span style="font-size: 16px">pss++; }</span><br /><span style="font-size: 16px">}</span><br /><span style="font-size: 16px">main(){</span><br /><span style="font-size: 16px">char *pa="CHINA",b[10],*pb;</span><br /><span style="font-size: 16px">pb=b;</span><br /><span style="font-size: 16px">cpystr(pa,pb);</span><br /><span style="font-size: 16px">printf("string a=%s\nstring b=%s\n",pa,pb);</span><br /><span style="font-size: 16px">}</span></p>
<p><span style="font-size: 16px">在上例中，程序完成了两项工作：一是把pss指向的源字符复制</span><br /><span style="font-size: 16px">到pds所指向的目标字符中，二是判断所复制的字符是否为`\0'，若</span><br /><span style="font-size: 16px">是则表明源字符串结束，不再循环。否则，pds和pss都加1，指向下</span><br /><span style="font-size: 16px">一字符。</span></p>
<p><br /><span style="font-size: 16px">四、使用字符串指针变量与字符数组的区别</span></p>
<p><span style="font-size: 16px">用字符数组和字符指针变量都可实现字符串的存储和运算。 但两者是有区别的。在使用时应注意以下几个问题：</span></p>
<p><span style="font-size: 16px">1. 字符串指针变量本身是一个变量，用于存放字符串的首地址。而字符串本身是存放在以该首地址为首的一块连续的内存空间中并以&#8216;\0&#8217;作为串的结束。字符数组是由于若干个数组元素组成的，它可用来存放整个字符串。</span></p>
<p><span style="font-size: 16px">2. 对字符数组作初始化赋值，必须采用外部类型或静态类型，如： static char st[]={&#8220;C Language&#8221;};而对字符串指针变量则无此限制，如： char *ps="C Language";</span></p>
<p><span style="font-size: 16px">3. 对字符串指针方式 char *ps="C Language";可以写为： char *ps;</span><br /><span style="font-size: 16px">ps="C Language"; 而对数组方式： static char st[]={"C Language"};不能写为： char st[20]; st={"C Language"};而只能对字符数组的各元素逐个赋值。</span></p>
<p><span style="font-size: 16px">从以上几点可以看出字符串指针变量与字符数组在使用时的区别，同时也可看出使用指针变量更加方便。</span></p>
<p><span style="font-size: 16px">前面说过，当一个指针变量在未取得确定地址前使用是危险的，容易引起错误。但是对指针变量直接赋值是可以的。因为C系统对指针变量赋值时要给以确定的地址。因此， char *ps="C Langage";或者 char *ps; ps="C Language";都是合法的。</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="font-size: 16px">这几天搞Unix上的C程序，里面用到了很多字符数组和字符串指针，我记得在学完C语言后相当一段时间里，对指针这个东西还是模模糊糊，后来工作也没怎么用到过C,虽然网上这类的文章也有很多，还是决定自己在这做个小总结，也算加深下自己的印象，写了下面的测试程序：</span><br /><br /><span style="font-size: 16px">#include &lt;stdio.h&gt;</span></p>
<p><span style="font-size: 16px">int main(int argc, char *argv[])</span><br /><span style="font-size: 16px">{</span></p>
<p><span style="font-size: 16px">&nbsp; char day[15] = "abcdefghijklmn";</span><br /><span style="font-size: 16px">char* strTmp = "opqrstuvwxyz";</span></p>
<p><span style="font-size: 16px">&nbsp; printf("&amp;day is %x\n",&amp;day);</span><br /><span style="font-size: 16px">printf("&amp;day[0] is %x\n",&amp;day[0]);</span><br /><span style="font-size: 16px">printf("day is %x\n",day);</span><br /><br /><span style="font-size: 16px">printf("\n&amp;strTmp is %x\n",&amp;strTmp);</span><br /><span style="font-size: 16px">printf("&amp;strTmp[0] is %x\n",&amp;strTmp[0]);</span><br /><span style="font-size: 16px">printf("strTmp is %x\n",strTmp);</span><br /><br /><span style="font-size: 16px">getchar();&nbsp;</span><br /><span style="font-size: 16px">return 0;</span><br /><span style="font-size: 16px">}</span><br /><br /><br /><span style="font-size: 16px">&amp;strTmp：strTmp这个字符指针的地址</span><br /><span style="font-size: 16px">&amp;strTmp[0]：strTmp所指字符常量第一个字符的地址</span><br /><span style="font-size: 16px">strTmp：strTmp这个字符指针的值，即字符常量的首地址</span><br /><br /><span style="font-size: 16px">因此，最后两个的值是一样的。</span><br /><span style="font-size: 16px">指针可以这样理解，指针这种类型，和int,char,double等等是一样的，只是它用来保存地址值的，而int变量保存整数，char变量保存字符，仅此而已，就char型指针或者int指针，本质是一样的，都是存放的地址，只不过那个地址所里面的变量类型不同而已，还有一种void型指针，就是可以放任何类型变量的地址。</span></p>
<p style="text-indent: 2em">&nbsp;</p><img src ="http://www.cppblog.com/ZhangShiyu/aggbug/161357.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ZhangShiyu/" target="_blank">ZhangShiyu</a> 2011-12-03 15:31 <a href="http://www.cppblog.com/ZhangShiyu/articles/161357.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>文件操作eof()的问题---转载 </title><link>http://www.cppblog.com/ZhangShiyu/articles/160566.html</link><dc:creator>ZhangShiyu</dc:creator><author>ZhangShiyu</author><pubDate>Sun, 20 Nov 2011 07:37:00 GMT</pubDate><guid>http://www.cppblog.com/ZhangShiyu/articles/160566.html</guid><wfw:comment>http://www.cppblog.com/ZhangShiyu/comments/160566.html</wfw:comment><comments>http://www.cppblog.com/ZhangShiyu/articles/160566.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ZhangShiyu/comments/commentRss/160566.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ZhangShiyu/services/trackbacks/160566.html</trackback:ping><description><![CDATA[<h5 class="posthead">&nbsp;</h5>
<div class="postText">大家在使用C++写操作文件的程序时,一定使用过eof()这个函数,用它来判别文件结束,但有不少也用来判别文件是否为空的.但是,这样操作的结果不是我们所想的.看下面程序:<br /><br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><span style="color: #000000">#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #0000ff">string</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">using</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">namespace</span><span style="color: #000000">&nbsp;std;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;main()<br /><img id="Codehighlighter1_52_280_Open_Image" onclick="this.style.display='none'; Codehighlighter1_52_280_Open_Text.style.display='none'; Codehighlighter1_52_280_Closed_Image.style.display='inline'; Codehighlighter1_52_280_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_52_280_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_52_280_Closed_Text.style.display='none'; Codehighlighter1_52_280_Open_Image.style.display='inline'; Codehighlighter1_52_280_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_52_280_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_52_280_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;c&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">'</span><span style="color: #000000">c</span><span style="color: #000000">'</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;ifstream&nbsp;FILE(</span><span style="color: #000000">"</span><span style="color: #000000">test.txt</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(FILE.eof())<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">文件是空的.</span><span style="color: #000000">"</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">endl;exit(</span><span style="color: #000000">1</span><span style="color: #000000">);&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">while</span><span style="color: #000000">&nbsp;(</span><span style="color: #000000">!</span><span style="color: #000000">FILE.eof())<br /><img id="Codehighlighter1_193_239_Open_Image" onclick="this.style.display='none'; Codehighlighter1_193_239_Open_Text.style.display='none'; Codehighlighter1_193_239_Closed_Image.style.display='inline'; Codehighlighter1_193_239_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_193_239_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_193_239_Closed_Text.style.display='none'; Codehighlighter1_193_239_Open_Image.style.display='inline'; Codehighlighter1_193_239_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_193_239_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_193_239_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FILE.</span><span style="color: #0000ff">get</span><span style="color: #000000">(c);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;c;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;system(</span><span style="color: #000000">"</span><span style="color: #000000">pause</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></span></div>
<p>当test.txt为空文件时,它输出的是:c<br />奇怪!应该输出是:文件是空的. while里面的操作也应该不用到的.但是结果偏偏和我们所想的相反.<br />好,那操作二进制文件又是怎样的呢?修改下为:<br />&nbsp;&nbsp;&nbsp;</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><span style="color: #000000">&nbsp;ifstream&nbsp;FILE(</span><span style="color: #000000">"</span><span style="color: #000000">test.txt</span><span style="color: #000000">"</span><span style="color: #000000">,ios::</span><span style="color: #0000ff">in</span><span style="color: #000000">|</span><span style="color: #000000">ios::binary);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(FILE.eof())<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">文件是空的.</span><span style="color: #000000">"</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">while</span><span style="color: #000000">&nbsp;(</span><span style="color: #000000">!</span><span style="color: #000000">FILE.eof())<br /><img id="Codehighlighter1_121_171_Open_Image" onclick="this.style.display='none'; Codehighlighter1_121_171_Open_Text.style.display='none'; Codehighlighter1_121_171_Closed_Image.style.display='inline'; Codehighlighter1_121_171_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_121_171_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_121_171_Closed_Text.style.display='none'; Codehighlighter1_121_171_Open_Image.style.display='inline'; Codehighlighter1_121_171_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_121_171_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_121_171_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FILE.read(</span><span style="color: #000000">&amp;</span><span style="color: #000000">c,</span><span style="color: #000000">1</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;c;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #008000">//</span><span style="color: #008000">代码其他部分相同<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></span></div>
<p>结果输出还是c..噢!!怎么会这样的.分明是骗人的东西嘛!!到底是什么原因呢?<br />&nbsp;&nbsp;&nbsp;&nbsp; 经过一段研究后,原来eof()返回true的条件是"读到文件结束符"，而不是文件内容的最后一个字符。<br />要清楚"文件结束符"(0xff).就是说我们文件最后的字符不是文件结束符,而最后的字符的下一位才是.所以操作再读多一次.就为什么上面if (FILE.eof())总是false的. 在一些编译器中(dev c++),它读到最后一个字符后文件位置的指针会定在那儿,所以就会重复最后一个字符.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; 在一个外国的CPP论坛见到一位同志的代码刚好有这解决方法.现在把上面的代码改为下面的:</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><span style="color: #000000">#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">iostream.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">stdlib.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">fstream.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;main()<br /><img id="Codehighlighter1_75_355_Open_Image" onclick="this.style.display='none'; Codehighlighter1_75_355_Open_Text.style.display='none'; Codehighlighter1_75_355_Closed_Image.style.display='inline'; Codehighlighter1_75_355_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_75_355_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_75_355_Closed_Text.style.display='none'; Codehighlighter1_75_355_Open_Image.style.display='inline'; Codehighlighter1_75_355_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_75_355_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_75_355_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;c&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">'</span><span style="color: #000000">c</span><span style="color: #000000">'</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;ifstream&nbsp;FILE(</span><span style="color: #000000">"</span><span style="color: #000000">test.txt</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(FILE.peek()&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;EOF)</span><span style="color: #008000">//</span><span style="color: #008000">修改&nbsp;</span><span style="color: #008000"><br /><img id="Codehighlighter1_163_220_Open_Image" onclick="this.style.display='none'; Codehighlighter1_163_220_Open_Text.style.display='none'; Codehighlighter1_163_220_Closed_Image.style.display='inline'; Codehighlighter1_163_220_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_163_220_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_163_220_Closed_Text.style.display='none'; Codehighlighter1_163_220_Open_Image.style.display='inline'; Codehighlighter1_163_220_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif"></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_163_220_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_163_220_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">文件是空的.</span><span style="color: #000000">"</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;endl;&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(</span><span style="color: #000000">1</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">while</span><span style="color: #000000">&nbsp;(FILE.peek()&nbsp;</span><span style="color: #000000">!=</span><span style="color: #000000">&nbsp;EOF)</span><span style="color: #008000">//</span><span style="color: #008000">修改</span><span style="color: #008000"><br /><img id="Codehighlighter1_268_314_Open_Image" onclick="this.style.display='none'; Codehighlighter1_268_314_Open_Text.style.display='none'; Codehighlighter1_268_314_Closed_Image.style.display='inline'; Codehighlighter1_268_314_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_268_314_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_268_314_Closed_Text.style.display='none'; Codehighlighter1_268_314_Open_Image.style.display='inline'; Codehighlighter1_268_314_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif"></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_268_314_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_268_314_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FILE.</span><span style="color: #0000ff">get</span><span style="color: #000000">(c);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;c;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;system(</span><span style="color: #000000">"</span><span style="color: #000000">pause</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></span></div>
<p>主要的是把eof()改为peek() == EOF来判别,其中peek()是取文件当前指针,EOF是文件尾标符,它的值为-1.所以采用这种方法就解决上面eof()的问题了..这种方法也可以用在读写二进制文件中.</p></div><img src ="http://www.cppblog.com/ZhangShiyu/aggbug/160566.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ZhangShiyu/" target="_blank">ZhangShiyu</a> 2011-11-20 15:37 <a href="http://www.cppblog.com/ZhangShiyu/articles/160566.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>