久久国产色AV免费看,久久美女网站免费,99久久无色码中文字幕人妻http://www.shnenglu.com/deercoder/category/11912.html身是菩提樹, 心如明鏡臺(tái); 時(shí)時(shí)勤拂拭, 莫使惹塵埃zh-cnSat, 27 Mar 2010 14:30:49 GMTSat, 27 Mar 2010 14:30:49 GMT60cin讀取失敗后進(jìn)入死循環(huán)?-------剖析輸入流的條件http://www.shnenglu.com/deercoder/articles/110696.html劉暢劉暢Sat, 27 Mar 2010 13:59:00 GMThttp://www.shnenglu.com/deercoder/articles/110696.htmlhttp://www.shnenglu.com/deercoder/comments/110696.htmlhttp://www.shnenglu.com/deercoder/articles/110696.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/110696.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/110696.html

考慮如下代碼:

 

#include <iostream>
using namespace std;

int main()
{
  
int a;
  
while(cout<<"input a integer (1- 10) :",cin>>a,! (a>=1 && a<=10))
   cout
<<"try again!"<<endl;
return 0;
}




本意是讓用戶選擇一個(gè)1-10的數(shù),如果不是1-10的數(shù)則重新輸入。

分析:

如果用戶輸入了一個(gè)不在1-10的 int,那么,程序會(huì)正確的執(zhí)行,并且提示用戶重新輸入。

但是如果用戶錯(cuò)誤的輸入了一個(gè)字符char,那么,后果就是一直執(zhí)行while循環(huán)!

錯(cuò)誤分析:

當(dāng)cin嘗試將輸入的字符讀為int型數(shù)據(jù)失敗后,會(huì)產(chǎn)生一個(gè)錯(cuò)誤狀態(tài)--cin.fail().而要用cin讀取輸入流中的數(shù)據(jù),輸入流必須處于無(wú)錯(cuò)誤狀態(tài)。因此,由于錯(cuò)誤狀態(tài)的存在,會(huì)一直執(zhí)行while循環(huán)。

錯(cuò)誤修正:

#include <iostream>
using namespace std;

int main()
{
int a;
while(cout<<"input a integer (1-10) :",cin>>a,! (a>=1 && a<=10) || cin.fail())
{
   cout<<"try again!"<<endl;
   cin.clear(); //清除std::cin的錯(cuò)誤狀態(tài)
   cin.sync(); //清空輸入緩沖區(qū)
}
return 0;
}

加上判斷輸入是否成功的cin.fail()以及修正錯(cuò)誤輸入的cin.clear()和cin.sync();

其中std::cin.sync();這一句必不可少,因?yàn)樗袕臉?biāo)準(zhǔn)輸入設(shè)備輸入的數(shù)據(jù)都是先保存在緩沖區(qū)中,然后istream對(duì)象再?gòu)木彌_區(qū)中進(jìn)行提取。如果不清空緩存,下次在讀取數(shù)據(jù)的時(shí)候又會(huì)再次產(chǎn)生錯(cuò)誤,也會(huì)陷入死循環(huán)。







劉暢 2010-03-27 21:59 發(fā)表評(píng)論
]]>
C++中的tips http://www.shnenglu.com/deercoder/articles/105216.html劉暢劉暢Fri, 08 Jan 2010 16:20:00 GMThttp://www.shnenglu.com/deercoder/articles/105216.htmlhttp://www.shnenglu.com/deercoder/comments/105216.htmlhttp://www.shnenglu.com/deercoder/articles/105216.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/105216.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/105216.html 

    題記:一直以來(lái)都被一些細(xì)節(jié)忽略了,然后,遇到很多的問題就杯具了……從現(xiàn)在開始,覺得很有必要從小事做起,認(rèn)真的來(lái)看看曾經(jīng)犯過(guò)的錯(cuò)誤,做過(guò)的事情。特別是對(duì)于曾經(jīng)以為很習(xí)以為常的事情,要特別的重視,于是便有了tips,下面不斷的更新中…………

題外話:(如何在Office 2007中創(chuàng)建并發(fā)布博文?)今天發(fā)現(xiàn)可以在Word 2007中編輯博客,然后直接點(diǎn)擊發(fā)布,就可以發(fā)布到C++博客網(wǎng)上了,很貼心的服務(wù),不是嗎?其實(shí)這個(gè)也是Office的一個(gè)功能,在新建中,點(diǎn)擊新建博客文章,就可以創(chuàng)建一個(gè)新的blog,然后會(huì)提示你創(chuàng)建一個(gè)賬戶,估計(jì)這個(gè)是最關(guān)鍵的,需要選擇其他運(yùn)營(yíng)商,然后下一步,會(huì)有個(gè)API讓你選擇,選擇下面的按個(gè)MetaWebLog,然后輸出你的賬號(hào)密碼,這里的昂URL,不是你的主頁(yè)的,開始的時(shí)候我也是選擇這個(gè),錯(cuò)誤,連接不上。需要的是:在你的主頁(yè)上,點(diǎn)擊管理,然后點(diǎn)擊選項(xiàng),下面有個(gè)configure選項(xiàng),進(jìn)入后,最下面就有一個(gè)你的那個(gè)URL了,添加進(jìn)去,OK!然后就可以發(fā)布了!

 

下面開始正式的tips:

  1. int到底占用多少個(gè)字節(jié)?

    一直以來(lái)都被這個(gè)問題糾結(jié),因?yàn)樯线^(guò)匯編和C的課,然后又看了《C++ Primer》一書,總是會(huì)出現(xiàn)各種的不一致,如果按照平時(shí)我們的認(rèn)為,都是4個(gè)Byte(字節(jié)),可是無(wú)奈很多書上講解不一致,所以造成了迷惑……今天找時(shí)間上網(wǎng)搜了下,發(fā)現(xiàn)答案很多,不過(guò)大致上都是一個(gè)解答,于是我也就憑借自己的思考,來(lái)說(shuō)說(shuō)了。

    答:首先摘錄網(wǎng)上的朋友們的留言:

int的字節(jié)長(zhǎng)度是由CPU和操作系統(tǒng)編譯器共同決定的,一般情況下,主要是由操作系統(tǒng)決定,比如,你在64位AMD的機(jī)器上安裝的是32位操作系統(tǒng),那么,int默認(rèn)是32位的;如果是64位操作系統(tǒng),64位操作系統(tǒng)分為兩種,1種是int為32位long為64位,2種int long均為64位。之所以說(shuō)int同時(shí)也與編譯器有關(guān),編譯器完全可以在32位系統(tǒng)模擬64位整數(shù),例如Unix/Linux下的long long和Windows下的__int64均為64位整數(shù)。

 

機(jī)器第一作用,編譯器第二作用.
現(xiàn)在新出的機(jī)器開始有64位的,編譯器也逐漸的要適應(yīng)這個(gè)改變,由32位向64位過(guò)渡.
如果機(jī)器是16位的,編譯器強(qiáng)制為32位的話,效率及其低下,沒那家廠商會(huì)做如此SB的事情,
我們現(xiàn)在的機(jī)器一般都是32位的,編譯器所以一般也是32位,但也支持64位的,
__int64  就是64字節(jié)的,
總之int 只是一個(gè)類型,沒有太大的意義,機(jī)器的位數(shù)才是關(guān)鍵所在!
離開機(jī)器,說(shuō)有編譯器決定的人,實(shí)在不敢恭維.
難道要在8位機(jī)上實(shí)現(xiàn)64bit的編譯器?
機(jī)器進(jìn)步了,編譯器跟不上,就要被淘汰,
編譯器超前了,效率低下,也不會(huì)有市場(chǎng),
所以不要單純的討論編譯器或者機(jī)器了。
OVER!

 


int僅是語(yǔ)言標(biāo)準(zhǔn)中的一項(xiàng)定義,定義了這類數(shù)據(jù)的性質(zhì)、范圍、操作等;
具體少長(zhǎng),標(biāo)準(zhǔn)并未硬性規(guī)定,而由編譯器自行決定,甚至編譯器也可由用戶根據(jù)需要自行設(shè)定。
基于此,可認(rèn)為還是受編譯器決定,所謂縣官不如現(xiàn)管。

 

綜合上面的說(shuō)法,我也覺得對(duì)于int到底占用多少個(gè)字節(jié),其實(shí)是和機(jī)器以及編譯器都有關(guān)系。這么來(lái)說(shuō)吧,我覺得機(jī)器起決定性作用,如果是32位機(jī),那么在這個(gè)平臺(tái)上面運(yùn)行的編譯器,可以使32位版本的,也可以是16位版本的(向下兼容,只不過(guò)浪費(fèi)了好機(jī)子,沒有充分發(fā)揮效果),這也就是說(shuō)我們?cè)诰W(wǎng)上下載驅(qū)動(dòng)的時(shí)候,有時(shí)候會(huì)發(fā)現(xiàn)官網(wǎng)上面有32位操作系統(tǒng)Windows版本和64位操作系統(tǒng)Windows的不同分類了。而決定這個(gè)位數(shù)的,就是你的CPU,也就是機(jī)器。

但是,編譯器沒有必要一定要這么做,對(duì)于TC 2.0這樣的16位軟件,曾經(jīng)在Dos下呼風(fēng)喚雨,但是到了32位機(jī)下,仍然是可以用的,這樣的話,也就是說(shuō),它運(yùn)算的結(jié)果是2個(gè)字節(jié),可是因?yàn)檐浖南拗疲荒軌蚰M出來(lái)16位機(jī),所以雖然可以在32位上面跑,但是不能反映實(shí)際的字長(zhǎng)。但是,沒有多少人會(huì)在32位機(jī)子上面模擬出128位或者64位,因?yàn)檫@樣尋址的話效率很低下,硬件條件沒有達(dá)到,利用軟件來(lái)模擬是不夠的。于是,就是上面的那種說(shuō)法。由于VC以及其他軟件更新很快,而且及時(shí)開發(fā)了Win 32下的版本,所以是32位軟件,也就是說(shuō),它計(jì)算處理的int是4個(gè)字節(jié)。

當(dāng)然,我們需要知道的是,標(biāo)準(zhǔn)并沒有規(guī)定int一定要是多少個(gè)字節(jié),而只是規(guī)定了一個(gè)范圍,只要你不越軌,那么肯定就沒有問題,至于實(shí)現(xiàn),那是你編譯器的開發(fā)的事情,跟我無(wú)關(guān)。同樣,CPU和機(jī)器的制造者,關(guān)心的是如何提高計(jì)算機(jī)的性能,讓尋址方式更大,范圍更長(zhǎng),也就是位數(shù)越多,(這也是為何目前的那些機(jī)器都朝著64位或者更高位發(fā)展的目的),而軟件開發(fā)者,面臨的則是需要來(lái)適應(yīng)硬件的更新,從而做出更好的軟件,充分利用到這個(gè)性能。

當(dāng)然,這個(gè)問題本身沒有多少討論的價(jià)值,不過(guò),如果在面試或者考試中,遇到sizeof的操作,最好問清楚是在32位機(jī)子下還是16位或者是64位,這個(gè)能夠反映你的嚴(yán)謹(jǐn)和認(rèn)真。

注: 32位下:1int = 4 Byte            16位下:1 int = 2B        (當(dāng)然,一般都不會(huì)考慮那個(gè)TC 2.0的)

 

 

 

 

 

2).普通類的繼承中,如果派生類中的函數(shù)和基類函數(shù)同名時(shí),是否會(huì)覆蓋原來(lái)的那個(gè)函數(shù)?

    在java中,很明顯是會(huì)覆蓋的,因?yàn)槔^承的特性,注意同名函數(shù),要求還有原型相同,否則的話,調(diào)用的時(shí)候是可以區(qū)分開來(lái)的,而當(dāng)原型相同的時(shí)候,那么派生類會(huì)繼承基類的函數(shù),同時(shí)由于有一個(gè)自己的函數(shù),所以兩個(gè)同名,同原型的函數(shù),是會(huì)發(fā)生覆蓋的。

上代碼看之:

#include <iostream>

using namespace std;

class A

{

    public:

        void moveto(){cout << "1" << endl;}

};

class B:public A

{

    public:

        void moveto(){cout << "2" << endl;}

};

int main()

{

    A a;

    B b;

    A *pstra = &b;

    B *pstrb = (B *)&a;

    pstra->moveto();

    pstrb->moveto();

    a.moveto();

    b.A::moveto();

    return 0;

}

輸出的結(jié)果是:

        

從上面的結(jié)果可以看到,派生類的指針是調(diào)用派生類的對(duì)應(yīng)的函數(shù),配套的,而且還選擇作用域較小的,而這樣的優(yōu)先級(jí)就要高些。這里有一個(gè)強(qiáng)制類型轉(zhuǎn)換,因?yàn)槭且獙⑴缮惖闹羔樦赶蚧惖膶?duì)象,會(huì)發(fā)生截?cái)啵?span style="COLOR: red">一定要強(qiáng)制類型轉(zhuǎn)換,與此對(duì)比的是,基類的指針指向派生類的話不需要強(qiáng)制類型轉(zhuǎn)換也可以實(shí)現(xiàn)。從結(jié)果可以看到,如果實(shí)行了轉(zhuǎn)換,那么還是聲明時(shí)候的類型,所以抓住了這點(diǎn),聲明時(shí)是B類型的,那么就調(diào)用B的moveto,所以輸出時(shí)2,下面的另外一些的輸出,就都是1了,也可以看到,如果要顯示的調(diào)用被隱藏的基類,需要用作用域限定符來(lái)指示。

 

 2.隱藏的this指針不是實(shí)際的一個(gè)參數(shù),也就是說(shuō),實(shí)際調(diào)用函數(shù)中,不能夠使用這個(gè)參數(shù)。
上代碼:

#include <string.h>
#include 
<iostream>
using namespace  std;

class STRING{
    
char *str;
public:
    STRING(
char *s=0);
    STRING(
const STRING &);
    
virtual int strlen(voidconst;
    
virtual int strcmp(const STRING &const;
    
virtual STRING &operator+(const STRING &);
    
virtual STRING &operator=(const STRING &);
    
virtual STRING &operator+=(const STRING &);
    
virtual operator const char *(voidconst;
    
virtual ~STRING();
}
;

STRING::STRING(
char *s/*=0*/){
    str 
= new char[::strlen(s)+1];
    ::strcpy(str,s);
}

STRING::
~STRING(){
    delete str;
}

int STRING::strlen(voidconst{
    
return ::strlen(this->str)+5//采用字符串的通用表示,不含null
}

int STRING::strcmp(const STRING &b) const{
    
return ::strcmp(this->str,b.str);
}

STRING 
&STRING::operator+(const STRING &b){
    ::strcat(
this->str,b.str);
    
return *this;
}

STRING 
&STRING::operator=(const STRING &b){
    
this->str = b.str;
    
return *this;
}

STRING 
&STRING::operator+=(const STRING &b){
    ::strcat(
this->str,b.str);
    
return *this;
}

STRING::
operator const char *(voidconst{
    
return this->str;
}

int main()
{
    STRING s(
"Hello,world");
    STRING e(
"I Love C++");
    cout 
<< "STRING:" << s << "\t strlen:" << s.strlen()<< endl;
    cout 
<< "STRING:" << e << "\t strlen:" << strlen(e)<< endl;
    
    
return 0;

}

 

  僅僅看輸出,前面的一個(gè)是調(diào)用類函數(shù)strlen,沒有參數(shù),看到?jīng)]有,如果有參數(shù)的話,就是下面的那個(gè),那么此時(shí)就是調(diào)用的系統(tǒng)函數(shù)了。兩者的輸出不一樣,我特意在自定義的strlen函數(shù)上面加5以表示區(qū)別,最后果然,前者就是調(diào)用自己的函數(shù)。
得到的結(jié)論就是,類的成員函數(shù),都是有一個(gè)默認(rèn)的this指針的,這個(gè)沒有錯(cuò),不過(guò)這個(gè)是編譯器加的,我們手動(dòng)是不能自己占有的,也就是說(shuō)不能理解為有一個(gè)參數(shù),然后放上面去,自己定義的是void參數(shù),就沒有參數(shù),編譯器加的是它的事情,那個(gè)地方提供給我們用戶使用的就是無(wú)參的函數(shù)。此點(diǎn)要銘記,而且,即使你調(diào)用無(wú)參的,在具體編譯器處理的時(shí)候,還是會(huì)給你加上,所以這部分你根本用不上,也不需要擔(dān)心。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



劉暢 2010-01-09 00:20 發(fā)表評(píng)論
]]>
C++中形參和數(shù)據(jù)成員同名的情況http://www.shnenglu.com/deercoder/articles/105124.html劉暢劉暢Thu, 07 Jan 2010 15:46:00 GMThttp://www.shnenglu.com/deercoder/articles/105124.htmlhttp://www.shnenglu.com/deercoder/comments/105124.htmlhttp://www.shnenglu.com/deercoder/articles/105124.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/105124.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/105124.html 

 

在C++中,如果出現(xiàn)函數(shù)的形參和類的數(shù)據(jù)成員同名的情況,一定不要為了圖簡(jiǎn)省而使用下面的寫法。例:

#include <iostream>

using namespace std;

 

class A

{

    int x;

    int y;

    public :

        A(int x,int y);

        void print();

};

 

A::A(int x,int y)

{

    x = x;

    y = y;

}

void A::print()

{

    cout << "x:" << x << " y: " << y << endl;

}

int main()

{

    A *a = new A(34,56);

    a->print();

    delete a;

    return 0;

在紅色部分突出顯示的就是錯(cuò)誤的寫法,實(shí)際上,形參的值根本沒有傳入到這個(gè)函數(shù)中,而在你輸出的時(shí)候,根本沒有x,y的值,也就是一個(gè)隨機(jī)的。說(shuō)明形參根本沒有傳入。

這個(gè)也是Java中遇到的,如果有這種情況,java中用到的是this引用來(lái)顯示的圈定范圍,而C++中,也需要用this指針來(lái)顯示的解決這個(gè)問題。或者用作用域限定符來(lái)解決。

更改后才會(huì)出現(xiàn)正確的結(jié)果,而以前,自己一直都沒有注意到。

為何會(huì)這樣呢?因?yàn)榘凑辗秶鷱男〉酱蟮捻樞颍螀⒌姆秶。蕴鎿Q的就是恒等式,那么自然不會(huì)顯示的來(lái)給成員賦值,因?yàn)轭惖某蓡T作用范圍更小,此處,要謹(jǐn)記。

而且對(duì)于Java也是一樣,都要顯示的來(lái)指出。

 



劉暢 2010-01-07 23:46 發(fā)表評(píng)論
]]>
特殊成員變量的初始化http://www.shnenglu.com/deercoder/articles/104790.html劉暢劉暢Mon, 04 Jan 2010 14:58:00 GMThttp://www.shnenglu.com/deercoder/articles/104790.htmlhttp://www.shnenglu.com/deercoder/comments/104790.htmlhttp://www.shnenglu.com/deercoder/articles/104790.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/104790.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/104790.html有些成員變量的數(shù)據(jù)類型比較特別,它們的初始化方式也和普通數(shù)據(jù)類型的成員變量有所不同。這些特殊的類型的成員變量包括:


a.       常量型成員變量

b.       引用型成員變量

c.        靜態(tài)成員變量

d.       整型靜態(tài)常量成員變量

e.       非整型靜態(tài)常量成員變量

 


對(duì)于常量型成員變量和引用型成員變量的初始化,必須通過(guò)構(gòu)造函數(shù)初始化列表的方式進(jìn)行。在構(gòu)造函數(shù)體內(nèi)給常量型成員變量和引用型成員變量賦值的方式是行不通的。

 

靜態(tài)成員變量的初始化也頗有些特別。

 

參考下面的代碼以及其中注釋:

// Initialization of Special Data Member

#include <iostream>

using namespace std;

 

class BClass

{

public:

         BClass() : i(1), ci(2), ri(i)   // 對(duì)于常量型成員變量和引用型成員變量,必須通過(guò)

         {                                             // 參數(shù)化列表的方式進(jìn)行初始化。在構(gòu)造函數(shù)體內(nèi)進(jìn)

         }                                             // 行賦值的方式,是行不通的。

 

         void print_values()

         {

                   cout << "i =\t" << i << endl;

                   cout << "ci =\t" << ci << endl;

                   cout << "ri =\t" << ri << endl;

                   cout << "si =\t" << si << endl;

                   cout << "csi =\t" << csi << endl;

                   cout << "csi2 =\t" << csi2 << endl;

                   cout << "csd =\t" << csd << endl;

         }

private:

         int i;                                                          // 普通成員變量

         const int ci;                                             // 常量成員變量

         int &ri;                                                      // 引用成員變量

         static int si;                                             // 靜態(tài)成員變量

         //static int si2 = 100;                             // error: 只有靜態(tài)常量成員變量,才可以這樣初始化

         static const int csi;                                // 靜態(tài)常量成員變量

         static const int csi2 = 100;                  // 靜態(tài)常量成員變量的初始化(Integral type)    (1)

         static const double csd;                      // 靜態(tài)常量成員變量(non-Integral type)

         //static const double csd2 = 99.9;      // error: 只有靜態(tài)常量整型數(shù)據(jù)成員才可以在類中初始化

};

 

// 靜態(tài)成員變量的初始化(Integral type)

int BClass::si = 0;

// 靜態(tài)常量成員變量的初始化(Integral type)

const int BClass::csi = 1;

// 靜態(tài)常量成員變量的初始化(non-Integral type)

const double BClass::csd = 99.9;

 

// 在初始化(1)中的csi2時(shí),根據(jù)Stanley B. Lippman的說(shuō)法下面這行是必須的。

// 但在VC2003中如果有下面一行將會(huì)產(chǎn)生錯(cuò)誤,而在VC2005中,下面這行則可有可無(wú),

// 這個(gè)和編譯器有關(guān)。

const int BClass::csi2;

 

int main(void)

{

         BClass b_class;

         b_class.print_values();

 

         return 0;

}

 

本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/pathuang68/archive/2009/11/25/4867323.aspx



劉暢 2010-01-04 22:58 發(fā)表評(píng)論
]]>
C/C++中的字符串字面值http://www.shnenglu.com/deercoder/articles/104213.html劉暢劉暢Sun, 27 Dec 2009 10:48:00 GMThttp://www.shnenglu.com/deercoder/articles/104213.htmlhttp://www.shnenglu.com/deercoder/comments/104213.htmlhttp://www.shnenglu.com/deercoder/articles/104213.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/104213.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/104213.html

C/C++中的字符串字面值

 

1.     字符串?dāng)?shù)組的大小如何得到。我們都知道,對(duì)于一個(gè)字符串?dāng)?shù)組,要得到它的大小,有多種辦法,常見的有下面的兩種。

.利用sizeof運(yùn)算符來(lái)實(shí)現(xiàn)。現(xiàn)在假設(shè)有一個(gè)字符數(shù)組str[] = “hello,world”,為了得到的它的長(zhǎng)度,我們利用這種辦法

具體就是sizeof(str) /sizeof(char);結(jié)果是12,比較發(fā)現(xiàn),實(shí)際的字符串大小事11啊,為什么會(huì)得到12的結(jié)果呢?

有這種疑問,是因?yàn)閷?duì)我們字符數(shù)組沒有一個(gè)更好的理解。上面初始化一個(gè)字符數(shù)組,是利用字符串來(lái)初始化的,

而字符串的話,默認(rèn)的是會(huì)有一個(gè)以null結(jié)尾的標(biāo)志,這個(gè)具體的就是’\0’,有很多人的程序有問題,可能都是因?yàn)檫@里

出現(xiàn)了問題,比如數(shù)組沒有封口,造成了指針非法訪問其他內(nèi)存單元,等等。所以實(shí)際上的長(zhǎng)度就是12.

具體來(lái)說(shuō)說(shuō)這個(gè)原理吧:sizeof是表示計(jì)算大小,即字節(jié)數(shù)。這里以一個(gè)數(shù)組名來(lái)作為參數(shù),就是計(jì)算這個(gè)數(shù)組的大小。

上面說(shuō)到,字符串?dāng)?shù)組的話是有一個(gè)默認(rèn)的null來(lái)封口的,所以,計(jì)算的大小事包括這個(gè)單元的。于是sizeof(str)的大小

就是12 個(gè)字節(jié),然后計(jì)算一個(gè)單元,即一個(gè)字符char類型的占據(jù)的字節(jié)數(shù),也就是1個(gè)字節(jié),兩者相除,就是12的結(jié)果。

.利用循環(huán)來(lái)實(shí)現(xiàn),這個(gè)部分是很多人都常常想到的。因?yàn)橐粋€(gè)字符串來(lái)定義的數(shù)組,默認(rèn)是以null即為的,所以,通過(guò)               循環(huán)遍歷的方式來(lái)實(shí)現(xiàn),這個(gè)方法還是可行的。定義一個(gè)變量i,然后利用for循環(huán),判斷str[i]不為’\0’,即可判斷              得到最后一個(gè)元素的下標(biāo),注意到的是這里是最后一個(gè)字符元素,但是不是最后一個(gè)真正的元素,有一個(gè)null,因此,還                要加上1才是真正的個(gè)數(shù),經(jīng)過(guò)這個(gè)過(guò)程,得到的就是總的長(zhǎng)度。這個(gè)方法比較容易理解。但是容易忽略了最后一個(gè)的作用。                                                                                                實(shí)際上,我們使用的很多C提供的函數(shù),關(guān)于字符串操作的,都需要用到這個(gè)知識(shí),我們?cè)谧鲇?jì)算的時(shí)候,很容易誤以為返                    回的。就是那個(gè)字符串的長(zhǎng)度,從而導(dǎo)致了錯(cuò)誤。實(shí)際在我們拷貝字符串的時(shí)候,尤其要注意這一點(diǎn)。

 

2.  在《C++ Primer》一書中,將以null結(jié)束的字符數(shù)組稱為字符數(shù)組,標(biāo)準(zhǔn)庫(kù)提供一批處理這類字符數(shù)組的函數(shù),包括strlen,strcmp,strcat,strcpy,strncat,strncpy等等,而這些函數(shù)中的參數(shù),都是以null結(jié)束的字符數(shù)組名,也就是字符數(shù)組的指針,而得到長(zhǎng)度,返回的就是一個(gè)長(zhǎng)度,沒有包括null這個(gè)單元,所以實(shí)際上,上面的那個(gè)還有一個(gè)方法,可以調(diào)用此函數(shù)來(lái)實(shí)現(xiàn)。當(dāng)然,還有一點(diǎn)要注意的是,strcat連接函數(shù),將右邊的字符串連接到左邊,所以對(duì)于左邊的字符串,一定要準(zhǔn)確的計(jì)算出長(zhǎng)度,如果不慎,就會(huì)溢出,出現(xiàn)嚴(yán)重的錯(cuò)誤。看看下面這個(gè)例子:

Char s1[25] = “hello,world”;  char s2[20] = “0123456789012345678”(剛好是20個(gè)字符,為何,因?yàn)橛幸粋€(gè)null).所以現(xiàn)在的那個(gè)s2[20] = “01234567890123456789”,此時(shí)你會(huì)發(fā)現(xiàn),字符串就有20個(gè),含有一個(gè)null,注意就溢出了,OK

下面,如果我將上面的那個(gè)采用字符串連接函數(shù)來(lái)做,就是strcat(s1,s2),那么又會(huì)出現(xiàn)錯(cuò)誤。因?yàn)橐绯隽恕?span lang=EN-US>

3.C++中提供了一個(gè)標(biāo)準(zhǔn)庫(kù)string來(lái)處理字符串,這個(gè)string類提供了很多操作,是一種更安全的做法,然而了,為了新舊代碼的兼容,需要進(jìn)行兩者之間的轉(zhuǎn)換,而把string的一個(gè)類函數(shù)c_str()返回值是C風(fēng)格字符串。const char *str = st2.c_str();其中st2是一個(gè)string類型的對(duì)象,返回值就是一個(gè)指向它的字符串。 此即為字符串的處理,作為C/C++的字符串值得注意的地方。                                                 



劉暢 2009-12-27 18:48 發(fā)表評(píng)論
]]>
C++中的引用http://www.shnenglu.com/deercoder/articles/104211.html劉暢劉暢Sun, 27 Dec 2009 10:47:00 GMThttp://www.shnenglu.com/deercoder/articles/104211.htmlhttp://www.shnenglu.com/deercoder/comments/104211.htmlhttp://www.shnenglu.com/deercoder/articles/104211.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/104211.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/104211.html閱讀全文

劉暢 2009-12-27 18:47 發(fā)表評(píng)論
]]>
[原創(chuàng)]操作系統(tǒng)的進(jìn)程http://www.shnenglu.com/deercoder/articles/102918.html劉暢劉暢Thu, 10 Dec 2009 06:41:00 GMThttp://www.shnenglu.com/deercoder/articles/102918.htmlhttp://www.shnenglu.com/deercoder/comments/102918.htmlhttp://www.shnenglu.com/deercoder/articles/102918.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/102918.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/102918.htmlLinux學(xué)習(xí)

1.操作系統(tǒng)的實(shí)驗(yàn)基本上都是以linux下面的系統(tǒng)編程為內(nèi)容,進(jìn)程的調(diào)度和創(chuàng)建都是很基本的內(nèi)容。很幸運(yùn)的是,linux為我們提供了很多的系統(tǒng)函數(shù),供我們來(lái)使用。通過(guò)熟悉這些函數(shù),使得我們可以能夠?qū)M(jìn)程和程序有一個(gè)更良好的認(rèn)識(shí)。

2.Fork函數(shù)的使用。下面引用自百度百科:

 fork()函數(shù),Linux系統(tǒng)調(diào)用

  頭文件:

  #include <unistd.h>

  函數(shù)定義:

  int fork( void );

  返回值:

  子進(jìn)程中返回0,父進(jìn)程中返回子進(jìn)程ID,出錯(cuò)返回-1

  函數(shù)說(shuō)明:

  一個(gè)現(xiàn)有進(jìn)程可以調(diào)用fork函數(shù)創(chuàng)建一個(gè)新進(jìn)程。由fork創(chuàng)建的新進(jìn)程被稱為子進(jìn)程(child process)。fork函數(shù)被調(diào)用一次但返回兩次。兩次返回的唯一區(qū)別是子進(jìn)程中返回0值而父進(jìn)程中返回子進(jìn)程ID

  子進(jìn)程是父進(jìn)程的副本,它將獲得父進(jìn)程數(shù)據(jù)空間、堆、棧等資源的副本。注意,子進(jìn)程持有的是上述存儲(chǔ)空間的副本,這意味著父子進(jìn)程間不共享這些存儲(chǔ)空間,它們之間共享的存儲(chǔ)空間只有代碼段。

  示例代碼:

  #include <unistd.h>

  #include <stdio.h>

  int main(int argc, void ** argv )

  {

  int pid = fork();

  if(pid == -1 ) {

  // print("error!");

  } else if( pid = =0 ) {

  // print("This is the child process!");

  } else {

  // print("This is the parent process! child process id = %d", pid);

  }

  return 0;

  }

 

 

 

1.      下面來(lái)詳細(xì)的說(shuō)說(shuō)我的程序和問題,通過(guò)比較學(xué)習(xí),相信對(duì)于linux的學(xué)習(xí),特別是進(jìn)程和程序直接的關(guān)系有一個(gè)更好的理解。

Process2.c

Code

#include <stdio.h>

#include <unistd.h>

int main()

{

 int p1;

 p1=fork();

 if (p1 == 0)      //子進(jìn)程,輸出它的父進(jìn)程和當(dāng)前進(jìn)程的PID

 {

     printf("current PID is %d\n",getpid());

     printf("father PID is %d\n",getppid());

     printf("\n");

 }

 else   //這里是父進(jìn)程嗎?

 {

     printf("father PID is %d\n",getppid());

     printf("current PID is %d\n",getpid());

     printf("\n");

 }

 return 0;

}

分析:此進(jìn)程的運(yùn)行結(jié)果是?(思考后再回答)

是的,有兩種情況。首先,程序運(yùn)行到fork語(yǔ)句之后,創(chuàng)建進(jìn)程,此時(shí)有兩種情況,創(chuàng)建成功和不成功,而成功又有兩種情況,fork的返回值為0,則運(yùn)行的是創(chuàng)建的子進(jìn)程,fork的返回值為1,則運(yùn)行的是父進(jìn)程。用if語(yǔ)句來(lái)判斷,OK

那么問題就是,if語(yǔ)句中沒有問題,p10,說(shuō)明創(chuàng)建成功,運(yùn)行的是子進(jìn)程,可是else語(yǔ)句來(lái)說(shuō),卻又兩種情況,如果創(chuàng)建不成功也在else語(yǔ)句中,那么此時(shí)當(dāng)前進(jìn)程就是那個(gè)原始的進(jìn)程,而它的父進(jìn)程卻是1號(hào)PID,因?yàn)樗械倪M(jìn)程都是1號(hào)進(jìn)程的子進(jìn)程,這個(gè)是linux下面的結(jié)論。操作系統(tǒng)的知識(shí)。

所以,此時(shí)的結(jié)果應(yīng)該是:

father PID is 32667

current PID is 15254

 

current PID is 15255

father PID is 1

先放著,先解釋下面的這個(gè),注意,這個(gè)對(duì)上面是有幫助的。

(看完之后回頭過(guò)來(lái)看看),看到?jīng)]有,首先輸出的那個(gè)father PID是什么,剛好就是下面的那個(gè)32667,這個(gè)不是偶然的,說(shuō)明什么,當(dāng)然,這個(gè)進(jìn)程就是父進(jìn)程,而創(chuàng)建它的那個(gè)進(jìn)程的PID32667,可以認(rèn)為是系統(tǒng)創(chuàng)建的。就是說(shuō)這種情況下面是,先運(yùn)行的父進(jìn)程。而它創(chuàng)建失敗了,那么它沒有子進(jìn)程啊,那么那個(gè)下面的這個(gè)進(jìn)程的父進(jìn)程就不是上面的那個(gè)了,為何,從結(jié)果可以看到,它的PID1,而不會(huì)是15254,說(shuō)明不是上面的那個(gè)創(chuàng)建。而創(chuàng)建卻是1,說(shuō)明是系統(tǒng)創(chuàng)建的,所以fork語(yǔ)句之后,沒有創(chuàng)建成功,而是由系統(tǒng)來(lái)親自創(chuàng)建一個(gè)進(jìn)程,所以PID號(hào)當(dāng)然是下一個(gè),不過(guò)父進(jìn)程就是1號(hào)了。(有興趣的可以查閱下資料,我們也是剛學(xué),所以我還有繼續(xù)探究中!!

 

 

 

current PID is 15302 //子進(jìn)程

father PID is 15301[l1]      

 

father PID is 32667 //父進(jìn)程

current PID is 15301

 

PID = 13501

父進(jìn)程

PID = 13504

子進(jìn)程

系統(tǒng)創(chuàng)建了當(dāng)前的那個(gè)父進(jìn)程,就是程序運(yùn)行的進(jìn)程

PID = 32667

 

 

 

 

 

 

 

 

 

 

 

 

 


下面還想討論這樣一個(gè)問題,這個(gè)問題是從上面那個(gè)第一種情況引申來(lái)的。

如下:

Code

#include <stdio.h>

int main()

{

 int p1;

 while (( p1 = fork())!= -1);

 if (p1 == -1)

 {

    printf("current PID is %d\n",getpid());

    printf("father PID is %d\n",getppid());

 }

 return 0;

}[l2] 

 

 

結(jié)果如下,雖然比較多,不過(guò)很能說(shuō)明問題:

current PID is 17600

father PID is 1

current PID is 17761

father PID is 1

current PID is 17602

father PID is 1

current PID is 18545

father PID is 1

current PID is 17608

father PID is 1

current PID is 17767

father PID is 1

current PID is 17624

father PID is 1

current PID is 17773

father PID is 1

current PID is 17616

father PID is 1

current PID is 18551

father PID is 1

current PID is 17630

father PID is 1

current PID is 18552

father PID is 1

current PID is 17636

father PID is 1

current PID is 17779

father PID is 1

current PID is 17642

father PID is 1

current PID is 17785

father PID is 1

current PID is 17648

father PID is 1

current PID is 17787

father PID is 1

current PID is 17654

father PID is 1

current PID is 17795

father PID is 1

current PID is 18510

father PID is 1

current PID is 17801

father PID is 1

current PID is 18511

father PID is 1

current PID is 17807

father PID is 1

current PID is 17656

father PID is 1

current PID is 17815

father PID is 1

current PID is 17384

father PID is 32667

current PID is 17819

father PID is 1

current PID is 17660

father PID is 1

father PID is 1

current PID is 17825

father PID is 1

current PID is 17668

father PID is 1

current PID is 18571

father PID is 1

father PID is 1

father PID is 1

father PID is 1

father PID is 1

current PID is 17672

father PID is 1

current PID is 18572

father PID is 1

current PID is 17678

father PID is 1

current PID is 17831

father PID is 1

father PID is 1

current PID is 17684

father PID is 1

current PID is 17839

father PID is 1

current PID is 17690

father PID is 1

current PID is 17845

father PID is 1

current PID is 17696

father PID is 1

current PID is 17851

father PID is 1

current PID is 17702

father PID is 1

current PID is 17857

father PID is 1

current PID is 17710

father PID is 1

current PID is 17863

father PID is 1

current PID is 18531

father PID is 1

current PID is 17786

father PID is 1

current PID is 17714

father PID is 1

current PID is 18566

father PID is 17786

current PID is 17720

father PID is 1

current PID is 18533

father PID is 1

current PID is 17728

father PID is 1

current PID is 18538

father PID is 1

current PID is 17730

father PID is 1

current PID is 18548

father PID is 17740

current PID is 17738

father PID is 1

current PID is 17794

father PID is 1

current PID is 17740

father PID is 1

current PID is 17804

father PID is 1

current PID is 17750

father PID is 1

current PID is 17810

father PID is 1

current PID is 17756

father PID is 1

current PID is 17814

father PID is 1

current PID is 17764

current PID is 17820

father PID is 1

father PID is 1

current PID is 17768

father PID is 1

current PID is 17826

father PID is 1

current PID is 17774

father PID is 1

current PID is 17832

father PID is 1

current PID is 17780

father PID is 1

current PID is 17838

father PID is 17913

father PID is 1

father PID is 17929

father PID is 17927

father PID is 1

father PID is 17941

father PID is 1

father PID is 17950

father PID is 1

 

看完了上面的那個(gè)例子,下面的這個(gè)例子就是小case了,當(dāng)然,其實(shí)上面的那個(gè)例子就是由下面的這個(gè)例子引申來(lái)的,是因?yàn)閷戝e(cuò)了代碼而引起的。當(dāng)然,根據(jù)錯(cuò)誤,我們收獲不小啊!

Code

#include <stdio.h>

#include <unistd.h>

int main()

{

 int p1;

 while ((p1=fork())==-1) ;

 if (p1 == 0)

 {

     printf("current PID is %d\n",getpid());

     printf("father PID is %d\n",getppid());

     printf("\n");

 }

 else

 {

     printf("father PID is %d\n",getppid());

     printf("current PID is %d\n",getpid());

     printf("\n");

 }

 return 0;

}

 

結(jié)果如下:

current PID is 20312[l3] 

father PID is 20311

 

father PID is 32667

current PID is 20311

 

----------------------------------------------------------------------------------------------------------------

father PID is 32667

current PID is 20309[l4] 

 

current PID is 20310

father PID is 1


 [l1]父進(jìn)程的PID剛好就是下面的那個(gè)父進(jìn)程的current PID,說(shuō)明下面的那個(gè)進(jìn)程就是父進(jìn)程。

 [l2]看看這個(gè)程序,雖然比較流氓,不過(guò)可以根據(jù)結(jié)果知道,如果創(chuàng)建失敗的話,那么也會(huì)有一個(gè)當(dāng)前的PID,而且還是由一個(gè)1號(hào)進(jìn)程創(chuàng)建。

 [l3]當(dāng)前是子進(jìn)程,而它的父進(jìn)程恰好是下面的這個(gè)進(jìn)程!

 [l4]父進(jìn)程就是這個(gè)進(jìn)程,而它的那個(gè)子進(jìn)程卻是由系統(tǒng)創(chuàng)建的!


后來(lái)通過(guò)查閱資料知道,如果父進(jìn)程創(chuàng)建一個(gè)子進(jìn)程后其先結(jié)束,那么子進(jìn)程就變成了孤兒進(jìn)程,這樣的話,就會(huì)由初始化進(jìn)程,即1號(hào)進(jìn)程來(lái)領(lǐng)養(yǎng)。所以會(huì)顯示它的父進(jìn)程為1.至此,完美的解決了。。

最近在看《Linux程序設(shè)計(jì)》(第三版)一書,收獲頗豐。本書是Linux下面程序設(shè)計(jì)的經(jīng)典,值得一睹。。而且最近的感觸是,懂得linux的操作和會(huì)在Linux下面進(jìn)程程序設(shè)計(jì)完全是兩回事,就像你會(huì)用windows和會(huì)開發(fā)windows下面的程序一樣。我輩任重而道遠(yuǎn)啊。。


劉暢 2009-12-10 14:41 發(fā)表評(píng)論
]]>
[轉(zhuǎn)載]gcc使用http://www.shnenglu.com/deercoder/articles/102581.html劉暢劉暢Fri, 04 Dec 2009 16:45:00 GMThttp://www.shnenglu.com/deercoder/articles/102581.htmlhttp://www.shnenglu.com/deercoder/comments/102581.htmlhttp://www.shnenglu.com/deercoder/articles/102581.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/102581.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/102581.html

GCC(gcc) 的不斷發(fā)展完善使許多商業(yè)編譯器都相形見絀, GCC GNU 創(chuàng)始人 Richard Stallman首創(chuàng),是 GNU 的標(biāo)志產(chǎn)品,由于 UNIX 平臺(tái)的高度可移植性, GCC 幾乎在各種常見的 UNIX 平臺(tái)上都有,即使是 Win32/DOS 也有 GCC 的移植。 比如說(shuō) SUN Solaris 操作系統(tǒng)配置的編譯器就是GNU GCC

GNU 軟件包括 C 編譯器 GCC C++ 編譯器 G++ ,匯編器 AS ,鏈接器 LD ,二進(jìn)制轉(zhuǎn)換工具(OBJCOPY OBJDUMP) ,調(diào)試工具 (GDB GDBSERVER KGDB) 和基于不同硬件平臺(tái)的開發(fā)庫(kù)。

GNU GCC 支持下用戶可以使用流行的 C/C++ 語(yǔ)言開發(fā)應(yīng)用程序,滿足生成高效率運(yùn)行代碼、易掌握的編程語(yǔ)言的用戶需求。

這些工具都是按 GPL 版權(quán)聲明發(fā)布,任何人可以從網(wǎng)上獲取全部的源代碼,無(wú)需使用任何費(fèi)用。關(guān)于 GNU 和公共許可證協(xié)議的詳細(xì)資料, 讀者可以參看 GNU 網(wǎng)站的介紹,

http://www.gnu.org/home.html

GNU 開發(fā)工具都是采用命令行的方式,用戶掌握起來(lái)相對(duì)比較困難,不如基于 Windows 系統(tǒng)的開發(fā)工具好用,但是 GNU 工具的復(fù)雜性是由于它更貼近編譯器和操作系統(tǒng)的底層,并提供了更大的靈活性。一旦學(xué)習(xí)和掌握了相關(guān)工具后,就了解了系統(tǒng)設(shè)計(jì)的基礎(chǔ)知識(shí)。

運(yùn)行于 Linux 操作系統(tǒng)下的自由軟件 GNU gcc 編譯器,不僅可以編譯 Linux 操作系統(tǒng)下運(yùn)行的應(yīng)用程序,還可以編譯 Linux 內(nèi)核本身,甚至可以作交叉編譯,編譯運(yùn)行于其它 CPU 上的程序。所以,在進(jìn)行嵌入式系統(tǒng)應(yīng)用程序開發(fā)時(shí),這些工具得到了日益廣泛的應(yīng)用。

GCC GNU 組織的免費(fèi) C 編譯器, Linux 的很多發(fā)布缺省安裝的就是這種。很多流行的自由軟件源代碼基本都能在 GCC 編譯器下編譯運(yùn)行。 所以掌握 GCC 編譯器的使用無(wú)論是對(duì)于編譯系統(tǒng)內(nèi)核還是自己的應(yīng)用程序都是大有好處的。

下面通過(guò)一個(gè)具體的例子,學(xué)習(xí)如何使用 GCC 編譯器。

Linux 操作系統(tǒng)中,對(duì)一個(gè)用標(biāo)準(zhǔn) C 語(yǔ)言寫的源程序進(jìn)行編譯,要使用 GNU gcc 編譯器。

例如下面一個(gè)非常簡(jiǎn)單的 Hello 源程序 (hello.c)

/*******************************************************

* Institute of Automation, Chinese Academy of Sciences

* File Name hello.c

* Description introduce how to compile a source file with gcc

* Author Xueyuan Nie

* Date

*******************************************************/

void main()

{

printf("Hello the world\n")

}

要編譯這個(gè)程序,我們只要在 Linux bash 提示符下輸入命令:

$ gcc -o hello hello.c

gcc 編譯器就會(huì)生成一個(gè) hello 的可執(zhí)行文件。在 hello.c 的當(dāng)前目錄下執(zhí)行 ./hello 就可以看到程序的輸出結(jié)果,在屏幕上打印出 “ Hello the world ” 的字符串來(lái)。

命令行中 gcc 表示是用 gcc 來(lái)編譯源程序;

-o outputfilename 選項(xiàng)表示要求編譯器生成文件名為 outputfilename 的可執(zhí)行文件,如果不指定 -o 選項(xiàng),則缺省文件名是 a.out 。在這里生成指定文件名為 hello 的可執(zhí)行文件,而 hello.c 是我們的源程序文件。

gcc 是一個(gè)多目標(biāo)的工具。 gcc 最基本的用法是:

gcc [options] file...

其中的 option 是以 - 開始的各種選項(xiàng), file 是相關(guān)的文件名。在使用 gcc 的時(shí)候,必須要給出必要的選項(xiàng)和文件名。 gcc 的整個(gè)編譯過(guò)程,實(shí)質(zhì)上是分四步進(jìn)行的,每一步完成一個(gè)特定的工作,

這四步分別是:預(yù)處理,編譯,匯編和鏈接。它具體完成哪一步,是由 gcc 后面的開關(guān)選項(xiàng)和文件類型決定的。

清楚的區(qū)別編譯和連接是很重要的。編譯器使用源文件編譯產(chǎn)生某種形式的目標(biāo)文件 (objectfiles) 。在這個(gè)過(guò)程中,外部的符號(hào)引用并沒有被解釋或替換,然后我們使用鏈接器來(lái)鏈接這些目標(biāo)文件和一些標(biāo)準(zhǔn)的頭文件,最后生成一個(gè)可執(zhí)行文件。在這個(gè)過(guò)程中,一個(gè)目標(biāo)文件中對(duì)別的文件中的符號(hào)的引用被解釋,并報(bào)告不能被解釋的引用,一般是以錯(cuò)誤信息的形式報(bào)告出來(lái)。

gcc 編譯器有許多選項(xiàng),但對(duì)于普通用戶來(lái)說(shuō)只要知道其中常用的幾個(gè)就夠了。在這里為讀者列出幾個(gè)最常用的選項(xiàng):

-o 選項(xiàng)表示要求編譯器生成指定文件名的可執(zhí)行文件;

-c 選項(xiàng)表示只要求編譯器進(jìn)行編譯,而不要進(jìn)行鏈接,生成以源文件的文件名命名但把其后綴由 .c .cc 變成 .o 的目標(biāo)文件;

-g 選項(xiàng)要求編譯器在編譯的時(shí)候提供以后對(duì)程序進(jìn)行調(diào)試的信息;

-E 選項(xiàng)表示編譯器對(duì)源文件只進(jìn)行預(yù)處理就停止,而不做編譯,匯編和鏈接;

-S 選項(xiàng)表示編譯器只進(jìn)行編譯,而不做匯編和鏈接;

-O 選項(xiàng)是編譯器對(duì)程序提供的編譯優(yōu)化選項(xiàng),在編譯的時(shí)候使用該選項(xiàng),可以使生成的執(zhí)行文件的執(zhí)行效率提高;

-Wall 選項(xiàng)指定產(chǎn)生全部的警告信息。

如果你的源代碼中包含有某些函數(shù),則在編譯的時(shí)候要鏈接確定的庫(kù),比如代碼中包含了某些數(shù)學(xué)函數(shù),在 Linux 下,為了使用數(shù)學(xué)函數(shù),必須和數(shù)學(xué)庫(kù)鏈接,為此要加入 -lm 選項(xiàng)。也許有讀者會(huì)問,前面那個(gè)例子使用 printf 函數(shù)的時(shí)候?yàn)楹螞]有鏈接庫(kù)呢?在 gcc 中對(duì)于一些常用函數(shù)的實(shí)現(xiàn), gcc 編譯器會(huì)自動(dòng)去鏈接一些常用庫(kù),這樣用戶就沒有必要自己去指定了。有時(shí)候在編譯程序的時(shí)候還要指定庫(kù)的路徑,這個(gè)時(shí)候要用到編譯器的 -L 選項(xiàng)指定路徑。比如說(shuō)我們有一個(gè)庫(kù)在/home/hoyt/mylib 下,這樣我們編譯的時(shí)候還要加上 -L/home/hoyt/mylib 。對(duì)于一些標(biāo)準(zhǔn)庫(kù)來(lái)說(shuō),沒有必要指出路徑。只要它們?cè)谄鹑笔?kù)的路徑下就可以了, gcc 在鏈接的時(shí)候會(huì)自動(dòng)找到那些庫(kù)的。

GNU 編譯器生成的目標(biāo)文件缺省格式為 elf(executive linked file) 格式,這是 Linux 系統(tǒng)所采用的可執(zhí)行鏈接文件的通用文件格式。 elf 格式由若干段 (section) 組成,如果沒有特別指明,由標(biāo)準(zhǔn) c 源代碼生成的目標(biāo)文件中包含以下段: .text( 正文段 ) 包含程序的指令代碼, .data( 數(shù)據(jù)段 ) 包含固定的數(shù)據(jù),如常量,字符串等, .bss( 未初始化數(shù)據(jù)段 ) 包含未初始化的變量和數(shù)組等。

讀者若想知道更多的選項(xiàng)及其用法,可以查看 gcc 的幫助文檔,那里有許多對(duì)其它選項(xiàng)的詳細(xì)說(shuō)明。

當(dāng)改變了源文件 hello.c 后,需要重新編譯它:

$ gcc -c hello.c

然后重新鏈接生成:

$ gcc o hello.o

對(duì)于本例,因?yàn)橹缓幸粋€(gè)源文件,所以當(dāng)改動(dòng)了源碼后,進(jìn)行重新的編譯鏈接的過(guò)程顯得并不是太繁瑣,但是,如果在一個(gè)工程中包含了若干的源碼文件,而這些源碼文件中的某個(gè)或某幾個(gè)又被其他源碼文件包含,那么,如果一個(gè)文件被改動(dòng),則包含它的那些源文件都要進(jìn)行重新編譯鏈接,工作量是可想而知的。幸運(yùn)的是, GNU 提供了使這個(gè)步驟變得簡(jiǎn)單的工具,就是下面要介紹給大家的 GNU Make 工具。

GNU Make

make 是負(fù)責(zé)從項(xiàng)目的源代碼中生成最終可執(zhí)行文件和其他非源代碼文件的工具。 make 命令本身可帶有四種參數(shù):標(biāo)志、宏定義、描述文件名和目標(biāo)文件名。

其標(biāo)準(zhǔn)形式為:

make [flags] [macro definitions] [targets]

Unix 系統(tǒng)下標(biāo)志位 flags 選項(xiàng)及其含義為:

-f file 指定 file 文件為描述文件,如果 file 參數(shù)為 '-' 符,那么描述文件指向標(biāo)準(zhǔn)輸入。如果沒有 '-f' 參數(shù),則系統(tǒng)將默認(rèn)當(dāng)前目錄下名為 makefile 或者名為 Makefile 的文件為描述文件。在Linux 中, GNU make 工具在當(dāng)前工作目錄中按照 GNUmakefile makefile Makefile 的順序搜索makefile 文件。

-i 忽略命令執(zhí)行返回的出錯(cuò)信息。

-s 沉默模式,在執(zhí)行之前不輸出相應(yīng)的命令行信息。

-r 禁止使用隱含規(guī)則。

-n 非執(zhí)行模式,輸出所有執(zhí)行命令,但并不執(zhí)行。

-t 更新目標(biāo)文件。

-q make 操作將根據(jù)目標(biāo)文件是否已經(jīng)更新返回 "0" 或非 "0" 的狀態(tài)信息。

-p 輸出所有宏定義和目標(biāo)文件描述。

-d Debug 模式,輸出有關(guān)文件和檢測(cè)時(shí)間的詳細(xì)信息。

Linux make 標(biāo)志位的常用選項(xiàng)與 Unix 系統(tǒng)中稍有不同,下面只列出了不同部分:

-c dir 在讀取 makefile 之前改變到指定的目錄 dir

-I dir 當(dāng)包含其他 makefile 文件時(shí),利用該選項(xiàng)指定搜索目錄。

-h help 文擋,顯示所有的 make 選項(xiàng)。

-w 在處理 makefile 之前和之后,都顯示工作目錄。

通過(guò)命令行參數(shù)中的 target ,可指定 make 要編譯的目標(biāo),并且允許同時(shí)定義編譯多個(gè)目標(biāo),操作時(shí)按照從左向右的順序依次編譯 target 選項(xiàng)中指定的目標(biāo)文件。如果命令行中沒有指定目標(biāo),則系統(tǒng)默認(rèn) target 指向描述文件中第一個(gè)目標(biāo)文件。

make 如何實(shí)現(xiàn)對(duì)源代碼的操作是通過(guò)一個(gè)被稱之為 makefile 的文件來(lái)完成的,在下面的小節(jié)里,主要向讀者介紹一下 makefile 的相關(guān)知識(shí)。

makefile 基本結(jié)構(gòu)

GNU Make 的主要工作是讀一個(gè)文本文件 makefile makefile 是用 bash 語(yǔ)言寫的, bash 語(yǔ)言是很像 BASIC 語(yǔ)言的一種命令解釋語(yǔ)言。這個(gè)文件里主要描述了有關(guān)哪些目標(biāo)文件是從哪些依賴文件中產(chǎn)生的,是用何種命令來(lái)進(jìn)行這個(gè)產(chǎn)生過(guò)程的。有了這些信息, make 會(huì)檢查磁盤的文件,如果目標(biāo)文件的日期 ( 即該文件生成或最后修改的日期 ) 至少比它的一個(gè)依賴文件日期早的話, make 就會(huì)執(zhí)行相應(yīng)的命令,以更新目標(biāo)文件。

makefile 一般被稱為 “makefile” 或 “Makefile” 。還可以在 make 的命令行中指定別的文件名。如果沒有特別指定的話, make 就會(huì)尋找 “makefile” 或 “Makefile” ,所以為了簡(jiǎn)單起見,建議讀者使用這兩名字。如果要使用其他文件作為 makefile ,則可利用類似下面的 make 命令選項(xiàng)指定 makefile 文件:

$ make -f makefilename

一個(gè) makefile 主要含有一系列的規(guī)則,如下:

目標(biāo)文件名: 依賴文件名

(tab ) 命令

第一行稱之為規(guī)則,第二行是執(zhí)行規(guī)則的命令,必須要以 tab 鍵開始。

下面舉一個(gè)簡(jiǎn)單的 makefile 的例子。

executable : main.o io.o

gcc main.o io.o -o executable

main.o : main.c

gcc -Wall -O -g -c main.c -o main.o

io.o : io.c

gcc -Wall -O -g -c io.c -o io.o

這是一個(gè)最簡(jiǎn)單的 makefile make 從第一條規(guī)則開始, executable makefile 最終要生成的目標(biāo)文件。給出的規(guī)則說(shuō)明 executable 依賴于兩個(gè)目標(biāo)文件 main.o io.o ,只要 executable 比它依賴的文件中的任何一個(gè)舊的話,下一行的命令就會(huì)被執(zhí)行。但是,在檢查文件 main.o io.o 的日期之前,它會(huì)往下查找那些把 main.o io.o 做為目標(biāo)文件的規(guī)則。 make 先找到了關(guān)于 main.o 的規(guī)則,該目標(biāo)文件的依賴文件是 main.c makefile 后面的文件中再也找不到生成這個(gè)依賴文件的規(guī)則了。此時(shí), make 開始檢查磁盤上這個(gè)依賴文件的日期,如果這個(gè)文件的日期比 main.o 日期新的話,那么這個(gè)規(guī)則下面的命令 gcc -c main.c o main.o 就會(huì)執(zhí)行,以更新文件 main.o 。同樣 make 對(duì)文件 io.o 做類似的檢查,它的依賴文件是 io.c ,對(duì) io.o 的處理和 main.o 類似。現(xiàn)在, 再回到第一個(gè)規(guī)則處,如果剛才兩個(gè)規(guī)則中的任何一個(gè)被執(zhí)行,最終的目標(biāo)文件executable 都需要重建 ( 因?yàn)?span> executable 所依賴的其中一個(gè) .o 文件就會(huì)比它新 ) ,因此鏈接命令就會(huì)被執(zhí)行。

有了 makefile ,對(duì)任何一個(gè)源文件進(jìn)行修改后,所有依賴于該文件的目標(biāo)文件都會(huì)被重新編譯 ( 因?yàn)?span> .o 文件依賴于 .c 文件 ) ,進(jìn)而最終可執(zhí)行文件會(huì)被重新鏈接 ( 因?yàn)樗蕾嚨?span> .o 文件被改變了 ) ,再也不用手工去一個(gè)個(gè)修改了。



劉暢 2009-12-05 00:45 發(fā)表評(píng)論
]]>
C++中的默認(rèn)構(gòu)造函數(shù)http://www.shnenglu.com/deercoder/articles/102113.html劉暢劉暢Fri, 27 Nov 2009 13:42:00 GMThttp://www.shnenglu.com/deercoder/articles/102113.htmlhttp://www.shnenglu.com/deercoder/comments/102113.htmlhttp://www.shnenglu.com/deercoder/articles/102113.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/102113.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/102113.html#include <iostream>
using namespace std;
class test
{
public:
    test(int a,float b)
    {
        x =  a;
        y = b;
    }
    void show()
    {
        cout << "x = " << x << endl
            << "y = " << y << endl;
    }
private:
    int x ;
    float y;
};
void main()
{
    test b(1,3.2);
    b.show();
}
完全沒有問題,自己定義了一個(gè)構(gòu)造函數(shù),而不是系統(tǒng)默認(rèn)的構(gòu)造函數(shù),這樣就不會(huì)出錯(cuò)了!!
然后看看下面的這段代碼:
#include <iostream>
using namespace std;
class test
{
public:
    void show()
    {
        cout << "x = " << x << endl
            << "y = " << y << endl;
    }
private:
    int x;
    double y;
};
void main()
{
    test b(1,3.2);
    b.show();
}
然后就會(huì)出錯(cuò),為什么,因?yàn)槟J(rèn)的構(gòu)造函數(shù)是沒有形參,所以你傳遞進(jìn)去的兩個(gè)形參就會(huì)報(bào)錯(cuò)!更不可能把你的那兩個(gè)參數(shù)賦值給它的private內(nèi)容中的形參。
還可以定義一個(gè)函數(shù)專門進(jìn)行賦值化或者初始化,這樣就相當(dāng)于一個(gè)構(gòu)造函數(shù),可是實(shí)現(xiàn)起來(lái)的話就要顯示的調(diào)用set函數(shù)。
class test
{
public:
    void set(int a,float b)
    {
         x = a;
         y = b;
    }
    void show()
    {
         cout << "x = " << x << endl
            << "y = " << y << endl;
    }
private:
    int x;
    float y;
};

void main()
{
    test b;
    b.set(1,3.4);
    b.show();
}


劉暢 2009-11-27 21:42 發(fā)表評(píng)論
]]>
C++中的重載運(yùn)算符http://www.shnenglu.com/deercoder/articles/102110.html劉暢劉暢Fri, 27 Nov 2009 13:38:00 GMThttp://www.shnenglu.com/deercoder/articles/102110.htmlhttp://www.shnenglu.com/deercoder/comments/102110.htmlhttp://www.shnenglu.com/deercoder/articles/102110.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/102110.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/102110.html1.為何要使用重載運(yùn)算符?

因?yàn)槲覀兿M褂玫筋惖囊恍┎僮鳎沟靡粋€(gè)類更像內(nèi)置的數(shù)據(jù)類型(int,float…………)

比如說(shuō)對(duì)于int類型的變量,自增運(yùn)算符是默認(rèn)的,即定義int i,即可以用到i++,而現(xiàn)在對(duì)于自定義

的一個(gè)類,如果沒有定義++操作,那么程序時(shí)不會(huì)找到這個(gè)操作的相應(yīng)定義的,更不會(huì)執(zhí)行相應(yīng)的操

作!

也就是說(shuō),實(shí)際上重載運(yùn)算符是給了++…………這些運(yùn)算符一些新的定義和操作,結(jié)果很明顯,我們

使用自定義類的時(shí)候可以像內(nèi)置類型一樣那么自然,簡(jiǎn)單,符合我們的用戶習(xí)慣!

 

2.如何定義重載運(yùn)算符?

前面說(shuō)到重載,對(duì),對(duì)于一個(gè)運(yùn)算符,實(shí)際上語(yǔ)言的本身是定義默認(rèn)的操作的,比如說(shuō)加法運(yùn)算,對(duì)于int類型可以知道是整數(shù)相加,對(duì)于float類型也是如此,這實(shí)際上也是一種重載,對(duì)于不同類型的數(shù)據(jù),可以用同一個(gè)運(yùn)算符來(lái)重載!

現(xiàn)在我們的問題是要增加自己定義的類的操作。

OK,言歸正傳,有兩種定義的方法,使用類內(nèi)置成員函數(shù)的方法和友元的方法來(lái)定義:

 

運(yùn)算符的重載形式有兩種:重載為類的成員函數(shù)和重載為類的友元函數(shù)。



劉暢 2009-11-27 21:38 發(fā)表評(píng)論
]]>
scanf函數(shù)詳解http://www.shnenglu.com/deercoder/articles/102100.html劉暢劉暢Fri, 27 Nov 2009 13:21:00 GMThttp://www.shnenglu.com/deercoder/articles/102100.htmlhttp://www.shnenglu.com/deercoder/comments/102100.htmlhttp://www.shnenglu.com/deercoder/articles/102100.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/102100.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/102100.htmlwhile(scanf("%d%d",&a,&b)!=EOF),這個(gè)語(yǔ)句就是說(shuō),當(dāng)讀取沒有到達(dá)文件尾的話,就不停的讀取。
scanf 函數(shù)的返回值反映的是按照指定的格式符正確讀入的數(shù)據(jù)的個(gè)數(shù)。如果輸入數(shù)據(jù)與指定格式不符,則會(huì)產(chǎn)生輸入錯(cuò)誤。遇到輸入錯(cuò)誤,scanf函數(shù)會(huì)立即終止,返回已經(jīng)成功讀取的數(shù)據(jù)的個(gè)數(shù)。所以,通過(guò)scanf函數(shù)的返回值和指定輸入數(shù)據(jù)的個(gè)數(shù)(由格式符決定)的比較,可以判斷數(shù)據(jù)輸入是否成功。

scanf("%d%d",&a,&b); 這個(gè)語(yǔ)句會(huì)去讀兩個(gè)整型到a, b。如果讀取成功,應(yīng)該返回2。就是它成功讀取變量的個(gè)數(shù)。


論壇上很多人對(duì)scanf的不太了解,導(dǎo)致程序出錯(cuò),我想把scanf的具體用法貼出來(lái),希望大家可以共同進(jìn)步,有什么不對(duì)的地方可以提出來(lái)。
int scanf(char *format,...);
這應(yīng)該是scanf的標(biāo)準(zhǔn)形式。先說(shuō)說(shuō)關(guān)于他的返回值的問題。
庫(kù)函數(shù)幾乎都是有返回值的,有些人可能很奇怪,怎么很少人用過(guò)scanf的返回值呢?
scanf會(huì)返回成功接收到的變量數(shù)量的值。比如scanf("%d",&j"),與scanf("%d=",&j),如果接受成功的話返回值都是1
我用如下語(yǔ)句作了測(cè)試
#include <stdio.h>
int main (){
    int j;
    printf ("%d",scanf("%d\n",&j));
    return 0;
}
如果你開始就輸入回車,程序會(huì)繼續(xù)等待你輸入,因?yàn)樵谳斎霐?shù)字的時(shí)候,scanf會(huì)跳過(guò)空白字符。(the c programming language 上說(shuō),scanf實(shí)際上是用getchar()接受由數(shù)字組成的字符串,再轉(zhuǎn)換成數(shù)字)
如果我輸入ctrl-z(unix上是ctrl-d)則會(huì)返回-1(隨編譯器而定).這實(shí)際上就是常量EOF的值,也就是所謂的返回eof
如果我鍵入的不是數(shù)字返回值就是0。但是如果我輸入浮點(diǎn)數(shù),又會(huì)怎么樣呢?
我舉的例子中同樣會(huì)返回1,但是緩沖區(qū)會(huì)留下垃圾,如果是scanf("%d%d",&a,&b);則會(huì)出錯(cuò)。
這是可以使用一個(gè)庫(kù)函數(shù)fflush(stdin)來(lái)清除緩沖。不過(guò)貌似雨中飛燕大姐說(shuō)這個(gè)用法是非標(biāo)準(zhǔn)的。K&R,只是說(shuō)行為沒有定義,但我們可以使用while((c=getchar())!='\n'&&c!=EOF);同樣可以清除后面的垃圾
scanf的格式匹配還是比較簡(jiǎn)單,一定要記住的就是普通變量一定要加上&,否則編譯器無(wú)法檢測(cè)錯(cuò)誤,但運(yùn)行肯定會(huì)段錯(cuò)誤。
    ┏━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
    ┃ 代  碼 │             意                          義            
    ┠────┼────────────────────────────┨
    ┃   %a   │讀浮點(diǎn)值(僅適用于 C99)                                 
    ┃   %A   │讀浮點(diǎn)值(僅適用于 C99)                                 
    ┃   %c   │讀單字符                                                
    ┃   %d   │讀十進(jìn)制整數(shù)                                            
    ┃   %i   │讀十進(jìn)制、八進(jìn)制、十六進(jìn)制整數(shù)                          
    ┃   %e   │讀浮點(diǎn)數(shù)                                                
    ┃   %E   │讀浮點(diǎn)數(shù)                                                
    ┃   %f   │讀浮點(diǎn)數(shù)                                                
    ┃   %F   │讀浮點(diǎn)數(shù)(僅適用于 C99)                                 
    ┃   %g   │讀浮點(diǎn)數(shù)                                                
    ┃   %G   │讀浮點(diǎn)數(shù)                                                
    ┃   %o   │讀八進(jìn)制數(shù)                                             
    ┃   %s   │讀字符串                                                
    ┃   %x   │讀十六進(jìn)制數(shù)                                            
    ┃   %X   │讀十六進(jìn)制數(shù)                                            
    ┃   %p   │讀指針值                                                
    ┃   %n   │至此已讀入值的等價(jià)字符數(shù)                                
    ┃   %u   │讀無(wú)符號(hào)十進(jìn)制整數(shù)                                      
    ┃  %[ ]  │掃描字符集合                                            
    ┃   %%   │讀 % 符號(hào)(百分號(hào))                                       
    ┗━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
前面都很簡(jiǎn)單,%p,%n很少用到,跳過(guò)。要輸入%必須要在前面再加一個(gè)%,
重點(diǎn)來(lái)談?wù)?s和%[]。%s是讀入一個(gè)數(shù)組,他與gets的區(qū)別就在于%s會(huì)以任何的空字符結(jié)束,而gets是回車結(jié)束。
同樣%s前可以加數(shù)字,表示只讀多少個(gè)。
ANSI C 標(biāo)準(zhǔn)向 scanf() 增加了一種新特性,稱為掃描集(scanset)。 掃描集定義一個(gè)字符集合,可由 scanf() 讀入其中允許的字符并賦給對(duì)應(yīng)字符數(shù)組。 掃描集合由一對(duì)方括號(hào)中的一串字符定義,左方括號(hào)前必須綴以百分號(hào)。 例如,以下的掃描集使 scanf() 讀入字符 A、B 和 C:
    %[ABC]
使用掃描集時(shí),scanf() 連續(xù)吃進(jìn)集合中的字符并放入對(duì)應(yīng)的字符數(shù)組,直到發(fā)現(xiàn)不在集合中的字符為止(即掃描集僅讀匹配的字符)。返回時(shí),數(shù)組中放置以 null 結(jié)尾、由讀入字符組成的字符串。
對(duì)于許多實(shí)現(xiàn)來(lái)說(shuō),用連字符可以說(shuō)明一個(gè)范圍。 例如,以下掃描集使 scanf() 接受字母 A 到 Z:
%[A-Z]
重要的是要注意掃描集是區(qū)分大小寫的。因此,希望掃描大、小寫字符時(shí),應(yīng)該分別說(shuō)明大、小寫字母。
對(duì)于%[]還可以用^+任意字符(包括eof)來(lái)結(jié)束字符串的輸入。比如%[^EOF]就是直到有EOF輸入,字符串才中止。
但一定要記住就是c語(yǔ)言是緩沖輸入,即使你%[^a],再你輸入回車之前輸入多少的a都是不可能結(jié)束的。
%s的輸入會(huì)跳過(guò)空白字符,但是%c則不會(huì)。
這也就是
scanf("%d",&h);
scanf("%c",&c);
如果這寫的話,變量c放的一定是回車。
如果想實(shí)現(xiàn)這種輸入,可以在兩個(gè)語(yǔ)句之間加入一個(gè)getchar(),他可以吃掉這個(gè)回車,
也可用scanf("%d %c",&h,&c);來(lái)做,再輸入數(shù)字后加一個(gè)空格。就可以了
但千萬(wàn)別用scanf("%d\n",&h)!!!!!!!!k&r說(shuō)的十分清楚,任何非格式化的字符都需要完全匹配。
意味著,只有輸入數(shù)字后面再加\n才是合法的。
還有就是*加在任何項(xiàng)的前面表示該項(xiàng)不符值,別的就沒什么好說(shuō)的了


劉暢 2009-11-27 21:21 發(fā)表評(píng)論
]]>
數(shù)據(jù)結(jié)構(gòu)與STL(一)http://www.shnenglu.com/deercoder/articles/100748.html劉暢劉暢Wed, 11 Nov 2009 14:49:00 GMThttp://www.shnenglu.com/deercoder/articles/100748.htmlhttp://www.shnenglu.com/deercoder/comments/100748.htmlhttp://www.shnenglu.com/deercoder/articles/100748.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/100748.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/100748.html

總括:此部分寫的還是比較好,特別是第一章,介紹了面向?qū)ο缶幊痰奶貏e,關(guān)鍵是從一個(gè)解決問題的角度來(lái)分析,相比較而言,C++ Primer更顯得雜亂無(wú)章。通過(guò)對(duì)問題深入,根據(jù)解決問題的方法,來(lái)實(shí)現(xiàn)最合理化的得到目的,從而引出繼承等等一系列概念和手段。

 

1.     構(gòu)造器

e.g  Data(int monthln,int dayln,int yearln)

{

  Month = monthln;

  Day  =  dayln;

  Year  =  yearln;

}

Date thedate(7,1,2003);

Date thisdate;

第一個(gè)調(diào)用了用戶定義的構(gòu)造函數(shù)來(lái)初始化相應(yīng)的數(shù)據(jù),問題是,如果是0-參數(shù)的構(gòu)造器呢?就是下面的那種情況,沒有任何參數(shù),默認(rèn)的,編譯器會(huì)自動(dòng)生成一個(gè),這個(gè)就是缺省構(gòu)造函數(shù),但是如果用戶定義了一個(gè)0-參數(shù)的構(gòu)造器,那么就不會(huì)自動(dòng)生成這樣一個(gè)了。從安全性角度去看,定義類的時(shí)候,應(yīng)當(dāng)顯示的定義一個(gè)缺省構(gòu)造函數(shù)(如果有繼承的話,沒有定義基類的缺省構(gòu)造函數(shù)是會(huì)出現(xiàn)編譯錯(cuò)誤的。)

注意:一個(gè)構(gòu)造器,不管有沒有參數(shù),都不會(huì)自動(dòng)初始化類的字段,所以必須自己顯式的寫出代碼來(lái)初始化。

2.     繼承的細(xì)節(jié)

我們可能經(jīng)常遇到這樣的問題,在開發(fā)一個(gè)類B的時(shí)候,發(fā)現(xiàn)其他的一些類A的方法是非常有用的。一個(gè)可能性就是令BA繼承,也就是說(shuō),BA的子類,這樣就可以使用A的所有方法;還有一種方案,就是在B中定義一個(gè)字段,它的類型是A,通過(guò)這個(gè)字段調(diào)用A的方法。前者,就是“Is a(是一個(gè))的關(guān)系,而后者就是”Has a”(有一個(gè)的關(guān)系)。如何實(shí)現(xiàn)這種區(qū)分更好的來(lái)規(guī)劃呢,一般,如果類B分享了A的全部功能,那么BA繼承是更好的選擇,但是如果B中只有一個(gè)組件能從A中受益,那么就是Has a來(lái)實(shí)現(xiàn)了。。

 





劉暢 2009-11-11 22:49 發(fā)表評(píng)論
]]>
虛函數(shù)的幾點(diǎn)注意和重載運(yùn)算符的疑問http://www.shnenglu.com/deercoder/articles/97488.html劉暢劉暢Mon, 28 Sep 2009 13:36:00 GMThttp://www.shnenglu.com/deercoder/articles/97488.htmlhttp://www.shnenglu.com/deercoder/comments/97488.htmlhttp://www.shnenglu.com/deercoder/articles/97488.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/97488.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/97488.html以下是幾點(diǎn)學(xué)習(xí)C++后續(xù)內(nèi)容的體會(huì)和注意之處,更新ing…………

對(duì)于類的幾點(diǎn)認(rèn)識(shí):
---------《以下的幾條規(guī)范是便于多文件管理,分別編譯的》---------
1.將類的聲明放在h文件中,注意是聲明,而不是定義,命名之,最好用類

名來(lái)給這個(gè)h文件命名。
2.將類的定義放在cpp文件中,單獨(dú)一個(gè)cpp文件中,以類名命名之。
3.將主函數(shù)放在單獨(dú)一個(gè)文件cpp中,文件名無(wú)所謂,不過(guò)取main的話便于

找到主體程序在哪里。

 

下面要說(shuō)的是虛函數(shù):virtual
1.在類中要聲明virtual,但是放在對(duì)應(yīng)的定義cpp文件中的時(shí)候,要注意去

掉virtual,否則會(huì)報(bào)錯(cuò)。
2.注意聲明和定義的原型都必須完全一樣,比如聲明中有一個(gè)const,那么

在定義中必須也要有,否則的話就會(huì)報(bào)錯(cuò),說(shuō)不認(rèn)識(shí)這個(gè)函數(shù)。
3.在類外定義的話一定要加上類型限定符,作用域限定符。

 下面寫點(diǎn)代碼:

student.h頭文件 
1
#ifndef STUDENT_H
 2#define STUDENT_H
 3
 4#include <iostream>
 5using std::string;
 6
 7
 8class Student
 9{
10public:
11    Student(const string& a="",double b=0.0,int c=0):score(b),name(a),number(c)
12    {}
13    ~Student(){}
14    //void show_score();
15    //void modify(Student& a);
16    friend Student operator+(Student& a,Student& b);
17    friend Student operator-(Student& a,Student& b);
18    friend std::ostream& operator<<(std::ostream &a,Student& b);  //改變狀態(tài)的一般都要定義為類成員,++,--及*
19    friend std::istream& operator>>(std::istream &a,Student& b);//進(jìn)行算術(shù)運(yùn)算和輸入輸出的就定義為友元
20    //Student& operator=(Student& a);
21private:
22    double score;
23    string name;
24    int number;
25}
;
26
27#endif

 

 1student.cpp文件,實(shí)現(xiàn)類函數(shù)
 2#include <iostream>
 3#include <string>
 4#include "Student.h"
 5using std::cout;
 6using std::cin;
 7using std::endl;
 8
 9Student operator+(Student& a,Student& b) //這里面又用到了<<這個(gè)運(yùn)算符的。而這個(gè)你已經(jīng)自定義了啊!
10{
11    cout << a.name << "" << b.name << "分?jǐn)?shù)之和為:" << a.score+ b.score;
12    cout << endl;
13    return a;
14}

15Student operator-(Student& a,Student& b)
16{
17    cout << a.name << " 比 " << b.name << "" << 
18        (a.score > b.score)?(a.score-b.score):(b.score - a.score);
19    cout << endl;
20    return a;
21}

22std::ostream& operator<<(std::ostream &a,Student& b)
23{
24    a << b.name<<"的分?jǐn)?shù):" << b.score << "\t 學(xué)號(hào):" << b.number << endl;
25    return a;
26}

27std::istream& operator>>(std::istream &a,Student& b)
28{
29    a >> b.name >>b.number >> b.score  ; 
30    return a;
31}

32/*
33問題1,修改定義函數(shù)的時(shí)候沒有修改聲明,為什么這么粗心呢?
342.返回值,特別是對(duì)于有輸入輸出流的,要有返回值啊!
353.流的返回值和調(diào)用。
364.返回值怎么能為void呢?因?yàn)橐敵鯽+b,所以要返回一個(gè)值啊,相當(dāng)于opreator+(a,b)
37*/

 

主函數(shù):main.cpp 
1
#include <iostream>
 2#include "Student.h"
 3
 4using namespace std;
 5
 6int main()
 7{
 8    Student a,b;
 9    cout << "依次輸入姓名,學(xué)號(hào),成績(jī)" << endl;
10    cin >> a >> b;
11    cout << a << b;
12    cout << endl;
13    return 0;
14}

15

 我想說(shuō)的是自己遇到的幾個(gè)問題:
1.重載<< 和>>操作符:這兩個(gè)操作符只能作為友元而不是成員函數(shù)。作為重載運(yùn)算符,有兩種定義形式,即:成員函數(shù)形式和非成員函數(shù)形式,對(duì)于成員函數(shù)的形式,它的聲明方式是形參數(shù)要比操作數(shù)少一個(gè),為什么呢,因?yàn)槭÷粤四J(rèn)的形參this指針,而這個(gè)省略的形參正式左操作數(shù),即定義這樣的運(yùn)算符的時(shí)候,this指針指向的是左操作數(shù)。其次,就是非成員函數(shù),即友元聲明方式。友元聲明方式較簡(jiǎn)單合理,形參數(shù)和操作數(shù)相同,顯示的是合理的調(diào)用函數(shù)的方式。
2.什么時(shí)候用成員函數(shù)的聲明方式,什么時(shí)候用友元函數(shù)的聲明方式?此部分需注意的是:1,對(duì)于=,(),【】,->這四個(gè)操作符只能作為成員函數(shù)來(lái)聲明,想想這個(gè)是為什么呢?
  (1)只能使用成員函數(shù)重載的運(yùn)算符有:=、()、[]、->、new、delete。
  (2)單目運(yùn)算符最好重載為成員函數(shù)。
  (3) 對(duì)于復(fù)合的賦值運(yùn)算符如+=、-=、*=、/=、&=、!=、~=、%=、>>=、<<=建議重載為成員函數(shù)。
  (4) 對(duì)于其它運(yùn)算符,建議重載為友元函數(shù)。
關(guān)于此問題的詳細(xì)討論,見:http://www.rupeng.com/forum/thread-4468-1-1-uid3573.html
在C++編程思想中有述,據(jù)網(wǎng)友而言,大意是:如果可以定義為全局變量的話,那么就可以定義為int operator =(int,mytype),而這種方式的話就不對(duì)了,因?yàn)橘x值=是和左邊的類緊密相連的,所以會(huì)定義為成員函數(shù)的……

 此部分詳細(xì)關(guān)注中………………

3.關(guān)于重載運(yùn)算符的返回值的問題:
我們是不是已經(jīng)習(xí)慣于重載運(yùn)算符有一個(gè)返回值類型呢?對(duì),是的,我們經(jīng)常這么干,現(xiàn)在的問題是,如果我定義為void的話,會(huì)出錯(cuò)嗎?
不會(huì)的,將上面的換成void的返回值照樣不會(huì)出錯(cuò)!
為什么呢?因?yàn)槎x有返回值只是我們的一個(gè)習(xí)慣,為何有返回值,因?yàn)槲覀円祷刂担馨装V吧?可是事實(shí)就是這樣,想想這個(gè):
cout << a + b;  這個(gè)代碼很簡(jiǎn)單是吧,a+b 實(shí)際上就是operator+(a,b)的一個(gè)等價(jià)形式,我要能夠cout ,那么必然有一個(gè)返回值,否則的話調(diào)用這個(gè)函數(shù)沒有返回值的話我怎么cout它呢?于是乎我們?cè)诙x加法的重載的時(shí)候就只能在前面加上a和b的類型了。
好,現(xiàn)在我沒有類型了,void,怎么辦?很簡(jiǎn)單,直接用 a + b;  因?yàn)樗喈?dāng)于:operator+(a,b);也就是調(diào)用一個(gè)函數(shù),直接調(diào)用,沒有返回值。
當(dāng)然,結(jié)果也還是對(duì)的,各位可以看看…………

注意我想說(shuō)的,學(xué)習(xí)計(jì)算機(jī)主要的是學(xué)習(xí)那個(gè)思想,而不是片面的記住語(yǔ)法或者其他,要想想為什么需要這樣,這樣我們的思維才會(huì)和計(jì)算機(jī)接近,才能更好的理解計(jì)算機(jī),上面的這個(gè)例子就是很好的說(shuō)明,這個(gè)函數(shù)很另類了吧,可是它完全符合各種語(yǔ)法,能夠順利運(yùn)行。。
可是要記住的是,重載運(yùn)算符為什么要重載,就是為了使用和內(nèi)置類型一樣的自然,如果像上面我定義的void那樣,那么恐怕就很難懂了,如果將減號(hào)定義為加法的話,那么就更加的匪夷所思。也很難讀了,違背了初衷,也就是一種錯(cuò)誤的做法了,雖然理論上是可行的。。

計(jì)算機(jī)是一個(gè)很奇妙的東西,需要我們用心去體會(huì)……
                                                                                                                  ------------------------------<本章完>

 

 

 

 

 

 

 

 

 

 



劉暢 2009-09-28 21:36 發(fā)表評(píng)論
]]>
C++中的重載運(yùn)算符----------------由運(yùn)算符引起的一個(gè)BUGhttp://www.shnenglu.com/deercoder/articles/97357.html劉暢劉暢Sun, 27 Sep 2009 06:15:00 GMThttp://www.shnenglu.com/deercoder/articles/97357.htmlhttp://www.shnenglu.com/deercoder/comments/97357.htmlhttp://www.shnenglu.com/deercoder/articles/97357.html#Feedback0http://www.shnenglu.com/deercoder/comments/commentRss/97357.htmlhttp://www.shnenglu.com/deercoder/services/trackbacks/97357.html閱讀全文

劉暢 2009-09-27 14:15 發(fā)表評(píng)論
]]>
国产免费福利体检区久久| 国产福利电影一区二区三区久久久久成人精品综合 | 99久久国产综合精品网成人影院| 久久强奷乱码老熟女| 久久精品国产清高在天天线| 国产亚洲成人久久| 久久精品国产久精国产思思| 一级女性全黄久久生活片免费| 日本久久久久久中文字幕| 久久精品人妻中文系列| 久久国产精品二国产精品| 国产精品对白刺激久久久| 久久久噜噜噜久久中文字幕色伊伊| 亚洲嫩草影院久久精品| 久久亚洲私人国产精品| 日韩人妻无码一区二区三区久久99| 国产免费久久精品丫丫| 精品国产乱码久久久久久郑州公司| 一本综合久久国产二区| 久久精品国产清自在天天线| 国产成人精品久久免费动漫| 久久亚洲精品中文字幕| 久久无码AV中文出轨人妻| 久久精品视屏| 久久艹国产| 精品国产青草久久久久福利| 国产精品热久久无码av| 99精品久久久久久久婷婷| 国产精品久久精品| 久久久久久久99精品免费观看| 丰满少妇人妻久久久久久| 久久精品亚洲精品国产色婷| 天天躁日日躁狠狠久久| 亚洲国产一成人久久精品| 久久人人爽人人爽人人爽| 久久精品国产乱子伦| 五月丁香综合激情六月久久| 少妇久久久久久被弄高潮| 日韩人妻无码一区二区三区久久| 人妻无码久久一区二区三区免费| 亚洲精品无码久久久久|