數組和指針 - 2【C++ Primer 學習筆記 - 第四章】

指針和 const 限定符

double dheight = 100.5;
const double dprice = 10.5;
const double *pd = &dprice;	// pd 指向的 dprice 是const 的
pd = &dheight;	// pd 可以指向非const 的對象

int ierr = 0;
int *const curErr = &ierr;  // 指針 curErr, 是const的

const int iMsg = 10;
const int *const pmsg = &iMsg;	// 指針 和 指向的對象,都是const的




指針和 typedef。以下:ps,ps2,ps3 都是等價的。
原因是:const 限定符可以放在類型前,也可以放在類型後
就是說,         const string a;  
也可以寫成: string const a;

typedef string * pstring;
string s("Hello");
const pstring ps = &s;
string *const ps2 = &s;  // 與上式,等價
pstring const ps3 = &s;  // 與上式,等價

此處,const 修飾的是 pstring 類型,也就是說,const 修飾的是指針。typedef,不是簡單的文本擴展!

因此,const pstring ps = &s;   其實等價於:   string *const ps = &s;



C風格字符串

字符串字面值 的類型,是字符常量的數組。
也就是,const char 類型的數組

C++ 從C語言 繼承下來的一種通用結構就是 C風格字符串(C-style character string)
而,字符串面值,就是該類型的實例。

實際上,C風格字符串既不能歸結爲C語言的類型,也不能歸結爲C++語言的類型,
而是以空字符 null 結束的字符數組。


char ca1[] = {'C', '+', '+'};
char ca2[] = {'C', '+', '+', '\0'};	// C風格
char ca3[] = "C++";		// C風格,末尾自動加 null

const char *cp = "C++"; // C風格
char *cp1 = ca1;  // 
char *cp2 = ca2;  // C風格


C++ 通過 (const) char * 類型的指針,來操作C風格字符串。

const char *cp = "some value";
while(*cp)
{
	++cp;
}
如果 cp 指向的字符串數組沒有null 字符,則,無法達到預期效果。
直到在內存中找到null 字符,循環纔會終止。

操縱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






注意:C風格字符串的操作容易出錯。
通常使用標準庫類型 string代替此類操作



動態數組

動態數組,不必在編譯時知道其長度,可以是在運行時再確定數組長度。
每個程序,執行時都佔用一塊可用內存,用於存放動態分配的對象,
此內存稱爲:自由存儲區(Free Store)或者 堆(Heap)
C++ 使用 new delete 來分配和釋放 自由存儲區。

string *sp = new string[10];
int *ip = new int[20];

size_t n = get_size();
int *ip3 = new int[n];

string *sp2 = new string[30]();
const int *ip2 = new const int[11]();

// char arr[0] 是錯誤的, 然而,動態分配時,長度可以是0,並返回非0 的指針,但該指針不能解引用
char *cp = new char[0];

delete [] ip3;


使用動態數組,通常是因爲,編譯時無法知道數組的準確長度。如:以下場景

const char *noerr = "success";
const char *err188 = "Error Code: 188";

const char *errorText;
if(errorFound)
	errorText = err188;
else
	errorText = noerr;

int dimension = strlen(errorText) + 1;
char *errMsg = new char[dimension];
strncpy(errMsg, errorText, dimension);


混合使用標準庫類 string 和 C風格字符串
c_str () :返回C風格字符串的表示方法

string str("Hello");
const char *cp = str.c_str();  // C 風格字符串自動轉換爲,指向字符數組首地址的指針
// char *cp = str.c_str(); 錯誤,因爲c_str() 返回的是 const char 類型的數組
// char *cp = str;   錯誤,無法使用 string 對象來初始化 字符指針

// str.c_str() 返回的數組未必永遠有效。因爲 str 有可能被修改。
// 因此,最好是複製 str.c_str() 返回的數組


string s("abcdefg");	
// char *a; 錯誤
// char *a = "x"; 
// 錯誤,"x"的內存是在棧上分配的,棧上的內存無法修改
// 返回的其實是 const char *,而不是 char *, 因此strcpy 將會無法寫入,報錯
char *a = new char[s.length()+1];
strcpy(a, s.c_str());




使用數組初始化 vector

const size_t array_size = 5;
int int_arr[array_size] = {88, 32, 13, 34, 65};

// 實際複製了 int_arr[1], int_arr[2], int_arr[3], int_arr[4]
vector<int> ivec(int_arr + 1, int_arr + array_size);


多維數組,即:數組的數組

int arr_first[2][3] = { {1, 2, 3}, {4, 5, 6} };

// 與上式等價
int arr_second[2][3] = {1, 2, 3, 4, 5, 6};

// 等價於:{ {1, 0, 0}, {2, 0, 0} }
int arr_third[2][3] = { {1}, {2} };

// 等價於:{ {1, 2, 0}, {0, 0, 0} }
int arr_fourth[2][3] = { 1, 2 };

// ip 是數組,長度爲3,數組元素是,指向int 的指針
int *ip[3]; 

// ip_second 是指針,指向一個長度爲3 的int 數組
int (*ip_second)[3];


typedef int int_array [3];
for(int_array *p_arr = arr_first; p_arr!=arr_first+2; ++p_arr)
	for(int *p_int = *p_arr; p_int!=*p_arr+3; ++p_int)
		*p_int = 100;
int c = arr_first[0][1];

..

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章