目前分類:C++ (56)

瀏覽方式: 標題列表 簡短摘要

以下是C++ 詳細教學文章,使用的是免費的dev C++。

(dev C++之下載處在第一篇文章:基本輸入與輸出中有連結網址,或自行google亦可)

文章中藍色部分為程式碼,紅色部分為重點概念,

並附帶有範例,方便同學學習。

 

* 朋友們若是覺得本教學對您有幫助,請點個讚~

 

* 廣告:
C#、C++、javascript程式語言、演算法專業一對一真人教學,可採視訊模式、以及到府家教。
有意者請在18:00後電洽 0963-631226 黃先生,科目、學費、時間、教學模式均可談。

 

1. C++基礎教學與範例篇:

(1) 基本輸入與輸出

(2) 常用變數型態與矩陣

(3) if判斷式與邏輯運算子

(4) 迴圈

(5) 綜合範例

(6) 函數

(7) 二維矩陣

 

2. C++ 物件導向篇:類別(class)

(1) 結構 struct

(2) 類別 (class) 簡介

(3) 類別 建構式

(4) 類別 嵌入

(5) 類別物件陣列

(6) 建構式的初值設定列

(7) 常數物件

(8) mutable的用法

(9) 靜態變數和static的用法

(10) friend的用法

 

3. C++ 類別的繼承

(1) 類別的繼承

(2) 衍生類別的建構式

(3) 類別的多重繼承

(4) 衍生類別物件的複製

(5) 抽象類別 (abstract class)

 

4. C++檔案的讀寫(IO)

(1) 檔案讀寫 IO簡介

(2) 檔案讀寫 IO控制參數

(3) 檔案管理 輸出排版

(4) 檔案管理 輸出排版(2)

(5) 檔案讀寫

(6) 檔案輸入/輸出的定位

 

5. STL序列容器(vector, list)

(1) 向量 (vector)介紹

(2) 向量的操作

(3) 迭代器 iterator

(4) 向量的複製 

(5) 多維向量

(6) list介紹

(7) List的其他常用功能

 

6. template (樣板)

(1) template

(2) 多參數樣板函式

(3) 樣板類別

(4) 函式參數

 

7. C++ 其他常用功能

(1) 字串 string

(2) 子字串 substring

(3) C++ 亂數

(4) C++ Sleep

(5) C++ sizeof

(6) C++ 數學函數

(7) C++ goto

(8) C++ typedef

(9) C++ 用 typeid 查詢變數型態

(10) C++ 計時器

(11) C++ 變數型態轉換

(12) C++ 二維矩陣

 

 

 

 

按此前往程式語言教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(4) 人氣()

按此前往C++完整教學目錄

 

 

其他常用成員函式:

(1) 映射或複映射名稱.count(索引值);

回傳此與此索引值相對應的資料值的個數。對於映射而言,此回傳值最大為1

(2) 映射或複映射名稱.empty();

回傳一bool,若此映射複映射為空,則為true;若不為空,則為false

(3) 映射或複映射名稱.size();

回傳此容器之節點數。

(4-1) 映射名稱一.swap(映射名稱二);

映射互相對調節點

(4-2) 複映射名稱一.swap(複映射名稱二);

複映射互相對調節點

(5) 刪除資料:

(5-1) 映射或複映射名稱.erase(迭代器);

將迭代器所指的節點去除。無回傳值。

(5-2) 映射或複映射名稱.erase(索引值);

將具有此索引值節點去除。回傳去除節點的數目(對映射而言,最多為1)

(5-3) 映射或複映射名稱.erase(迭代器1,迭代器2);

迭代器1迭代器2之間的節點去除。無回傳值。

(5-4) 映射或複映射名稱.clear();

將此映射複映射清空。無回傳值。

文章標籤

埃伯 發表在 痞客邦 留言(3) 人氣()

按此前往C++完整教學目錄

 

 

找尋節點及其資料值

(1) 映射或複映射名稱.find(索引值);

可依照此索引值來找到相對應的節點,並且回傳此與此節點位址相對應的迭代器。注意:複映射也可以使用find()函數,但因複映射中一個索引值可能對應多個資料值,find()函數只能找到複映射中符合此索引值、而記憶位址最前面的節點,無法找到其他符合此索引值的節點,因此使用上需小心。範例:

class person

{

public:

string name;

int age;

person(string name_,int age_){

name=name_;age=age_;}

};

void show(person m)

{cout<<"我是"<<m.name<<",今年"<<m.age<<"歲。";}

 

int main(){  //主程式在此

person m1("維維",18);

person m2("小藍",19);

person m3("雅芯",24);

person m4("小杜",27);

person m5("木村靜香",17);

map<int,person> a;

a.insert(make_pair(85,m1));

a.insert(make_pair(90,m2));

a.insert(make_pair(77,m3));

a.insert(make_pair(82,m4));

a.insert(make_pair(77,m5));

 

show(a.find(85)->second);  //顯示:我是維維,今年18歲。

show(a.find(77)->second);  //顯示:我是雅芯,今年24歲。

}

(2) 映射或複映射名稱.equal_range(索引值);

可依照此索引值來找到相對應的節點,主要是針對複映射所用。會回傳一個成對結構,包含兩個迭代器,first為符合此索引值、而記憶位址最前面的節點之位址(稱為下限」,lower bound)second為符合此索引值、而記憶位址最後面的節點的下一個節點之位址(稱為上限」,upper bound)

例:

class person

{

public:

string name;

int age;

person(string name_,int age_){

name=name_;age=age_;}

};

void show(person m)

{ cout<<"我是"<<m.name<<",今年"<<m.age<<"歲。"<<endl;}

int main(){   //主程式在此

person m1("維維",18);

person m2("小藍",19);

person m3("雅芯",24);

person m4("小杜",27);

person m5("木村靜香",17);

 

multimap<int,person> ma;

multimap<int,person>::iterator i;

ma.insert(make_pair(85,m1));

ma.insert(make_pair(90,m2));

ma.insert(make_pair(77,m3));

ma.insert(make_pair(82,m4));

ma.insert(make_pair(77,m5));

 

for(i=ma.begin();i!=ma.end();i++)

{show(i->second);}

cout<<endl;

/* 顯示:

我是雅芯,今年24歲。

我是木村靜香,今年17歲。

我是小杜,今年27歲。

我是維維,今年18歲。

我是小藍,今年19歲。*/

 

show(ma.equal_range(77).first->second); //顯示:我是雅芯,今年24歲。

show(ma.equal_range(77).second->second); //顯示:我是小杜,今年27歲。

}

註:ma.equal_range(77).first為第一個迭代器,也就是下限ma.equal_range(77).second為第二個迭代器,也就是上限

 

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

 

映射(map)複映射(multimap)

(1) map以及multimap中,一個節點所存取的資料有兩種,一為索引(key),一為資料值(value)

(2) map中,一個索引只能對應一個資料值;而在multimap中,一個索引可以對應多個資料值。此二容器之中各節點的排列順序,是以索引的大小來做排列。預設是依索引的ASCII碼由小排到大。

(3) 使用者不能隨意修改某資料的索引,但可以修改某索引上的資料值。

(4) 一個映射或者複映射中,不容許兩個重複相同的索引。

(5) 資料值的資料型態,可為一般資料型態(intbool…)或是類別物件

(6) 無論使用映射還是複映射,均需在標頭檔寫下#include <map>

 

1. 建構:

映射種類<索引資料型態 , 資料的資料型態> 名稱;

映射種類<索引資料型態 , 資料的資料型態 , 雙元判斷式> 名稱;

註一:映射種類可為mapmultimap

註二:以上的第一種建構方法,其實是默認less<索引資料型態>雙元判斷式

 

 

2. 成對結構資料型態:成對結構(pair structure)C++內建的樣板結構,在建構映射和複映射時需要用到。成對結構有兩個成員:firstsecond,這兩個成員可以為不同的資料型態。建立一個成對結構有以下2種方法:

(1) pair<成員first的資料型態 , 成員second的資料型態> 成對結構名稱(成員first的值 , 成員second的值);

舉例:

pair<string , int> tt1("國文",98);  //建構一個成對結構tt1

pair<string , int> tt2("英文",60);  //建構一個成對結構tt2

cout<<tt1.first<<"考了"<<tt1.second<<"分。"<<endl;  //顯示:國文考了98分。

cout<<tt2.first<<"考了"<<tt2.second<<"分。"<<endl;  //顯示:英文考了60分。

(2)利用C++內建樣板函式make_pair()

pair<成員first的資料型態 , 成員second的資料型態> 成對結構名稱;

成對結構名稱 = make_pair(成員first的值 , 成員second的值);

舉例:

pair<string , int> tt1;

tt1=make_pair("國文",98);

pair<string , int> tt2;

tt2=make_pair("英文",60);

cout<<tt1.first<<"考了"<<tt1.second<<"分。"<<endl;  //顯示:國文考了98分。

cout<<tt2.first<<"考了"<<tt2.second<<"分。"<<endl;  //顯示:英文考了60分。

註:要將資料加入映射或者是複映射,必須先將資料轉換成成對結構。其中first對應索引second對應資料值

 

3. 將資料加入映射或複映射(需要使用上一篇所提到的「成對結構」)

(1)若要將資料加入映射,可使用:

(a)映射名稱.insert(成對結構名稱);

其中成對結構的成員first對應索引,成對結構的成員second對應資料。由於在映射中,一個索引只能對應一個資料,故若新加入的成對結構之first的值與映射中的某個索引值相同,則這個新加入的成對結構會被剔除掉,表示加入失敗了。

(b) 映射名稱.insert(迭代器 , 成對結構名稱);

由迭代器位址開始尋找適當的插入位址,以將成對結構加入映射

若加入成功,insert函式回傳此成對結構映射中的位址相應的迭代器。

(c) 映射名稱.insert(迭代器1 , 迭代器2);

迭代器1迭代器2之間(包含迭代器1、不包含迭代器2),的成對結構資料加入此映射,若新加入的成對結構之first的值與映射中的某個索引值相同,則這個新加入的成對結構會被剔除掉,即加入失敗的意思。

(2)若要將資料加入複映射,可使用:

(a)複映射名稱.insert(成對結構名稱);

其中成對結構的成員first對應索引,成對結構的成員second對應資料。

此函式會回傳一個迭代器,和新加入資料的位址對應。

(b) 複映射名稱.insert(迭代器 , 成對結構名稱);

由迭代器位址開始尋找適當的插入位址,以將成對結構加入複映射

並回傳此成對結構複映射中的位址相應的迭代器。

(c) 複映射名稱.insert(迭代器1 , 迭代器2);

迭代器1迭代器2之間(包含迭代器1、不包含迭代器2),的成對結構資料加入複映射

此函式無回傳值。

(3) 範例:

class person

{

public:

string name;

int age;

person(string name_,int age_)

{name=name_;age=age_;}

};

 

void show(person m){

cout<<"我是"<<m.name<<",今年"<<m.age<<"歲。";}

 

int main() {    //主程式在此

person m1("維維",18);

person m2("小藍",19);

person m3("雅芯",24);

person m4("小杜",27);

person m5("木村靜香",17);

 

map<int,person> a;

multimap<int,person> ma;

map<int,person> b;

multimap<int,person> mb;

map<int,person>::iterator i;

map<int,person>::iterator j;

   

a.insert(make_pair(85,m1));

a.insert(make_pair(90,m2));

a.insert(make_pair(77,m3));

a.insert(make_pair(82,m4));

a.insert(make_pair(77,m5));

      

ma.insert(make_pair(85,m1));

ma.insert(make_pair(90,m2));

ma.insert(make_pair(77,m3));

ma.insert(make_pair(82,m4));

ma.insert(make_pair(77,m5));

  

for(i=a.begin();i!=a.end();i++)

{

show(i->second);

cout<<"此次考試考了"<<i->first<<"分。"<<endl;

}

cout<<endl;

/* 顯示為(注意,最後一個加入的m5,是加入失敗的。)

我是雅芯,今年24歲。此次考試考了77分。

我是小杜,今年27歲。此次考試考了82分。

我是維維,今年18歲。此次考試考了85分。

我是小藍,今年19歲。此次考試考了90分。 */

 

for(i=ma.begin();i!=ma.end();i++)

{

show(i->second);

cout<<"此次考試考了"<<i->first<<"分。"<<endl;

}

cout<<endl;

/* 顯示為:

我是雅芯,今年24歲。此次考試考了77分。

我是木村靜香,今年17歲。此次考試考了77分。

我是小杜,今年27歲。此次考試考了82分。

我是維維,今年18歲。此次考試考了85分。

我是小藍,今年19歲。此次考試考了90分。*/

i=ma.begin();

j=ma.end();

j--; j--;

b.insert(i,j);

mb.insert(i,j);

for(i=b.begin();i!=b.end();i++)

{

show(i->second);

cout<<"此次考試考了"<<i->first<<"分。"<<endl;

}

cout<<endl;

/* 顯示為:

我是雅芯,今年24歲。此次考試考了77分。

我是小杜,今年27歲。此次考試考了82分。 */

for(i=mb.begin();i!=mb.end();i++)

{

show(i->second);

cout<<"此次考試考了"<<i->first<<"分。"<<endl;

}

cout<<endl;

/* 顯示為:

我是雅芯,今年24歲。此次考試考了77分。

我是木村靜香,今年17歲。此次考試考了77分。

我是小杜,今年27歲。此次考試考了82分。*/

}

// 註:以上均以分數為索引,可見資料是依分數由小排到大。

 

4. 下標運算子[]

映射可以和矩陣一樣,使用下標運算子[]來直接藉由索引存取資料值。如:

map<int , string> b;

b[85]="唐某";

b[116]="李某";  

cout<<b[85]<<endl;  //顯示:唐某

註:此種方法只有映射能用,對複映射而言,此法是沒有效果的。

 

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

 

集合(set)複集合(multiset)

 

集合、複集合的使用方法與成員函式幾乎相同,主要差別在於集合不允許元素間有重複的值(不允許已經存在於集合內的值,重複存入),而複集合則無此限制。

無論是使用集合或複集合,均須先在標頭檔處寫上:#include <set>

建構:

(1)  集合種類<資料型態> 名稱;

(1)  集合種類<資料型態 , 雙元判斷式> 名稱;

註一:集合種類可為setmultiset,資料型態可為一般資料型態或類別物件

註二:以上的第一種建構方法,沒有設定雙元判斷式,因此默認less<資料型態>雙元判斷式less<資料型態>C++內建的樣板函式,用來逐個比較集合內兩元素間,誰比較小。其結果使得無論是set還是multiset中的元素均會由小排到大。若元素資料型態非是數字,便直接比較ASCII大小,一樣由小排到大。

範例:

int tt[5] = {2,8,3,3,9};    

set<int> s1;     //建構一空集合

multiset<int> ms1;   //建構一空複集合

set<int> s2(tt,tt+5);   //建構一集合,存入矩陣tt中元素

multiset<int> ms2(tt,tt+5);   //建構一複集合,存入矩陣tt中元素

set<int , greater<int> > s3(tt,tt+5);  //建構一集合,存入矩陣tt中元素,且以C++內建樣板函式greater<資料型態>,來使集合元素由大排到小,不同於s2的由小排到大。

multiset<int, greater<int> > ms3(tt,tt+5);    //建構一複集合,存入矩陣tt中元素,且以C++內建樣板函式greater<資料型態>,來使複集合元素由大排到小,不同於ms2的由小排到大。

set<int>::iterator i;   //set的迭代器可與multiset共用。

 

for(i=s2.begin();i!=s2.end();i++){

cout<<*i<<","; }cout<<endl;  //顯示:2,3,8,9,

for(i=ms2.begin();i!=ms2.end();i++){

cout<<*i<<","; }cout<<endl;  //顯示:2,3,3,8,9,

for(i=s3.begin();i!=s3.end();i++){

cout<<*i<<","; }cout<<endl;  //顯示:9,8,3,2,

for(i=ms3.begin();i!=ms3.end();i++){

cout<<*i<<","; }cout<<endl;  //顯示:9,8,3,3,2,

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

介紹:

    1. 關聯容器(associative container)序列容器(sequence container)之不同在於,關聯容器中資料的值的特性,與其存放的位置有關。舉例來說,一整數關聯容器,其資料可能依照數值大小進行排列,因此數值大小(也是此資料的其中一種特性)便與存放的位置有關。這樣做的好處是,在搜尋資料時比較有效率,依照其特性搜尋,不用一個一個搜尋;不過在存放資料時較花功率,要將資料特性進行比對再存入。

    2. 關聯容器也是所謂的節點式容器」。容器的各個節點在記憶空間內不要求是連續的,且只能用雙向迭代器在節點之間逐步移動,沒辦法直接用引數(或稱索引)存取。

    3. 關聯容器分為:集合(set)複集合(multiset)映射(map)複映射(multimap)。說明如下篇。

    4. 所有關聯容器的均有逆向迭代器常數迭代器,宣告方式與串列容器一樣,如:容器種類名稱<資料型態>::迭代器名稱;

    其中容器種類名稱可為:setmultisetmapmultimap

    亦均有:begin()end()rbegin()rend() 這些成員函式。

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

有時,設計者須把函式當作參數,輸入進其他函式中,以方便「在函式中執行函式」。比如以函式A」做為「函式B的輸入參數」,可使程式碼的撰寫更方便。這需要透過一個所謂的「函式指標」。

(1)

class point  //宣告一類別point

public:

int x,y;

point(int x_,int y_){x=x_;y=y_;}};

   

void special_move1(point &P) //宣告一函式special_move1

              if(P.x>=P.y){P.y++;cout<<"this point go up to "<<P.x<<","<<P.y<<endl;}

              else{P.x++;cout<<"this point go right to "<<P.x<<","<<P.y<<endl;}

}

void special_move2(point &P) //宣告一函式special_move2

{

              if(P.y>0){P.y=-(P.y+1);}

              else {P.y=-(P.y-1);}

              if(P.x>0){P.x=-(P.x+1);}

              else {P.x=-(P.x-1);}

              cout<<"this point go to "<<P.x<<","<<P.y<<endl;

}

void move_n_step(point& P1,void (*f)(point&),int n)

{ //宣告一函式move_n_step,其輸入參數列可以輸入一個函式,這個輸入函式的回傳值為void,輸入參數型別為point&。用 回傳值 (*自訂函式指標)(輸入參數型別) 代表此一輸入函式。

              for(int i=0;i<n;i++)

            {(*f)(P1);}  //(*自訂函式指標)(輸入參數型別) 來執行輸入函式。

          }

}; 

 

int main(int argc, char *argv[]) //主程式在此

point P1(1,1);

move_n_step(P1,special_move1,10);

move_n_step(P1,special_move2,10);

}

註:自訂函式指標只要是英文字母開頭就可以,如:QK1jackbbbddd12345,隨設計者高興。

(2) 如果嫌上述寫法過於麻煩,也可以用樣板的方式撰寫,將上述:

void move_n_step(point& P1,void (*f)(point&),int n)

{

     for(int i=0;i<n;i++)

     {(*f)(P1);}

}

改成:

template<class Q1>

void move_n_step(point& P1,Q1 f , int n)

{

     for(int i=0;i<n;i++)

     {(*f)(P1);}

}  

其餘完全不用更改,便可達到相同的執行效果。

 

 

上一篇:樣板類別

下一篇:字串(string)

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

 

樣板類別:有些類別,其類別成員也是個類別物件,但其具體的型態是在建構時才能確定的。我們可以先宣樣板參數型別,然後利用此樣板參數型別宣告類別成員的資料形態。範例如下:

class jewelry // 建立一類別jewelry

{        

public:

    int price;

    string kind;

    jewelry(){}  //類別jewelry的備用建構式

    jewelry(string kind_,int price_)

{kind=kind_;price=price_;}

};

 

class car  // 建立一類別car

    public:

    int price;

    string kind;

    car(){}  //類別car的備用建構式

    car(string kind_,int price_)

{kind=kind_;price=price_;}

};

     

class art  // 建立一類別art

    public:

    int price;

    string kind;

    art(){}  //類別art的備用建構式

    art(string kind_,int price_)

{kind=kind_;price=price_;}

};

 

template <class Q>  //宣告樣板參數型別Q

class person   //建立樣板類別person

{

    public:

    string name;

    Q item;   //不定型別的類別成員,可以是jewelry, car或是art

    person(string name_,Q item_){name=name_;item=item_;}

    void get_item()

{cout<<name<<" have a "<<item.kind<<" worth "<<item.price<<endl;}

};

 

int main()  //程式在此

jewelry j1("ruby",500);

car c1("ford",600);

art a1("paint",700);

person<art> person1("thurmo",a1);  //建構樣板類別物件樣板類別名稱<欲指定的樣板參數型別> 樣板類別物件名稱 建構式

person1.get_item();  //顯示:thurmo have a paint worth 700

}

註一:以上例而言,若欲指定的樣板參數型別是個類別,則該類別一定要有備用建構式。否則會造成編譯錯誤。

註二:若某一類別是樣板類別,則要做一函式,其輸入參數是此樣板類別物件,則此函式的寫法應該是(以上例來看)

template <class Q>

void print_name(person<Q> p){cout<<p.name;} //函式當然應該定義在主程式之外

也就是說,在函式宣告之前應先宣告樣板參數型別,而類別名稱後也該加入樣板參數型別

 

 

上一篇:多參數樣板函式

下一篇:函式參數

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

 

多參數樣板函式:可以宣告多個樣板參數型別,讓一個樣板函式可以輸入多個樣板參數,如:

class jewelry // 建立一類別jewelry

{          

    public:

    int price;

    string kind;

    jewelry(string kind_,int price_){kind=kind_;price=price_;}

};

 

class car  //建立一類別car

{   

    public:

    int price;

    string kind;

    car(string kind_,int price_){kind=kind_;price=price_;}

};

     

class art  //建立一類別art

{          

public:

    int price;

    string kind;

    art(string kind_,int price_){kind=kind_;price=price_;}

};

 

template <class X, class Y>   //告樣板參數型別X,Y

void which_is_more_valuable(X x,Y y) //宣告樣板函式which_valuable

{       

if(x.price>y.price){cout<<x.kind<<" is valuable than "<<y.kind<<endl;}

    else if(x.price<y.price){cout<<y.kind<<" is valuable than "<<x.kind<<endl;}

    else {cout<<"same";}

}

 

int main()  //主程式在此

{   

jewelry j1("ruby",500);

car c1("ford",600);

art a1("paint",700);

which_is_more_valuable (j1,c1);  //顯示:ford is valuable than ruby

which_is_more_valuable (a1,c1);  //顯示:paint is valuable than ford 

}

由以上可知,樣板函式which_is_more_valuable可以輸入兩個樣板參數,而且不限所輸入的參數型別,此乃樣板函式之功效所在。

 

 

上一篇:template

下一篇:樣板類別

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

 

樣板函式樣板參數型別

使用時機:程式設計者需要設計好幾個函式,有時,這些函式除了輸入的參數型別或回傳型別不同外,其函式內容是相同的。為了避免重複撰寫同樣的函式內容,這時就可以利用樣板函式,避免浪費時間,也可簡化程式的寫法。說明如下:

利用以下程式碼宣告樣板參數型別:

template <class 樣板參數型別>   //這裡的class,指的不是類別,而是樣板參數型別

或是:

template <typename 樣板參數型別>

註一:其中,樣板參數型別是自訂的代號,只要是英文字母開頭就可以。如:QK1jackbbbddd12345,隨設計者高興。

註二:上述,一定要寫在主程式之外

利用宣告樣板參數型別,可以建立樣板函式。舉例:

template <typename Q12>   //宣告樣板參數型別Q12

void test(Q12 q) //建立樣板函式test

{     

     for(int i=0;i<2;i++){cout<<q<<endl;}

}

int main( )    //主程式在這裡

{

test("test,"); 

        test(5);

}

輸出結果為:

test,

test,

5

5

從以上可以知道,函式test的輸入參數是不限型別的,任何型別都可以輸入進去。上例說明了stringint都能輸入進去,這樣就不用為stringint各寫一個函式,此乃樣板函式的效用所在。

 

 

上一篇:list的其他常用功能

下一篇:多參數樣板函式

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

 

List的其他功能(排序、合併、切割、反轉、對換)

範例如:

bool sort1(int x,int y)

{

return x%10<y%10;

}

bool u1(int x,int y)

{

return x%10==y%10;

}

int main(int argc, char *argv[])

{   //主程式在此

int tta[5]={25,55,55,34,90};

int ttb[5]={34,22,12,17,49};

list<int> a(tta,tta+5), b(ttb,ttb+5);

list<int>::iterator i,j,k;

for(i=a.begin();i!=a.end();i++)

{

cout<<*i<<",";

}

cout<<endl;   //顯示:25,55,55,34,90,

for(i=b.begin();i!=b.end();i++)

{

cout<<*i<<",";

}

cout<<endl;    //顯示:34,22,12,17,49,

[操作程式碼 // 以下有範例說明

for(i=a.begin();i!=a.end();i++)

{

                  cout<<*i<<",";

}

cout<<endl;  //顯示結果一

for(i=b.begin();i!=b.end();i++)

{

cout<<*i<<",";

}

cout<<endl;    //顯示結果二

}

(1) 排序:將串列元素由小排到大。例若[操作程式碼]a.sort();,顯示結果一為25,34,55,55,90,

(2) 有條件的排序:[操作程式碼]為:串列名稱.sort(雙元判斷式);,則會從串列的第1個位置開始,將第1個位置的元素和第1+1個位置的元素放入雙元判斷式,回傳true則第1個位置的元素、第1+1個位置的元素兩者位置對調,回傳false則不更動。然後再如法炮製將第2、第2+1個元素放入雙元判斷式,再將第3、第3+1個元素放入雙元判斷式在將第n、第n+1個元素放入雙元判斷式

例如:操作程式碼為:a.sort(sort1);,顯示結果為:90,34,25,55,55,

(3) 排序合併:可將一串列併入另一串列。若兩串列都經sort()排序,則合併出的串列排序法也經sort()排序。例若[操作程式碼]為:

a.sort();b.sort();

a.merge(b);

顯示結果一為:12,17,22,25,34,34,49,55,55,90,

顯示結果二為:                         //空無一物

註:若兩者沒有使用排序法,也可合併。不過合併結果便無排序法。

(4) 有條件的排序合併:若兩串列使用的條件排序規則(雙元判斷式)相同,使用串列名稱一.merge(串列名稱二 , 雙元判斷式);,則將串列二合併入串列一,並且合併後依照相同的條件排序規則。

例若[操作程式碼]為:

a.sort(sort1);b.sort(sort1);

a.merge(b,sort1);

顯示結果一為:90,22,12,34,34,25,55,55,17,49,

顯示結果二為:                         //空無一物

(5) 切割搬移串列元素的第一種方法:[操作程式碼]為:串列名稱一.splice(迭代器一 , 串列名稱二 , 迭代器二);,則將串列二在迭代器二位址上的元素,切割下來、並搬移到串列一在迭代器一的位址。例若操作程式碼為:

i=a.begin();i++;

j=b.begin();j++;

a.splice(i,b,j);

顯示結果一為:25,22,55,55,34,90,

顯示結果二為:34,12,17,49,

(6) 切割搬移串列元素的第二種方法:[操作程式碼]為:串列名稱一.splice(迭代器一 , 串列名稱二 , 迭代器二 , 迭代器三);,則將串列二在「迭代器二位址到迭代器三位址」之間的元素,切割下來、並搬移到串列一在迭代器一的位址。例若操作程式碼為:

i=a.begin();i++;

j=b.begin();j++;

k=b.end();k--;

a.splice(i,b,j,k);

顯示結果一為:25,22, 12,17,55,55,34,90,

顯示結果二為:34, 49,

(7) 切割搬移串列元素的第三種方法:[操作程式碼]為:串列名稱一.splice(迭代器一 , 串列名稱二);,則將串列二整個切割下來、並搬移到串列一在迭代器一的位址。例若操作程式碼為:

i=a.begin();i++;

a.splice(i,b);

顯示結果一為:25,34,22,12,17,49,55,55,34,90,

顯示結果二為:                         //空無一物

(8) 倒轉串列元素次序:例若[操作程式碼]為:a.reverse();

顯示結果一為:90,34,55,55,25,

(9) 與其他串列整個對換:例若[操作程式碼]為:a.swap(b);

顯示結果一為:34,22,12,17,49,

顯示結果二為:25,55,55,34,90,

(10) 將此串列內,位址相鄰且值相同的元素合併為單一元素:例若[操作程式碼]為:a.unique();

顯示結果一為:25,55,34,90,

(11)若操作程式碼為:串列名稱. unique (雙元判斷式);,則會從串列的第1個位置開始,將第1個位置的元素和第1+1個位置的元素放入雙元判斷式,回傳true則第1個位置的元素、第1+1個位置的元素兩者合併為單一元素,回傳false則不更動。然後再如法炮製將第2、第2+1個元素放入雙元判斷式,再將第3、第3+1個元素放入雙元判斷式在將第n、第n+1個元素放入雙元判斷式

例若[操作程式碼]為:a.unique(u1);

顯示結果一為:25,34,90,

 

 

上一篇:list

下一篇:樣板(template)

文章標籤

埃伯 發表在 痞客邦 留言(2) 人氣()

按此前往C++完整教學目錄

 

* 朋友們若是覺得本教學對您有幫助,請點個讚~

 

串列(list)

為使用雙鍊結串列(double linked list)資料結構設計而成的容器。每個元素有其相對應的「節點」,節點之中儲存元素的值,還有兩個指標:指向上一個節點的記憶位址、下一個節點的記憶位址。串列中節點的記憶位址並不需要相鄰,在呼叫串列的某元素時,是從串列的第一個節點開始,一個節點一個節點的連接,因此無法用 串列名稱[n] 來呼叫序數為n的元素。以下是雙鍊結串列的示意圖:

image

 

1. 欲使用串列時,需在標頭檔內寫下#include <list>

2.

(1) 串列的建構與向量、佇列同,如:list<int> a; 等等。

串列的元素,亦可以一般資料形態或物件(同樣,若是物件,則類別或結構應寫在主程式之前)

(2) 串列迭代器的宣告與向量、佇列同,如:list<int>::iterator i; 等等。

串列迭代器必須使用i++的方式,跳到下一個元素位址。若是使用i=i+1;,因串列中元素未必各個相鄰,故可能造成錯誤。

(3) push_backpop_backbeginendrbeginrendsizeresizeclearempty這些成員函式的用法皆同於向量(請看向量篇教學)。

 

3. 插入與移除元素:

bool even(int x)

{

if(x%2==0)return true;

else return false;

}

 

int main(int argc, char *argv[]) //主程式在此

int tt[9]={1,2,3,4,5,6,7,8,9};   

list<int> a(tt,tt+9);    //tt中,「tt初始元素位置」到「初始後第九個元素位置」的元素都複製給a

list<int>::iterator I,j,k;

for(i=a.begin();i!=a.end();i++)

{cout<<*i<<",";}cout<<endl;   //顯示:1,2,3,4,5,6,7,8,9,

[操作程式碼 //以下有說明

for(i=a.begin();i!=a.end();i++)

{cout<<*i<<",";}cout<<endl;   //最終結果顯示

(1) [操作程式碼]為:串列名稱.remove(資料值),則會把串列中符合此值的資料都移除掉。如:a.remove(2);,最終結果顯示為1,3,4,5,6,7,8,9,

(2) 所謂「真假判斷式」,指的是回傳bool值的函式。若此回傳bool值的函式輸入參數只有一個,稱之為「單元判斷式」;若此回傳bool值的函式輸入參數有二個,稱之為「雙元判斷式」;以此類推。

[操作程式碼]為:串列名稱.remove_if(單元判斷式名稱),則會把串列中的值代入此單元判斷式,符合此單元判斷式的資料都移除掉。如:a.remove_if(even);,最終結果顯示為1,3,5,7,9,

(3) [操作程式碼]為:串列名稱.erase(迭代器),則會把迭代器所指的元素給刪除,並回傳被移除元素後一個節點位址的迭代器。如:

j=a.begin();

j=j++;

a.erase(j);

最終結果顯示為:2,3,4,5,6,7,8,9,

(4) [操作程式碼]為:串列名稱.erase(迭代器1 , 迭代器2),則會把兩迭代器之間的元素給刪除,並回傳最後被移除元素之後一個節點位址的迭代器。如:j=a.begin();

j=j++;

k=a.end();

k--;

k--;

a.erase(j,k);

最終結果顯示為:8,9,

(5) [操作程式碼]為:串列名稱.insert(迭代器 , ),則會在迭代器所指的位址上,加入此值元素,並回傳此新元素位址的迭代器。如:

j=a.begin();

j=j++;

a.insert(j,10);

最終結果顯示為:10,1,2,3,4,5,6,7,8,9,

(6) [操作程式碼]為:串列名稱.insert(迭代器 , 非負整數N , ),則會在迭代器所指的位址上,加入N個此值元素。如:

j=a.begin();

j=j++;

a.insert(j,3,10);

最終結果顯示為:10,10,10,1,2,3,4,5,6,7,8,9,

(7) [操作程式碼]為:串列名稱.insert(迭代器1 , 迭代器2, 迭代器3),則會將該串列從迭代器2到迭代器3之間的元素複製並且插入迭代器1的位址。如:i=a.begin();

j=a.begin();

k=a.end();

i++; j++; j++; j++; k--;

a.insert(i,j,k);

最終結果顯示為:1,4,5,6,7,8,2,3,4,5,6,7,8,9,

評:因串列元素資料的記憶空間位址並非緊鄰,故不可用i=i+n(n為整數)來直接指定迭代器位址,而要靠i++i--來逐項移動。

 

 

上一篇:多維向量

下一篇:list的其他常用功能

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

 

多維向量

容器中存放的元素,也可以是一種容器。如向量以向量為元素,佇列以佇列為元素。不同種類的容器亦可為元素,如向量以佇列為元素,佇列以串列為元素。被當成元素的容器,其長度不需要一樣長。

示範二維向量,如下程式碼:

vector<int> a;          //建構儲存整數的向量

vector< vector<int> > Agroup;    //建構儲存向量的向量

for(int i =1;i<=9;i++)

{

a.push_back(i);

Agroup.push_back(a);

}

for(int i=0;i<Agroup.size();i++)

{

for(int j=0;j<Agroup[i].size();j++)

{

cout<<Agroup[i][j]<<" ";

}       //可用 二重向量名稱[i][j] 呼叫二重向量的值

cout<<endl;
}

/*  顯示結果為:

1

1 2

1 2 3

1 2 3 4

1 2 3 4 5

1 2 3 4 5 6

1 2 3 4 5 6 7

1 2 3 4 5 6 7 8

1 2 3 4 5 6 7 8 9

*/

註:三維、四n向量都是可以建構的。

 

 

上一篇:向量的複製

下一篇:list

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

 

向量的複製:

vector<int>::iterator h;

vector<int> a;      //建構向量a

for(int i=0;i<10;i++)

{

a.push_back(i);

}

vector<int> b(a);   //將向量a複製給向量b

vector<int> c=a;   //將向量a複製給向量c

vector<int> d(a.begin()+4,a.begin()+7);  //將向量a的第567個元素複製給向量d

 

for( h=b.begin();h!=b.end();h++)

{cout<<*h;}

cout<<endl;  //顯示0123456789

for( h=c.begin();h!=c.end();h++)

{ cout<<*h;}

cout<<endl;  //顯示0123456789

for( h=d.begin();h!=d.end();h++)

{cout<<*h;}

cout<<endl;  //顯示456

註:亦可將矩陣的資料內容複製給向量。

 

 

上一篇:迭代器 iterator

下一篇:多維向量

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

 

迭代器(iterator)

(1) 迭代器是一種資料形態,其意義為記憶空間位址,使用方法如指標。向量可使用迭代器來呼叫其元素,如:

vector<int> a;    //建構整數向量a

vector<int>::iterator h;   //宣告一整數向量迭代器h

for(int i=0;i<10;i++){

a.push_back(i);}

for( h=a.begin();h!=a.end();h++){

cout<<*h;}    //顯示0123456789

cout<<endl<<*(h-1);     //顯示9

cout<<endl<<*(h-2);     //顯示8

cout<<endl<<*(h-3);     //顯示7

註一:a.begin()是記憶空間位址,表示向量a首位元素的記憶空間位址。a.end()也是記憶空間位址,表示向量a末位元素的下一個記憶空間位址。

註二:h也是記憶空間位址,*h表示此記憶空間所指的資料。

註三:h++表示h跳到下一個元素的記憶空間位址。

(2) 上述所言的迭代器乃是正向迭代器,順序由前到後。還有一種迭代器為逆向迭代器,順序由後到前。正向迭代器和逆向迭代器為不同的資料形態。

int tt[]={1,2,3,4,5};   //宣告整數矩陣tt

vector<int> a(tt,tt+5);  //tt的第一個元素到第五個元素複製給整數向量a

vector<int>::reverse_iterator i;  //宣告整數向量逆向迭代器i

for(i=a.rbegin();i!=a.rend();i++){

cout<<*i;}  //顯示54321

註一:a.rbegin()是記憶空間位址,表示向量a首位元素的前一個記憶空間位址。a.rend()也是記憶空間位址,表示向量a末位元素的記憶空間位址。

圖示:此乃向量a,灰色代表有元素占據的記憶空間,白色則為空白空間。

image

註二:i++表示i跳到下一個記憶空間位址,因是逆向迭代器,故位址應為前一個元素。

(3) 所謂的常數迭代器,宣告方式例如:vector<int>::const_iterator I;。其功用與一般迭代器幾乎相同,惟一不同者在於:常數迭代器僅只能對容器中資料進行「讀取」的動作,而無法存入或更改其值。也需注意,我們無法將常數迭代器的值指派給其他迭代器,沒事少用常數迭代器。

 

 

上一篇:向量的操作

下一篇:向量的複製

文章標籤

埃伯 發表在 痞客邦 留言(1) 人氣()

按此前往C++完整教學目錄

 

 

向量的存取與操作:

(1) 將資料值存取入向量的尾端:

向量名稱.push_back(資料值);

(2) 將向量尾端的資料值刪除:

向量名稱.pop_back();

(3) 回傳向量元素個數:

向量名稱.size();

(4) 利用序數直接呼叫向量中第n個元素:

cout<<向量名稱[n];  //例:

vector<int> a;

for(int i=0;i<10;i++){

a.push_back(i);}

cout<<a[0];  //顯示0

(5) 利用at函式讀取向量中第n個元素:向量名稱.at(元素序數)

vector<int> a;

a.push_back(10);

a.push_back(15);

a.push_back(20);

cout<<a.at(1);  //顯示15

cout<<a.at(3);  //序數3超過了向量a最大的序數,造成執行錯誤

(6) 利用swap函數將兩向量對調:向量名稱1.swap(向量名稱2)

vector<int> a(5,1) ,b(5,2);

for(int i=0;i<5;i++){

cout<<a.at(i);}cout<<endl;   //顯示11111

for(int i=0;i<5;i++){  

cout<<b.at(i);}cout<<endl;   //顯示22222

a.swap(b);   //將向量a和向量b對調

for(int i=0;i<5;i++){

cout<<a.at(i);}cout<<endl;   //顯示22222

for(int i=0;i<5;i++){

cout<<b.at(i);}cout<<endl;   //顯示11111

(7) 利用front函式和back函式存取一向量的首位或末位元素:

vector<int> a(5,1);

a.front()=6;   

a.back()=9;

cout<<a.front()<<endl;   //顯示6

cout<<a.back()<<endl;   //顯示9

for(int i=0;i<5;i++){

cout<<a.at(i);}cout<<endl;   //顯示61119

(8) 將向量所有元素都移除,使向量清空成為空向量:

向量名稱.clear();

確認向量是否為空向量:

向量名稱.empty();  //回傳布林值

(9) 強迫向量改變長度:

vector<int> a(10,1);   //向量a長度為10個元素,每個值都是1

a.resize(6);    //向量a長度為6個元素,每個值都是1,有4個元素被強迫刪除。

a.resize(16,2);  //向量a長度為16個元素,前六個值是1,後十個新增的值為2

(10) 指定向量位置,插入消除元素(關於迭代器(iterator),請參看迭代器篇)

vector<int>::iterator i;

vector<int> a , b;

b.push_back(6);b.push_back(7);

for(int k=1;k<6;k++)a.push_back(k);

for(i=b.begin();i!=b.end();i++){

cout<<*i;}cout<<endl;    //顯示 67

for(i=a.begin();i!=a.end();i++){

cout<<*i;} cout<<endl;    //顯示12345

[操作程式碼]

for(i=a.begin();i!=a.end();i++){

cout<<*i;} cout<<endl;   //結果顯示

插入函式1向量名稱.insert(開始插入的迭代器位址 , )

[操作程式碼]a.insert(a.begin()+2,9);,結果顯示為129345

插入函式2向量名稱.insert(開始插入的迭代器位址 , 欲插入的元素個數 , )

[操作程式碼]a.insert(a.begin()+2,3,9);,結果顯示為12999345

插入函式3,可將其他向量切下複製、插入此向量內:向量名稱.insert(開始插入的迭代器位址 , 其他向量被切下之元素的首位迭代器位址 , 其他向量被切下之元素的末位迭代器位址(本身不包含) )

[操作程式碼]a.insert(a.begin()+2,b.begin(),b.end());,結果顯示為1267345

消除函式1向量名稱.erase(欲消除元素的迭代器位址)

[操作程式碼]a.erase(a.begin()+3);,結果顯示為1235

消除函式1向量名稱.erase(欲消除元素的首位迭代器位址 , 欲消除元素的末位迭代器位址(本身不包含) )

[操作程式碼]a.erase(a.begin()+1, a.end()-1);,結果顯示為15

(11)向量排序:

利用函式:sort(記憶空間位址一 , 記憶空間位址二); 將兩記憶空間之間的元素排序(預設為升序排序,也就是由小到大)。例:

int tta[10]={24,13,8,1,67,89,2,13,6,27};

vector<int> a(tta,tta+10);

vector<int>::iterator i;

sort(a.begin(),a.end()-1);    //a.begin()a.end()-1之間的元素按升序排序

for(i=a.begin();i!=a.end();i++){

cout<<*i<<",";}    //顯示結果為:1,2,6,8,13,13,24,67,89,27,

 

 

上一篇:向量

下一篇:迭代器 iterator

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

 

1. 欲使用向量,必須先在標頭檔寫入 #include <vector>

2. 在記憶空間上,向量的每個元素之間所佔的記憶空間是相鄰的(這點和矩陣相同)。但為使向量可以隨時加入元素,一個向量所使用的記憶空間便不是恆定的。

  向量所佔有的記憶空間分為兩種:一為既用空間,即向量既有元素所佔有的空間。一為預留空間,即向量在建構時預留給元素用的空間(既用空間+尚未用到的空間)。若加入的元素溢出了預留空間,系統會自動將向量搬移至與更多空白空間連接的空間,並且增加預留空間以供更多元素加入。

 

3. 向量的建構有許多方式:

vector<資料形態> 向量名稱 //建構向量,但不設向量大小與初始值

vector<資料形態> 向量名稱(n) ;  //建構向量,設向量大小為可容納n個元素

vector<資料形態> 向量名稱(n, 資料值) ;  //建構向量,設向量大小為可容納n個元素,且每個元素都是資料值。如:vector<int> V1(10, 5); vector<char> V2(10,’a’)

註:資料型態不只可為一般常見的資料形態,如intstringbooldouble…等,也可以為結構物件或者類別物件。不過物件必須寫在主程式之前:

class person //建構類別person

{   

public:

string name;

int age;

person(string name_,int age_,int money_)

{name=name_;age=age_; money = money_;}

private:

int money;

};

 

void main( ){  //主程式在此

person person1("wiewie",18,2000);

person person2("nunu",19,2500);

person person3("ting",23,1800);

vector<person> a;   //建立存放person物件的向量a

vector<person>::iterator i;  //宣告存放person物件之向量的迭代器i(請參看迭代器篇)

a.push_back(person1);

a.push_back(person2);

a.push_back(person3);

for(i=a.begin();i!=a.end();i++)

{cout<<(*i).name<<",";}  //顯示:weiwei,nunu,ting,

}

註一:cout<<(*i).name<<",";若是寫成cout<<*i.name<<",";,編譯器會以為是cout<<*(i.name)<<",";,即會發生編譯錯誤。

註二:二維向量之宣告法為:

vector< vector<資料形態> > 向量名稱;

要注意的是,>>必須要用空白字元隔開,如果寫成>>,編譯器會以為這是輸入運算子,而產生錯誤。

 

 

上一篇:檔案輸入輸出的定位

下一篇:向量的操作

文章標籤

埃伯 發表在 痞客邦 留言(4) 人氣()

按此前往C++完整教學目錄

 

 

輸入/輸出物件的定位:

(1) 輸入物件名稱.seekg(n); 設定輸入物件由字元位置n開始讀取。n為整數,

亦可以用以下三者(又稱ios_base::seekdir列舉型別變數)來設定:

ios_base::beg //輸入資料串流中的起始位置

ios_base::cur //輸入資料串流中的目前位置

ios_base::end //輸入資料串流中的終端位置

例如:

若在C++編譯軟體安裝的目錄或者是特定的工作區底下,有tt.txt檔,內容為:

12345

而程式碼如:

string a;

ifstream fin("tt.txt");

fin.seekg(ios_base::beg+2);

fin>>a;

fin.close();

cout<<a;   //顯示為345

(2) 輸入物件名稱.seekg(n , ios_base::seekdir列舉型別變數); 設定由ios_base::seekdir列舉型別變數的位置相對n個位置的地方開始讀取。其中n為整數。例如:

若在C++編譯軟體安裝的目錄或者是特定的工作區底下,有tt.txt檔,內容為:

12345

而程式碼如:

string a;

ifstream fin("tt.txt");

fin.seekg(-2,ios_base::end);

fin>>a;

fin.close();

cout<<a;  //顯示45

(3) 輸出物件名稱.seekp(n); 設定輸出物件由字元位置n開始存入。n為整數,

或是ios_base::seekdir列舉型別變數但需注意,此方法會覆蓋原本檔案中的內容,沒事少用。如:

若在C++編譯軟體安裝的目錄或者是特定的工作區底下,有tt.txt檔,內容為:

12345

而程式碼如:

ofstream fout("tt.txt");

fout.seekp(3);

fout<<"aa";

fout.close();

tt.txt檔中內容為:

   aa

前三格是空格。

(4) 輸出物件名稱.seekp(n , ios_base::seekdir列舉型別變數); 設定由ios_base::seekdir列舉型別變數的位置相對n個位置的地方開始輸出。其中n為整數。

在資料處理上,以上對檔案的存取方式,稱為隨機存取檔(random-access file)或者是直接存取檔(direct-access file)。意即,程式直接跳到檔案的某位置進行存取,不似傳統方法要一個一個位置、逐項找到該位置再進行存取(稱為循序檔(sequence file))。

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

* 朋友們若是覺得本教學對您有幫助,請點個讚~

 

檔案的輸入與輸出:

資料過大時,利用檔案來管理輸入和輸出是較好的選擇。

ofstream 類別物件可以用來管理檔案的輸出。

ifstream 類別物件可以用來管理檔案的輸入。

以上兩者在使用時,需在標頭檔上加入#include <fstream>

(1)利用建構式建立ofstream物件:

(1-1)

ofstream 檔案輸出物件名稱;

檔案輸出物件名稱.open(“檔案路徑名稱” , 檔案設定參數); //開啟路徑名稱中的檔案,並且利用參數選擇開啟的方法

以下是常用的檔案設定參數

ios_base::in

開啟檔案準備輸入

ios_base::out

開啟檔案準備輸出

ios_base::app

將欲輸出的資料接在檔案內容的終端

ios_base::ate

開啟檔案並移到檔案內容尾端

ios_base::binary

以二位元方式輸入/輸出檔案

ios_base::trunc

將檔案內容清空

ios_base::nocreate

如路徑上的檔案不存在,則不執行開啟

ios_base::noreplace

如路徑上的檔案存在,則不執行開啟

註:對於檔案輸出物件而言,成員函式open的第二個參數預設為ios_base::out。即:

ofstream 檔案輸出物件名稱;

檔案輸出物件名稱.open(“檔案路徑名稱” ); //這一行相當於檔案輸出物件名稱.open(“檔案路徑名稱” , ios_base::out);

(1-2)更方便的建構式:

ofstream 檔案輸出物件名稱(“檔案路徑名稱” , 檔案設定參數);

註一:ofstream 檔案輸出物件名稱(“檔案路徑名稱”);這一行相當於ofstream 檔案輸出物件名稱(“檔案路徑名稱” , ios_base::out);

註二:若想在同一行輸入兩個以上的檔案設定參數,可使用 | 運算子:

ofstream 檔案輸出物件名稱(“檔案路徑名稱” , 檔案設定參數一 | 檔案設定參數二 | 檔案設定參數三);

(2)利用建構式建立ifstream物件:

(2-1)

ifstream 檔案輸入物件名稱;

檔案輸入物件名稱.open(“檔案路徑名稱” , 檔案設定參數); //開啟路徑名稱中的檔案,並且利用參數選擇開啟的方法。檔案設定參數同上。

對於檔案輸入物件而言,成員函式open的第二個參數預設為ios_base::in。即:

ifstream 檔案輸入物件名稱;

檔案輸入物件名稱.open(“檔案路徑名稱” ); //這一行相當於檔案輸入物件名稱.open(“檔案路徑名稱” , ios_base::in);

(1-2)更方便的建構式:

ifstream 檔案輸入物件名稱(“檔案路徑名稱” , 檔案設定參數);

註一:ifstream 檔案輸入物件名稱(“檔案路徑名稱”);這一行相當於ifstream 檔案輸入物件名稱(“檔案路徑名稱” , ios_base::in);

註二:若想在同一行輸入兩個以上的檔案設定參數,可使用 | 運算子:

ifstream 檔案輸入物件名稱(“檔案路徑名稱” , 檔案設定參數一 | 檔案設定參數二 | 檔案設定參數三);

註三(非常重要):檔案路徑與名稱是個字串,若用變數A來儲存,則A的變數型態只能是傳統字串,並不能是C++字串。

傳統字串宣告方式:

(1) char A[]=”字串值”;

(2) char* A=”字串值”;

若是使用C++字串來宣告,則必須將其轉型為傳統字串,即利用成員函式c_str()

string A=”字串值”;

A.c_str(); //此函式回傳A的傳統字串型式

 

(3)正式執行輸出資料給檔案、從檔案輸入資料的動作,仍是由<<>>這兩個運算子值執行。程式碼例如:

ofstream c1("ttaa.txt");

c1<<"aaa";  //C++編譯軟體安裝的目錄或者是特定的工作區底下,建立一個ttaa.txt檔,其中內容為aaa

c1.close();  //關閉ttaa.txt檔案

string test;

ifstream c2("ttaa.txt"); 

c2>>test;  //ttaa.txt檔的內容輸入給字串test

c2.close();  //關閉ttaa.txt檔案

cout<<test;  //顯示aaa

註一:檔案路徑名稱為ttaa.txt,表示在C++編譯軟體安裝的目錄或者是特定的工作區底下,開啟一個名叫ttaatxt文字檔。如果ttaa.txt本來並不存在,則會自動建立並且開啟。

註二:如要開啟其他路徑下的檔案,則必須輸入全部路徑名。如:C:/test_directory/test.txt D:/game/save/data1.txt 等等。

註三:如沒執行c1.close()c2.close(),可能造成最後的結果無法顯示。

(4)管理、分配檔案內容。

若有tt.txt檔,其內容為:

11111

22222

33333

44444

55555

66666

則撰寫程式碼如:

string test;

ifstream c2("tt.txt");

for(int i=0;i<6;i++)

{getline(c2,test);  //getline(檔案輸入物件名稱 , 變數名稱)這一函式的作用是從tt.txt取出一行資料,並且複製給變數test

if(i%2==0)

{ofstream c1("aa.txt",ios_base::out | ios_base::app);

c1<<test<<endl;c1.close();}

else

{ofstream c1("bb.txt",ios_base::out | ios_base::app);

c1<<test<<endl;c1.close();}

}

c2.close();

執行結果:在C++編譯軟體安裝的目錄或者是特定的工作區底下,建立aa.txt檔和bb.txt檔。

aa.txt內容為:

11111

33333

55555

bb.txt內容為:

22222

44444

66666

 

 

上一篇:檔案管理 輸出排版(2)

下一篇:檔案輸入輸出的定位

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

按此前往C++完整教學目錄

 

 

在上一篇:輸出排版中提到,排版時要在每一個cout物件之前設定cout.width()

若嫌這樣太過麻煩,可利用setw(n)函式來設定n個預留的空白字元,而使用前要在標頭檔加上#include <iomanip>

使用方法例如:

cout<<setw(5)<<"aaa"<<setw(5)<<"bbb"<<"ccc";

顯示結果為  aaa  bbbcc

(2)對於大量排版輸出,上述方法還是很麻煩,且容易寫錯。此時,建議使用自定函式來解決,如:

void my_out(int n,string s1,string s2,string s3,string s4,string s5,string s6)

{cout.setf(ios_base::left,ios_base::adjustfield);

cout.width(n);cout<<s1;

cout.width(n);cout<<s2;

cout.width(n);cout<<s3;

cout.width(n);cout<<s4;

cout.width(n);cout<<s5;

cout.width(n);cout<<s6;

cout<<endl;

cout.setf(ios_base::right,ios_base::adjustfield);}

int main()  //主程式在此

{

my_out(6,"name","age","level","hp","mp","score");

my_out(6,"weiwei","18","1","50","20","95");

my_out(6,"nunu","20","1","60","12","92");

}

執行後的即可顯示排版結果。

 

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

1 23