C++?數據類型
- 使用變量來存儲各種信息,變量保留的是它所存儲的值的內存位置。這意味著,當創建一個變量時,就會在內存中保留一些空間。這段內存空間可以用于存儲各種數據類型(比如字符型、寬字符型、整型、浮點型、雙浮點型、布爾型等)的信息,操作系統會根據變量的數據類型,來分配內存和決定在保留內存中存儲什么。
-
typedef short int wchar_t;因此?wchar_t 實際上的空間是和 short int 一樣。?
-
一些基本類型可以使用一個或多個類型修飾符進行修飾:
- signed
- unsigned
- short
- long
typedef 聲明
- 您可以使用?typedef?為一個已有的類型取一個新的名字。下面是使用 typedef 定義一個新類型的語法:
- typedef type newname;
- typedef int feed;給int給一個別名,feed
枚舉類型
- 枚舉類型(enumeration)是C++中的一種派生數據類型,它是由用戶定義的若干枚舉常量的集合。
- 如果一個變量只有幾種可能的值,可以定義為枚舉(enumeration)類型。所謂"枚舉"是指將變量的值一一列舉出來,變量的值只能在列舉出來的值的范圍內。創建枚舉,需要使用關鍵字?enum。枚舉類型的一般形式為:
enum 枚舉名{ 標識符[=整型常數], 標識符[=整型常數],
... 標識符[=整型常數]
} 枚舉變量;
- 如果枚舉沒有初始化, 即省掉"=整型常數"時, 則從第一個標識符開始。例如,下面的代碼定義了一個顏色枚舉,變量 c 的類型為 color。最后,c 被賦值為 "blue"。
enum color { red, green, blue } c;
c = blue;
- ?默認情況下,第一個名稱的值為 0,第二個名稱的值為 1,第三個名稱的值為 2,以此類推。但是,您也可以給名稱賦予一個特殊的值,只需要添加一個初始值即可。例如,在下面的枚舉中,green?的值為 5。
enum color { red, green=5, blue };
- 在這里,blue?的值為 6,因為默認情況下,每個名稱都會比它前面一個名稱大 1,但 red 的值依然為 0。
C++變量的類型
Extern?
- 當使用多個文件且只在其中一個文件中定義變量時(定義變量的文件在程序連接時是可用的),變量聲明就顯得非常有用。可以使用?extern?關鍵字在任何地方聲明一個變量。雖然可以在 C++ 程序中多次聲明一個變量,但變量只能在某個文件、函數或代碼塊中被定義一次。?
C++ 中的左值(Lvalues)和右值(Rvalues)
C++ 中有兩種類型的表達式:
- 左值(lvalue):指向內存位置的表達式被稱為左值(lvalue)表達式。左值可以出現在賦值號的左邊或右邊。
- 右值(rvalue):術語右值(rvalue)指的是存儲在內存中某些地址的數值。右值是不能對其進行賦值的表達式,也就是說,右值可以出現在賦值號的右邊,但不能出現在賦值號的左邊。
變量是左值,因此可以出現在賦值號的左邊。數值型的字面值是右值,因此不能被賦值,不能出現在賦值號的左邊。下面是一個有效的語句:int g = 20;
C++?變量作用域
作用域是程序的一個區域,一般來說有三個地方可以定義變量:
- 在函數或一個代碼塊內部聲明的變量,稱為局部變量。
- 在函數參數的定義中聲明的變量,稱為形式參數。
- 在所有函數外部聲明的變量,稱為全局變量。
初始化局部變量和全局變量
- 當局部變量被定義時,系統不會對其初始化,必須自行對其初始化。定義全局變量時,系統會自動初始化為下列值:
?整數變量
- 整數常量也可以帶一個后綴,后綴是 U 和 L 的組合,U 表示無符號整數(unsigned),L 表示長整數(long)。后綴可以是大寫,也可以是小寫,U 和 L 的順序任意。?
字符常量
- 字符常量是括在單引號中。如果常量以 L(僅當大寫時)開頭,則表示它是一個寬字符常量(例如 L'x'),此時它必須存儲在?wchar_t?類型的變量中。否則,它就是一個窄字符常量(例如 'x'),此時它可以存儲在?char?類型的簡單變量中。
- 字符常量可以是一個普通的字符(例如 'x')、一個轉義序列(例如 '\t'),或一個通用的字符(例如 '\u02C0')。
- 在 C++ 中,有一些特定的字符,當它們前面有反斜杠時,它們就具有特殊的含義,被用來表示如換行符(\n)或制表符(\t)等。下表列出了一些這樣的轉義序列碼:
定義常量
在 C++ 中,有兩種簡單的定義常量的方式:
- 使用?#define?預處理器。
- 使用?const?關鍵字。
C++ 中的類型限定符
類型限定符提供了變量的額外信息。?
C++?存儲類
- auto
- register
- static
- extern
- mutable
- thread_local (C++11)
auto 存儲類
- 自 C++ 11 以來,auto?關鍵字用于兩種情況:聲明變量時根據初始化表達式自動推斷該變量的類型、聲明函數時函數返回值的占位符。C++98標準中auto關鍵字用于自動變量的聲明,但由于使用極少且多余,在C++11中已刪除這一用法。
- 根據初始化表達式自動推斷被聲明的變量的類型,如:
auto f=3.14; //double
auto s("hello"); //const char*
auto z = new auto(9); // int*
auto x1 = 5, x2 = 5.0, x3='r';//錯誤,必須是初始化為同一類型
register 存儲類
- register?存儲類用于定義存儲在寄存器中而不是 RAM 中的局部變量。這意味著變量的最大尺寸等于寄存器的大小(通常是一個詞),且不能對它應用一元的 '&' 運算符(因為它沒有內存位置)。
{register int miles;
}
- 寄存器只用于需要快速訪問的變量,比如計數器。還應注意的是,定義 'register' 并不意味著變量將被存儲在寄存器中,它意味著變量可能存儲在寄存器中,這取決于硬件和實現的限制。
static 存儲類
- static?存儲類指示編譯器在程序的生命周期內保持局部變量的存在,而不需要在每次它進入和離開作用域時進行創建和銷毀。因此,使用 static 修飾局部變量可以在函數調用之間保持局部變量的值。
- static 修飾符也可以應用于全局變量。當 static 修飾全局變量時,會使變量的作用域限制在聲明它的文件內。
- 在 C++ 中,當 static 用在類數據成員上時,會導致僅有一個該成員的副本被類的所有對象共享。
extern 存儲類
- extern?存儲類用于提供一個全局變量的引用,全局變量對所有的程序文件都是可見的。當您使用 'extern' 時,對于無法初始化的變量,會把變量名指向一個之前定義過的存儲位置。
- 當您有多個文件且定義了一個可以在其他文件中使用的全局變量或函數時,可以在其他文件中使用?extern?來得到已定義的變量或函數的引用。可以這么理解,extern?是用來在另一個文件中聲明一個全局變量或函數。
- extern 修飾符通常用于當有兩個或多個文件共享相同的全局變量或函數的時候
mutable 存儲類
- mutable?說明符僅適用于類的對象,這將在本教程的最后進行講解。它允許對象的成員替代常量。也就是說,mutable 成員可以通過 const 成員函數修改。
thread_local 存儲類
- 使用 thread_local 說明符聲明的變量僅可在它在其上創建的線程上訪問。 變量在創建線程時創建,并在銷毀線程時銷毀。 每個線程都有其自己的變量副本。
- thread_local 說明符可以與 static 或 extern 合并。
- 可以將 thread_local 僅應用于數據聲明和定義,thread_local 不能用于函數聲明或定義。
- 以下演示了可以被聲明為 thread_local 的變量:
thread_local int x; // 命名空間下的全局變量
class X
{static thread_local std::string s; // 類的static成員變量
};
static thread_local std::string X::s; // X::s 是需要定義的void foo()
{thread_local std::vector<int> v; // 本地變量
}
C++?運算符
運算符是一種告訴編譯器執行特定的數學或邏輯操作的符號。C++ 內置了豐富的運算符,并提供了以下類型的運算符:
- 算術運算符
- 關系運算符
- 邏輯運算符
- 位運算符
- 賦值運算符
- 雜項運算符
C++ 教程
C++ 教程C++ 簡介C++ 環境設置C++ 基本語法C++ 注釋C++ 數據類型C++ 變量類型C++ 變量作用域C++ 常量C++ 修飾符類型C++ 存儲類C++ 運算符C++ 循環C++ 判斷C++ 函數C++ 數字C++ 數組C++ 字符串C++ 指針C++ 引用C++ 日期 & 時間C++ 基本的輸入輸出C++ 數據結構
C++?面向對象
C++ 類 & 對象C++ 繼承C++ 重載運算符和重載函數C++ 多態C++ 數據抽象C++ 數據封裝C++ 接口(抽象類)
C++?高級教程
C++ 文件和流C++ 異常處理C++ 動態內存C++ 命名空間C++ 模板C++ 預處理器C++ 信號處理C++ 多線程C++ Web 編程
C++?資源庫
C++ STL 教程C++ 標準庫C++ 有用的資源C++ 實例
?C++ 存儲類
C++ 循環?
C++?運算符
運算符是一種告訴編譯器執行特定的數學或邏輯操作的符號。C++ 內置了豐富的運算符,并提供了以下類型的運算符:
- 算術運算符
- 關系運算符
- 邏輯運算符
- 位運算符
- 賦值運算符
- 雜項運算符
本章將逐一介紹算術運算符、關系運算符、邏輯運算符、位運算符、賦值運算符和其他運算符。
算術運算符
下表顯示了 C++ 支持的算術運算符。
假設變量 A 的值為 10,變量 B 的值為 20,則:
運算符 | 描述 | 實例 |
---|---|---|
+ | 把兩個操作數相加 | A + B 將得到 30 |
- | 從第一個操作數中減去第二個操作數 | A - B 將得到 -10 |
* | 把兩個操作數相乘 | A * B 將得到 200 |
/ | 分子除以分母 | B / A 將得到 2 |
% | 取模運算符,整除后的余數 | B % A 將得到 0 |
++ | 自增運算符,整數值增加 1 | A++ 將得到 11 |
-- | 自減運算符,整數值減少 1 | A-- 將得到 9 |
實例
請看下面的實例,了解 C++ 中可用的算術運算符。
復制并粘貼下面的 C++ 程序到 test.cpp 文件中,編譯并運行程序。
實例
#include <iostream> using namespace std; int main() { int a = 21; int b = 10; int c; c = a + b; cout << "Line 1 - c 的值是 " << c << endl ; c = a - b; cout << "Line 2 - c 的值是 " << c << endl ; c = a * b; cout << "Line 3 - c 的值是 " << c << endl ; c = a / b; cout << "Line 4 - c 的值是 " << c << endl ; c = a % b; cout << "Line 5 - c 的值是 " << c << endl ; int d = 10; // 測試自增、自減 c = d++; cout << "Line 6 - c 的值是 " << c << endl ; d = 10; // 重新賦值 c = d--; cout << "Line 7 - c 的值是 " << c << endl ; return 0; }
當上面的代碼被編譯和執行時,它會產生以下結果:
Line 1 - c 的值是 31
Line 2 - c 的值是 11
Line 3 - c 的值是 210
Line 4 - c 的值是 2
Line 5 - c 的值是 1
Line 6 - c 的值是 10
Line 7 - c 的值是 10
關系運算符
下表顯示了 C++ 支持的關系運算符。
假設變量 A 的值為 10,變量 B 的值為 20,則:
運算符 | 描述 | 實例 |
---|---|---|
== | 檢查兩個操作數的值是否相等,如果相等則條件為真。 | (A == B) 不為真。 |
!= | 檢查兩個操作數的值是否相等,如果不相等則條件為真。 | (A != B) 為真。 |
> | 檢查左操作數的值是否大于右操作數的值,如果是則條件為真。 | (A > B) 不為真。 |
< | 檢查左操作數的值是否小于右操作數的值,如果是則條件為真。 | (A < B) 為真。 |
>= | 檢查左操作數的值是否大于或等于右操作數的值,如果是則條件為真。 | (A >= B) 不為真。 |
<= | 檢查左操作數的值是否小于或等于右操作數的值,如果是則條件為真。 | (A <= B) 為真。 |
實例
請看下面的實例,了解 C++ 中可用的關系運算符。
復制并黏貼下面的 C++ 程序到 test.cpp 文件中,編譯并運行程序。
實例
#include <iostream> using namespace std; int main() { int a = 21; int b = 10; int c ; if( a == b ) { cout << "Line 1 - a 等于 b" << endl ; } else { cout << "Line 1 - a 不等于 b" << endl ; } if ( a < b ) { cout << "Line 2 - a 小于 b" << endl ; } else { cout << "Line 2 - a 不小于 b" << endl ; } if ( a > b ) { cout << "Line 3 - a 大于 b" << endl ; } else { cout << "Line 3 - a 不大于 b" << endl ; } /* 改變 a 和 b 的值 */ a = 5; b = 20; if ( a <= b ) { cout << "Line 4 - a 小于或等于 b" << endl ; } if ( b >= a ) { cout << "Line 5 - b 大于或等于 a" << endl ; } return 0; }
當上面的代碼被編譯和執行時,它會產生以下結果:
Line 1 - a 不等于 b
Line 2 - a 不小于 b
Line 3 - a 大于 b
Line 4 - a 小于或等于 b
Line 5 - b 大于或等于 a
邏輯運算符
下表顯示了 C++ 支持的關系邏輯運算符。
假設變量 A 的值為 1,變量 B 的值為 0,則:
運算符 | 描述 | 實例 |
---|---|---|
&& | 稱為邏輯與運算符。如果兩個操作數都非零,則條件為真。 | (A && B) 為假。 |
|| | 稱為邏輯或運算符。如果兩個操作數中有任意一個非零,則條件為真。 | (A || B) 為真。 |
! | 稱為邏輯非運算符。用來逆轉操作數的邏輯狀態。如果條件為真則邏輯非運算符將使其為假。 | !(A && B) 為真。 |
實例
請看下面的實例,了解 C++ 中可用的邏輯運算符。
復制并黏貼下面的 C++ 程序到 test.cpp 文件中,編譯并運行程序。
實例
#include <iostream> using namespace std; int main() { int a = 5; int b = 20; int c ; if ( a && b ) { cout << "Line 1 - 條件為真"<< endl ; } if ( a || b ) { cout << "Line 2 - 條件為真"<< endl ; } /* 改變 a 和 b 的值 */ a = 0; b = 10; if ( a && b ) { cout << "Line 3 - 條件為真"<< endl ; } else { cout << "Line 4 - 條件不為真"<< endl ; } if ( !(a && b) ) { cout << "Line 5 - 條件為真"<< endl ; } return 0; }
當上面的代碼被編譯和執行時,它會產生以下結果:
Line 1 - 條件為真
Line 2 - 條件為真
Line 4 - 條件不為真
Line 5 - 條件為真
位運算符
位運算符作用于位,并逐位執行操作。&、 | 和 ^ 的真值表如下所示:
p | q | p & q | p | q | p ^ q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
假設如果 A = 60,且 B = 13,現在以二進制格式表示,它們如下所示:
A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A? = 1100 0011
下表顯示了 C++ 支持的位運算符。假設變量 A 的值為 60,變量 B 的值為 13,則:
運算符 | 描述 | 實例 |
---|---|---|
& | 如果同時存在于兩個操作數中,二進制 AND 運算符復制一位到結果中。 | (A & B) 將得到 12,即為 0000 1100 |
| | 如果存在于任一操作數中,二進制 OR 運算符復制一位到結果中。 | (A | B) 將得到 61,即為 0011 1101 |
^ | 如果存在于其中一個操作數中但不同時存在于兩個操作數中,二進制異或運算符復制一位到結果中。 | (A ^ B) 將得到 49,即為 0011 0001 |
~ | 二進制補碼運算符是一元運算符,具有"翻轉"位效果,即0變成1,1變成0。 | (~A ) 將得到 -61,即為 1100 0011,一個有符號二進制數的補碼形式。 |
<< | 二進制左移運算符。左操作數的值向左移動右操作數指定的位數。 | A << 2 將得到 240,即為 1111 0000 |
>> | 二進制右移運算符。左操作數的值向右移動右操作數指定的位數。 | A >> 2 將得到 15,即為 0000 1111 |
實例
請看下面的實例,了解 C++ 中可用的位運算符。
復制并黏貼下面的 C++ 程序到 test.cpp 文件中,編譯并運行程序。
實例
#include <iostream> using namespace std; int main() { unsigned int a = 60; // 60 = 0011 1100 unsigned int b = 13; // 13 = 0000 1101 int c = 0; c = a & b; // 12 = 0000 1100 cout << "Line 1 - c 的值是 " << c << endl ; c = a | b; // 61 = 0011 1101 cout << "Line 2 - c 的值是 " << c << endl ; c = a ^ b; // 49 = 0011 0001 cout << "Line 3 - c 的值是 " << c << endl ; c = ~a; // -61 = 1100 0011 cout << "Line 4 - c 的值是 " << c << endl ; c = a << 2; // 240 = 1111 0000 cout << "Line 5 - c 的值是 " << c << endl ; c = a >> 2; // 15 = 0000 1111 cout << "Line 6 - c 的值是 " << c << endl ; return 0; }
當上面的代碼被編譯和執行時,它會產生以下結果:
Line 1 - c 的值是 12
Line 2 - c 的值是 61
Line 3 - c 的值是 49
Line 4 - c 的值是 -61
Line 5 - c 的值是 240
Line 6 - c 的值是 15
賦值運算符
下表列出了 C++ 支持的賦值運算符:
運算符 | 描述 | 實例 |
---|---|---|
= | 簡單的賦值運算符,把右邊操作數的值賦給左邊操作數 | C = A + B 將把 A + B 的值賦給 C |
+= | 加且賦值運算符,把右邊操作數加上左邊操作數的結果賦值給左邊操作數 | C += A 相當于 C = C + A |
-= | 減且賦值運算符,把左邊操作數減去右邊操作數的結果賦值給左邊操作數 | C -= A 相當于 C = C - A |
*= | 乘且賦值運算符,把右邊操作數乘以左邊操作數的結果賦值給左邊操作數 | C *= A 相當于 C = C * A |
/= | 除且賦值運算符,把左邊操作數除以右邊操作數的結果賦值給左邊操作數 | C /= A 相當于 C = C / A |
%= | 求模且賦值運算符,求兩個操作數的模賦值給左邊操作數 | C %= A 相當于 C = C % A |
<<= | 左移且賦值運算符 | C <<= 2 等同于 C = C << 2 |
>>= | 右移且賦值運算符 | C >>= 2 等同于 C = C >> 2 |
&= | 按位與且賦值運算符 | C &= 2 等同于 C = C & 2 |
^= | 按位異或且賦值運算符 | C ^= 2 等同于 C = C ^ 2 |
|= | 按位或且賦值運算符 | C |= 2 等同于 C = C | 2 |
實例
請看下面的實例,了解 C++ 中可用的賦值運算符。
復制并黏貼下面的 C++ 程序到 test.cpp 文件中,編譯并運行程序。
實例
#include <iostream> using namespace std; int main() { int a = 21; int c ; c = a; cout << "Line 1 - = 運算符實例,c 的值 = : " <<c<< endl ; c += a; cout << "Line 2 - += 運算符實例,c 的值 = : " <<c<< endl ; c -= a; cout << "Line 3 - -= 運算符實例,c 的值 = : " <<c<< endl ; c *= a; cout << "Line 4 - *= 運算符實例,c 的值 = : " <<c<< endl ; c /= a; cout << "Line 5 - /= 運算符實例,c 的值 = : " <<c<< endl ; c = 200; c %= a; cout << "Line 6 - %= 運算符實例,c 的值 = : " <<c<< endl ; c <<= 2; cout << "Line 7 - <<= 運算符實例,c 的值 = : " <<c<< endl ; c >>= 2; cout << "Line 8 - >>= 運算符實例,c 的值 = : " <<c<< endl ; c &= 2; cout << "Line 9 - &= 運算符實例,c 的值 = : " <<c<< endl ; c ^= 2; cout << "Line 10 - ^= 運算符實例,c 的值 = : " <<c<< endl ; c |= 2; cout << "Line 11 - |= 運算符實例,c 的值 = : " <<c<< endl ; return 0; }
當上面的代碼被編譯和執行時,它會產生以下結果:
Line 1 - = 運算符實例,c 的值 = 21
Line 2 - += 運算符實例,c 的值 = 42
Line 3 - -= 運算符實例,c 的值 = 21
Line 4 - *= 運算符實例,c 的值 = 441
Line 5 - /= 運算符實例,c 的值 = 21
Line 6 - %= 運算符實例,c 的值 = 11
Line 7 - <<= 運算符實例,c 的值 = 44
Line 8 - >>= 運算符實例,c 的值 = 11
Line 9 - &= 運算符實例,c 的值 = 2
Line 10 - ^= 運算符實例,c 的值 = 0
Line 11 - |= 運算符實例,c 的值 = 2
雜項運算符
下表列出了 C++ 支持的其他一些重要的運算符。
運算符 | 描述 |
---|---|
sizeof | sizeof 運算符返回變量的大小。例如,sizeof(a) 將返回 4,其中 a 是整數。 |
Condition ? X : Y | 條件運算符。如果 Condition 為真 ? 則值為 X : 否則值為 Y。 |
, | 逗號運算符會順序執行一系列運算。整個逗號表達式的值是以逗號分隔的列表中的最后一個表達式的值。 |
.(點)和 ->(箭頭) | 成員運算符用于引用類、結構和共用體的成員。 |
Cast | 強制轉換運算符把一種數據類型轉換為另一種數據類型。例如,int(2.2000) 將返回 2。 |
& | 指針運算符 &?返回變量的地址。例如 &a; 將給出變量的實際地址。 |
* | 指針運算符 *?指向一個變量。例如,*var; 將指向變量 var。 |
- sizeof(data type);
- Exp1?Exp2:Exp3;
- 表達式1,表達式2? ?先求解表達式 1,再求解表達式 2。整個逗號表達式的值是表達式 2 的值。最右邊的那個表達式的值將作為整個逗號表達式的值,其他表達式的值會被丟棄。
-
.(點)運算符和 ->(箭頭)運算符用于引用類、結構和共用體的成員。點運算符應用于實際的對象。箭頭運算符與一個指向對象的指針一起使用。
struct Employee {char first_name[16];int age;
} emp;
(.)點運算符
下面的代碼把值 "zara" 賦給對象 emp 的?first_name?成員:
strcpy(emp.first_name, "zara");
(->)箭頭運算符
如果 p_emp 是一個指針,指向類型為 Employee 的對象,則要把值 "zara" 賦給對象 emp 的?first_name?成員,需要編寫如下代碼:
strcpy(p_emp->first_name, "zara");
-> 稱為箭頭運算符,它是由一個減號加上一個大于號組成。
簡而言之,訪問結構的成員時使用點運算符,而通過指針訪問結構的成員時,則使用箭頭運算符。
強制類型轉換負號
-
const_cast<type> (expr):?const_cast 運算符用于修改類型的 const / volatile 屬性。除了 const 或 volatile 屬性之外,目標類型必須與源類型相同。這種類型的轉換主要是用來操作所傳對象的 const 屬性,可以加上 const 屬性,也可以去掉 const 屬性。
-
dynamic_cast<type> (expr):?dynamic_cast 在運行時執行轉換,驗證轉換的有效性。如果轉換未執行,則轉換失敗,表達式 expr 被判定為 null。dynamic_cast 執行動態轉換時,type 必須是類的指針、類的引用或者 void*,如果 type 是類指針類型,那么 expr 也必須是一個指針,如果 type 是一個引用,那個 expr 也必須是一個引用。
-
reinterpret_cast<type> (expr):?reinterpret_cast 運算符把某種指針改為其他類型的指針。它可以把一個指針轉換為一個整數,也可以把一個整數轉換為一個指針。
-
static_cast<type> (expr):?static_cast 運算符執行非動態轉換,沒有運行時類檢查來保證轉換的安全性。例如,它可以用來把一個基類指針轉換為派生類指針。
取地址運算符號
- C++ 提供了兩種指針運算符,一種是取地址運算符 &,一種是間接尋址運算符 *。?
- 指針是一個包含了另一個變量地址的變量,可以把一個包含了另一個變量地址的變量說成是"指向"另一個變量。變量可以是任意的數據類型,包括對象、結構或者指針。
-
取地址運算符 &
& 是一元運算符,返回操作數的內存地址。例如,如果 var 是一個整型變量,則 &var 是它的地址。該運算符與其他一元運算符具有相同的優先級,在運算時它是從右向左順序進行的。
您可以把 & 運算符讀作"取地址運算符",這意味著,&var?讀作"var 的地址"。
間接尋址運算符 *
第二個運算符是間接尋址運算符 *,它是 & 運算符的補充。* 是一元運算符,返回操作數所指定地址的變量的值。
請看下面的實例,理解這兩種運算符的用法。
-
#include <iostream>using namespace std;int main () {int var;int *ptr;int val;var = 3000;// 獲取 var 的地址ptr = &var;// 獲取 ptr 的值val = *ptr;cout << "Value of var :" << var << endl;cout << "Value of ptr :" << ptr << endl;cout << "Value of val :" << val << endl;return 0; } //Value of var :3000 //Value of ptr :0xbff64494 //Value of val :3000
?
C++ 中的運算符優先級
類別? | 運算符? | 結合性? |
---|---|---|
后綴? | () [] -> . ++ - - ? | 從左到右? |
一元? | + - ! ~ ++ - - (type)* & sizeof? | 從右到左? |
乘除? | * / %? | 從左到右? |
加減? | + -? | 從左到右? |
移位? | << >>? | 從左到右? |
關系? | < <= > >=? | 從左到右? |
相等? | == !=? | 從左到右? |
位與 AND? | &? | 從左到右? |
位異或 XOR? | ^? | 從左到右? |
位或 OR? | |? | 從左到右? |
邏輯與 AND? | &&? | 從左到右? |
邏輯或 OR? | ||? | 從左到右? |
條件? | ?:? | 從右到左? |
賦值? | = += -= *= /= %=>>= <<= &= ^= |=? | 從右到左? |
逗號? | ,? | 從左到右? |
循環
循環類型 | 描述 |
---|---|
while 循環 | 當給定條件為真時,重復語句或語句組。它會在執行循環主體之前測試條件。 |
for 循環 | 多次執行一個語句序列,簡化管理循環變量的代碼。 |
do...while 循環 | 除了它是在循環主體結尾測試條件外,其他與 while 語句類似。 |
嵌套循環 | 您可以在 while、for 或 do..while 循環內使用一個或多個循環。 |
循環控制語句
控制語句 | 描述 |
---|---|
break 語句 | 終止?loop?或?switch?語句,程序流將繼續執行緊接著 loop 或 switch 的下一條語句。 |
continue 語句 | 引起循環跳過主體的剩余部分,立即重新開始測試條件。 |
goto 語句 | 將控制轉移到被標記的語句。但是不建議在程序中使用 goto 語句。 |
判斷語句
語句 | 描述 |
---|---|
if 語句 | 一個?if 語句?由一個布爾表達式后跟一個或多個語句組成。 |
if...else 語句 | 一個?if 語句?后可跟一個可選的?else 語句,else 語句在布爾表達式為假時執行。 |
嵌套 if 語句 | 您可以在一個?if?或?else if?語句內使用另一個?if?或?else if?語句。 |
switch 語句 | 一個?switch?語句允許測試一個變量等于多個值時的情況。 |
嵌套 switch 語句 | 您可以在一個?switch?語句內使用另一個?switch?語句。 |
函數的參數
調用類型 | 描述 |
---|---|
傳值調用 | 該方法把參數的實際值賦值給函數的形式參數。在這種情況下,修改函數內的形式參數對實際參數沒有影響。 |
指針調用 | 該方法把參數的地址賦值給形式參數。在函數內,該地址用于訪問調用中要用到的實際參數。這意味著,修改形式參數會影響實際參數。 |
引用調用 | 該方法把參數的引用賦值給形式參數。在函數內,該引用用于訪問調用中要用到的實際參數。這意味著,修改形式參數會影響實際參數。 |
Lambda 函數與表達式
- C++11 提供了對匿名函數的支持,稱為 Lambda 函數(也叫 Lambda 表達式)。
- Lambda 表達式把函數看作對象。Lambda 表達式可以像對象一樣使用,比如可以將它們賦給變量和作為參數傳遞,還可以像函數一樣對其求值。
- Lambda 表達式本質上與函數聲明非常類似。Lambda 表達式具體形式如下
[](int x, int y){ return x < y ; }
- 如果沒有返回值,可以表示為:
[]{ ++global_x; }
在一個更為復雜的例子中,返回類型可以被明確的指定如下:
[](int x, int y) -> int { int z = x + y; return z + x; }
- 本例中,一個臨時的參數 z 被創建用來存儲中間結果。如同一般的函數,z 的值不會保留到下一次該不具名函數再次被調用時。如果 lambda 函數沒有傳回值(例如 void),其返回類型可被完全忽略。在Lambda表達式內可以訪問當前作用域的變量,這是Lambda表達式的閉包(Closure)行為。 與JavaScript閉包不同,C++變量傳遞有傳值和傳引用的區別。可以通過前面的[]來指定:
[] // 沒有定義任何變量。使用未定義變量會引發錯誤。
[x, &y] // x以傳值方式傳入(默認),y以引用方式傳入。
[&] // 任何被使用到的外部變量都隱式地以引用方式加以引用。
[=] // 任何被使用到的外部變量都隱式地以傳值方式加以引用。
[&, x] // x顯式地以傳值方式加以引用。其余變量以引用方式加以引用。
[=, &z] // z顯式地以引用方式加以引用。其余變量以傳值方式加以引用。
- 另外有一點需要注意。對于[=]或[&]的形式,lambda 表達式可以直接使用 this 指針。但是,對于[]的形式,如果要使用 this 指針,必須顯式傳入:
[this]() { this->someFunc(); }();
C++ 隨機數
- 在許多情況下,需要生成隨機數。關于隨機數生成器,有兩個相關的函數。一個是?rand(),該函數只返回一個偽隨機數。生成隨機數之前必須先調用?srand()?函數。
- 下面是一個關于生成隨機數的簡單實例。實例中使用了?time()?函數來獲取系統時間的秒數,通過調用 rand() 函數來生成隨機數:
C++數組詳解
概念 | 描述 |
---|---|
多維數組 | C++ 支持多維數組。多維數組最簡單的形式是二維數組。 |
指向數組的指針 | 您可以通過指定不帶索引的數組名稱來生成一個指向數組中第一個元素的指針。 |
傳遞數組給函數 | 您可以通過指定不帶索引的數組名稱來給函數傳遞一個指向數組的指針。 |
從函數返回數組 | C++ 允許從函數返回數組。 |
C++?傳遞數組給函數
方式 1
形式參數是一個指針:
void myFunction(int *param)
{
.
.
.
}
方式 2
形式參數是一個已定義大小的數組:
void myFunction(int param[10])
{
.
.
.
}
方式 3
形式參數是一個未定義大小的數組:
void myFunction(int param[])
{
.
.
.
}
C++?從函數返回數組
- C++ 不允許返回一個完整的數組作為函數的參數。但是,可以通過指定不帶索引的數組名來返回一個指向數組的指針。如果想要從函數返回一個一維數組,必須聲明一個返回指針的函數,如下:
- int * myFunction() { . . . }
- 另外,C++ 不支持在函數外返回局部變量的地址,除非定義局部變量為?static?變量。
C++?字符串
序號 | 函數 & 目的 |
---|---|
1 | strcpy(s1, s2); 復制字符串 s2 到字符串 s1。 |
2 | strcat(s1, s2); 連接字符串 s2 到字符串 s1 的末尾。 |
3 | strlen(s1); 返回字符串 s1 的長度。 |
4 | strcmp(s1, s2); 如果 s1 和 s2 是相同的,則返回 0;如果 s1<s2 則返回值小于 0;如果 s1>s2 則返回值大于 0。 |
5 | strchr(s1, ch); 返回一個指針,指向字符串 s1 中字符 ch 的第一次出現的位置。 |
6 | strstr(s1, s2); 返回一個指針,指向字符串 s1 中字符串 s2 的第一次出現的位置。 |
C++中使用指針
概念 | 描述 |
---|---|
C++ Null 指針 | C++ 支持空指針。NULL 指針是一個定義在標準庫中的值為零的常量。 |
C++ 指針的算術運算 | 可以對指針進行四種算術運算:++、--、+、- |
C++ 指針 vs 數組 | 指針和數組之間有著密切的關系。 |
C++ 指針數組 | 可以定義用來存儲指針的數組。 |
C++ 指向指針的指針 | C++ 允許指向指針的指針。 |
C++ 傳遞指針給函數 | 通過引用或地址傳遞參數,使傳遞的參數在調用函數中被改變。 |
C++ 從函數返回指針 | C++ 允許函數返回指針到局部變量、靜態變量和動態內存分配。 |
- C++ 不支持在函數外返回局部變量的地址,除非定義局部變量為?static?變量。
C++ 引用 vs 指針
引用很容易與指針混淆,它們之間有三個主要的不同:
- 不存在空引用。引用必須連接到一塊合法的內存。
- 一旦引用被初始化為一個對象,就不能被指向到另一個對象。指針可以在任何時候指向到另一個對象。
- 引用必須在創建時被初始化。指針可以在任何時間被初始化。
int i = 17;
int& r = i; //r 是一個初始化為 i 的整型引用
double& s = d; //s 是一個初始化為 d 的 double 型引用
#include <iostream>using namespace std;int main ()
{// 聲明簡單的變量int i;double d;// 聲明引用變量int& r = i;double& s = d;i = 5;cout << "Value of i : " << i << endl;cout << "Value of i reference : " << r << endl;d = 11.7;cout << "Value of d : " << d << endl;cout << "Value of d reference : " << s << endl;return 0;
}//Value of i : 5
//Value of i reference : 5
//Value of d : 11.7
//Value of d reference : 11.7
C++?日期 & 時間
- C++ 標準庫沒有提供所謂的日期類型。C++ 繼承了 C 語言用于日期和時間操作的結構和函數。為了使用日期和時間相關的函數和結構,需要在 C++ 程序中引用 <ctime> 頭文件。
- 有四個與時間相關的類型:clock_t、time_t、size_t?和?tm。類型 clock_t、size_t 和 time_t 能夠把系統時間和日期表示為某種整數。
- 結構類型?tm?把日期和時間以 C 結構的形式保存,tm 結構的定義如下:
struct tm {int tm_sec; // 秒,正常范圍從 0 到 59,但允許至 61int tm_min; // 分,范圍從 0 到 59int tm_hour; // 小時,范圍從 0 到 23int tm_mday; // 一月中的第幾天,范圍從 1 到 31int tm_mon; // 月,范圍從 0 到 11int tm_year; // 自 1900 年起的年數int tm_wday; // 一周中的第幾天,范圍從 0 到 6,從星期日算起int tm_yday; // 一年中的第幾天,范圍從 0 到 365,從 1 月 1 日算起int tm_isdst; // 夏令時
}
序號 | 函數 & 描述 |
---|---|
1 | time_t time(time_t *time); 該函數返回系統的當前日歷時間,自 1970 年 1 月 1 日以來經過的秒數。如果系統沒有時間,則返回 -1。 |
2 | char *ctime(const time_t *time); 該返回一個表示當地時間的字符串指針,字符串形式?day month year hours:minutes:seconds year\n\0。 |
3 | struct tm *localtime(const time_t *time); 該函數返回一個指向表示本地時間的?tm?結構的指針。 |
4 | clock_t clock(void); 該函數返回程序執行起(一般為程序的開頭),處理器時鐘所使用的時間。如果時間不可用,則返回 -1。 |
5 | char * asctime ( const struct tm * time ); 該函數返回一個指向字符串的指針,字符串包含了 time 所指向結構中存儲的信息,返回形式為:day month date hours:minutes:seconds year\n\0。 |
6 | struct tm *gmtime(const time_t *time); 該函數返回一個指向 time 的指針,time 為 tm 結構,用協調世界時(UTC)也被稱為格林尼治標準時間(GMT)表示。 |
7 | time_t mktime(struct tm *time); 該函數返回日歷時間,相當于 time 所指向結構中存儲的時間。 |
8 | double difftime ( time_t time2, time_t time1 ); 該函數返回 time1 和 time2 之間相差的秒數。 |
9 | size_t strftime(); 該函數可用于格式化日期和時間為指定的格式。 |
C++?基本的輸入輸出
- C++ 的 I/O 發生在流中,流是字節序列。如果字節流是從設備(如鍵盤、磁盤驅動器、網絡連接等)流向內存,這叫做輸入操作。如果字節流是從內存流向設備(如顯示屏、打印機、磁盤驅動器、網絡連接等),這叫做輸出操作。
頭文件 | 函數和描述 |
---|---|
<iostream> | 該文件定義了?cin、cout、cerr?和?clog?對象,分別對應于標準輸入流、標準輸出流、非緩沖標準錯誤流和緩沖標準錯誤流。 |
<iomanip> | 該文件通過所謂的參數化的流操縱器(比如?setw?和?setprecision),來聲明對執行標準化 I/O 有用的服務。 |
<fstream> | 該文件為用戶控制的文件處理聲明服務。我們將在文件和流的相關章節討論它的細節。 |
標準輸入流(cin)
標準錯誤流(cerr)
#include <iostream>using namespace std;int main( )
{char str[] = "Unable to read....";cerr << "Error message : " << str << endl;
}
標準日志流(clog)
- 預定義的對象?clog?是?iostream?類的一個實例。clog 對象附屬到標準錯誤設備,通常也是顯示屏,但是?clog?對象是緩沖的。這意味著每個流插入到 clog 都會先存儲在緩沖區,直到緩沖填滿或者緩沖區刷新時才會輸出。
- clog?也是與流插入運算符 << 結合使用的,如下所示:
#include <iostream>using namespace std;int main( )
{char str[] = "Unable to read....";clog << "Error message : " << str << endl;
}
輸入輸出流中的函數(模板)
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{cout<<setiosflags(ios::left|ios::showpoint); // 設左對齊,以一般實數方式顯示cout.precision(5); // 設置除小數點外有五位有效數字 cout<<123.456789<<endl;cout.width(10); // 設置顯示域寬10 cout.fill('*'); // 在顯示區域空白處用*填充cout<<resetiosflags(ios::left); // 清除狀態左對齊cout<<setiosflags(ios::right); // 設置右對齊cout<<123.456789<<endl;cout<<setiosflags(ios::left|ios::fixed); // 設左對齊,以固定小數位顯示cout.precision(3); // 設置實數顯示三位小數cout<<999.123456<<endl; cout<<resetiosflags(ios::left|ios::fixed); //清除狀態左對齊和定點格式cout<<setiosflags(ios::left|ios::scientific); //設置左對齊,以科學技術法顯示 cout.precision(3); //設置保留三位小數cout<<123.45678<<endl;return 0;
}
setiosflags(ios::fixed) 固定的浮點顯示
setiosflags(ios::scientific) 指數表示
setiosflags(ios::left) 左對齊
setiosflags(ios::right) 右對齊
setiosflags(ios::skipws 忽略前導空白
setiosflags(ios::uppercase) 16進制數大寫輸出
setiosflags(ios::lowercase) 16進制小寫輸出
setiosflags(ios::showpoint) 強制顯示小數點
setiosflags(ios::showpos) 強制顯示符號
標志 | 功能 |
---|---|
boolalpha | 可以使用單詞”true”和”false”進行輸入/輸出的布爾值. |
oct | 用八進制格式顯示數值. |
dec | 用十進制格式顯示數值. |
hex | 用十六進制格式顯示數值. |
left | 輸出調整為左對齊. |
right | 輸出調整為右對齊. |
scientific | 用科學記數法顯示浮點數. |
fixed | 用正常的記數方法顯示浮點數(與科學計數法相對應). |
showbase | 輸出時顯示所有數值的基數. |
showpoint | 顯示小數點和額外的零,即使不需要. |
showpos | 在非負數值前面顯示”+(正號)”. |
skipws | 當從一個流進行讀取時,跳過空白字符(spaces, tabs, newlines). |
unitbuf | 在每次插入以后,清空緩沖區. |
internal | 將填充字符回到符號和數值之間. |
uppercase | 以大寫的形式顯示科學記數法中的”e”和十六進制格式的”x”. |
操作符 | 描述 | 輸入 | 輸出 |
---|---|---|---|
boolalpha | 啟用boolalpha標志 | √ | √ |
dec | 啟用dec標志 | √ | √ |
endl | 輸出換行標示,并清空緩沖區 | ? | √ |
ends | 輸出空字符 | ? | √ |
fixed | 啟用fixed標志 | ? | √ |
flush | 清空流 | ? | √ |
hex | 啟用 hex 標志 | √ | √ |
internal | 啟用 internal 標志 | ? | √ |
left | 啟用 left 標志 | ? | √ |
noboolalpha | 關閉boolalpha 標志 | √ | √ |
noshowbase | 關閉showbase 標志 | ? | √ |
noshowpoint | 關閉showpoint 標志 | ? | √ |
noshowpos | 關閉showpos 標志 | ? | √ |
noskipws | 關閉skipws 標志 | √ | ? |
nounitbuf | 關閉unitbuf 標志 | ? | √ |
nouppercase | 關閉uppercase 標志 | ? | √ |
oct | 啟用 oct 標志 | √ | √ |
right | 啟用 right 標志 | ? | √ |
scientific | 啟用 scientific 標志 | ? | √ |
showbase | 啟用 showbase 標志 | ? | √ |
showpoint | 啟用 showpoint 標志 | ? | √ |
showpos | 啟用 showpos 標志 | ? | √ |
skipws | 啟用 skipws 標志 | √ | ? |
unitbuf | 啟用 unitbuf 標志 | ? | √ |
uppercase | 啟用 uppercase 標志 | ? | √ |
ws | 跳過所有前導空白字符 | √ |
操作符 | 描述 | 輸入 | 輸出 |
---|---|---|---|
resetiosflags(long f) | 關閉被指定為f的標志 | √ | √ |
setbase(int base) | 設置數值的基本數為base | ? | √ |
setfill(int ch) | 設置填充字符為ch | ? | √ |
setiosflags(long f) | 啟用指定為f的標志 | √ | √ |
setprecision(int p) | 設置數值的精度(四舍五入) | ? | √ |
setw(int w) | 設置域寬度為w | ? | √ |
C++?數據結構
- C/C++ 數組允許定義可存儲相同類型數據項的變量,但是結構是 C++ 中另一種用戶自定義的可用的數據類型,它允許您存儲不同類型的數據項。
- 結構用于表示一條記錄,假設您想要跟蹤圖書館中書本的動態,您可能需要跟蹤每本書的下列屬性:
Title :標題
Author :作者
Subject :類目
Book ID :書的 IDstruct type_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
} object_names;type_name 是結構體類型的名稱,member_type1 member_name1 是標準的變量定義,比如 int i; 或者 float f; 或者其他有效的變量定義。在結構定義的末尾,最后一個分號之前,您可以指定一個或多個結構變量,這是可選的。下面是聲明一個結構體類型 Books,變量為 book:struct Books
{char title[50];char author[50];char subject[100];int book_id;
} book;
訪問結構成員
- 為了訪問結構的成員,我們使用成員訪問運算符(.)。成員訪問運算符是結構變量名稱和我們要訪問的結構成員之間的一個句號。
- 下面的實例演示了結構的用法:
#include <iostream>
#include <cstring>using namespace std;// 聲明一個結構體類型 Books
struct Books
{char title[50];char author[50];char subject[100];int book_id;
};int main( )
{Books Book1; // 定義結構體類型 Books 的變量 Book1Books Book2; // 定義結構體類型 Books 的變量 Book2// Book1 詳述strcpy( Book1.title, "C++ 教程");strcpy( Book1.author, "Runoob"); strcpy( Book1.subject, "編程語言");Book1.book_id = 12345;// Book2 詳述strcpy( Book2.title, "CSS 教程");strcpy( Book2.author, "Runoob");strcpy( Book2.subject, "前端技術");Book2.book_id = 12346;// 輸出 Book1 信息cout << "第一本書標題 : " << Book1.title <<endl;cout << "第一本書作者 : " << Book1.author <<endl;cout << "第一本書類目 : " << Book1.subject <<endl;cout << "第一本書 ID : " << Book1.book_id <<endl;// 輸出 Book2 信息cout << "第二本書標題 : " << Book2.title <<endl;cout << "第二本書作者 : " << Book2.author <<endl;cout << "第二本書類目 : " << Book2.subject <<endl;cout << "第二本書 ID : " << Book2.book_id <<endl;return 0;
}
結構體作為函數的參數
#include <iostream>
#include <cstring>using namespace std;
void printBook( struct Books book );// 聲明一個結構體類型 Books
struct Books
{char title[50];char author[50];char subject[100];int book_id;
};int main( )
{Books Book1; // 定義結構體類型 Books 的變量 Book1Books Book2; // 定義結構體類型 Books 的變量 Book2// Book1 詳述strcpy( Book1.title, "C++ 教程");strcpy( Book1.author, "Runoob"); strcpy( Book1.subject, "編程語言");Book1.book_id = 12345;// Book2 詳述strcpy( Book2.title, "CSS 教程");strcpy( Book2.author, "Runoob");strcpy( Book2.subject, "前端技術");Book2.book_id = 12346;// 輸出 Book1 信息printBook( Book1 );// 輸出 Book2 信息printBook( Book2 );return 0;
}
void printBook( struct Books book )
{cout << "書標題 : " << book.title <<endl;cout << "書作者 : " << book.author <<endl;cout << "書類目 : " << book.subject <<endl;cout << "書 ID : " << book.book_id <<endl;
}
指向結構的指針
- 可以定義指向結構的指針,方式與定義指向其他類型變量的指針相似,如下所示:
struct Books *struct_pointer;
- 現在,您可以在上述定義的指針變量中存儲結構變量的地址。為了查找結構變量的地址,請把 & 運算符放在結構名稱的前面,如下所示:
struct_pointer = &Book1;
- 為了使用指向該結構的指針訪問結構的成員,您必須使用 -> 運算符,如下所示:
struct_pointer->title;
#include <iostream>
#include <cstring>using namespace std;
void printBook( struct Books *book );struct Books
{char title[50];char author[50];char subject[100];int book_id;
};int main( )
{Books Book1; // 定義結構體類型 Books 的變量 Book1Books Book2; // 定義結構體類型 Books 的變量 Book2// Book1 詳述strcpy( Book1.title, "C++ 教程");strcpy( Book1.author, "Runoob"); strcpy( Book1.subject, "編程語言");Book1.book_id = 12345;// Book2 詳述strcpy( Book2.title, "CSS 教程");strcpy( Book2.author, "Runoob");strcpy( Book2.subject, "前端技術");Book2.book_id = 12346;// 通過傳 Book1 的地址來輸出 Book1 信息printBook( &Book1 );// 通過傳 Book2 的地址來輸出 Book2 信息printBook( &Book2 );return 0;
}
// 該函數以結構指針作為參數
void printBook( struct Books *book )
{cout << "書標題 : " << book->title <<endl;cout << "書作者 : " << book->author <<endl;cout << "書類目 : " << book->subject <<endl;cout << "書 ID : " << book->book_id <<endl;
}
typedef 關鍵字
下面是一種更簡單的定義結構的方式,您可以為創建的類型取一個"別名"。例如:
typedef struct Books
{char title[50];char author[50];char subject[100];int book_id;
}Books;
現在,您可以直接使用 Books 來定義 Books 類型的變量,而不需要使用 struct 關鍵字。下面是實例:Books Book1, Book2;
您可以使用 typedef 關鍵字來定義非結構類型,如下所示:typedef long int *pint32;pint32 x, y, z;
x, y 和 z 都是指向長整型 long int 的指針。
?