【C++注意事項】4 指標 Pointers

nomasp發表於2015-05-21

和上一節的引用類似,指標(pointer)是“指向(point to)”另外一種型別的複合型別。與引用類似,指標也實現了對其他物件的間接訪問。然後指標和引用相比有許多不同。其一,指標本身就是一個物件,允許對指標賦值和拷貝,而且在指標的生命週期內它可以先後指向幾個不同的物件。其二,指標無須在定義時賦初值。和其他內建型別一樣,在塊作用域內定義的指標如果沒有被初始化,也將擁有一個不確定的值。

因為引用不是物件,沒有實際地址,所以不能定義指向引用的指標。

指標的值(即地址)應屬下列4種狀態之一:

1)指向一個物件

2)指向緊鄰物件所佔空間的下一個位置

3)空指標,意味著指標沒有指定任何物件

4)無效指標,也就是上述情況之外的其他值

試圖拷貝或以其他方式訪問無效指標的值都將引發錯誤。編譯器並不負責檢查此類錯誤,這一點和試圖使用未經初始化的變數是一樣的。訪問無效指標的後果無法預計,因此程式設計師必須清楚任意給定的指標是否有效。因此解引用符也只適用於那些確實指向了某個物件的有效指標。

所謂的解引用符就是使用操作符*來訪問指標指向的物件。

int ival= 42;
int *p= &ival;  // p存放著變數ival的地址,或者說p是指向變數ival的指標
cout<<*p;  // 由符號*得到指標p所指的物件,輸出42
*p= 0;  // 由符號*得到指標p所指的物件,即可經由p為變數ival賦值
cout<<*p;  // 輸出0

取地址符(&)和解引用符(*)的多重含義:

int i= 42;   
int &r= i;  // &緊隨型別名出現,因此是宣告的一部分,r是一個引用
int *p;  // *緊隨型別名出現,因此是宣告的一部分,p是一個指標
p= &i;  // &出現在表示式中,是一個取地址符
*p= i;  // *出現在表示式中,是一個解引用符
int &r2= *p;  // &是宣告的一部分,*是一個解引用符

空指標(null pointer)不指向任何物件,在試圖使用一個指標之前程式碼可以檢查它是否為空。下面有3種生成空指標的方式:

// 需要首先#include cstdlib
inht *p1=NULL;

過去的程式會用到一個名為NULL的預處理變數(preprocessor variable)來給指標賦值,這個變數在標頭檔案cstdlib中定義,它的值就是0。

int *p2= 0;

直接將p2初始化為字面常量0

int *p3= nullptr;

這是C++11新標準所引入的一種方法。

需要注意的是不能將int變數直接賦值給指標,即便int變數的值恰好等於0也不行。

void*是一種特殊的指標型別,可用於存放任意物件的地址。

但是不能直接操作void*指標,因為我們並不知道這個物件到底是什麼型別,也就無法確定能在這個物件上做哪些操作。


English…


With two exceptions, which we will see at later, the types of the pointer and the object to which it points must match:

double dval;
double *pd= &dval;  // ok: initializer is the address of a double
double *pd2= pd;  // ok: initializer is a pointer to double
int *pi= pd;  // error: types of pi and pd differ
pi= &dval;  // error: assigning the address of a double to a pointer to int

The types must match because the type of the pointer is used to infer the type of the object to which the pointer points. If a pointer addressed an object of another type, operations performed on the underlying object would fail.

As with reference, we can define pointers that point to either const or not const types. Like a reference to const, a pointer to const may not be used to change the object to which the pointer points. We may store the address of a const object only in a pointer to const:

const double pi= 3.14;  // pi is const; its value may not be changed
double *ptr= &pi;  // error: ptr is a plain pointer
const double *cptr=&pi;  // ok: cptr may point to a double that is const
*cptr= 42;  // error: cannot assign to *cptr

The first exception is that we can use a pointer to const to point to a nonconst object:

double dval= 3.14;  // dval is a double; its value can be changed
cptr= &dval;  // ok: but can't change dval through cptr

Defining a pointer as a pointer to const affects only what we can do with the pointer. It is important to remenber that there is no guarantee that an object pointed to by a pointer to const won’t change.

It may be helpful to think of pointers and reference to const as pointers or references “that think they point to refer to const.”

const pointers

Unlike references, pointers are objects. Hence, as with any other object type, we can have a pointer that is itself const. Like any other const object, a const pointer must be initialized, and once initialized, its value(i.e., the address that it holds) may not be changed. We indicate that the pointer is const by putting the const after the *. This placement indicates that it is the pointer, not the pointed-to type, that is const:

int errNumb= 0;
int *const curErr= &errNumb;  // curErr will always point to errNumb
const double pi= 3.14159;
const double *const pip= &pi;  // pip is a const pointer to a cosnt object

The symbol closest to curErr is const, which means that curErr itself will be a const object. The type of that object is formed from the rest of the declarator. the next symbol in the declarator is *, which means that curErr is a const pointer. Finally, the base type of the declaration completes type of curErr, which is a const pointer to an object of type int. Similarly, pip is a const pointer to an object of type const double.

The fact that a pointer is itself const says nothing about whether we can use the pointer to change the underlying object. Whether we can change that object depends entirely on the type to which the pointer points. For example, pip is a const pointer to const. Neither the value of the object addressed by pip nor the address stored in pip can be changed. On the other hand, curErr addresses a plain, nonconst int. We can use curErr to change the value of errNumb:

*pip= 2.72;  // error: pip is a pointers to const
// if the object to which curErr points(i.e., errNumb) is nonzero
if(*curErr)
{
    errorHandler();
    *curErr= 0;  // ok: reset the value of the object to which curErr is bound
}

Note: “C++ Notes” series of blog mainly reference books of C++ Prime is the fifth edition of the Chinese version and English version. My English is very poor, and I don’t want there are some syntax error in blog. So the blogs have lots of words and sentences from the book. I wrote this series in order to consolidate the knowledge of C++, but also in order to improve my poor English. I also hope to help readers. Thank you.、



感謝您的訪問,希望對您有所幫助。 歡迎大家關注、收藏以及評論。

我的更多部落格文章:NoMasp部落格導讀


為使本文得到斧正和提問,轉載請註明出處:
http://blog.csdn.net/nomasp


相關文章