C++:數組、字元串和指針
- 字元串
- 字元串
-
- C-風格字元串
- 基于string類庫的字元串
- 結構體
- 共用體
- 枚舉
- 指針和自由存儲空間
字元串
要建立數組可以使用聲明語句。數組語句應該包含三個要素:
- 存儲在每個元素中的值的類型;
- 數組名;
-
數組中的元素數
通用格式為:
具體例子如下:
另外對數組使用sizeof函數可以得到數組的位元組數。
數組的初始化方式如下:
int demo1[]{ 1,2,3,4 };//等價于int number[4]={ 1,2,3,4 };
int demo2[4]{};//在大括号中什麼都不加代表全0
如果隻初始化一部分元素則剩下的元素預設為0。
字元串
C++中字元串有兩種形式,一種是C-風格字元串,另一種基于string類庫的字元串。
C-風格字元串
對于C-風格字元串,其最後總是以’\0’結尾,是以在确定字元串數組的最短長度時,’\0’字元也應該被計算在内。如下所示:
char animal1[4] = { 'd','o','g','s' };//僅僅是一個char數組
char animal2[4] = { 'c','a','t','\0' };//是一個字元串
cout << animal1 << endl;//使用cout會導緻持續輸出直到遇到\0
cout << animal2 << endl;//正常輸出
其初始化還有更加簡便的方法——字元串常量:
char animal3[] = "fish";
cout << sizeof(animal3) << endl;
//長度為5,最後一位為0,如果數組長度大于字元串常量長度,多餘的位置全部被指派為\0;得出結論:數組大小至少等于字元串長度+1
這裡"fish"就是一個字元串常量,其表示的實際上是該字元串常量(由’f’,‘i’,‘s’,‘h’,’\0’組成)所在的記憶體位址。
字元串可以進行拼接,将需要拼接的字元串放在一起即可,如下所示:
對于C-風格字元串我們常常使用sizeof和stlen計算其長度,其差別為:
- sizeof運算指出的是整個字元串數組的長度,即初始化和未初始化的元素長度之和,機關為位元組;
- strlen傳回的是儲存在字元串數組中字元串的長度(不包括’\0’),是以字元串的實際長度應該是strlen的傳回值加1。該函數的原理是從第一個元素開始依次掃描直到遇到’\0’,是以如果将未初始化的字元串數組傳入該函數,由于值不确定,傳回的長度也是不确定的。
将輸入的字元串傳入字元串數組中有多種方式,第一種就是使用cin,但是該方法有一個缺陷,那就是直接使用cin,其傳入的字元串會在遇到空白時結束,空白後面的剩餘字元串無法被存儲到字元串數組中。
另一個方法是使用cin.getline,第一個參數為用于存儲輸入字元串的數組名稱,第二個為需要讀取字元串的長度(包括’\0’)。
char name[20];
cin.getline(name,20);//讀取20個字元儲存在name中,如果在讀取到第20個字元之前遇到了換行符則提前停止,并将遇到的換行符丢棄;
cout << name;
與cin.getline類似的還有cin.get。cin.get遇到換行符停止後不會丢棄換行符。是以連續兩個get可能會導緻第二個get無法讀取到任何字元(碰到換行直接停止)。如果get不包含任何參數則會讀取一個字元,使用cin.get()可以來處理換行。
char name[20];
cin.get(name, 20).get();//cin.get()會傳回一個cin對象,之後調用get讀取換行符
int year;
cin >> name;
cout << name << "len:"<<strlen(name)<<endl;
基于string類庫的字元串
對于基于string類庫的字元串,使用前需要包含頭檔案stirng,未初始化之前長度為0,使用size()方法可以擷取字元串長度,其大小根據所賦的值由系統自行調整,是以更加安全。
其初始化可以直接使用字元串常量。
通過輸入來為字元串指派也有多種方法,其中一種就是直接使用cin,其缺點與C-風格字元串使用cin來初始化類似,遇到空白會自動停止。
也可以使用getline來對string進行初始化,其輸入的參數與cin.getline有差別,如下所示:
string str;
getline(cin, str);//第一個參數為輸入源,第二個為指派對象
C++ 11中加入了原始字元串的概念,原始字元串中不會進行轉義操作。其格式為以大寫R開頭,以"(開頭,以)"結尾。
結構體
結構的定義如下所示:
struct inflatable
{
char name[20];
float volume;
double price;
};
結構體的聲明、内部元素的通路以及結構體數組的聲明如下所示:
inflatable hat = {"lee",1.88,29.99}; //初始化,等号也可以省略,不允許縮窄轉換
hat.volume;//通路結構體中的元素
//結構數組與其他數組類似,構造方式如下:
inflatable guest[2] = {
{"Bambi",0.5,21.99},
{"Godzilla",2000,565.99}
};
共用體
共用體Union,可以儲存不同類型的資料,但是同時隻能存儲一種,這樣可以達到節省記憶體的效果。
其聲明形式如下:
union one4all
{
int int_val;
long long_val;
double double_val;
};
可以使用上述共用體存儲int、long或者double類型的資料,但是同一時刻隻能存儲一種資料。可以加入到結構體中。如果想要
匿名結構體:沒有名稱,裡面的成員是相同記憶體位址處的變量,其通路方式如下:
struct widget
{
char brand[20];
int type;
union
{
long id_num;
char id_char[20];
};
};
widget prize;
if (prize.type == 1) //直接将兩個變量看作是prize的兩個成員
{
cin >> prize.id_num;
}
else
{
cin >> prize.id_char;
}
枚舉
使用枚舉類型可以輕易的定義常量,定義方式如下:
該語句首先定義了一種枚舉類型spectrum,其中read、orange、yellow則作為符号常量,分别代表0~7。
枚舉類型的值可以被提升為int型,但是不能反向轉換。是以該變量可以使用red、orange等等變量為其指派,但是不可以使用0~7為其指派(除非使用強制轉換)。如果隻打算使用定義的常量而不需要使用枚舉類型的變量,則枚舉類型的名稱可以省略:
enum {paramsError,memoryError,unkonwError}; //0~2分别代表參數錯誤、記憶體錯誤以及未知的錯誤
cout << memoryError;
指針和自由存儲空間
在C++在變量名前加上&符号可以檢視該變量名的位址,儲存着記憶體位址的變量稱為指針,‘*’代表解除引用運算符,将其加在指針變量前則可以檢視儲存在對應記憶體位址的值。
聲明指針的格式為:
int* p1, * p2;//每聲明一個指針都要在前方加上*
int foo = 100;
p1 = &foo;//也可在聲明時直接指派
指針也存在着安全隐患,聲明一個指針隻會為其配置設定用于存儲位址的記憶體,但是不會為其配置設定指針所指向資料的記憶體,是以在對指針使用解除引用運算符(*)之前一定要對其進行初始化。
如果想對指針直接使用數字指派,則在這之前需要進行強制的類型轉換:
我們可以使用new進行動态記憶體的配置設定,在使用完成後應該使用delete對配置設定的記憶體進行釋放,數組和實體的delete方式有差別:
int arraySize = 20;
int* pArray = new int[arraySize];//為數組動态配置設定記憶體
delete []pArray;//釋放記憶體
int* p = new int;//為一個實體配置設定記憶體
delete p;//釋放記憶體
總之,new和delete之前必須遵守如下規則:
- 不要使用delete來釋放不是new配置設定的記憶體;
- 不要使用delete釋放同一塊記憶體兩次
- 如果使用new[]為數組配置設定記憶體,則應該使用delete []來釋放
- 如果使用new為一個實體配置設定記憶體,應使用delete(沒有方括号)來釋放。
- 對空指針(指針中存儲的位址為0)使用delete是安全的
動态數組的通路:通路方式與數組的通路方式類似,事實上C++中數組和指針基本等價,不同的地方是可以修改指針的值但是不可以修改數組名的值,另外對數組使用sizeof函數傳回的将是數組的長度,而對指針使用則傳回的是指針的長度。對于整數變量,其加1之後其值會加1;而對于指針,其加1之後增加的兩等于它指向的類型的位元組數
pArray += 1;//此時應該指向的是第二個元素
pArray -= 1;//此時應該指向的是第一個元素
如果使用cout顯示字元串指針,則會顯示字元串指針指向的内容,如果需要顯示字元串指針的位址則需要進行強制轉換。
char fruit[10] = "apple";
char* pointer;
pointer = fruit;
cout << pointer << (int*)pointer << endl; //第一次輸入的是apple,第二次輸出的是位址
pointer = new char[strlen(fruit) + 1];
strcpy(pointer,fruit);//将fruit儲存的字元串複制到pointer指向的記憶體位址
cout << pointer << (int*)pointer << endl;//發現位址改變
char* newPointer = new char[10];
strcpy(newPointer, "hello");
cout << newPointer << endl;
對于指向結構體的指針,通路結構體成員應該使用->,如:inflatable *ps = new inflatable; ps->price//通路成員price。