1. 定義數組程序員
數組是由類型名,標識符和維數組成的複合數據類型。其中,類型名能夠是內置類型或類類型,除引用以外,數組元素的類型還能夠是任意的複合類型。數組
數組的維數必須用大於等於1的常量表達式定義。在定義數組時,可爲其元素提供一組用逗號分隔的初值,這些初值用花括號{}括起來,稱爲初始化列表:安全
const unsigned array_size = 3; int ia[array_size] = {0, 1, 2};
若是沒有顯式提供元素初值,則數組元素會像普通變量同樣初始化。iphone
對於數組元素的顯式初始化應當注意兩點:函數
第一,顯式初始化的數組不需指定數組維數值,例如ui
int ia[] = {2, 22, 222};
第二,若是指定維數大於列出的元素初值數,對剩餘元素來講,內置類型初始化爲零,類類型調用默認構造函數初始化。例如spa
double coords[3] = {}; // all elements default initialized to 0 int nums[5] = {0, 1, 2}; // nums[3] and nums[4] default initialized to 0 // lables[1] and labels[2] default initialized to empty string string labels[3] = {"Hello"};
總結來看,內置類型的數組,在定義後要進行初始化,對於顯式初始化方式,一旦指定了其維數可確保全部元素都會被初始化,即便初始化列表中指定的元素初值數不足。而對於類類型的數組來講,在定義時就會調用默認構造函數初始化,若是顯式初始化,則調用相應構造函數進行初始化。例以下面本身寫的一個簡單類數組:指針
#include using namespace std; class Apple { public: Apple(int startVer):m_version(startVer) { } int GetVersion() { return m_version; } private: int m_version; }; int main(void) { Apple iphones[4] = {4, 5, 6, 7}; int latest = sizeof(iphones)/sizeof(iphones[0])-1; cout<<"iphone "<<iphones[latest].GetVersion()<<endl; return 0; }
不論是內置類型數組(包括字符數組),仍是類類型數組,都不支持直接複製與賦值操做。code
通常經過下標操做符來訪問數組的元素。在用下標訪問元素時,vector使用vector::size_type做爲下標的類型,而數組下標的正確類型是size_t。程序員必須對數組下標的使用負責,防止緩衝區溢出(buffer overflow)錯誤。對象
2. 數組下標與指針
在表達式中使用數組名時,該名字會自動轉換爲指向數組第一個元素的指針。使用指針的算術操做(pointer arithmetic)來獲取指定內容的存儲地址相比下標操做更加方便。例如:
int ia[] = {0, 2, 4, 6, 8}; int last = *(ia +4); // ok: last initialized to value of ia[4] int *ip = ia; // ip points to ia[0] int *ip2 = ip+4; // ok: ip2 points to ia[4]
使用下標訪問數組時,其實是對指向數組元素的指針作下標操做。只要指針指向數組元素,就能夠對它進行下標操做:
int *p = &ia[2]; int j = p[1]; // ok: p[1] equivalent to *(p+1) int j = p[-2]; //ok: p[-2] equivalent to *(p-2), same to ia[0]
數組類型的變量有三個重要的限制:
動態分配的數組沒必要在編譯時知道其長度,一般在運行時才肯定其數組長度,與數組變量不一樣,動態分配的數組將一直存在,直到程序顯式釋放它爲止。
每個程序在執行時都佔用一塊內存空間,用於存放動態分配的對象,此內存空間稱爲程序的自由存儲區(free store)或堆(heap)。C語言使用一對標準庫函數malloc和free在自由存儲區分配存儲空間,而C++語言則使用new和delete表達式實現相同的功能。
1. 動態數組的定義與初始化
動態分配數組只需指定類型和數組長度,沒必要爲數組對象命名,new表達式返回指向新分配數組的第一個元素的指針:
int *pia = new int[10]; // array of 10 uninitialized ints inr *pia2 = new int[10](); // 10 elements of ints array initialized to 0
new表達式須要指定指針類型以及在方括號中給出的數組維數,該維數能夠是任意的複雜表達式。在動態分配數組時,若想初始化內置類型,則只能採用值初始化方式,而類類型無論有沒有值初始化都會調用默認構造函數初始化。總的來講,動態分配的數組,其數組元素只能初始化爲元素類型的默認值,而不能採用初始化列表的方式提供初值。
2. 容許動態分配空數組
size_t n = get_size(); int *p = new int[n]; for(int *q = p; q != p + n; ++q) /* process the array *
上例中,即便n = 0(get_size返回0)時,程序仍能正常運行。C++雖然不容許定義長度爲0的數組變量,但使用new動態建立長度爲0的數組是合法的。
對數組爲零的動態數組容許的操做包括:比較運算,指針加減零運算。
3. 動態空間的釋放
若是再也不須要使用動態建立的數組,程序員必須顯式地將其佔用的存儲空間返還給自由存儲區。C++中釋放指針所指向的數組空間:
delete [] pia;
關鍵字delete與指針間的空方括號是必不可少的,不然將產生內存泄漏(memory leak)。
1. 字符數組
字符數組既能夠用一組由花括號括起來,逗號隔開的字符字面值進行初始化,也能夠用一個字符串字面值進行初始化。需注意的是字符串字面值包含一個額外的空字符(null)用於結束字符串,例如:
char chs1[] = {‘C’, '+', '+'}; char chs2[] = {'C', '+', '+', '\0'}; char chs3[] = "C++"; // null terminator added automatically
其中,字符數組chs2和chs3值相同,而且維數都是4。
動態字符數組的定義與初始化:
char *pNewChars = new char[newSize]; // uninitialized if(pNewChars != NULL) { char *iter = pNewChars; while(iter != (pNewChars + newSize)) *iter++ = '\0'; }
2. C風格字符串(C-style character string)
實際上,C風格字符串既不能確切地歸結爲C語言的類型,也不能歸結爲C++語言的類型,能夠說它是以空字符null結束的字符數組,例如上面的ch2和ch3,字符串字面值是該類型的實例。
C++語言中通常經過(const) char*類型的指針來操縱C風格字符串。須要注意的是,C風格字符串必定是以null結束的,若是發現char*的數組中不是以null結束,那麼它就不是C風格字符串,這樣來看,C風格字符串實際上是字符數組的一個子集。
const char* cp = "some value"; // null terminated
標準庫類string
string類型支持長度可變的字符串。要使用string類對象,必須包含相關頭文件:
#include <string>
表1 幾種初始化string對象的方式 |
string s1; 默認構造函數,空字符串 string s2(s1); 將s2初始化爲s1的一個副本 string s3("Value"); 將s3初始化爲一個字符串字面值副本 string s4(n, 'c'); 將s4初始化爲字符'c'的n個副本 |
表中的第三種初始化方式就是使用字符串字面值(屬於C風格字符串類型)進行初始化string類對象的,但須要注意的是string類型不符合C風格字符串的特徵,例如:
string str("Hi, C++"); cout<<"string size = "<<str.size()<<endl; // size = 7
string對象會自動將字符串字面值末尾null結束符去掉,所以獲得的string對象size = 7。但string類提供了一個名爲c_str的成員函數來轉換獲得C風格字符串:
const char *cStr = str.c_str(); //ok
注意:c_str函數返回的指針是指向const char類型的數組,須要賦給const char*類型
C風格字符串的標準庫函數
C語言標準庫提供了一系列處理C風格字符串的庫函數,須要包含C頭文件:
#include <cstring>
cstring是string.h頭文件的C++版本,string.h文件則是C語言的標準庫。
表2 C風格字符串的標準庫函數 |
strlen(s) 返回s的長度,不包括字符串結束符null strcmp(s1, s2) 比較兩個字符串s1和s2是否相同,相等返回0;若s1大於s2返回正數,若s1小於s2返回負數 strcat(s1, s2) 將字符串s2鏈接到s1,並返回s1 strcpy(s1, s2) 將s2複製給s1,並返回s1 strncat(s1, s2, n) 將s2的前n個字符鏈接到s1後面,並返回s1 strncpy(s1, s2, n) 將s2的前n個字符複製給s1,並返回s1 |
在使用這些標準庫函數時,必須保證傳遞的指針具備非零值,而且指向以null結束的字符數組中的第一個元素。對於會修改傳入字符串的標準庫函數,程序員必須確保目標字符串必須足夠大,不然會產生嚴重錯誤。
正是存在不少缺陷,C++中推薦儘可能使用標準庫類型string來代替這些操做,提升安全性和效率。
Reference book: C++ primer