C++ premier Plus書之--C++指標, 陣列, 結構體, 字串
指標和字串, demo:
#include "iostream" #include "cstring" using namespace std; int main() { char animal[20] = "bear"; // 字元常量指標, 也就是bird指向的記憶體時不允許修改的 const char* bird = "wren"; char* ps; cout << animal << " and "; cout << bird << endl; // 隨機顯示, 可能是空格, 也可能崩潰 // cout << ps << endl; cout << "Enter a kind of animal : "; cin >> animal; ps = animal; cout << ps << "!\n"; cout << "Before using strcpy()" << endl; // 輸出的是animal字元陣列的首地址 cout << animal << " at " << (int *) animal << endl; cout << "&animal is " << &animal << endl; cout << ps << " at " << (int *)ps << endl; cout << " ps is " << ps << endl; // 這裡輸出的不是指標指向的內容的地址, 而是指標變數的地址, 因此與上面的輸出地址不同 cout << " &ps " << &ps << endl; // 這麼宣告字元陣列可以節省空間 ps = new char[strlen(animal) + 1]; stpcpy(ps, animal); cout << "After using strcpy() : " << endl; cout << animal << " at " << (int *) animal << endl; cout << ps << " at " << (int *)ps << endl; delete[] ps; return 0; }
上面程式的執行結果如下:
從程式執行結果可以看出:
對陣列名應用(int *)animal 可以得到字元陣列的首地址, 和對指標應用(int *)類似
指標和結構體
看一個簡單的應用demo:
// 指標和結構體 #include "iostream" #include "cstring" using namespace std; struct things { int good; int bad; }; struct inflatable { char name[20]; float volume; double price; }; int main() { things gurbnose = {1, 23}; // 將建立的結構體的首地址賦值給指標 things* pt = &gurbnose; // 結構體變數訪問結構體內成員使用.符號 cout << "gurbnose.good = " << gurbnose.good << ", and gurbnose.bad = " << gurbnose.bad << endl; // 結構體指標訪問結構體內成員使用->符號 cout << "pt->good = " << pt->good << ", and pt->bad = " << pt->bad << endl; // 另一種通過指標訪問結構體的成員的方法使使用(*pt).price, 這種方法 // 因為pt是指向結構體的指標, 因此(*pt)就是該結構體, 因此可以通過(*pt).的這種方式訪問成員 // 建立了一個結構體指標 inflatable* ps = new inflatable; cout << "Enter name of inflatable item: "; cin.get(ps->name, 20); cout << "Enter volume in cubic feet: "; cin >> (*ps).volume; cout << "Enter the price : "; cin >> ps->price; cout << "Name : " << (*ps).name << endl; cout << "volume : " << ps->volume << endl; cout << "price : " << (*ps).price << endl; // 記得釋放new申請的空間 delete ps; return 0; }
程式的執行結果如下:
從demo中可以看出指標引用結構體的成員的方法有兩種, 假如ps是指向結構體的指標, 結構體裡有price這個成員:
- ps->price
- (*ps).price
這兩種方法均可
從上面的demo中可以看出new和delete是成對出現的, 再看一個new和delete的例子:
// new和delete #include "iostream" #include "cstring" using namespace std; // 宣告函式原型 char* getName(void); int main() { char* name; name = getName(); cout << name << " at " << (int*)name << endl; cout << "name : " << name << endl; // 釋放資源 delete[] name; name = getName(); cout << name << " at " << (int*)name << endl; // 這個輸出的是指標name的地址而不是指標指向的字串的首地址 cout << "&name : " << &name << endl; delete[] name; return 0; } char* getName() { // 聲明瞭一個臨時儲存空間 char temp[80]; cout << "Enter your name : "; cin >> temp; // 聲明瞭一個char型指標, 指向一個長度是輸入的字串長度+1的char型陣列的起始地址 char* pn = new char[strlen(temp) + 1]; strcpy(pn, temp); return pn; }
程式執行結果:
從程式碼中可以看出來,
1.new和delete要成對的使用,
2.delete釋放的空間可以重複使用
3.new和delete可以分別在兩個函式中使用, 但是要注意的是需要成對的使用
最後看一個多種型別混合使用的例子:
#include "iostream"
#include "cstring"
using namespace std;
struct my_year {
int year;
};
int main() {
// 聲明瞭三個my_year結構體的變數
my_year y1, y2, y3;
y1.year = 1998;
// 聲明瞭一個my_year結構體指標, 並指向y2的首地址
my_year* py2 = &y2;
py2->year = 1999;
// 聲明瞭一個長度為3的my_year結構體陣列
my_year years[3];
years[0].year = 2003;
// 輸出2003, 第一個元素的year
cout << years->year << endl;
// 聲明瞭一個指標陣列
const my_year* parr[3] = {&y1, &y2, &y3};
// 1999
cout << parr[1]->year << endl;
// 指向指標的指標
const my_year** pparr = parr;
const my_year** pparr2 = parr;
// 下面這種寫法需要c++11才能編譯通過
// auto pparr2 = parr;
// 由於pparr是指向指標的指標, 所以*pparr還是指標, 因此需要用->來引用year
cout << (*pparr)->year << endl;
// (*(pparr2 + 1)) 是一個指向了parr[1]的結構體的指標,
// 因此(*(*(pparr2 + 1)))就是parr[1]這個指標指向的結構體了, 1999
cout << (*(*(pparr2 + 1))).year << endl;
return 0;
}
看一下執行結果:
具體的程式碼解釋, 看一下注釋即可, 寫的比較詳細
接下來說一下C++裡的自動儲存, 靜態儲存和動態儲存
1.自動儲存
在函式內部定義的常規變數使用自動儲存空間, 被稱為自動變數(automatic variable), 也就是它們在所屬的函式被呼叫的時候自動產生, 在該函式結束的時候消亡.
例如上上個demo中的getName()函式活動的時候temp被建立, 當getName執行完畢的時候釋放.
自動變數通常儲存在棧中, 這意味著執行程式碼塊的時候, 其中的變數將以此加入到棧中, 而在離開程式碼塊的時候, 將按相反的順序釋放這些變數(LIFO後進先出).
2.靜態儲存
靜態儲存是整個程式執行期間都存在的儲存方式. 宣告方式有兩種:
一種是在函式外面定義,
另一種是在宣告變數時使用關鍵字static如: static double fee = 1.23;
3.動態儲存
new和delete運算子提供了一種比自動變數和靜態變數更靈活的方法. 他們管理了一個記憶體池, 在c++中稱為自由儲存空間或者堆(heap). 該記憶體池同用於靜態變數和自動變數的記憶體是分開的. 上上個demo表明, new和delete能讓我們在一個函式中分配記憶體, 而在另一個函式中釋放. 因此資料的生命週期不完全受程式或函式的生存時間控制. 需要注意delete否則可能導致記憶體洩漏的危險
注意在堆記憶體上使用new建立變數後, 要記得使用delete進行釋放, 否則可能會造成記憶體洩漏