標籤:
預先處理命令:存在於xxx.h檔案中
#ifndef //防止重複包含
#define //定義
#endif //結束
標頭檔中不加上先行編譯指令,造成的重複定義是編譯期錯誤。
在實際操作過程中,一般不在標頭檔中定義變數。
某些函數不是為了提供給使用者,而是只針對某個其他函數使用,此時不應該把這些函數的聲明放在標頭檔中,而是直接在標頭檔對應的源檔案中定義。反映在C++的類定義中,這些函數應該設為私人。
類型轉換:
若運算式中有double 類型,則結果也為double(float),若都為int型,做除法運算時會丟失小數部分.
強制類型轉換 c :()a c++: static_cast< 類型>(變數);
指標:
指標第1個含義是指向的記憶體的基地址,第二個含義是本身的類型
int c = 5;
int *a = &c;
a 是一個指向int類型的指標,a中存放的是c的地址,&是取址符
聲明和賦值
int c = 5; //聲明初始化
int c;
c = 5;//賦值
變數聲明,函式宣告;
- //正確的交換函數
- int swap(int *a,int *b) //*a 和 *b 是聲明,下文的 a,b指的是兩個int型指標;
- {
- int temp=*a; //*是取值操作
- *a=*b; //將 a和b變數對應的內容交換
- *b=temp;
- }
在C++中,初始化和賦值是兩個不同的概念。比如:
- //初始化一個string類的對象,初始值為helloworld
- string str1("helloworld");
- //錯誤,初始化的一個Null 物件,不能像初始化那樣賦值
- string str2;
- str2("helloworld);
- //正確,初始化的一個Null 物件,利用符號重載後的“=”進行賦值
- string str3;
- str3 = "helloworld";
- 很多操作中,只是通過複製一個副本來進行,就像函數傳參中的值傳遞一樣。比如:
- //從左至右,先將str1串連到str中,然後再將,str2串連到str的尾部。但str1與str2中的值未變
- string str, str1, str2;
- str = str1 + str2;
- //這裡只是將str的一個副本複製到vec中
- vector<string> vec;
- string str(helloworld);
- vec.push_back(str);
//錯誤的申請一維動態數組的函數
- #include <stdio.h>
- void test(char *s)
- {
- s=malloc(1000);
- //形參s的初始值為NULL,malloc後為堆上一塊地區的首址,此時,實參中指標的值沒變化,所以函數結束後,實參指標申請失敗,函數傳遞的本質是值傳遞,我們要改變的是實參的內容,而不是指向實參的內容。
- }
- //兩種正確寫法void test(char **s) //實參是個指標,形參是個指標的地址
- {
- *s=malloc(1000); //改變實參的內容
- }
- char *test(char *s)
- {
- s=malloc(1000);
- return s;
- }
- int main(int argc,char *argv[])
- {
- char *s=NULL;
- //傳入函數的是s的副本,是一個臨時變數,也是局部變數,是指標變數的值拷貝,即兩個指標變數的值一樣。所已要在函數中改變一個變數,要把這邊變數的地址傳進去。*xx只是一個語義的寫法,是個聲明
- test(s);
- return 0;
- }
動態分配記憶體
int *p = (int*)malloc(sizeof(int) *10));
sizeof(int) 是一種跨平台的做法
malloc 返回的實void* 需要強制類型裝換
New 的三種申請方法
1 int *p = new int;
2 int *p = new int(10);
3 int *p = new int[10];
malloc 和 new的區別:
new是運算子,malloc是函數
new會執行某些類型的建構函式,而malloc僅僅申請記憶體。
所以對於string類型,只可以使用new,絕對不可以使用malloc!!
常見的異常有:
exception 最常見的問題
out_of_range 越界錯誤
invalid_argument非法參數
千萬不要返回局部對象的引用或者指標!!!
例如:
const std::string &manip(const std::string &s)
{
std::string ret = s;
return ret;
}
上例中的ret是個局部對象,離開這個函數後就被銷毀了,此時函數返回一個它的引用,實際上是引用了一塊非法的記憶體地區。
動態開闢一個二維數組 3*4 的思維: 首先使用一個二重指標,二重指標開闢三個一重指標的空間. 每個一重指標再開闢4個空間
- int **arr=(int **)malloc(3*sizeof(int*));
- for (int i=0;i!=3;i++)
- {
- arr[i]=(int *)malloc(4*sizeof(int));
- }
釋放空間的過程與分配動態空間的過程剛好相反:
- for (int i=0;i!=3;i++)
- {
- free[arr[i]);
- }
- free(arr);
這種動態分配的數組可以直接用 void print(int **array)進行傳參。
函數指標 void (*函數指標名字)(int, int)
記憶體泄露 記憶體配置使用後,並沒有回收,導致失去了分配的那片記憶體的控制方式
值傳遞、地址傳遞、引用
- 值傳遞是指在函數傳參過程中,複製一個副本給函數的形參,實參和形參的值相同,但問題是,一旦形參發生改變,則不會作用到實參上。解決方案為,地址傳遞或引用,或通過傳回值來傳遞修改後的值。
- 地址傳遞是指在函數傳參過程中,傳遞的是變數的地址,實質上仍是值傳遞,傳遞的是指標的值,即變數的地址。
- 引用是指給變數起了一個別名。在C++中,對於傳值操作,一般用引用而不用指標。同時,注意要根據是否要改變實參值而判斷是否要用const來修飾。
聲明常量時要初始化,對變數最好也先初始化
輸入/輸出資料流 istream 和 ostream 都是有緩衝區的 作為形參時不能為const
宏函數和內嵌函式的區別:
宏函數是在先行編譯期間進行替換。
內嵌函式是在編譯期間進行代碼擴充。
內嵌函式可以看做進階的宏函數,它進行語法檢查。
宏函數只要不進行調用,就不會產生語法檢查,而內嵌函式必須首先經過嚴格的語法檢查才能進行代碼擴充.
/*
* 這裡在返回int時產生了一個無名的int值
* 這是一個臨時的值
*/
int get_val(){
int a = 2;
return a;
}
int main(int argc, const char *argv[])
{
cout << get_val() << endl;
//a的值賦予返回的中間值,然後賦值給res
int res = get_val();
return 0;
}
static資料成員
- static資料成員沒有this指標,它直屬於這個類,也即所有這個類的對象共用這個資料成員。非static資料成員隸屬於這個類的各個對象,也即各個對象都獨自擁有這個資料成員。
- 它並不是真正意義上的全域變數,範圍僅僅為這個類。
- static資料成員必須在類的外部定義,不像普通資料成員那樣通過建構函式來進行初始化的。
- static成員函數沒有this指標,原因同上。
- static成員函數不能被聲明為const,因為static成員函數是直屬於類,而非對象,而成員函式宣告為const就是承諾不會修改該函數所屬的對象,兩者矛盾。
- 可以通過範圍從類直接調用static成員函數,當然也可像普通成員函數那樣,通過對象、對象的引用、指向該類類型的對象的指標間接。
- static成員函數只能對static資料成員進行操作,因為static成員函數是直屬於這個類的,而非static資料成員是直屬於對象的,若它對一些非static資料成員進行操作,會影響對象的非static資料成員的安全。
static成員函數
非static成員函數能夠對static資料成員和非static資料成員進行操作
c++基礎