久久99精品久久久久久琪琪,久久人人爽人人爽人人片亞洲,熟妇人妻无码中文字幕,亚洲精品无码久久久久久久

程序員實驗室 - C 基礎教程

時間:2019-05-14 16:00:18下載本文作者:會員上傳
簡介:寫寫幫文庫小編為你整理了多篇相關的《程序員實驗室 - C 基礎教程》,但愿對你工作學習有幫助,當然你在寫寫幫文庫還可以找到更多《程序員實驗室 - C 基礎教程》。

第一篇:程序員實驗室 - C 基礎教程

C++ 基礎教程Beta 版

原作:Juan Soulié 翻譯:Jing Xu(aqua)英文原版

本教程根據Juan Soulie的英文版C++教程翻譯并改編。本版為最新校對版,尚未定稿。如有不明或錯誤之處,請參考英文原版,并敬請在本站留言指正。版權歸作者所有,歡迎鏈接,請勿轉載。

本教程對C++語言進行了深入淺出的介紹,從基礎知識到ANSI-C++標準的最新功能,內容涵蓋了從數組,類等基本概念到多態、模板等高級概念。教程本著實用的原則,每一小節都結合了可以工作的程序實例,以便讀者從第一課開始就可以上手實習。

本翻譯版本對許多C++概念中的關鍵詞保留了中英文對照,以便讀者增強理解,并方便日后閱讀英文原版教材 目錄

1.簡介

怎樣使用本教程 2.C++基礎 Basics of C++ 1.C++程序結構

Structure of a program 2.變量和數據類型

Variables and Data types 3.常量 Constants 4.操作符/運算符 Operators 5.控制臺交互

Communication through console 3.控制結構和函數

Control structures and Functions 1.控制結構

Control Structures 2.函數I Functions I 3.函數II Functions II 4.高級數據類型 Advanced Data 1.數組 Arrays 2.字符序列

Character Sequences 3.指針 Pointers 4.動態內存分配 Dynamic memory 5.數據結構 Data Structures 6.自定義數據類型

User defined data types 5.面向對象編程

Object-oriented Programming 1.類,構造函數和析構函數,類的指針

Classes.Constructors and Destructors.Pointers to classes.2.操作符重載,this,靜態成員

Overloading Operators.this.Static members 3.類之間的關系

Relationships between classes: friend.Inheritance 4.虛擬成員,抽象,多態

Virtual Members.Abstraction.Polymorphism 6.C++高級

Advanced concepts 1.模板 Templates 2.名空間 Namespaces 3.出錯處理

Exception handling 4.類型轉換高級

Advacned Class Type-casting 5.預處理指令

Preprocessor Directives 7.C++ 標準函數庫 C++ Standard Library 1.文件的輸入輸出

Input/Output with files C++基礎教程簡介 怎樣使用本教程 讀者范圍

本教程面向所有希望學習C++語言的讀者。如果讀者有其他編程語言背景或計算機相關基本知識可以幫助更好的理解教程內容,但這并非必須條件。

對于C語言熟悉的讀者可將前三章(1.1 到 3.4)當作復習,因為這部分內容主要介紹C++中的C部分。不過某些C++的語法與C還是有些差別,所以建議還是快速的讀一下這部分。第四章講述面向對象編程。

第五章主要介紹ANSI-C++標準中的新增的功能。

本教程結構

教程共分6章,每章分若干小節。你可以直接從主目錄進入任意小節,并循每頁底部的鏈接向后瀏覽。

很多小節含有一頁例題介紹該章節主要知識點的使用。建議在進入下一章學習之前最好先閱讀這些例題,理解每行代碼。

學習和練習一種編程語言的最好辦法是自己修改書中例題程序,設法在程序中增加新的功能。不要不敢修改這些例題程序,這正是學習的方法。

兼容性備注

ANSI-C++標準近幾年來被接受為國際標準。盡管C++語言從二十世紀80年代即存在,ANSI-C++在1997年才被發表,2003年又被修訂過。因此很多編譯器不支持ANSI-C++中的部分新功能,特別是那些在此標準發表前即被發布的編譯器。

在本教程中,那些ANSI-C++中新增的而老一代C++編譯器大多不支持概念將備用如下標志標出:

ANSI C++新增的概念

同樣對于C和C++在實現上有明顯不同的概念,將備用如下標志標出: C 與 C++不同的地方 編譯器

本教程中所有例題程序均為console程序(控制臺程序)。此類程序以文本形式與用戶交換信息,顯示結果。

所有C++編譯器均支持console程序的編譯。要了解更多關于如何編譯的說明,請查詢你的編譯器用戶使用手冊。C++編譯器和開發環境推薦

很多讀者詢問編譯器和開發環境的問題。除了常用的商用收費的MS Visual Studio, VC++,Borland C++等工具外,還有很多免費的工具也是很好用的。這里推薦兩種免費的C++開發軟件:

1、Eclipse的CDT開發工具,官方網站在http://www.tmdps.cn/cdt/

2、開源工具Dev-C++和wxDev-C++ 第一章 C++ 基礎知識(Basics of C++)1.C++程序結構

Structure of a program 2.變量和數據類型

Variables and Data types 3.常量 Constants 4.操作符/運算符 Operators 5.控制臺交互

Communication through console

1.1 C++程序結構(Structure of a program)

下面我們從一個最簡單的程序入手看一個C++程序的組成結構。// my first program in C++ #include using namespace std;

int main(){ cout << “Hello World!”;return 0;} Hello World!上面左側顯示了我們的第一個程序的源代碼,代碼文件名稱為hellowworld.cpp。右邊顯示了程序被編譯執行后的輸出結果。編輯和編譯一個程序的方法取決于你用的是什么編譯器,根據它是否有圖形化的界面及版本的不同,編譯方法也有可能不同,具體請參照你所使用的編譯器的使用說明。

以上程序是多數初學者學會寫的第一個程序,它的運行結果是在屏幕上打出”Hello World!”這句話。雖然它可能是C++可寫出的最簡單的程序之一,但其中已經包含了每一個C++程序的基本組成結構。下面我們就逐個分析其組成結構的每一部分: // my first program in C++ 這是注釋行。所有以兩個斜線符號(//)開始的程序行都被認為是注釋行,這些注釋行是程序員寫在程序源代碼內,用來對程序作簡單解釋或描述的,對程序本身的運行不會產生影響。在本例中,這行注釋對本程序是什么做了一個簡要的描述。# include < iostream.h > 以#標志開始的句子是預處理器的指示語句。它們不是可執行代碼,只是對編譯器作出指示。在本例中這個句子# include < iostream.h > 告訴編譯器的預處理器將輸入輸出流的標準頭文件(iostream.h)包括在本程序中。這個頭文件包括了C++中定義的基本標準輸入-輸出程序庫的聲明。此處它被包括進來是因為在本程序的后面部分中將用到它的功能。using namespace std;C++標準函數庫的所有元素都被聲明在一個名空間中,這就是std名空間。因此為了能夠訪問它的功能,我們用這條語句來表達我們將使用標準名空間中定義的元素。這條語句在使用標準函數庫的C++程序中頻繁出現,本教程中大部分代碼例子中也將用到它。int main()這一行為主函數(main function)的起始聲明。main function是所有C++程序的運行的起始點。不管它是在代碼的開頭,結尾還是中間 – 此函數中的代碼總是在程序開始運行時第一個被執行。并且,由于同樣的原因,所有C++程序都必須有一個main function。main 后面跟了一對圓括號(),表示它是一個函數。C++中所有函數都跟有一對圓括號(),括號中可以有一些輸入參數。如例題中顯示,主函數(main function)的內容緊跟在它的聲明之后,由花括號({})括起來。cout << “Hellow World!”;這個語句在本程序中最重要。cout 是C++中的標準輸出流(通常為控制臺,即屏幕),這句話把一串字符串(本例中為”Hello World”)插入輸出流(控制臺輸出)中。cout 在的聲明在頭文件iostream.h中,所以要想使用cout 必須將該頭文件包括在程序開始處。注意這個句子以分號(;)結尾。分號標示了一個語句的結束,C++的每一個語句都必須以分號結尾。(C++ 程序員最常犯的錯誤之一就是忘記在語句末尾寫上分號)。return 0;返回語句(return)引起主函數 main()執行結束,并將該語句后面所跟代碼(在本例中為0)返回。這是在程序執行沒有出現任何錯誤的情況下最常見的程序結束方式。在后面的例子中你會看到所有C++程序都以類似的語句結束。

你可能注意到并不是程序中的所有的行都會被執行。程序中可以有注釋行(以//開頭),有編譯器預處理器的指示行(以#開頭),然后有函數的聲明(本例中main函數),最后是程序語句(例如調用cout <<),最后這些語句行全部被括在主函數的花括號({})內。本例中程序被寫在不同的行中以方便閱讀。其實這并不是必須的。例如,以下程序 int main(){ cout << “ Hello World ”;return 0;} 也可以被寫成:

int main(){ cout << “ Hello World ”;return 0;} 以上兩段程序是完全相同的。

在C++中,語句的分隔是以分號(;)為分隔符的。分行寫代碼只是為了更方便人閱讀。以下程序包含更多的語句: // my second program in C++ #include

int main(){ cout << “Hello World!”;cout << “I'm a C++ program”;return 0;} Hello World!I'm a C++ program 在這個例子中,我們在兩個不同的語句中調用了cout << 函數兩次。再一次說明分行寫程序代碼只是為了我們閱讀方便,因為這個main 函數也可以被寫為以下形式而沒有任何問題: int main(){ cout << “ Hello World!”;cout << “ I'm to C++ program ”;return 0;}

為方便起見,我們也可以把代碼分為更多的行來寫: int main(){ cout << “Hello World!”;cout << “I'm a C++ program”;return 0;} 它的運行結果將和上面的例子完全一樣。

這個規則對預處理器指示行(以#號開始的行)并不適用,因為它們并不是真正的語句。它們由預處理器讀取并忽略,并不會生成任何代碼。因此他們每一個必須單獨成行,末尾不需要分號(;)

注釋(Comments)注釋(comments)是源代碼的一部分,但它們會被編譯器忽略。它們不會生成任何執行代碼。使用注釋的目的只是使程序員可以在源程序中插入一些說明解釋性的內容。C++ 支持兩中插入注釋的方法: // line comment /* block comment */ 第一種方法為行注釋,它告訴編譯器忽略從//開始至本行結束的任何內容。第二種為塊注釋(段注釋),告訴編譯器忽略在/*符號和*/符號之間的所有內容,可能包含多行內容。在以下我們的第二個程序中,我們插入了更多的注釋。/* my second program in C++ with more comments */

#include

int main(){ cout << “Hello World!”;// says Hello World!cout << “I'm a C++ program”;// says I'm a C++ program return 0;} Hello World!I'm a C++ program

如果你在源程序中插入了注釋而沒有用//符號或/*和*/符號,編譯器會把它們當成C++的語句,那么在編譯時就會出現一個或多個錯誤信息。1.2 變量和數據類型(Variables and Data types)

你可能覺得這個“Hellow World”程序用處不大。我們寫了好幾行代碼,編譯,然后執行生成的程序只是為了在屏幕上看到一句話。的確,我們直接在屏幕上打出這句話會更快。但是編程并不僅限于在屏幕上打出文字這么簡單的工作。為了能夠進一步寫出可以執行更有用的任務的程序,我們需要引入變量(variable)這個的概念。

讓我們設想這樣一個例子,我要求你在腦子里記住5這個數字,然后再記住2這個數字。你已經存儲了兩個數值在你的記憶里。現在我要求你在我說的第一個數值上加1,你應該保留6(即5+1)和2在你的記憶里。現在如果我們將兩數相減可以得到結果4。

所有這些你在腦子里做的事情與計算機用兩個變量可以做的事情非常相似。同樣的處理過程用C++來表示可以寫成下面一段代碼: a = 5;b = 2;a = a + 1;result = a38(7 個數字(7digits))double 8 雙精度浮點數(double precision floating point number)1.7e + /308(15 digits)bool 1 布爾Boolean值。它只能是真(true)或假(false)兩值之一。true 或 false wchar_t 2 寬字符(Wide character)。這是為存儲兩字節(2 bytes)長的國際字符而設計的類型。一個寬字符(1 wide characters)

* 字節數一列和范圍一列可能根據程序編譯和運行的系統不同而有所不同。這里列出的數值是多數32位系統的常用數據。對于其他系統,通常的說法是整型(int)具有根據系統結構建議的自然長度(即一個字one word的長度),而4中整型數據char, short, int, long的長度必須是遞增的,也就是說按順序每一類型必須大于等于其前面一個類型的長度。同樣的規則也適用于浮點數類型float, double和 long double,也是按遞增順序。

除以上列出的基本數據類型外,還有指針(pointer)和void 參數表示類型,我們將在后面看到。

變量的聲明(Declaration of variables)

在C++中要使用一個變量必須先聲明(declare)該變量的數據類型。聲明一個新變量的語法是寫出數據類型標識符(例如int, short, float...)后面跟一個有效的變量標識名稱。例如: int a;float mynumber;以上兩個均為有效的變量聲明(variable declaration)。第一個聲明一個標識為a 的整型變量(int variable),第二個聲明一個標識為mynumber 的浮點型變量(float variable)。聲明之后,我們就可以在后面的程序中使用變量a和 mynumber 了。

如果你需要聲明多個同一類型的變量,你可以將它們縮寫在同一行聲明中,在標識之間用逗號(comma)分隔。例如: int a, b, c;以上語句同時定義了a、b、c 3個整型變量,它與下面的寫法完全等同: int a;int b;int c;整型數據類型(char, short, long 和 int)可以是有符號的(signed)或無符號的(unsigned),這取決于我們需要表示的數據范圍。有符號類型(signed)可以表示正數和負數,而無符號類型(unsigned)只能表示正數和0。在定義一個整型數據變量時可以在數據類型前面加關鍵字 signed 或 unsigned 來聲明數據的符號類型。例如: unsigned short NumberOfSons;signed int MyAccountBalance;如果我們沒有特別寫出signed或 unsigned,變量默認為signed,因此以上第二個聲明我們也可以寫成:

int MyAccountBalance;因為以上兩種表示方式意義完全一樣,因此我們在源程序通常省略關鍵字signed。

唯一的例外是字符型(char)變量,這種變量獨立存在,與signed char 和 unsigned char型均不相同。

short 和 long 可以被單獨用來表示整型基本數據類型,short 相當于 short int,long 相當于 long int。也就是說 short year;和 short int year;兩種聲明是等價的。

最后,signed 和 unsigned 也可以被單獨用來表示簡單類型,意思分別同signed int 和 unsigned int 相同,即以下兩種聲明互相等同: unsigned MyBirthYear;unsigned int MyBirthYear;下面我們就用C++代碼來解決在這一節開頭提到的記憶問題,來看一下變量定義是如何在程序中起作用的。

// operating with variables

#include using namespace std;

int main(){ // declaring variables: int a, b;int result;

// process: a = 5;b = 2;a = a + 1;result = ab;cout << result;

return 0;} 6

字符串(strings)字符串是用來存儲一個以上字符的非數字值的變量。

C++提供一個string類來支持字符串的操作,它不是一個基本的數據類型,但是在一般的使用中與基本數據類型非常相似。

與普通數據類型不同的一點是,要想聲明和使用字符串類型的變量,需要引用頭文件,并且使用using namespace語句來使用標準名空間(std),如下面例子所示: // C++字符串例題 #include #include using namespace std;

int main(){ string mystring = “This is a string”;cout << mystring;return 0;} This is a string 如上面例子所示,字符串變量可以被初始化為任何字符串值,就像數字類型變量可以被初始化為任何數字值一樣。

以下兩種初始化格式對字符串變量都是可以使用的: string mystring = “This is a string”;string mystring(“This is a string”);字符串變量還可以進行其他與基本數據類型變量一樣的操作,比如聲明的時候不指定初始值,和在運行過程中被重新賦值。// C++字符串例題2 #include #include using namespace std;

int main(){ string mystring;mystring = “This is the initial string content”;cout << mystring << endl;mystring = “This is a different string content”;cout << mystring << endl;return 0;} This is the initial string content This is a different string content 要了解更加詳細的C++字符串操作,建議參考Cplusplus上的string類reference。1.3 常量(Constants)

一個常量(constant)是一個有固定值的表達式。字(Literals)

字是用來在程序源碼中表達特定的值。在前面的內容中我們已經用了很多的字來給變量賦予特定的值。例如: a = 5;

這句代碼中5就是一個字常量。

字常量(literal constant)可以被分為整數(Integer Numbers), 浮點數(Floating-Point Numbers),字符(Characters)和字符串(Strings)。

整數(Integer Numbers)1776 707-273 他們是整型常數,表示十進制整數值。注意表示整型常數時我們不需要些引號(quotes(“))或任何特殊字符。毫無疑問它是個常量:任何時候當我們在程序中寫1776,我們指的就是1776這個數值。

除十進制整數另外,C++還允許使用八進制(octal numbers)和十六進制(hexadecimal numbers)的字常量(literal constants)。如果我們想要表示一個八進制數,我們必須在它前面加上一個0字符(zero character),而表示十六進制數我們需要在它前面加字符0x(zero, x)。例如以下字常量(literal constants)互相等值: 75 // 十進制 decimal 0113 // 八進制 octal 0x4b // 十六進制 hexadecimal 所有這些都表示同一個整數: 75(seventy five),分別以十進制數,八進制數和十六進制數表示。

像變量一樣,常量也是有數據類型的。默認的整數字常量的類型為int型。我們可以通過在后面加字母u或l來迫使它為無符號(unsigned)的類型或長整型(long)。75 // int 75u // unsigned int 75l // long 75ul // unsigned long

這里后綴u和l可以是大寫,也可以是小寫。

浮點數(Floating Point Numbers)浮點數以小數(decimals)和/或指數冪(exponents)的形式表示。它們可以包括一個小數點,一個e字符(表示”by ten at the Xth height“,這里X是后面跟的整數值),或兩者都包括。

3.14159 // 3.14159 6.02e23 // 6.02 x 10^1023 1.6e-19 // 1.6 x 10^-19 3.0 // 3.0 以上是包含小數的以C++表示的4個有效數值。第一個是PI,第二個是Avogadro數之一,第三個是一個電子(electron)的電量(electric charge)(一個極小的數值)– 所有這些都是近似值。最后一個是浮點數字常量表示數3。

浮點數的默認數據類型為double。如果你想使用float或long double類型,可以在后面加f或l后綴,同樣大小寫都可以: 3.14159L // long double 6.02e23f // float

字符和字符串(Characters and strings)此外還有非數字常量,例如: 'z' 'p' ”Hello world“ ”How do you do?“ 前兩個表達式表示單獨的字符(character),后面兩個表示由若干字符組成的字符串(string)。注意在表示單獨字符的時候,我們用單引號(single quotes(')),在表示字符串或多于一個字符的時候我們用雙引號(double quotes(”))。

當以常量方式表示單個字符和字符串時,必須寫上引號以便把他們和可能的變量標識或保留字區分開,注意以下例子: x 'x' x 指一個變量名稱為 x, 而'x'指字符常量'x'。字符常量和字符串常量各有特點,例如escape codes,這些是除此之外無法在源程序中表示的特殊的字符,例如換行符 newline(n)或跳躍符tab(t)。所有這些符號前面要加一個反斜杠inverted slash()。這里列出了這些escape codes: n 換行符newline r 回車carriage return t 跳躍符tabulation v 垂直跳躍vertical tabulation b backspace f page feed a 警告alert(beep)' 單引號single quotes(')“ 雙引號double quotes(”)? 問號question(?)反斜杠inverted slash()例如: 'n' 't' “Left t Right” “onentwonthree” 另外你可以數字ASCII 碼表示一個字符,這種表示方式是在反斜杠()之后加以8進制數或十六進制數表示的ASCII 碼。在第一種(八進制octal)表示中,數字必需緊跟反斜杠(例如23或40),第二種(十六進制hexacedimal),必須在數字之前寫一個x字符(例如x20或x4A)。

如果每一行代碼以反斜杠inverted slash()結束,字符串常量可以分多行代碼表示: “string expressed in two lines” 你還可以將多個被空格blankspace、跳躍符tabulator、換行符newline或其他有效空白符號分隔開的字符串常量連接在一起:

“we form” “a single” “string” “of characters” 最后如果我們想讓字符串使用寬字符(wchar_t),而不是窄字符(char),可以在常量的前面加前綴L:

L“This is a wide character string” 寬字符通常用來存儲非英語字符,比如中文字符,一個字符占兩個字節。布爾型常量(Boolean Literals)布爾型只有兩個有效的值:true和false,其數據類型為bool。

定義常量Defined constants(#define)使用預處理器指令#define,你可以將那些你經常使用的常量定義為你自己取的名字而不需要借助于變量。它的格式是: #define identifier value 例如:

#define PI 3.14159265 #define NEWLINE 'n' #define WIDTH 100 以上定義了三個常量。一旦做了這些聲明,你可以在后面的程序中使用這些常量,就像使用其它任何常量一樣,例如: circle = 2 * PI * r;cout << NEWLINE;實際上編譯器在遇到#define指令的時候做的只是把任何出現這些 常量名(在前面的例子中為PI, NEWLINE或WIDTH)的地方替換成他們被定義為的代碼(分別為3.14159265, 'n'和100)。因此,由#define定義的常量被稱為宏常量macro constants。

#define 指令不是代碼語句,它是預處理器指令,因此指令行末尾不需要加分號semicolon(;)。如果你在宏定義行末尾加了分號(;),當預處理器在程序中做常量替換的時候,分號也會被加到被替換的行中,這樣可能導致錯誤。

聲明常量declared constants(const)通過使用const前綴,你可以定義指定類型的常量,就像定義一個變量一樣: const int width = 100;const char tab = 't';const zip = 12440;如果沒有指定類型(如上面最后例子中最后一行),編譯器會假設常量為整型int。1.4 操作符/運算符(Operators)

前面已經學習了變量和常量,我們可以開始對它們進行操作,這就要用到C++的操作符。有些語言,很多操作符都是一些關鍵字,比如add, equals等等。C++的操作符主要是由符號組成的。這些符號不在字母表中,但是在所有鍵盤上都可以找到。這個特點使得C++程序更簡潔,也更國際化。運算符是C++語言的基礎,所以非常重要。

你不需要背下所有這一小節的內容,這些細節知識僅供你以后需要時參考。賦值Assignation(=)賦值運算符的功能是將一個值賦給一個變量。a = 5;將整數5賦給變量a。= 運算符左邊的部分叫做lvalue(left value),右邊的部分叫做rvalue(right value)。lvalue 必須是一個變量,而右邊的部分可以是一個常量,一個變量,一個運算(operation)的結果或是前面幾項的任意組合。

有必要強調賦值運算符永遠是將右邊的值賦給左邊,永遠不會反過來。a = b;將變量b(rvalue)的值賦給變量a(lvalue),不論a當時存儲的是什么值。同時考慮到我們只是將b的數值賦給a,以后如果b的值改變了并不會影響到a的值.例如:如果我們使用以下代碼(變量值的變化顯示在綠色注釋部分): // 賦值符號例子

#include using namespace std;

int main(){ int a, b;// a:?, b:? a = 10;// a:10, b:? b = 4;// a:10, b:4 a = b;// a:4, b:4 b = 7;// a:4, b:7

cout << “a:”;cout << a;cout << “ b:”;cout << b;

return 0;} a:4 b:7 以上代碼結果是a的值為4,b的值為7。最后一行中b的值被改變并不會影響到a,雖然在此之前我們聲明了a = b;(從右到左規則right-to-left rule)。

C++擁有而其他語言沒有的一個特性是賦值符(=)可以被用作另一個賦值符的rvalue(或rvalue的一部分)。例如: a = 2 +(b = 5);等同于: b = 5;a = 2 + b;它的意思是:先將5賦給變量b,然后把前面對b的賦值運算的結果(即5)加上2再賦給變量a,這樣最后a中的值為7。因此,下面的表達式在C++中也是正確的: a = b = c = 5;//將5同時賦給3個變量a, b和c。

數學運算符Arithmetic operators(+,-, *, /, %)C++語言支持的5種數學運算符為: ? + 加addition ?5;a /= b;等同于 a = a / b;price *= units + 1;等同于 price = price *(units + 1);其他運算符以此類推。例如: // 組合運算符例子

#include using namespace std;

int main(){ int a, b=3;a = b;a+=2;// 相當于 a=a+2 cout << a;return 0;} 5

遞增和遞減Increase and decrease 書寫簡練的另一個例子是遞增(increase)運算符(++)和遞減(decrease)運算符(--)。它們使得變量中存儲的值加1或減1。它們分別等同于+=1和-=1。因此: a++;a+=1;a=a+1;在功能上全部等同,即全部使得變量a的值加1。

它的存在是因為最早的C編譯器將以上三種表達式的編譯成不同的機器代碼,不同的機器代碼運行速度不一樣。現在,編譯器已經基本自動實行代碼優化,所以以上三種不同的表達方式編譯成的機器代碼在實際運行上已基本相同。

這個運算符的一個特點是它既可以被用作prefix前綴,也可以被用作后綴suffix,也就是說它既可以被寫在變量標識的前面(++a),也可以被寫在后面(a++)。雖然在簡單表達式如a++或++a中,這兩種寫法代表同樣的意思,但當遞增increase或遞減decrease的運算結果被直接用在其它的運算式中時,它們就代表非常不同的意思了:當遞增運算符被用作前綴prefix(++a)時,變量a的值線增加,然后再計算整個表達式的值,因此增加后的值被用在了表達式的計算中;當它被用作后綴suffix(a++)時,變量a的值在表達式計算后才增加,因此a在增加前所存儲的值被用在了表達式的計算中。注意以下兩個例子的不同: 例 1 例 2 B=3;A=++B;// A 的值為 4, B 的值為 4 B=3;A=B++;// A 的值為 3, B 的值為 4 在第一個例子中,B在它的值被賦給A之前增加1。而在第二個例子中B原來的值3被賦給 A然后B的值才加1變為4。

關系運算符Relational operators(==,!=, >, <, >=, <=)我們用關系運算符來比較兩個表達式。如ANSI-C++ 標準中指出的,關系預算的結果是一個bool值,根據運算結果的不同,它的值只能是真true或false。

例如我們想通過比較兩個表達式來看它們是否相等或一個值是否比另一個的值大。以下為C++的關系運算符: == 相等Equal!= 不等Different > 大于Greater than < 小于Less than >= 大于等于Greater or equal than <= 小于等于Less or equal than 下面你可以看到一些實際的例子:(7 == 5)將返回false.(5 > 4)將返回true.(3!= 2)將返回true.(6 >= 6)將返回true.(5 < 5)將返回false.當然,除了使用數字常量,我們也可以使用任何有效表達式,包括變量。假設有a=2, b=3和c=6,(a == 5)將返回false.(a*b >= c)將返回true 因為它實際是(2*3 >= 6)

(b+4 > a*c)將返回false因為它實際是(3+4 > 2*6)

((b=2)== a)將返回true.注意:運算符=(單個等號)不同于運算符==(雙等號)。第一個是賦值運算符(將等號右邊的表達式值賦給左邊的變量);第二個(==)是一個判斷等于的關系運算符,用來判斷運算符兩邊的表達式是否相等。因此在上面例子中最后一個表達式((b=2)== a),我們首先將數值2賦給變量b,然后把它和變量a進行比較。因為變量a中存儲的也是數值2,所以整個運算的結果為true。

在ANSI-C++標準出現之前的許多編譯器中,就像C語言中,關系運算并不返回值為真true或假false的bool值,而是返回一個整型數值最為結果,它的數值可以為0,代表“false”或一個非0數值(通常為1)來代表“true”。

邏輯運算符Logic operators(!, &&, ||)運算符!等同于boolean 運算NOT(取非),它只有一個操作數(operand),寫在它的右邊。它做的唯一工作就是取該操作數的反面值,也就是說如果操作數值為真true,那么運算后值變為假false,如果操作數值為假false,則運算結果為真true。它就好像是說取與操作數相反的值。例如:

!(5 == 5)返回false,因為它右邊的表達式(5 == 5)為真true.!(6 <= 4)返回true因為(6 <= 4)為假false.!true 返回假false.!false 返回真true.邏輯運算符&&和||是用來計算兩個表達式而獲得一個結果值。它們分別對應邏輯運算中的與運算AND 和或運算OR。它們的運算結果取決于兩個操作數(operand)的關系: 第一個操作數 a 第二個操作數 b 結果 a && b 結果 a || b true true true true true false false true false true false true false false false false 例如 :

((5 == 5)&&(3 > 6))返回false(true && false).((5 == 5)||(3 > 6))返回true(true || false).條件運算符Conditional operator(?)條件運算符計算一個表達式的值并根據表達式的計算結果為真true或假false而返回不同值。它的格式是:

condition ? result1 : result2(條件?返回值1:返回值2)

如果條件condition 為真true,整個表達式將返回esult1,否則將返回result2。7==5 ? 4 : 3 返回3,因為7不等于5.7==5+2 ? 4 : 3 返回4,因為7等于5+2.5>3 ? a : b 返回a,因為5大于3.a>b ? a : b 返回較大值,a 或b.// 條件運算符例子

#include using namespace std;int main(){ int a,b,c;

a=2;b=7;c =(a>b)? a : b;

cout << c;

return 0;} 7 上面的例子中a的值為2,b的值為7,所以表達式(a>b)運算值為假(false),所以整個表達式(a>b)?a:b要取分號后面的值,也就是b的值7。因此最后輸出 c 的值為7。

逗號運算符(,)逗號運算符(,)用來分開多個表達式,并只取最右邊的表達式的值返回。

例如有以下代碼: a =(b=3, b+2);

這行代碼首先將3賦值給變量b,然后將 b+2 賦值給變量 a。所以最后變量a 的值為5,而變量b的值為3。

位運算符Bitwise Operators(&, |, ^, ~, <<, >>)位運算符以比特位改寫變量存儲的數值,也就是改寫變量值的二進制表示: op asm Description & AND 邏輯與 Logic AND | OR 邏輯或Logic OR ^ XOR 邏輯異或Logical exclusive OR ~ NOT 對1取補(位反轉)Complement to one(bit inversion)<< SHL 左移Shift Left >> SHR 右移Shift Right

變量類型轉換運算符Explicit type casting operators 變量類型轉換運算符可以將一種類型的數據轉換為另一種類型的數據。在寫C++中有幾種方法可以實現這種操作,最常用的一種,也是與C兼容的一種,是在原轉換的表達式前面加用括號()括起的新數據類型: int i;float f = 3.14;i =(int)f;以上代碼將浮點型數字3.14轉換成一個整數值(3)。這里類型轉換操作符為(int)。在C++中實現這一操作的另一種方法是使用構造函數constructor 的形式:在要轉換的表達式前加變量類型并將表達式括在括號中: i = int(f);以上兩種類型轉換的方法在C++中都是合法的。另外ANSI-C++針對面向對象編程(object oriented programming)增加了新的類型轉換操作符(參考Section 5.4, Advanced class type-casting).sizeof()這個運算符接受一個輸入參數,該參數可以是一個變量類型或一個變量自己,返回該變量類型(variable type)或對象(object)所占的字節數: a = sizeof(char);這將會返回1給a,因為char是一個常為1個字節的變量類型。

sizeof返回的值是一個常數,因此它總是在程序執行前就被固定了。

其它運算符

在本教程后面的章節里我們將看到更多的運算符,比如指向指針的運算或面向對象編程特有的運算,等等,我們會在它們各自的章節里進行詳細討論。

運算符的優先度 Precedence of operators 當多個操作數組成復雜的表達式時,我們可能會疑惑哪個運算先被計算,哪個后被計算。例如以下表達式: a = 5 + 7 % 2 我們可以懷疑它實際上表示:

a = 5 +(7 % 2)結果為6,還是 a =(5 + 7)% 2 結果為0? 正確答案為第一個,結果為6。每一個運算符有一個固定的優先級,不僅對數學運算符(我們可能在學習數學的時候已經很了解它們的優先順序了),所有在C++中出現的運算符都有優先級。從最從最高級到最低級,運算的優先級按下表排列: 優先級

Level 操作符 Operator 說明 Description 結合方向 Grouping 1 :: 范圍 從左到右()[].-> ++--dynamic_cast static_cast reinterpret_cast const_cast typeid 后綴 從左到右 ++--~!sizeof new delete 一元(前綴)從右到左

* & 指針和取地址

+加減 從左到右 8 << >> 位移 從左到右 < > <= >= 關系操作符 從左到右 10 ==!= 等于、不等于 從左到右 11 & 按位與運算 從左到右 12 ^ 按位異或運算 從左到右 13 | 按位或運算 從左到右 14 && 邏輯與運算 從左到右 15 || 邏輯或運算 從左到右 16 ?: 條件運算 從右到左 = *= /= %= +=-= >>= <<= &= ^= |= 賦值運算 從右到左 18 , 逗號 從左到右

結合方向Grouping定義了當有同優先級的多個運算符在一起時,哪一個必須被首先運算,最右邊的還是最左邊的。

所有這些運算符的優先級順序可以通過使用括號parenthesis signs(和)來控制,而且更易讀懂,例如以下例子: a = 5 + 7 % 2;根據我們想要實現的計算的不同,可以寫成: a = 5 +(7 % 2);或者 a =(5 + 7)% 2;所以如果你想寫一個復雜的表達式而不敢肯定各個運算的執行順序,那么就加上括號。這樣還可以使代碼更易讀懂。

1.5 控制臺交互(Communication through console)控制臺(console)是電腦的最基本交互接口,通常包括鍵盤(keyboard)和屏幕(screen)。鍵盤通常為標準輸入設備,而 屏幕為標準輸出設備。

在C++的iostream函數庫中,一個程序的標準輸入輸出操作依靠兩種數據流:cin 給輸入使用和cout給輸出使用。另外,cerr和clog也已經被實現――它們是兩種特殊設計的數據流專門用來顯示出錯信息。它們可以被重新定向到標準輸出設備或到一個日志文件(log file)。因此cout(標準輸出流)通常被定向到屏幕,而cin(標準輸入流)通常被定向到鍵盤。通過控制這兩種數據流,你可以在程序中與用戶交互,因為你可以在屏幕上顯示輸出并從鍵盤接收用戶的輸入。

輸出Output(cout)輸出流cout與重載(overloaded)運算符<<一起使用:

cout << “Output sentence”;// 打印Output sentence到屏幕上 cout << 120;// 打印數字 120 到屏幕上 cout << x;// 打印變量 x 的值到屏幕上

運算符<<又叫插入運算符(insertion operator)因為它將后面所跟的數據插入到它前面的數據流中。在以上的例子中,字符串常量Output sentence,數字常量120和變量x先后被插入輸出流cout中。注意第一句中字符串常量是被雙引號引起來的。每當我們使用字符串常量的時候,必須用引號把字符串引起來,以便將它和變量名明顯的區分開來。例如,下面兩個語句是不同的:

cout << “Hello”;// 打印字符串Hello到屏幕上

cout << Hello;// 把變量Hello存儲的內容打印到屏幕上

插入運算符insertion operator(<<)可以在同一語句中被多次使用: cout << “Hello, ” << “I am ” << “a C++ sentence”;上面這一行語句將會打印 Hello, I am a C++ sentence 到屏幕上。插入運算符(<<)的重復使用在我們想要打印變量和內容的組合內容或多個變量時有所體現:

cout << “Hello, I am ” << age << “ years old and my zipcode is ” << zipcode;如果我們假設變量age的值為24,變量zipcode的值為90064,以上句子的輸出將為: Hello, I am 24 years old and my zipcode is 90064 必須注意,除非我們明確指定,cout并不會自動在其輸出內容的末尾加換行符,因此下面的語句:

cout << “This is a sentence.”;cout << “This is another sentence.”;將會有如下內容輸出到屏幕:

This is a sentence.This is another sentence.雖然我們分別調用了兩次cout,兩個句子還是被輸出在同一行。所以,為了在輸出中換行,我們必須插入一個換行符來明確表達這一要求。在C++中換行符可以寫作n: cout << “First sentence.n ”;cout << “Second sentence.nThird sentence.”;將會產生如下輸出: First sentence.Second sentence.Third sentence.另外,你也可以用操作符endl來換行,例如: cout << “First sentence.” << endl;cout << “Second sentence.” << endl;將會輸出:

First sentence.Second sentence.當操作符endl被用在buffered streams中時有一點特殊:它們被flushed。不過cout 默認為unbuffered,所以不會被影響。你可以暫時不管這一點。

你可以使用n或endl來指定cout輸出換行,請注意前面所講的兩者的不同用法。

輸入Input(cin)C++中的標準輸入是通過在cin數據流上重載運算符extraction(>>)來實現的。它后面必須跟一個變量以便存儲讀入的數據。例如: int age;cin >> age;聲明一個整型變量age然后等待用戶從鍵盤輸入到cin并將輸入值存儲在這個變量中。cin 只能在鍵盤輸入回車鍵(RETURN)后才能處理前面輸入的內容。因此即使你只要求輸入一個單獨的字符,在用戶按下回車鍵(RETURN)之前cin將不會處理用戶的輸入的字符。在使用cin輸入的時候必須考慮后面的變量類型。如果你要求輸入一個整數,extraction(>>)后面必須跟一個整型變量,如果要求一個字符,后面必須跟一個字符型變量,如果要求一個字符串,后面必須跟一個字符串型變量。// i/o example #include int main(){ int i;cout << “Please enter an integer value: ”;cin >> i;cout << “The value you entered is ” << i;cout << “ and its double is ” << i*2 << “.n”;return 0;} Please enter an integer value: 702 The value you entered is 702 and its double is 1404.使用程序的用戶可以使引起錯誤的原因之一,即使是在最簡單的需要用cin做輸入的程序中(就像我們上面看到的這個程序)。因為如果你要求輸入一個整數數值,而用戶輸入了一個名字(一個字符串),其結果可能導致程序產生錯誤操作,因為它不是我們期望從用戶處獲得的數據。當你使用由cin 輸入的數據的時候,你不得不假設程序的用戶將會完全合作而不會在程序要求輸入整數的時候輸入他的名字。后面當我們看到怎樣使用字符串的時候,我們將會同時看到一些解決這一類出錯問題的辦法。你也可以利用cin 要求用戶輸入多個數據 : cin >> a >> b;等同于: cin >> a;cin >> b;在以上兩種情況下用戶都必須輸入兩個數據,一個給變量a,一個給變量b。輸入時兩個變量之間可以以任何有效的空白符號間隔,包括空格,跳躍符tab或換行。

cin和字符串

我們可以像讀取基本類型數據一樣,使用cin和>>操作符來讀取字符串,例如: cin >> mystring;但是,cin >> 只能讀取一個單詞,一旦碰到任何空格,讀取操作就會停止。在很多時候這并不是我們想要的操作,比如我們希望用戶輸入一個英文句子,那么這種方法就無法讀取完整的句子,因為一定會遇到空格。

要一次讀取一整行輸入,需要使用C++的函數 getline,相對于是用cin,我們更建議使用getline來讀取用戶輸入。例如:

// 讀取字符串例子 #include #include using namespace std;

int main(){ string mystr;cout << “What's your name? ”;getline(cin, mystr);cout << “Hello ” << mystr << “.n”;cout << “What is your favorite color? ”;getline(cin, mystr);cout << “I like ” << mystr << “ too!n”;return 0;} What's your name? Aqua Hello Aqua.What is your favorite color? blue I like blue too!你可能注意到在上面的例子中,兩次調用 getline 函數我們都是用了同一個字符串變量(mystr)。在第二次調用的時候,程序會自動用第二次輸入的內容取代以前的內容。

字符串流(stringstream)

標準頭文件 定義了一個叫做 stringstream 的類,使用這個類可以對基于字符串的對象進行像流(stream)一樣的操作。這樣,我們可以對字符串進行抽取和插入操作,這對將字符串與數值互相轉換非常有用。例如,如果我們想將一個字符串轉換為一個整數,可以這樣寫: string mystr(“1204”);int myint;stringstream(mystr)>> myint;這個例子中先定義了一個字符串類型的對象mystr,初始值為“1204”,又定義了一個整數變量myint。然后我們使用 stringstream 類的構造函數定義了這個類的對象,并以字符串變量mystr為參數。因為我們可以像使用流一樣使用stringstream 的對象,所以我們可以像使用cin那樣使用操作符 >> 后面跟一個整數變量來進行提取整數數據。這段代碼執行之后變量 myint 存儲的是數值 1204。// 字符串流的使用示例 #include #include #include using namespace std;

int main(){ string mystr;float price=0;int quantity=0;

cout << “Enter price: ”;getline(cin,mystr);stringstream(mystr)>> price;cout << “Enter quantity: ”;getline(cin,mystr);stringstream(mystr)>> quantity;cout << “Total price: ” << price*quantity << endl;return 0;} Enter price: 22.25 Enter quantity: 7 Total price: 155.75 在這個例子中,我們要求用戶輸入數值,但不同于從標準輸入中直接讀取數值,我們使用函數getline從標注輸入流cin中讀取字符串對象(mystr),然后再從這個字符串對象中提取數值price和quantity。

通過使用這種方法,我們可以對用戶的輸入有更多的控制,因為它將用戶輸入與對輸入的解釋分離,只要求用戶輸入整行的內容,然后再對用戶輸入的內容進行檢驗操作。這種做法在用戶輸入比較集中的程序中是非常推薦使用的。第二章 控制結構和函數

(Control structures and Functions)1.控制結構

Control Structures 2.函數I Functions I 3.函數II Functions II 2.1 控制結構(Control Structures)

一個程序的語句往往并不僅限于線性順序結構。在程序的執行過程中它可能被分成兩支執行,可能重復某些語句,也可能根據一些判斷結果而執行不同的語句。因此C++ 提供一些控制結構語句(control structures)來實現這些執行順序。

為了介紹程序的執行順序,我們需要先介紹一個新概念:語句塊(block of instructions)。一個語句塊(A block of instructions)是一組互相之間由分號semicolons(;)分隔開但整體被花括號curly bracket signs: { and }括起來的語句。

本節中我們將看到的大多數控制結構允許一個通用的statement做參數,這個statement根據需要可以是一條語句,也可以是一組語句組成的語句塊。如果我們只需要一條語句做statement,它可以不被括在花括號({})內。但如果我們需要多條語句共同做statement,則必須把它們括在花括號內({})以組成一個語句塊。

條件結構Conditional structure: if and else 條件結構用來實現僅在某種條件滿足的情況下才執行一條語句或一個語句塊。它的形式是: if(condition)statement 這里 condition 是一個將被計算的表達式(expression)。如果表達式值為真,即條件(condition)為true,statement 將被執行。否則,statement 將被忽略(不被執行),程序從整個條件結構之后的下一條語句繼續執行。

例如,以下程序段實現只有當變量x存儲的值確實為100的時候才輸出“x is 100”: if(x == 100)cout << “x is 100”;如果我們需要在條件condition為真true的時候執行一條以上的語句,我們可以花括號{}將語句括起來組成一個語句塊: if(x == 100){ cout << “x is ”;cout << x;} 我們可以用關鍵字else 來指定當條件不能被滿足時需要執行的語句,它需要和if 一起使用,形式是:

if(condition)statement1 else statement2 例如: if(x == 100)cout << “x is 100”;else cout << “x is not 100”;以上程序如果x的值為100,則在屏幕上打出x is 100,如果x不是100,而且也只有在x不是100的時候,屏幕上將打出x is not 100。

多個if + else 的結構被連接起來使用來判斷數值的范圍。以下例子顯示了如何用它來判斷變量 x中當前存儲的數值是正值,負值還是既不正也不負,即等于0。if(x > 0)cout << “x is positive”;else if(x < 0)cout << “x is negative”;else cout << “x is 0”;記住當我們需要執行多條語句時,必須使用花括號{}將它們括起來以組成一個語句塊block of instructions。

重復結構 Iteration structures 或循環loops 循環Loops 的目的是重復執行一組語句一定的次數或直到滿足某種條件。while 循環 格式是:

while(表達式expression)語句statement 它的功能是當expression 的值為真true時重復執行statement。例如,下面我們將用while循環來寫一個倒計數程序: // custom countdown using while #include int main(){ int n;cout << “Enter the starting number > ”;cin >> n;while(n>0){ cout << n << “, ”;--n;} cout << “FIRE!”;return 0;} Enter the starting number > 8 8, 7, 6, 5, 4, 3, 2, 1, FIRE!程序開始時提示用戶輸入一個倒計數的初始值。然后while 循環開始,如果用戶輸入的數值滿足條件n>0(即 n 比0 大),后面跟的語句塊將會被執行一定的次數,直到條件(n>0)不再滿足(變為false)。

以上程序的所有處理過程可以用以下的描述來解釋: 從main開始: 1.用戶輸入一個數值賦給n.2.while語句檢查(n>0)是否成立,這時有兩種可能: o true: 執行statement(到第3步)o false: 跳過statement.程序直接執行第5步.3.執行statement: cout << n << “, ”;--n;(將n 的值打印在屏幕上,然后將n 的值減1).4.語句塊結束,自動返回第2步。

5.繼續執行語句塊之后的程序:打印 FIRE!,程序結束。

我們必須考慮到循環必須在某個點結束,因此在語句塊之內(loop的statement之內)我們必須提供一些方法使得條件condition 可以在某個時刻變為假 false,否則循環將無限重復下去。在這個例子里,我們用語句--n;使得循環在重復一定的次數后變為false :當 n 變為0,倒計數結束。do-while 循環 格式:

do 語句statement while(條件condition);它的功能與while 循環一抹一樣,除了在do-while循環中是先執行statement 然后才檢查條件condition,而不想while循環中先檢查條件然后才執行statement。這樣,即使條件condition從來沒有被滿足過,statement 仍至少被執行一次。例如,下面的程序重復輸出(echoes)用戶輸入的任何數值,直到用戶輸入0為止。// number echoer #include int main(){ unsigned long n;do { cout << “Enter number(0 to end): ”;cin >> n;cout << “You entered: ” << n << “n”;} while(n!= 0);return 0;} Enter number(0 to end): 12345 You entered: 12345 Enter number(0 to end): 160277 You entered: 160277 Enter number(0 to end): 0 You entered: 0 do-while 循環通常被用在判斷循環結束的條件是在循環語句內部被決定的情況下,比如以上的例子,在循環的語句塊內用戶的輸入決定了循環是否結束。如果用戶永遠不輸入0,則循環永遠不會結束。for 循環 格式是:

for(initialization;condition;increase)statement;它的主要功能是當條件condition 為真true時重復執行語句statement,類似while 循環。但除此之外,for 還提供了寫初始化語句initialization 和增值語句increase 的地方。因此這種循環結構是特別為執行由計數器控制的循環而設計的。它按以下方式工作:

1.執行初始化initialization。通常它是設置一個計數器變量(counter variable)的初始值,初始化僅被執行一次。

2.檢查條件condition,如果條件為真true,繼續循環,否則循環結束循環中語句statement 被跳過。

3.執行語句statement。像以前一樣,它可以是一個單獨的語句,也可以是一個由花括號{ }括起來的語句塊。

4.最后增值域(increase field)中的語句被執行,循環返回第2步。注意增值域中可能是任何語句,而不一定只是將計數器增加的語句。例如下面的例子中計數器實際為減1,而不是加1。

下面是用for循環實現的倒計數的例子: // countdown using a for loop #include int main(){ for(int n=10;n>0;n--){ cout << n << “, ”;} cout << “FIRE!”;return 0;} 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, FIRE!初始化initialization 和增值increase 域是可選的(即可以為空)。但這些域為空的時候,它們和其他域之間間隔的分號不可以省略。例如我們可以寫:for(;n<10;)來表示沒有初始化和增值語句;或for(;n<10;n++)來表示有增值語句但沒有初始化語句。另外我們也可以在for循環初始化或增值域中放一條以上的語句,中間用逗號 coma(,)隔開。例如假設我們想在循環中初始化一個以上的變量,可以用以下的程序來實現: for(n=0, i=100;n!=i;n++, i--){ // whatever here...} 這個循環將被執行50 次,如果n 和i 在循還內部都不被改變的話:

n初始值為0,i初始值為100,條件是(n!=i)(即n不能等于i)。因為每次循環n加1,而且i減1,循環的條件將會在第50次循環之后變為假false(n 和 i 都等于50)。分支控制和跳轉(Bifurcation of control and jumps)break 語句

通過使用break語句,即使在結束條件沒有滿足的情況下,我們也可以跳出一個循環。它可以被用來結束一個無限循環(infinite loop),或強迫循環在其自然結束之前結束。例如,我們想要在倒計數自然結束之前強迫它停止(也許因為一個引擎故障): // break loop example #include int main(){ int n;for(n=10;n>0;n--){ cout << n << “, ”;if(n==3){ cout << “countdown aborted!”;break;} return 0;} 10, 9, 8, 7, 6, 5, 4, 3, countdown aborted!continue 語句

continue語句使得程序跳過當前循環中剩下的部分而直接進入下一次循環,就好像循環中語句塊的結尾已經到了使得循環進入下一次重復。例如,下面例子中倒計數時我們將跳過數字5的輸出:

// continue loop example #include int main(){ for(int n=10;n>0;n--){ if(n==5)continue;cout << n << “, ”;} cout << “FIRE!”;return 0;} 10, 9, 8, 7, 6, 4, 3, 2, 1, FIRE!goto 語句

通過使用goto語句可以使程序從一點跳轉到另外一點。你必須謹慎只用這條語句,因為它的執行可以忽略任何嵌套限制。

跳轉的目標點可以由一個標示符(label)來標明,該標示符作為goto語句的參數。一個標示符(label)由一個標識名稱后面跟一個冒號colon(:)組成。

通常除了底層程序愛好者使用這條語句,它在結構化或面向對象的編程中并不常用。下面的例子中我們用goto來實現倒計數循環: // goto loop example #include int main(){ int n=10;loop: cout << n << “, ”;n--;if(n>0)goto loop;cout << “FIRE!”;return 0;} 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, FIRE!exit 函數

exit是一個在cstdlib(stdlib.h)庫中定義的函數。

exit的目的是一個特定的退出代碼來結束程序的運行,它的原型(prototype)是: void exit(int exit code);exit code是由操作系統使用或被調用程序使用。通常exit code為0表示程序正常結束,任何其他值表示程序執行過程中出現了錯誤。

選擇結構The selective Structure: switch switch 語句的語法比較特殊。它的目標是對一個表達式檢查多個可能常量值,有些像我們在本節開頭學習的把幾個if 和else if 語句連接起來的結構。它的形式是: switch(expression){ case constant1: block of instructions 1 break;case constant2: block of instructions 2 break;...default: default block of instructions } 它按以下方式執行:

switch 計算表達式expression 的值,并檢查它是否與第一個常量constant1相等,如果相等,程序執行常量1后面的語句塊block of instructions 1 直到碰到關鍵字break,程序跳轉到switch 選擇結構的結尾處。如果expression 不等于constant1,程序檢查表達式expression 的值是否等于第二個常量constant2,如果相等,程序將執行常量2后面的語句塊block of instructions 2 直到碰到關鍵字break。

依此類推,直到最后如果表達式expression 的值不等于任何前面的常量(你可以用case語句指明任意數量的常量值來要求檢查),程序將執行默認區default: 后面的語句,如果它存在的話。default: 選項是可以省略的。下面的兩段代碼段功能相同:

switch example if-else equivalent switch(x){ case 1: cout << “x is 1”;break;case 2: cout << “x is 2”;break;default: cout << “value of x unknown”;} if(x == 1){ cout << “x is 1”;} else if(x == 2){ cout << “x is 2”;} else { cout << “value of x unknown”;} 前面已經提到switch的語法有點特殊。注意每個語句塊結尾包含的break語句。這是必須的,因為如果不這樣做,例如在語句塊block of instructions 1 的結尾沒有break,程序執行將不會跳轉到switch選擇的結尾處(}),而是繼續執行下面的語句塊,直到第一次遇到break語句或到switch選擇結構的結尾。因此,不需要在每一個case 域內加花括號{ }。這個特點同時可以幫助實現對不同的可能值執行相同的語句塊。例如: switch(x){ case 1: case 2: case 3: cout << “x is 1, 2 or 3”;break;default: cout << “x is not 1, 2 nor 3”;} 注意switch只能被用來比較表達式和不同常量的值constants。因此我們不能夠把變量或范圍放在case之后,例如(case(n*2):)或(case(1..3):)都不可以,因為它們不是有效的常量。如果你需要檢查范圍或非常量數值,使用連續的if 和else if 語句。2.2 函數I(Functions I)

通過使用函數(functions)我們可以把我們的程序以更模塊化的形式組織起來,從而利用C++所能提供的所有結構化編程的潛力。

一個函數(function)是一個可以從程序其它地方調用執行的語句塊。以下是它的格式:

type name(argument1, argument2,...)statement

這里:

? type 是函數返回的數據的類型 ? name 是函數被調用時使用的名

? argument 是函數調用需要傳入的參量(可以聲明任意多個參量)。每個參量(argument)由一個數據類型后面跟一個標識名稱組成,就像變量聲明中一樣(例如,int x)。參量僅在函數范圍內有效,可以和函數中的其它變量一樣使用,它們使得函數在被調用時可以傳入參數,不同的參數用逗號(comma)隔開.? statement 是函數的內容。它可以是一句指令,也可以是一組指令組成的語句塊。如果是一組指令,則語句塊必須用花括號{}括起來,這也是我們最常見到情況。其實為了使程序的格式更加統一清晰,建議在僅有一條指令的時候也使用花括號,這是一個良好的編程習慣。下面看一下第一個函數的例子: // function example #include int addition(int a, int b){ int r;r=a+b;return(r);}

int main(){ int z;z = addition(5,3);cout << “The result is ” << z;return 0;} The result is 8 記得在我們教程開始時說過:一個C++程序總是從main函數開始執行。因此我們從那里開始。

我們可以看到 main 函數以定義一個整型變量z 開始。緊跟著我們看到調用addition 函數。我們可以看到函數調用的寫法和上面函數定義本身十分相似:

參數有明顯的對應關系。在main 函數中我們調用addition 函數,并傳入兩個數值: 5 和3,它們對應函數addition 中定義的參數int a 和int b。當函數在main 中被調用時,程序執行的控制權從main轉移到函數addition。調用傳遞的兩個參數的數值(5 和3)被復制到函數的本地變量(local variables)int a 和int b 中。函數addition 中定義了新的變量(int r;),通過表達式r=a+b;, 它把a 加b 的結果賦給r。因為傳過來的參數a 和b 的值分別為5 和3,所以結果是8。下面一行代碼: return(r);結束函數addition,并把控制權交還給調用它的函數(main),從調用addition的地方開始繼續向下執行。另外,return 在調用的時候后面跟著變量r(return(r);), 它當時的值為8, 這個值被稱為函數的返回值。

函數返回的數值就是函數的計算結果,因此,z 將存儲函數addition(5, 3)返回的數值, 即8。用另一種方式解釋,你也可以想象成調用函數(addition(5,3))被替換成了它的返回值(8)。

接下來main中的下一行代碼是: cout << “The result is ” << z;它把結果打印在屏幕上。

變量的范圍(Scope of variables)你必須考慮到變量的范圍只是在定義該變量的函數或指令塊內有效,而不能在它的函數或指令塊之外使用。例如,在上面的例子里就不可能在main 中直接使用變量a, b 或 r,因為它們是函數addition的本地變量(local variable)。在函數addition中也不可能直接使用變量z,因為它是main的本地變量。

因此,本地變量(local variables)的范圍是局限于聲明它的嵌套范圍之內的。盡管如此,你還可以定義全局變量(global variables),它們可以在代碼的任何位置被訪問,不管在函數以內還是以外。要定義全局變量,你必須在所有函數或代碼塊之外定義它們,也就是說,直接在程序體中聲明它們。這里是另一個關于函數的例子: // function example #include int subtraction(int a, int b){ int r;r=a-b;return(r);}

int main(){ int x=5, y=3, z;z = subtraction(7,2);cout << “The first result is ” << z << 'n';cout << “The second result is ” << subtraction(7,2)<< 'n';cout << “The third result is ” << subtraction(x,y)<< 'n';z= 4 + subtraction(x,y);cout << “The fourth result is ” << z << 'n';return 0;} The first result is 5 The second result is 5 The third result is 2 The fourth result is 6 在這個例子中,我們定義了函數subtraction。這個函數的功能是計算傳入的兩個參數的差值并將結果返回。

在 main 函數中,函數subtraction被調用了多次。我們用了幾種不同的調用方法,因此你可以看到在不同的情況下函數如何被調用。為了更好的理解這些例子,你需要考慮到被調用的函數其實完全可以由它所返回的值來代替。例如在上面例子中第一種情況下(這種調用你應該已經知道了,因為我們在前面的例子中已經用過這種形式的調用): z = subtraction(7,2);cout << “The first result is ” << z;如果我們把函數調用用它的結果(也就是5)替換,我們將得到: z = 5;cout << “The first result is ” << z;同樣的

cout << “The second result is ” << subtraction(7,2);與前面的調用有同樣的結果,但在這里我們把對函數subtraction 的調用直接用作cout的參數。這可以簡單想象成我們寫的是: cout << “The second result is ” << 5;因為5 是subtraction(7,2)的結果。在

cout << “The third result is ” << subtraction(x,y);中,與前面的調用唯一的不同之處是這里調用subtraction 時的參數使用的是變量而不是常量。這樣用時毫無問題的。在這個例子里,傳入函數subtraction 的參數值是變量x 和y中存儲的數值,即分別為5 和3,結果為2。第四種調用也是一樣的。只要知道除了 z = 4 + subtraction(x,y);我們也可以寫成:

z = subtraction(x,y)+ 4;它們的結果是完全一樣的。注意在整個表達式的結尾寫上分號semicolon sign(;)。它并不需要總是跟在函數調用的后面,因為你可以有一次把它們想象成函數被它的結果所替代: z = 4 + 2;z = 2 + 4;沒有返回值類型的函數,使用void.如果你記得函數聲明的格式:

type name(argument1, argument2...)statement 就會知道函數聲明必須以一個數據類型(type)開頭,它是函數由return 語句所返回數據類型。但是如果我們并不打算返回任何數據那該怎么辦呢? 假設我們要寫一個函數,它的功能是打印在屏幕上打印一些信息。我們不需要它返回任何值,而且我們也不需要它接受任何參數。C語言為這些情況設計了void 類型。讓我們看一下下面的例子:

// void 函數示例 #include using namespace std;

void printmessage(){ cout << “I'm a function!”;}

int main(){ printmessage();return 0;} I'm a function!void還可以被用在函數參數位置,表示我們明確希望這個函數在被調用時不需要任何參數。例如上面的函數printmessage也可以寫為以下形式: void printmessage(void){ cout << “I'm a function!”;} 雖然在C++ 中void可以被省略,我們還是建議寫出void,以便明確指出函數不需要參數。你必須時刻知道的是調用一個函數時要寫出它的名字并把參數寫在后面的括號內。但如果函數不需要參數,后面的括號并不能省略。因此調用函數 printmessage 的格式是 printmessage();函數名稱后面的括號就明確表示了它是一個函數調用,而不是一個變量名稱或其它什么語句。以下調用函數的方式就不對: printmessage;2.3 函數II(Functions II)

參數按數值傳遞和按地址傳遞(Arguments passed by value and by reference)到目前為止,我們看到的所有函數中,傳遞到函數中的參數全部是按數值傳遞的(by value)。也就是說,當我們調用一個帶有參數的函數時,我們傳遞到函數中的是變量的數值而不是變量本身。例如,假設我們用下面的代碼調用我們的第一個函數addition : int x=5, y=3, z;z = addition(x , y);在這個例子里我們調用函數addition 同時將x和y的值傳給它,即分別為5和3,而不是兩個變量:

這樣,當函數addition被調用時,它的變量a和b的值分別變為5和3,但在函數addition內對變量a 或b 所做的任何修改不會影響變量他外面的變量x 和 y 的值,因為變量x和y并沒有把它們自己傳遞給函數,而只是傳遞了他們的數值。

但在某些情況下你可能需要在一個函數內控制一個函數以外的變量。要實現這種操作,我們必須使用按地址傳遞的參數(arguments passed by reference),就象下面例子中的函數duplicate:

// passing parameters by reference #include

void duplicate(int& a, int& b, int& c){ a*=2;b*=2;c*=2;}

int main(){ int x=1, y=3, z=7;duplicate(x, y, z);cout << “x=” << x << “, y=” << y << “, z=” << z;return 0;} x=2, y=6, z=14 第一個應該注意的事項是在函數duplicate的聲明(declaration)中,每一個變量的類型后面跟了一個地址符ampersand sign(&),它的作用是指明變量是按地址傳遞的(by reference),而不是像通常一樣按數值傳遞的(by value)。當按地址傳遞(pass by reference)一個變量的時候,我們是在傳遞這個變量本身,我們在函數中對變量所做的任何修改將會影響到函數外面被傳遞的變量。

用另一種方式來說,我們已經把變量a, b,c和調用函數時使用的參數(x, y和 z)聯系起來了,因此如果我們在函數內對a 進行操作,函數外面的x 值也會改變。同樣,任何對b 的改變也會影響y,對c 的改變也會影響z>。

這就是為什么上面的程序中,主程序main中的三個變量x, y和z在調用函數duplicate 后打印結果顯示他們的值增加了一倍。如果在聲明下面的函數:

void duplicate(int& a, int& b, int& c)時,我們是按這樣聲明的:

void duplicate(int a, int b, int c)也就是不寫地址符 ampersand(&),我們也就沒有將參數的地址傳遞給函數,而是傳遞了它們的值,因此,屏幕上顯示的輸出結果x, y,z 的值將不會改變,仍是1,3,7。

這種用地址符 ampersand(&)來聲明按地址“by reference”傳遞參數的方式只是在C++中適用。在C 語言中,我們必須用指針(pointers)來做相同的操作。

按地址傳遞(Passing by reference)是一個使函數返回多個值的有效方法。例如,下面是一個函數,它可以返回第一個輸入參數的前一個和后一個數值。// more than one returning value #include void prevnext(int x, int& prev, int& next){ prev = x-1;next = x+1;}

int main(){ int x=100, y, z;prevnext(x, y, z);cout << “Previous=” << y << “, Next=” << z;return 0;} Previous=99, Next=101

參數的默認值(Default values in arguments)當聲明一個函數的時候我們可以給每一個參數指定一個默認值。如果當函數被調用時沒有給出該參數的值,那么這個默認值將被使用。指定參數默認值只需要在函數聲明時把一個數值賦給參數。如果函數被調用時沒有數值傳遞給該參數,那么默認值將被使用。但如果有指定的數值傳遞給參數,那么默認值將被指定的數值取代。例如: // default values in functions #include int divide(int a, int b=2){ int r;r=a/b;return(r);}

int main(){ cout << divide(12);cout << endl;cout << divide(20,4);return 0;} 6 5 我們可以看到在程序中有兩次調用函數divide。第一次調用: divide(12)只有一個參數被指明,但函數divide允許有兩個參數。因此函數divide 假設第二個參數的值為2,因為我們已經定義了它為該參數缺省的默認值(注意函數聲明中的int b=2)。因此這次函數調用的結果是 6(12/2)。在第二次調用中: divide(20,4)這里有兩個參數,所以默認值(int b=2)被傳入的參數值4所取代,使得最后結果為 5(20/4).函數重載(Overloaded functions)兩個不同的函數可以用同樣的名字,只要它們的參量(arguments)的原型(prototype)不同,也就是說你可以把同一個名字給多個函數,如果它們用不同數量的參數,或不同類型的參數。例如:

// overloaded function #include

int divide(int a, int b){ return(a/b);}

float divide(float a, float b){ return(a/b);}

int main(){ int x=5,y=2;float n=5.0,m=2.0;cout << divide(x,y);cout << “n”;cout << divide(n,m);cout << “n”;return 0;} 2 2.5 在這個例子里,我們用同一個名字定義了兩個不同函數,當它們其中一個接受兩個整型(int)參數,另一個則接受兩個浮點型(float)參數。編譯器(compiler)通過檢查傳入的參數的類型來確定是哪一個函數被調用。如果調用傳入的是兩個整數參數,那么是原型定義中有兩個整型(int)參量的函數被調用,如果傳入的是兩個浮點數,那么是原型定義中有兩個浮點型(float)參量的函數被調用。

為了簡單起見,這里我們用的兩個函數的代碼相同,但這并不是必須的。你可以讓兩個函數用同一個名字同時完成完全不同的操作。

Inline 函數(inline functions)

inline 指令可以被放在函數聲明之前,要求該函數必須在被調用的地方以代碼形式被編譯。這相當于一個宏定義(macro)。它的好處只對短小的函數有效,這種情況下因為避免了調用函數的一些常規操作的時間(overhead),如參數堆棧操作的時間,所以編譯結果的運行代碼會更快一些。

它的聲明形式是:

inline type name(arguments...){ instructions...} 它的調用和其他的函數調用一樣。調用函數的時候并不需要寫關鍵字inline,只有在函數聲明前需要寫。

遞歸(Recursivity)

遞歸(recursivity)指函數將被自己調用的特點。它對排序(sorting)和階乘(factorial)運算很有用。例如要獲得一個數字n的階乘,它的數學公式是: n!= n *(n-1)*(n-2)*(n-3)...* 1 更具體一些,5!(factorial of 5)是: 5!= 5 * 4 * 3 * 2 * 1 = 120 而用一個遞歸函數來實現這個運算將如以下代碼: // factorial calculator #include

long factorial(long a){ if(a > 1)return(a * factorial(a-1));else return(1);}

int main(){ long l;cout << “Type a number: ”;cin >> l;cout << “!” << l << “ = ” << factorial(l);return 0;} Type a number: 9!9 = 362880 注意我們在函數factorial中是怎樣調用它自己的,但只是在參數值大于1的時候才做調用,因為否則函數會進入死循環(an infinite recursive loop),當參數到達0的時候,函數不繼續用負數乘下去(最終可能導致運行時的堆棧溢出錯誤(stack overflow error)。

這個函數有一定的局限性,為簡單起見,函數設計中使用的數據類型為長整型(long)。在實際的標準系統中,長整型long無法存儲12!以上的階乘值。

函數的聲明(Declaring functions)

到目前為止,我們定義的所有函數都是在它們第一次被調用(通常是在main中)之前,而把main 函數放在最后。如果重復以上幾個例子,但把main 函數放在其它被它調用的函數之前,你就會遇到編譯錯誤。原因是在調用一個函數之前,函數必須已經被定義了,就像我們前面例子中所做的。

但實際上還有一種方法來避免在main 或其它函數之前寫出所有被他們調用的函數的代碼,那就是在使用前先聲明函數的原型定義。聲明函數就是對函數在的完整定義之前做一個短小重要的聲明,以便讓編譯器知道函數的參數和返回值類型。它的形式是:

type name(argument_type1, argument_type2,...);它與一個函數的頭定義(header definition)一樣,除了:

? 它不包括函數的內容,也就是它不包括函數后面花括號{}內的所有語句。? 它以一個分號semicolon sign(;)結束。

? 在參數列舉中只需要寫出各個參數的數據類型就夠了,至于每個參數的名字可以寫,也可以不寫,但是我們建議寫上。例如:

// 聲明函數原型

#include

void odd(int a);void even(int a);

int main(){ int i;do { cout << “Type a number:(0 to exit)”;cin >> i;odd(i);} while(i!=0);return 0;}

void odd(int a){ if((a%2)!=0)cout << “Number is odd.n”;else even(a);}

void even(int a){ if((a%2)==0)cout << “Number is even.n”;else odd(a);} Type a number(0 to exit): 9 Number is odd.Type a number(0 to exit): 6 Number is even.Type a number(0 to exit): 1030 Number is even.Type a number(0 to exit): 0 Number is even.這個例子的確不是很有效率,我相信現在你已經可以只用一半行數的代碼來完成同樣的功能。但這個例子顯示了函數原型(prototyping functions)是怎樣工作的。并且在這個具體的例子中,兩個函數中至少有一個是必須定義原型的。這里我們首先看到的是函數odd 和even的原型: void odd(int a);void even(int a);這樣使得這兩個函數可以在它們被完整定義之前就被使用,例如在main中被調用,這樣main就可以被放在邏輯上更合理的位置:即程序代碼的開頭部分。

盡管如此,這個程序需要至少一個函數原型定義的特殊原因是因為在odd 函數里需要調用even 函數,而在even 函數里也同樣需要調用odd函數。如果兩個函數任何一個都沒被提前定義原型的話,就會出現編譯錯誤,因為或者odd 在even 函數中是不可見的(因為它還沒有被定義),或者even 函數在odd函數中是不可見的。

很多程序員建議給所有的函數定義原型。這也是我的建議,特別是在有很多函數或函數很長的情況下。把所有函數的原型定義放在一個地方,可以使我們在決定怎樣調用這些函數的時候輕松一些,同時也有助于生成頭文件。

第三章 高級數據類型(Advanced Data)1.數組 Arrays 2.字符序列

Characters Sequences 3.指針 Pointers 4.動態內存分配 Dynamic memory 5.數據結構 Data Structures 6.自定義數據類型

User defined data types 3.1 數組(Arrays)

數組(Arrays)是在內存中連續存儲的一組同種數據類型的元素(變量),每一數組有一個唯一名稱,通過在名稱后面加索引(index)的方式可以引用它的每一個元素。

也就是說,例如我們有5個整型數值需要存儲,但我們不需要定義5個不同的變量名稱,而是用一個數組(array)來存儲這5個不同的數值。注意數組中的元素必須是同一數據類型的,在這個例子中為整型(int)。

例如一個存儲5個整數叫做billy的數組可以用下圖來表示:

這里每一個空白框代表數組的一個元素,在這個例子中為一個整數值。白框上面的數字0 到4 代表元素的索引(index)。注意無論數組的長度如何,它的第一個元素的索引總是從0開始的。

同其它的變量一樣,數組必須先被聲明然后才能被使用。一種典型的數組聲明顯示如下: type name [elements];這里type 是可以使任何一種有效的對象數據類型(object type),如 int, float...等,name 是一個有效地變量標識(identifier),而由中括號[]引起來的elements 域指明數組的大小,即可以存儲多少個元素。

因此,要定義上面圖中顯示的 billy 數組,用一下語句就可以了: int billy [5];備注:在定義一個數組的時候,中括號[]中的elements 域必須是一個常量數值,因為數組是內存中一塊有固定大小的靜態空間,編譯器必須在編譯所有相關指令之前先能夠確定要給該數組分配多少內存空間。

初始化數組(Initializing arrays)當聲明一個本地范圍內(在一個函數內)的數組時,除非我們特別指定,否則數組將不會被初始化,因此它的內容在我們將數值存儲進去之前是不定的。如果我們聲明一個全局數組(在所有函數之外),則它的內容將被初始化為所有元素均為0。因此,如果全局范圍內我們聲明: int billy [5];那么billy 中的每一個元素將會被初始化為0:

另外,我們還可以在聲明一個變量的同時把初始值付給數組中的每一個元素,這個賦值用花括號{ }來完成。例如:

int billy [5] = { 16, 2, 77, 40, 12071 };這個聲明將生成如下數組:

花括號中我們要初始化的元素數值個數必須和數組聲明時方括號[ ]中指定的數組長度相符。例如,在上面例子中數組billy 聲明中的長度為5,因此在后面花括號中的初始值也有5個,每個元素一個數值。

因為這是一種信息的重復,因此C++允許在這種情況下數組[ ]中為空白,而數組的長度將有后面花括號{}中數值的個數來決定,如下例所示。int billy [] = { 16, 2, 77, 40, 12071 };存取數組中數值(Access to the values of an Array)在程序中我們可以讀取和修改數組任一元素的數值,就像操作其他普通變量一樣。格式如下: name[index] 繼續上面的例子,數組billy 有5個元素,其中每一元素都是整型int,我們引用其中每一個元素的名字分別為如下所示:

例如,要把數值75存入數組billy 中第3個元素的語句可以是: billy[2] = 75;又例如,要把數組billy 中第3個元素的值賦給變量a,我們可以這樣寫: a = billy[2];因此,在所有使用中,表達式billy[2]就像任何其他整型變量一樣。

注意數組billy 的第3個元素為billy[2],因為索引(index)從0開始,第1個元素是billy[0],第2個元素是billy[1],因此第3個是 billy[2]。同樣的原因,最后一個元素是billy[4]。如果我們寫billy[5],那么是在使用billy的第6個元素,因此會超出數組的長度。

在C++ 中對數組使用超出范圍的index是合法的,這就會產生問題,因為它不會產生編譯錯誤而不易被察覺,但是在運行時會產生意想不到的結果,甚至導致嚴重運行錯誤。超出范圍的index 之所以合法的原因我們在后面學習指針(pointer)的時候會了解。學到這里,我們必須能夠清楚的了解方括號[ ]在對數組操作中的兩種不同用法。它們完成兩種任務:一種是在聲明數組的時候定義數組的長度;另一種是在引用具體的數組元素的時候指明一個索引號(index)。我們要注意不要把這兩種用法混淆。int billy[5];// 聲明新數組(以數據類型名稱開頭)billy[2] = 75;// 存儲數組的一個元素 其它合法的數組操作:

billy[0] = a;// a為一個整型變量 billy[a] = 75;b = billy [a+2];billy[billy[a]] = billy[2] + 5;

// arrays example #include

int billy [ ] = {16, 2, 77, 40, 12071};int n, result=0;

int main(){ for(n=0;n<5;n++){ result += billy[n];}

cout << result;return 0;} 12206

多維數組(Multidimensional Arrays)

多維數組(Multidimensional Arrays)可以被描述為數組的數組。例如,一個2維數組(bidimensional array)可以被想象成一個有同一數據類型的2維表格。

jimmy 顯示了一個整型(int)的3x5二維數組,聲明這一數組的的方式是: int jimmy [3][5];而引用這一數組中第2列第4排元素的表達式為:jimmy[1][3]

(記住數組的索引總是從0開始)。多維數組(Multidimensional arrays)并不局限于2維。如果需要,它可以有任意多維,雖然需要3維以上的時候并不多。但是考慮一下一個有很多維的數組所需要的內存空間,例如: char century [100][365][24][60][60];給一個世紀中的每一秒賦一個字符(char),那么就是多于30億的字符!如果我們定義這樣一個數組,需要消耗3000M的內存。

多維數組只是一個抽象的概念,因為我們只需要把各個索引的乘積放入一個簡單的數組中就可以獲得同樣的結果。例如:

int jimmy [3][5];效果上等價于 int jimmy [15];(3 * 5 = 15)唯一的區別是編譯器幫我們記住每一個想象中的維度的深度。下面的例子中我們就可以看到,兩段代碼一個使用2維數組,另一個使用簡單數組,都獲得同樣的結果,即都在內存中開辟了一塊叫做jimmy的空間,這個空間有15個連續地址位置,程序結束后都在相同的位置上存儲了相同的數值,如后面圖中所示: // multidimensional array #include #define WIDTH 5 #define HEIGHT 3

int jimmy [HEIGHT][WIDTH];int n,m;

int main(){ for(n=0;n

return 0;} // pseudo-multidimensional array #include #define WIDTH 5 #define HEIGHT 3

int jimmy [HEIGHT * WIDTH];int n,m;

int main(){ for(n=0;n

#define HEIGHT 4 而不需要對程序的其他部分作任何修改。

數組參數(Arrays as parameters)

有時候我們需要將數組作為參數傳給函數。在C++ 中將一整塊內存中的數值作為參數完整的傳遞給一個函數是不可能的,即使是一個規整的數組也不可能,但是允許傳遞它的地址。它們的實際作用是一樣的,但傳遞地址更快速有效。

要定義數組為參數,我們只需要在聲明函數的時候指明參數數組的基本數據類型,一個標識后面再跟一對空括號[]就可以了。例如以下的函數: void procedure(int arg[])接受一個叫做arg的整型數組為參數。為了給這個函數傳遞一個按如下定義的數組: int myarray [40];其調用方式可寫為: procedure(myarray);下面我們來看一個完整的例子: // arrays as parameters #include

void printarray(int arg[ ], int length){ for(int n=0;n

int main(){ int firstarray[ ] = {5, 10, 15};int secondarray[ ] = {2, 4, 6, 8, 10};printarray(firstarray,3);printarray(secondarray,5);return 0;} 5 10 15 2 4 6 8 10 可以看到,函數的第一個參數(int arg[ ])接受任何整型數組為參數,不管其長度如何。因此,我們用了第2個參數來告知函數我們傳給它的第一個參數數組的長度。這樣函數中打印數組內容的for 循環才能知道需要檢查的數組范圍。

在函數的聲明中也包含多維數組參數。定義一個3維數組(tridimensional array)的形式是:

base_type[ ][depth][depth] 例如,一個函數包含多維數組參數的函數可以定義為: void procedure(int myarray[ ][3][4])注意第一對括號[ ]中為空,而后面兩對不為空。這是必須的,因為編譯器必須能夠在函數中確定每一個增加的維度的深度。

數組作為函數的參數,不管是多維數組還是簡單數組,都是初級程序員容易出錯的地方。建議閱讀章節3.3, 指針(Pointers),以便更好的理解數組(arrays)是如何操作的。

3.2 字符序列(Character Sequences)

前面基礎知識部分講C++變量類型的時候,我們已經提到過C++的標準函數庫提供了一個string類來支持對字符串的操作。然而,字符串實際就是一串連續的字符序列,所以我們也可以用簡單的字符數組來表示它。例如,下面這個數組: char jenny [20];是一個可以存儲最多20個字符類型數據的數組。你可以把它想象成:

理論上這數組可以存儲長度為20的字符序列,但是它也可以存儲比這短的字符序列,而且實際中常常如此。例如,jenny 在程序的某一點可以只存儲字符串“Hello” 或者“Merry christmas”。因此,既然字符數組經常被用于存儲短于其總長的字符串,就形成了一種習慣在字符串的有效內容的結尾處加一個空字符(null character)來表示字符結束,它的常量表示可寫為0 或'

主站蜘蛛池模板: 久久人人爽爽爽人久久久| 日日av色欲香天天综合网| 日韩成人极品在线内射3p蜜臀| 无码人妻丰满熟妇区视频| 无码中文精品专区一区二区| 久久国产精品_国产精品| 国产成人av在线免播放app| 精品久久伊人99热超碰| 国产成人av一区二区三区无码| 亚洲高请码在线精品av| 欧美精品v国产精品v日韩精品| 少妇高潮惨叫久久久久久| 日韩亚洲欧美在线com| 国产女精品视频网站免费蜜芽| 丰满人妻熟妇乱又伦精品视频三| 亚洲aⅴ无码成人网站国产app| 波多野结衣绝顶大高潮| √最新版天堂资源在线| 久久九九有精品国产23百花影院| 国产成人无码h在线观看网站| 99久久国产综合精品女同图片| 精品乱人伦一区二区三区| 无码一区二区三区老色鬼| 久久国产精品99久久久久久口爆| 欧美熟妇精品一区二区三区| 国产又色又爽又高潮免费视频麻豆| 在线观看一区二区三区av| 色老汉免费网站免费视频| 色拍拍在线精品视频| 97se亚洲综合在线| 大伊香蕉精品视频在线天堂| 老司机亚洲精品影院无码| 四川老熟妇乱子xx性bbw| 亚洲春色cameltoe一区| 大尺度无遮挡激烈床震网站| 国产成人精品123区免费视频| 中文无码伦av中文字幕| 国产成人无码牲交免费视频| 国产精品国产三级国产av品爱网| 国产欧美国日产高清| 欧美精品久久久久久|