一、 數據類型及運算
求補碼
- 原碼的基礎上, 符號位不變, 其余各位取反, 最后+1
- 原碼轉補碼不考慮符號位
- 補碼轉原碼,符號位不參與運算
- 取反后 + 1 == 取反前 - 1
科學計數法表示
- 1.8 * 10^11 --> 1.8E11
- 9.34 * 10^-3 --> 9.34E-3
相關細節
- sizeof()是一個運算,而非函數
- ++運算不能用在實數上
- 判斷一個整數是否是2^n(2,4,6,8,16...)
- !(x & (x - 1))
- 三目條件運算符代碼更優
- 編譯器能產生比if...else...更優的代碼
運算符優先級、結合方向規則
- 單目 > 雙目
- 算術 > 關系 > 位 > 邏輯 > 條件(三目)> 賦值 > 逗號
- 算術: + - * /
- 關系: > < >= <=
- 位: & | ^
- 單目: ~
- 邏輯: && ||
- 單目: !
- 自右向左的三種運算符
- 單目
- 賦值
- 條件
數據輸入與輸出
- printf()語句從右向左計算輸出表達式的值
i = 1;
printf("%d, %d\\\\n", i++, i--);
//res: 0,1
//先執行i--,再執行i++
常用輸出函數
- printf()
- putchar()
- 輸出一個字符
- 必須是字符型變量或常量
- puts()
- 輸出一個字符串
- 必須是字符串或常量
常用輸入函數
scanf()
-
gets()
- 每次讀取一個字符串
-
getche()
- conio.h中
- 讀取字符不用按回車
-
getchar()
- stdio.h中
- 完成后須按回車
getche() & getchar():
每次讀取一個字符scanf() & gets()區別:
scanf不能輸入含空格字符串,gets可以
二、選擇語句和循環語句
switch:case 常量表達式
- 常量表達式只能為整型、字符型
- 不允許浮點型
三、數組
定義
- 定義數組未賦初值
- Turbo C會給數組置0
- VC則取隨機值
- 定義靜態數組,則系統自動賦0
比較字符串數組中的值
- C: strcmp(str1,str2)
- C++: str1 == str2
- JAVA: str1.equals(str2)
- java中,str1 == str2 比較的是地址
四、指針
指針運算
- 指針相減: 表示兩指針所指地址之間的數據個數
- 指針相加: 沒有意義,錯誤
數組與指針
1、一維數組首地址
int a[10], *p;
p = &a[0];
p = a
//等價,將數組首元素的首地址賦給指針p
-
表示:
&a[0], a: 數組首元素的首地址
&a: 數組首地址 對比:
a == &a[0]
a != &a //地址值相同,含義不同
2、二維數組首地址
int a[10][10];
地址值相同,含義不同:
a:
- 二維數組首元素首地址
- 代表一維數組元素的首地址
&a:
- 數組首地址
&a[0]:
- 二維數組首元素首地址
&a[0][0]:
- &a[0][0] != a
- a[0] == &a[0][0]
3、二維數組指針
-
int (*p)[3]:
- 指向含3個元素的二維數組的行指針
- 數組每列有3個元素
-
int \p[3] & int \(p[3]):
- 指針數組,每個元素均是一個指針
指針與引用的區別
- 非空區別
- 引用必須總是指向某些對象
- 不能使用指向空值的引用
- 不存在指向空值的引用
- 效率比使用指針高
- 指針可以指向空值
- 引用必須總是指向某些對象
- 合法性區別
- 使用引用前,無需測試其合法性
- 使用指針總是需要判空
- 可修改區別
- 指針可被重新賦值,以指向另一對象
- 引用
總指向初始化時被指定的對象
以后都不能改變
但指定對象的內容可以改變
- 應用區別
- 指針場景
存在不指向任何對象的情況
不同的時刻指向不同對象的情況
- 引用場景
指向一個對象后就不會改變指向的情況
- 指針場景
ps:聲明引用 / const常量 的同時,必須初始化
函數指針
-
float(**def)[10];
二級指針
指向一個一維數組的指針
數組元素都是float
-
double\(\gh)[10];
指針gh,指向一個一維數組
該數組元素的類型均為double *
-
double(*f[10])();
-
f是一個數組,含10個元素
- 元素都是函數指針
-
指向的函數
沒有參數
返回double類型的值
-
-
int \( (\b)[10] );
- 和int \(\b)[10]一樣
-
Long (* fun)(int)
- 函數指針
五、類型轉換
(int &)相關
float a = 1.0f;
(int)a實際上是以浮點數a為參數構造了一個整型數,該整數的值是1。
(int&)a則是告訴編譯器將a當作整數看(并沒有做任何實質上的轉換)。
unsigned int
unsigned int a = 0xFFFFFFF7;
-
unsigned char i = (unsigned char)a;
i: 000000f7
-
char \*b = (char *)&a;
*b: fffffff7
隱式類型轉換
算術運算式中,低類型能夠轉換為高類型
-
賦值運算式
- 右邊表達式的值自動隱式轉換為左邊變量的類型,并賦值給他
函數調用中參數傳遞時,系統隱式地將實參轉換為形參的類型后,賦給形參
函數有返回值時,系統將隱式地將返回表達式類型轉換為返回值類型,賦值給調用函數
六、位運算相關
取兩數的平均值:
(x & y) + [(x ^ y) >> 1]
另類取兩數較大值:
max = [(a + b) + abs(a - b)] / 2
三數取中間數:
t1 = max(a, b);
t2 = max(b, c);
t3 = max(a, c);
min( t1, min(t2, t3) )
七、函數
靜態函數: 不可被其他文件調用的函數
函數重載:
參數類型不同
參數個數不同
對返回類型沒有要求
八、#define & const & sizeof
#define實例
* #define SEC (60 * 60 * 24 * 365)UL
* #define MIIN(A, B) ( (A) <= (B) ? (A) : (B) )
const,#define的區別
-
const
有數據類型
可進行類型安全檢查
可對其進行調試
-
\#define
沒有數據類型
僅進行字符替換,沒有類型安全檢查
無法調試
-
c中const
- 被當做一個不能被改變的普通變量
error
const bufsize = 100;
char buf[bufsize];
字節對齊
-
數據對齊規則
結構的首地址必須是結構內最寬類型的整數倍地址
結構體的每一個成員起始地址必須是自身類型大小的整數倍
結構體的整體大小必須可被對齊值整除
結構體的整體大小必須可被本結構內的最寬類型整除
sizeof
- 結構體或類內的靜態變量
struct s{
int a;
static int b;
};
s ss;
sizeof(ss)
結果:4
靜態變量存放在全局數據區
sizeof計算棧中分配的大小
任何類型指針大小相同:4(32位)
對函數使用sizeof
在編譯階段會被函數返回值的類型取代
-
空類大小
- 單繼承:1
- 多繼承:1
- 虛繼承:4
- 涉及虛表(虛指針)
內聯函數 vs. 宏
- 內聯
- 相比普通函數: 加快程序運行速度
- 直接嵌入目標代碼
- 要做參數類型檢查
- 宏
- 簡單的替換
- 不做參數類型檢查
九、 C++面向對象
1、類和對象
類對象的存儲空間
- 只為每個對象的數據成員和函數地址分配內存空間
- 類中所有成員函數只生成一個副本
- 該類每個對象執行相同的函數成員
拷貝構造函數
- 功能
- 用一個已知的對象來初始化一個被創建的同類的對象
- 特點
- 函數只有一個參數,并且是對某個對象的引用
- 每個類都必須有一個拷貝初始化構造函數
- 格式
- 類名::拷貝初始化構造函數名(const 類名 &引用名)
靜態成員
- 靜態數據成員
- 特點
- 類的所有對象共享
- 必須初始化,且要在類外初始化
- 引用格式
- 類名::靜態數據成員名
- 特點
- 靜態成員函數
- 特點
- 類的所有對象共享
- 只能使用類的靜態成員和非數據成員
- 引用格式
- 類名::靜態成員函數名
- 特點
類成員指針
const成員函數
定義: 任何不修改成員數據的函數都應聲明為const函數
原型: int GetY() const;
細節:
- const函數想修改成員變量
- 在相應變量定義處加上mutable
- mutable int m_Count;
2、友元函數
定義
- 需在類體內聲明
- 可訪問類的私有成員
- 不是類的成員函數
優點: 提高程序運行效率
缺點: 破壞類的封裝性和隱藏性
特點: 可以是多個類的友元
3、繼承和派生
公有繼承
- 派生類成員函數可訪問基類中的公有成員和保護成員
- 派生類的對象僅可訪問基類中的公有成員
派生類
-
構造函數執行順序
- 基類構造函數
- 子對象類的構造函數(如果有的話)
- 派生類構造函數
-
析構函數執行順序
- 派生類的析構函數
- 基類的析構函數
虛基類