第五章 表達式(C++語言定義的操作符,使用內置類型的操作數)
一元操作符unary,如取地址操作符&,解引用操作符*
二元操作符binary,如加法操作符+,減法操作符-
5.1&5.2算數操作符、關係操作符、邏輯操作符
溢出:表達式的求值結果超出了其類型的表示範圍。
關係操作符和邏輯操作符使用算術或指針類型的操作數,並返回bool類型的值:&&與,||或
string s("Expression in c++ are composed by some data and control symbols");
string::iterator it = s.begin();
while(it != s.end() && !isspace(*it)){
*it = toupper(*it);
++it;
}
cout << "convert the string to" << endl;
if(i < j < k)語句中的k與0、1相比較,關係操作符是從左開始進行計算
bool值本身可以進行if()語句的判斷,bool值爲真是1,爲假是0.
5.3位操作符bitwise operator
char是C/C++整型數據中比較古怪的一個,其它的如int/long/short等不指定signed/unsigned時都默認是signed,但char在標準中是unsigned
0UL 表示 無符號長整型0 unsigned long
1UL 表示 無符號長整型 1 unsigned long
如果不寫UL後綴,系統默認爲:int, 即,有符號整數。
1.數值常數有:整型常數、浮點常數;
2.只有數值常數纔有後綴說明;
3.數值常數後綴不區分字母大小寫。
(1)整型常數的表示形式有:十進制形式、以0開頭的八進制形式、以0x開頭的十六進制形式,無二進制形式。
整型常數默認是signed int的。
對整型常數進行類型轉換的後綴只有:u或U(unsigned)、l或L(long)、u/U與l/L的組合(如:ul、lu、Lu等)。例:100u; -123u; 0x123l;
(2)浮點常數的表示形式有:科學計數形式和小數點形式。
浮點常數默認是double的。
對浮點常數進行類型轉換的後綴只有:f或F(單精度浮點數)、l或L(長雙精度浮點數)。(注:因浮點型常數總是有符號的,故沒有u或U後綴)。例:1.23e5f; 1.23l; -123.45f;
位操作符:~ 位求反 << 左移 >> 右移 & 位與 ^ 位異或 | 位或
bitset<30> bitset_quizl;
unsigned long int_quizl = 0;
bitset_quizl.set(27);使用bitset來進行賦值計算
邏輯與、邏輯或操作符采用成爲“短路求值”(short-circuit evaluation)的求值策略
輸入輸出標準庫(IO library)分別重載了位操作符 >> 和 << 用於輸入和輸出。
移位操作符具有中等優先級:其優先級比算術操作符低,高於關係操作符、賦值操作符、條件操作符
5.4賦值操作符
數組名是不可修改的左值,而下標和解引用操作符都返回左值。
賦值操作符的優先級低於 不等操作符 賦值操作符具有“右結合性”
5.5、5.6自增和自減操作符
儘量使用前自增操作:前置操作只需要加1後返回加1後的結果;後置操作符必須先保存操作數原來的值,以便返回未加1的值作爲操作結果。
後自增操作優先級 > 解引用操作
每一個變量都有一個內存位置,每一個內存位置都定義了可使用連字號(&)運算符訪問的地址,它表示了在內存中的一個地址。可以對指針進行四種算術運算:++、--、+、-
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main()
{
vector<string*> spevc;
//讀取vector對象
string pv;
while (cin >> pv) {
string *tr = new string; //指向string 的指針
*tr = pv;
spevc.push_back(tr); //push_back必須兩個的類型相同 spevc爲指向string的指針,而tr也必須是指針
}
//輸出每個string 的內容及大小
vector<string*>::iterator iter = spevc.begin();
while (iter != spevc.end()) {
cout << "every string is " << **iter << (**iter).size() << endl; //第一個*解釋的是迭代器iterator的地址,第二個*解釋的是迭代器中元素的地址
cout << "every string is " << *iter << endl; //*iter的類型爲std::vector<string>::iterator類型
iter++;
}
//釋放各個動態分配的string對象
iter = spevc.begin();
while (iter != spevc.end()) {
delete *iter;
iter++;
}
return 0;
}
iter -> empty()調用iter所指向的string對象的成員函數empty
iter++ -> empty()調用iter所指向的string對象的成員函數empty,並使iter加1
5.7、條件操作符
語法格式:cond ?expr1:expr2;cond爲條件判斷表達式,爲真時計算expr1。爲假時計算expr2。 二元判斷的最優選擇
int max = i > j
? i > k ? i : k
: j > k ? j : k;
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int T;
vector<int> s;
while (cin >> T) {
s.push_back(T);
}
for (vector<int>::iterator iter = s.begin(); iter != s.end(); iter++) {
*(iter+1) = ((*iter > *(iter + 1)) ? *iter : *(iter + 1));
cout << *(iter + 1) << endl;
}
return 0;
}
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> ivec(20, 1);
;
size_t a = 0;
for (; a != ivec.size(); ++a) { //for語句中必須要有兩個分隔符,隔開三個語句
if (a % 2 == 0) {
ivec[a] = ivec[a] * 2;
cout << ivec[a] << endl;
}
else
{
cout << ivec[a] << endl;
}
}
return 0;
}
// int iv, a = 0;
// while (cin >> iv)
// ivec.push_back(iv)
// for (vector<int>::iterator i = ivec.begin(); i != ivec.end(); i++) {
// if ((*i % 2) == 0) {
// *i = *i * 2;
5.8 sizeof () 操作符
返回一個對象或類型名的長度,類型爲size_t 表達式的結果爲編譯時常量
1、對 char 類型或值爲 char 類型的表達式做 sizeof 操作保證得 1。
2、對引用類型做 sizeof 操作將返回存放此引用類型對象所需的內在空間大小。
3、對指針做 sizeof 操作將返回存放指針所需的內在大小;注意,如果要獲取該指針所指向對象的大小,則必須對指針進行引用。
4、操作等效於將對其元素類型做 sizeof 操作的結果乘上數組元素的個數。
5.9 逗號操作符
逗號表達式是一組由逗號分隔的表達式,這些表達式從左向右計算。逗號表達式的結果是其最右邊表達式的值。
5.10 優先級
++ 的優先級高於 * 操作符
第二個規則有一個重要的例外:如果一個子表達式修改操作數的值,然後將該子表達式的結果用於另一個子表達式,這樣則是安全的。例如,*++iter 表達式的自增操作修改了 iter 的值,然後將 iter(修改後)的值用作 * 操作符的操作數。對於這個表達式或其他類似的表達式,其操作數的計算次序無關緊要。而爲了計算更復雜的表達式,改變操作數值的子表達式必須首先計算。這種方法很常用,不會產生什麼問題。
5.11 new 和 delete 表達式
動態創建和釋放數組、單個對象等。
定義變量時,必須指定其數據類型和名字。而動態創建對象時,只需指定其數據類型,而不必爲該對象命名。取而代之的是,new 表達式返回指向新創建對象的指針,
對於類類型的對象,用該類的默認構造函數初始化,string類型等提供了默認構造函數;而內置類型的對象則無初始化。
int *pi = new int();
delete p;刪除語句後,p沒有定義,但是仍然存放了之前所指對象的地址。p所指向的內存已釋放,p不再有效,變爲懸垂指針。懸垂指針指向曾經存放對象的內存,但該對象已不存在。delete語句需要指向指針的對象。
const int *pci = new const int(1024);
5.12 類型轉換
隱式類型轉換:混合類型轉換相同類型;用作條件的表達式被轉換爲bool類型。
最簡單的轉換爲整型提升:對於所有比 int 小的整型,包括 char、signed char、unsigned char、short 和 unsigned short,如果該類型的所有可能的值都能包容在 int 內,它們就會被提升爲 int 型,否則,它們將被提升爲 unsigned int。如果將 bool 值提升爲 int ,則 false 轉換爲 0,而 true 則轉換爲 1。
在使用數組時,大多數情況下數組都會自動轉換爲指向第一個元素的指針;
不將數組轉換爲指針的例外情況有:數組用作取地址(&)操作符的操作數或 sizeof 操作符的操作數時,或用數組對數組的引用進行初始化時,不會將數組轉換爲指針。
指向任意數據類型的指針都可轉換爲 void* 類型;整型數值常量 0 可轉換爲任意指針類型
while(cin >> s)其中,while循環條件爲bool類型的值,此時給出的卻是istream類類型的值,istream類型的值應該轉換爲bool類型。將istream類型轉換爲bool類型需要檢驗流的狀態。
顯式轉換:強制類型轉換cast,static cast、dynamic cast、const cast、reinterpret cast
dynamic_cast支持運行時識別指針或引用所指向的對象
const_cast 將轉換掉表達式的 const 性質
const char *pc_str;
char *pc = string_copy(const_cast<char*>(pc_str));
static_cast 編譯器隱式執行的任何類型轉換都可以顯式完成
reinterpret_cast 通常爲操作數的位模式提供較低層次的重新解釋。
舊式強制轉換符號有下列兩種形式:
type (expr); // Function-style cast notation
(type) expr; // C-language-style cast notation