一、程序源文件命名約定
無論你使用命令行界面或者IDE,大多數編譯器都要求程序源碼存儲在一個或多個文件中。程序文件通常被稱為源文件(source file)。在大多數系統中,源文件的名字以一個后綴為結尾,后綴是由一個句點后接-一個或多個字符組成的。后綴告訴系統這個文件是一個C++程序。不同編譯器使用不同的后綴命名約定,最常見的包括. cc、.cxx、.cpp、.cp及.C。
二、初識輸入輸出
本書中的很多示例都使用了iostream 庫。iostream 庫包含兩個基礎類型istream和ostream,分別表示輸入流和輸出流。一個流就是一個字符序列,是從IO設備讀出或寫入IO設備的。術語“流" (stream)想要表達的是,隨著時間的推移,字符是順序生成或消耗的。
#include < iostream > // 頭文件
int main()
{
std::cout < < "Enter two numbers : " < < std::endl;
int v1 = 0, v2 = 0;
std::cin > > v1 > > v2 ;
std::cout< < "The sum of " < < v1 < < " and " < < v2 < < " is " < < v1 + v2 < < std::endl;
return 0;
}
這個程序開始時在用戶屏幕打印
Enter two numbers :
然后等待用戶輸入。如果用戶鍵入
6 8
然后鍵入一個回車,則程序產生如下輸出:
The sum of 6 and 8 is 14
1、向流寫入數據
main 的函數體的第一條語句執行了一個表達式(expression)。在C++中,一個表達式產生一個計算結果,它由一個或多個運算對象和(通常是) 一個運算符組成。這條語句中的表達式使用了輸出運算符(<<)在標準輸出上打印消息:
std::cout < < "Enter two numbers : " < < std::endl;
<< 運算符接受兩個運算對象:左側的運算對象必須是一個 ostream對象,右側的運算對象是要打印的值。此運算符將給定的值寫到給定的ostream對象中。輸出運算符的計算結果就是其左側運算對象。即,計算結果就是我們寫入給定值的那個ostream對象。我們的輸出語句使用了兩次<<運算符。因為此運算符返回其左側的運算對象,因此第一個運算符的結果成為了第二個運算符的左側運算對象。這樣,我們就可以將輸出請求連接起來。
因此,我們的表達式等價于;
(std::cout << "Enter two numbers:") << std::endl;
等價于:
std: :cout << "Enter two numbers:";
std: :cout << std: :endl;
第一個輸出運算符給用戶打印一條消息。這個消息是一個字符串字面值常量(string literal),是用一對雙引號包圍的字符序列。在雙引號之間的文本被打印到標準輸出。
第二個運算符打印endl,這是一個被稱為操縱符(manipulator)的特殊值。寫入endl的效果是結束當前行,并將與設備關聯的緩沖區( buffer)中的內容刷到設備中。緩沖刷新操作可以保證到目前為止程序所產生的所有輸出都真正寫入輸出流中,而不是僅停留在內存中等待寫入流。
2、使用標準庫中的名字
細心的讀者可能會注意到這個程序使用了std: :cout和std: :endl。前綴std: :指出名字cout和endl是定義在名為std的命名空間(namespace)中的。標準庫定義的所有名字都在命名空間std中。通過命名空間使用標準庫有一個副作用:當使用標準庫中的一個名字時,必須顯式說明我們想使用來自命名空間std中的名字。例如,需要寫出std: :cout,通過使用作用域運算符( :: )來指出我們想使用定義在命名空間std中的名字cout。將給出一個更簡單的訪問標準庫中名字的方法。
3、從流讀取數據
在提示用戶輸入數據之后,接下來我們希望讀入用戶的輸入。
std: :cin >> v1 >> v2;
它讀入輸入數據。輸入運算符(>>)與輸出運算符類似,它接受一個istream作為其左側運算對象,接受一個對象作為其右側運算對象。它從給定的istream 讀入數據,并存入給定對象中。與輸出運算符類似,輸入運算符返回其左側運算對象作為其計算結果。
因此,此表達式等價于(std: :cin >> v1) >> v2;
等價于:
std::cin >> v1;
std::cin>>v2;
三、注釋簡介
// 正確
/* 正確 */
/* 正確
*/
/*
★注釋對/* */不 能嵌套。
★
“不能嵌套”幾個字會被認為是源碼,
★像剩余程序一樣處理
*/
#include < iostream >
int main()
{
std ::cout < < "/*";
std ::cout < "*/";
std ::cout < < /* "*/" */";
std ::cout < < /*"*/"/*"/*" */;
return 0;
}
四、控制流
語句一般是順序執行的:語句塊的第一條語句首先執行, 然后是第二條語句,依此類推。但程序設計語言提供了多種不同的控制流語句,允許我們寫出更為復雜的執行路徑。
1、while語句
C語言學習進階~總貼
2、for語句
C語言學習進階~總貼
3、讀取數量不定的輸人數據
在某種情況下,我們預先不知道要對多少個數求和,這就需要不斷讀取數據直至沒有新的輸入為止:
#include < iostream >
int main()
{
int sum = 0, value = 0;
std::cout < < "Enter " < < std::endl;
while (std::cin > > value) //讀取數據直到遇到文件尾,計算所有讀入的值的和
sum += value; //等價于sum=sum+value
std::cout < < "Sum is : " < < sum < < std::endl;
return 0;
}
如果我們輸入.
3 4 5 6 7 8
則程序會輸出
Sum is : 33
因此,我們的while 循環會一直執行 直至遇到文件結束符(或輸入錯誤)。while循環體使用復合賦值運算符將當前值加到sum上。一旦條件失敗,while循環將會結束。將執行下一條語句,打印sum的值和一個endl。
從鍵盤輸入文件結束符
當從鍵盤向程序輸入數據時,對于如何指出文件結束,不同操作系統有不同的約定。在Windows系統中,輸入文件結束符的方法是敲Ctrl+Z (按住Ctrl 鍵的同時按Z鍵),然后按Enter或Return鍵。在UNIX系統中,包括MacOSX系統中,文件結束符輸入是用Ctrl+D。
4、if 語句
與大多數語言一樣,C++也提供了if語句來支持條件執行。我們可以用if語句寫一個程序,來統計在輸入中每個值連續出現了多少次:
#include < iostream >
int main()
{
// currVal 是我們正在統計的數; 我們將讀入的新值存入val .
int currVal = 0, val = 0;
//讀取第一個數,并確保確實有數據可以處理
if (std::cin > > currVal) {
int cnt = 1;
//保存我們正在處理的當前值的個數
while (std::cin > > val)
{ // 讀取剩余的數
if (val == currVal) // 如果值相同
++cnt;
//將cnt加1
else
{
//否則,打印前一個值的個數
std::cout < < currVal < < " occurs "< < cnt < < " times" < < std::endl;
currVal = val;
//記住新值
cnt = 1;
//重置計數器
} // while循環在這里結束
//記住打印文件中最后一個值的個數
}
std::cout < < currVal < < " occurs " < < cnt < < " times" < < std::endl;
}//最外層的if語句在這里結束
return 0;
}
5、類簡介
在C++中,我們通過定義一個類(class) 來定義自己的數據結構。一個類定義了一個類型,以及與其關聯的一組操作。類機制是C++最重要的特性之一。實際上,C++最初的一個設計焦點就是能定義使用上像內置類型一樣自然的類類型(class type)。
為了使用類,我們需要了解三件事情:
- 類名是什么?
- 它是在哪里定義的?
- 它支持什么操作?
每個類實際上都定義了一個新的類型,其類型名就是類名。因此,我們的Sales_ item類定義了一個名為Sales_ item的類型。與內置類型一樣,我們可以定義類類型的變量。當我們寫下如下語句:
Sales item item;
是想表達item是一個Sales_ item 類型的對象。
(1)讀寫Sales_ item
#include < iostream >
#include "Sales_item.h"
int main()
{
Sales_item book;
//讀入ISBN號、售出的冊數以及銷售價格.
std:: cin > > book;
//寫入ISBN、 售出的冊數、總銷售額和平均價格
std:: cout < < book < < std:: endl;
return 0;
}
如果輸入:
0-201-70353-X 4 24.99
則輸出為:
0-201-70353-x 4 99.96 24.99
(2)Sales_ item對象的加法
#include < iostream >
#include "Sales_ item.h"
int main()
{
Sales_item item1,item2;
std:: cin > > iteml > > item2;
//讀取一對交易記錄
std:: cout < < item1 + item2 < < std :: endl;
//打印它們的和
return 0;
}
如果輸入如下內容:
0-201-78345-X 3 20. 00
0-201-78345-x 2 25.00
則輸出為:
0-201-78345-X 5 110 22
(3)初識成員函數
將兩個Sales_item對象相加的程序首先應該檢查兩個對象是否具有相同的ISBN。
方法如下:
#include < iostream >
#include "Sales item.h"
int main()
{
Sales_item iteml, item2;
std::cin > > iteml > > item2;
//首先檢查item1和item2是否表示相同的書
if (iteml.isbn() == item2.isbn()) {
std::cout < < item1 + item2 < < std::endl;
return 0; // 表示成功
}
else {
std::cerr < < "Data must refer to same ISBN" < < std :: endl;
return -1;
//表示失敗
}
}
什么是成員函數?
這個if語句的檢測條件 item1. isbn() == item2.isbn()
調用名為isbn的成員函數(member function)。成員函數是定義為類的一部分的函數,有時也被稱為方法(method)。我們通常以一個類對象的名義來調用成員函數。
使用點運算符(.)來表達我們需要“名為item1的對象的isbn成員”。點運算符只能用于類類型的對象。其左側運算對象必須是一個類類型的對象,右側運算對象必須是該類型的一個成員名,運算結果為右側運算對象指定的成員。
6、書店程序
我們需要從一個文件中讀取銷售記錄,生成每本書的銷售報告,顯示售出冊數、總銷售額和平均售價。我們假定每個ISBN書號的所有銷售記錄在文件中是聚在一起保存的。
我們的程序會將每個ISBN的所有數據合并起來,存入名為total的變量中。我們使用另一-個名為trans的變量保存讀取的每條銷售記錄。如果trans和total指向相同的ISBN,我們會更新total的值。否則,我們會打印total的值,并將其重置為剛剛讀取的數據(trans):
#include < iostream >
#include "Sales item. h"
int main()
{
Sales_item total; // 保存下一條交易記錄的變量
//讀入第一條交易記錄,并確保有數據可以處理
if (std:: cin > > total)
{
Sales_item trans;
//保存和的變量
//讀入并處理剩余交易記錄
while (std:: cin > > trans)
{
//如果我們仍在處理相同的書
if (total.isbn() == trans.isbn())
total += trans; // 更新總銷售額
else
{
//打印前一本書的結果
std:: cout < < total < < std :: endl;
total = trans; // total 現在表示下一本書的銷售額
}
}
std:: cout < < total < < std :: endl; //打印最后一本書的結果
}
else
{
//沒有輸入!警告讀者
std:: cerr < < "No data?!" < < std :: endl;
return -1; // 表示失敗
}
return 0;
}
#include "sales_item.h"
#ifndef __C__project__Sales_item__
#define __C__project__Sales_item__
#include < stdio.h >
#include < iostream >
#include < string >
class Sales_item {
// these declarations are explained section 7.2.1, p. 270
// and in chapter 14, pages 557, 558, 561
friend std::istream& operator >?>(std::istream&, Sales_item&);
friend std::ostream& operator< (std::ostream&, const Sales_item&);
friend bool operator< (const Sales_item&, const Sales_item&);
friend bool
operator==(const Sales_item&, const Sales_item&);
public:
// constructors are explained in section 7.1.4, pages 262 - 265
// default constructor needed to initialize members of built-in type
Sales_item() : units_sold(0), revenue(0.0) { }
Sales_item(const std::string &book) :
bookNo(book), units_sold(0), revenue(0.0) { }
Sales_item(std::istream &is) { is > > *this; }
public:
// operations on Sales_item objects
// member binary operator: left-hand operand bound to implicit this pointer
Sales_item& operator+=(const Sales_item&);
// operations on Sales_item objects
std::string isbn() const { return bookNo; }
double avg_price() const;
// private members as before
private:
std::string bookNo; // implicitly initialized to the empty string
unsigned units_sold;
double revenue;
};
// used in chapter 10
inline
bool compareIsbn(const Sales_item &lhs, const Sales_item &rhs)
{
return lhs.isbn() == rhs.isbn();
}
// nonmember binary operator: must declare a parameter for each operand
Sales_item operator+(const Sales_item&, const Sales_item&);
inline bool
operator==(const Sales_item &lhs, const Sales_item &rhs)
{
// must be made a friend of Sales_item
return lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue &&
lhs.isbn() == rhs.isbn();
}
inline bool
operator!=(const Sales_item &lhs, const Sales_item &rhs)
{
return !(lhs == rhs); // != defined in terms of operator==
}
// assumes that both objects refer to the same ISBN
Sales_item& Sales_item::operator+=(const Sales_item& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// assumes that both objects refer to the same ISBN
Sales_item
operator+(const Sales_item& lhs, const Sales_item& rhs)
{
Sales_item ret(lhs); // copy (|lhs|) into a local object that we'll return
ret += rhs; // add in the contents of (|rhs|)
return ret; // return (|ret|) by value
}
std::istream&
operator >?>(std::istream& in, Sales_item& s)
{
double price;
in > > s.bookNo > > s.units_sold > > price;
// check that the inputs succeeded
if (in)
s.revenue = s.units_sold * price;
else
s = Sales_item(); // input failed: reset object to default state
return in;
}
std::ostream&
operator< (std::ostream& out, const Sales_item& s)
{
out < < s.isbn() < < " " < < s.units_sold < < " "
< < s.revenue < < " " < < s.avg_price();
return out;
}
double Sales_item::avg_price() const
{
if (units_sold)
return revenue / units_sold;
else
return 0;
}
#endif /* defined(__C__project__Sales_item__) */
五、術語表
- 參數(實參,argument)向函數傳遞的值。
- 賦值( assignment)抹去一個對象的當前值,用一個新值取代之。
- 程序塊(block) 零條或多條語句的序列,用花括號包圍。
- 緩沖區(buffer)一個存儲區域,用于保存數據。I0設施通常將輸入(或輸出)數據保存在一個緩沖區中,讀寫緩沖區的動作與程序中的動作是無關的。我們可以顯式地刷新輸出緩沖,以便強制將緩沖區中的數據寫入輸出設備。默認情況下,讀cin會刷新cout;程序非正常終止時也會刷新cout.
- 內置類型(built-in type)由語言定義的類型,如int。
- Cerr一個ostream對象,關聯到標準錯誤,通常寫入到與標準輸出相同的設備。默認情況下,寫到cerr的數據是不緩沖的。cerr通常用于輸出錯誤信息或其他不屬.于程序正常邏輯的輸出內容。
- 字符串字面值常量( character stringliteral)術語string literal的另-種叫法。cin一個istream對象,用來從標準輸入讀取數據。
- 類(class)一種用于定義自己的數據結構及其相關操作的機制。類是C++中最基本的特性之一。標準庫類型中,如istream和ostream都是類。
- 類類型(class type)類定義的類型。類名即為類型名。
- clog一個ostream對象,關聯到標準錯誤。默認情況下,寫到clog的數據是被緩沖的。clog通常用于報告程序的執行信息,存入一個日志文件中。
- 注釋(comment)被編譯器忽略的程序文本。C++有兩種類型的注釋:單行注釋和界定符對注釋。單行注釋以//開始,從//到行尾的所有內容都是注釋。界定符對注釋以/ 開始,其后的所有內容都是注釋,直至遇到 /為止。
- 條件(condition)求值結果為真或假的表達式。通常用值0表示假,用非零值表示真。
- cout一個ostream對象,用于將數據寫入標準輸出。通常用于程序的正常輸出內容。
- 花括號(curly brace)花括號用于劃定程序塊邊界。左花括號({)為程序塊開始,右花括號(})為結束。
- 數據結構(data structure) 數據及其.上所允許的操作的一種 邏輯組合。
- 編輯-編譯-調試( edit-compile-debug)使程序能正確執行的開發過程。
- 文件結束符(end-of-file) 系 統特定的標識,指出文件中無更多數據了。表達式(expression) 最小的計算單元。一個表達式包含一個或多個運算對象,通常還包含一個或多個運算符。表達式求值會產生一個結果。例如,假設i和j是int對象,則i+j是一個表達式,它產生兩個int值的和。
- for語句( for statement)迭代語句,提供重復執行能力。通常用來將一個計算反復執行指定次數。
- 函數(function)具名的計算單元。
- 函數體(function body)語句塊,定義了函數所執行的動作。
- 函數名( function name)函數 為人所知的名字,也用來進行函數調用。
- 頭文件(header) 使類或其他名字的定義可被多個程序使用的一種機制。程序通過#include指令使用頭文件。
- if語句(if statement) 根據一 個特定條件的值進行條件執行的語句。如果條件為真,執行if語句體。否則,執行else語句體(如果存在的話)。
- 初始化(initialize) 在一個對象創建的時候賦予它一個值。
- iostream頭文件,提供了面向流的輸入輸出的標準庫類型。
- istream提供了面向流的輸入的庫類型。
- 庫類型(library type)標準庫定義的類型,如istream.
- main操作系統執行一個C++程序時所調用的函數。每個程序必須有且只有一個命名為main的函數。
- 操縱符(manipulator)對象,如std:end1,在讀寫流的時候用來“操縱”流本身。
- 成員函數( member function)類定義的操作。通常通過調用成員函數來操作特定對象。
- 方法(method)成員函數的同義術語。
- 命名空間( namespace)將庫定義的名字放在一個單一位置的機制。命名空間可以幫助避免不經意的名字沖突。C++標準庫定義的名字在命名空間std中。
- ostream標準庫類型,提供面向流的輸出。
- 形參列表( parameter list) 函數定義的部分,指出調用函數時可以使用什么樣的實參,可能為空列表。
- 返回類型(return type)函數返回值的類型。
- 源文件( source file )包含C++程序的文件。
- 標準錯誤(standard error)輸出流,用于報告錯誤。標準輸出和標準錯誤通常關聯到程序執行所在的窗口。
- 標準輸入(standard input)輸入流,通常與程序執行所在窗口相關聯。
- 標準庫(standard library) 一個類型和函數的集合,每個C++編譯器都必須支持。標準庫提供了支持I0操作的類型。C++程序員傾向于用“庫”指代整個標準庫,還傾向于用庫類型表示標準庫的特定部分,例如用“iostream庫”表示標準庫中定義I0類的部分。
- 標準輸出(standard output) 輸出流,通常與程序執行所在窗口相關聯。
- 語句(statement) 程序的一部分,指定了當程序執行時進行什么動作。一個表達式接一個分號就是一條語句;其他類型的語旬包括語句塊、if語旬、for語句和while語句,所有這些語句內都包含其他語句。
- std標準庫所使用的命名空間。std: :cout表示我們要使用定義在命名空間std中的名字cout.
- 字符串常量(string literal) 零或多個字符組成的序列,用雙引號包圍("a stringliteral")。
- 未初始化的變量( uninitialized variable )未賦予初值的變量。類類型的變量如果未指定初值,則按類定義指定的方式進行初始化。定義在函數內部的內置類型變量默認是不初始化的,除非有顯式的初始化語句。試圖使用一個未初始化變量的值是錯誤的。未初始化變量是bug的常見成因。
- 變量(variable)具名對象。:
- while語句( while statement)迭代語句,提供重復執行直至一個特定條件為假的機制。循環體會執行零次或多次,依賴于循環條件求值結果。
- ()運算符() operator)調用運算符。跟隨在函數名之后的一對括號“()”,起到調用函數的效果。傳遞給函數的實參放置在括號內。
- ++運算符(++ operator)遞增運算符。將運算對象的值加1,++i等價于i=i+1。
- +=運算符(+= operator)復合賦值運算符,將右側運算對象加到左側運算對象上;a+=b等價于a=a+b.
- .運算符(. operator) 點運算符。左側運算對象必須是一個類類型對象,右側運算對象必須是此對象的一個成員的名字。運算結果即為該對象的這個成員。
- ::運算符(:: operator)作用域運算符。其用處之一是訪問命名空間中的名字。例如,std::cout表示命名空間std中的名字cout。
- =運算符(= operator) 將右側運算對象的值賦予左側運算對象所表示的對象。
- --運算符(-- operator)遞減運算符。將運算對象的值減1,--i等價于i=i-1。
- <<運算符(<< operator)輸出運算符。將右側運算對象的值寫到左側運算對象表示的輸出流: (cout<< "hi"表示將hi寫到標準輸出。輸出運算符可以連接: cout <<"hi" << "bye"表示將輸出hibye.
運算符(>> operator)輸入運算符。從左側運算對象所指定的輸入流讀取數據,存入右側運算對象中: cin>> i表示從標準輸入讀取下一個值,存入i中。輸入運算符可以連接: cin>> i>> j表示先讀取一個值存入i,再讀取一個值存入j。
- #include頭文件包含指令,使頭文件中代碼可被程序使用。
- ==運算符(== operator)相等運算符。檢測左側運算對象是否等于右側運算對象。
- !=運算符(!= operator)不等運算符。檢測左側運算對象是否不等于右側運算對象。
- <=運算符(<= operator)小于等于運算符。檢測左側運算對象是否小于等于右側運算對象。
- <運算符(< operator)小于運算符。檢測左側運算對象是否小于右側運算對象。
=運算符(>= operator)大于等于運算符。檢測左側運算對象是否大于等于右側運算對象。
運算符(> operator)大于運算符。檢測左側運算對象是否大于右側運算對象。
評論
查看更多