1. 程式人生 > >C++ premier Plus書之--C++指標, 陣列, 結構體, 字串

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這個成員:

  1. ps->price
  2. (*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進行釋放, 否則可能會造成記憶體洩漏