close
From: http://sandwichc.blogspot.com/2007/02/cc-pointer-reference.html
良多程式員說:學C/C++而不會利用指標,相當於沒學過C/C++翻譯
本文針對C/C++中,指標與參考的常見問題或錯誤,做了一番清算,但求能到達拋磚引玉之效翻譯如有疏漏或毛病的地方,尚請不吝告知指教翻譯
目次
int *p1 = &a;
int *p2 = &b;
此中的&,稱為address of (取址)。即,p1 = address of a,p2 = address of b。
另外一個符號*,代表的意義是指標。
int *p1要由後往前浏覽來瞭解它的意義:p1 is a pointer points to an integer。是以,
int *p1 = &a;這整行,華頓翻譯公司們可以看成:p1 is a pointer points to integer variable a,即:p1是一個指標,指向整數變數a。
且讓我們臨時打住指標的接洽,轉頭看看參考 (reference)。
參考,可以想像成是一個變數或物件的別名 (alias)。凡是,當函式 (function) 的參數 (parameter) 在函式中會被修改,而且要把這個修改成果讓呼叫函式的部份繼續使用,我們會用參考來當參數傳入函式中。
讓我們看看下面的例子:
void swap(int &a翻譯社 int &b){
int tmp = a;
a = b;
b = tmp;
}
當其他程式呼喚此交換程式時,只要直接寫swap(x, y)就能互換x與y的值。在這裡,a和b為x與y的別號,即:a就是x,b就是y,如同美國國父就是華盛頓一樣。a和b不是x和y的複製品,任何做用在a與b上的動作城市反映在x與y上面,反之亦然。
指標和參考之所以難懂,有很大一部分的緣由是符號上的生疏而至。加上&既能用於取址又能用於參考,輕易造成初學者的混淆翻譯下面我們供給幾個建議來輔助列位看懂這些符號翻譯
- 把int *p視為 int* p。
把int和*連在一路看,看成是一種型態叫做 "指向整數之指標",要比int *p天然很多翻譯同樣的體例也能夠套在char* p或void* p等翻譯但要注意的是下面的狀況:int* p, q;
不要把這行誤解成p, q都是指向int之指標,事實上,q只是一個int變數翻譯上面這行相當於int *p, q;
或int *p; int q;
若是p, q都要宣佈成指向int之指標,應寫成:int *p, *q
或干脆分兩行寫:int* p;
int* q; - 若&前面有資料型態 (ex: int &),則為參考,&前面有等號 (ex: int* p = &a),則為取址翻譯
由於&同時具有多種意義,是以輕易造成攪渾。這裡列出的這個方式,可以扶助弄清晰每一個&的意義。
JAVA中的reference與C++的reference意義上其實不溝通,卻利用統一個字,這也是reference輕易造成混淆的緣由。在此,我們暫不斟酌JAVA中reference的觀念 (關於java中reference的觀念,請參考Reference in JAVA -- 淺談java的指標),純粹把主題放在C/C++上。
呼叫副函式時,call by value, address, 或reference是三種分歧的參數傳遞體例。其意義以下:
- call by value
假設函式A呼叫函式B(p, q),則B中的p和q是「複製」自函式A所傳入的參數,B中對p翻譯社 q所做的任何運算都不會影響到A中的p和q,因為B履行完後,並不會把複製的p, q存回到A中。這類參數傳遞方式,我們稱之為call by value。
以swap這個常見的函式為例,若swap寫成下面的樣子:
void swap(int a, int b){
int tmp = a;
a = b;
b = tmp;
}
則呼喚swap(x, y)
後,x和y的值其實不會有變化翻譯 - call by address (或call by pointer)
利用指標來做參數傳遞,這種方式骨子裡還是call by value,只不過call by value的value,其資料型態為指標罷了。我們一樣看看用call by address來寫swap互換兩個integer的例子。
void swap(int* a翻譯社 int* b){
int tmp = *a;
*a = *b;
*b = tmp;
}
呼喚swap時,要寫成swap(&x, &y)。呼喚swap時,x的指標 (x的貯存位置) 與y的指標 (y的貯存位置) 會被複製一份到swap中,然後把該位置內所記錄的值做改換。swap竣事後,&x (address of x) 和&y (address of y) 仍然沒變,只是address of x所記實之變數值與address of y所記錄之變數值互換了。因為&x 和&y 實際上是行使call by value在傳,因此,call by address其實骨子裡就是call by value。 - call by reference
這是C++才加進來的工具,C自己並沒有call by reference。call by reference基本上是把參數做個別名 (alias),以下面的swap為例:swap(int &a, int &b){
int tmp = a;
a = b;
b = tmp;
}
將來利用時,只要呼喚swap(x, y),就能夠讓x和y的值互換翻譯在這個例子中,a 就是 x, b 就是 y。這個觀念在上一節已提過,在此不再贅述。
當華頓翻譯公司們用call by pointer (或address) 來傳遞參數時,被呼喚的函式複製一份pointer的值曩昔。然則,當我們想在函式內改變pointer的值 (而非pointer所指向之變數的值),並且改變的結果要能在函式外看獲得時,call by pointer就不足夠用了翻譯此時應當用的是"call by pointer to pointer"或"call by reference to pointer"翻譯我們先看下面的例子:
int g_int = 0;
void changePtr(int* pInt){
pInt = &g_int;
}
void main(){
int localInt = 1;
int* localPInt = &localInt;
changePtr(localPInt);
printf("%d ", *localPInt);
}
在這個例子中,印出來的數字依然會是localInt的1,因為changPtr中的pInt是由localPInt「複製」曩昔的,對pInt做改變並不會反映到localPInt身上翻譯
我們先用pointer to pointer對localPInt做改變,請看下例翻譯
int g_int = 0;
void changePtr(int** pInt){
*pInt = &g_int;
}
void main(){
int localInt = 1;
int* localPInt = &localInt;
changePtr(&localPInt);
printf("%d ", *localPInt);
}
本例中,印出來的數字會是g_int的0翻譯changePtr函式中的pInt是由&localPInt複製所得,是以對pInt做改變並不會影響main中的&localPInt (資料型態:pointer to pointer to integer)。但在changePtr函式中我們改變的對象是pInt所指向的內容,因此這項改變在main中會顯示出來。
一樣的功能,我們也可改用reference to pointer來完成。但一樣切記,reference是C++才有的功能,是以reference to pointer也只能在支援C++的環境中使用翻譯
int g_int = 0;
void changePtr(int* &refPInt){
refPInt = &g_int;
}
void main(){
int localInt = 1;
int* localPInt = &localInt;
changePtr(localPInt);
printf("%d "翻譯社 *localPInt);
}
這段程式印出來的數字會是0。因為在changePtr中,我們宣佈的參數型態為int* &,即:reference to pointer to integer。是以,main中的localPInt與changePtr函式中的refPInt其實是「同一件工具」。
另外一種常見的混淆是pointer array (指標陣列) 與pointer to pointers,因為兩種都可以寫成**的型式。如,int**可能是pointer to pointer to integer,也可能是integer pointer array。但pointer array的觀念相對來說要簡單且直觀很多,這裡華頓翻譯公司們就暫不花篇幅敘述。常見的例子:main(int argc翻譯社 char** argv)其實應該是main(int argc, char* argv[])。
4. function pointer
變數的指標指向變數的位址,一樣的,function pointer (函式指標) 也是指向函式的位址的指標。
函式指標的插足,讓C/C++的符號更複雜,也使更多人望之而卻步。在申明函式指標的用處前,我們先直接由語法來看看函式指標該怎麼宣佈、怎麼理解。
假定有個函式長成下面的模樣:
void func1(int int1翻譯社 char char1);
我們想宣佈一個能指向func1的指標,則寫成下面如許:
void (*funcPtr1)(int, char);
如許的寫法應理解成:funcPtr1是一個函數指標,它指向的函數接管int與char兩個參數並回傳void。如果今天有另外一個函式長成
void func2(int int2, char char2);
則funcPtr1也能指向func2。
指標指向的方式,寫成下面如許:
funcPtr1 = &func1;
取址符號省略亦可,效果不異:
funcPtr1 = func1;
若欲在宣佈時就直接給予初值,則寫成下面這樣:
void (*funcPtr1)(int, char) = &func1; //&亦可省略
stdlib.h中供給的qsort函式是函式指標最多見的運用之一翻譯此函式之prototype長得以下:
void qsort(void* base, size_t n, size_t size翻譯社 int (*cmp)(const void*, const void*));
此中的int (*cmp)(const void*, const void*) 就利用到函式指標翻譯
函式指標常見的利用機會是multithread時翻譯函數指標負責把函數傳進設立建設履行緒的API中翻譯
別的,callback function也是常利用函式指標的處所翻譯所謂callback function即:産生某事宜時,自動履行某些動作翻譯在event driven的情況中,便時常使用callback function來實現此機制。
事實上,函式指標還能讓C說話實作polymorphism。但礙於篇幅,在此不再胪陳。
5. void ** (*d) (int &, char **(*)(char *, char **))....若何看懂複雜的宣告…
在這裡,我們介紹兩種方式來看懂複雜的宣佈。第一種要判定的是:常數與指標混合使用時,到底const潤色的是指標仍是指標所指的變數? 第二種是面對如標題所示這種複雜的宣佈時,華頓翻譯公司們要怎麼讀懂它翻譯
5.1 常數與指標的讀法
const double *ptr;
double *const ptr;
double const* ptr;
const double *const ptr;
以上幾個宣佈,到底const修飾的對象是指標,還是指標所指向的變數呢?
其實,環節在於:*與const的前後關係!
當*在const之前,則是常數指標,反之則為常數變數。是以,
const double *ptr; // ptr指向常數變數
double *const ptr; // ptr是常數指標
double const* ptr; // ptr指向常數變數
const double *const ptr; // 指向常數變數的常數指標
事實上,在The C++ Programming Language中有提到一個簡單的要訣:由右向左讀!!讓我們用這個要訣再來試一次。
const double *ptr; // ptr is a pointer points to double翻譯社 which is a constant
double *const ptr; // ptr is a constant pointer points to double
double const* ptr; // ptr is a pointer points to constant double
const double *const ptr; // ptr is a constant pointer points to double翻譯社 which is a constant
了局完全不異 :-)
5.2 複雜宣佈的讀法 void ** (*d) (int &, char **(*)(char *, char **)).......
其實浏覽C/C++中複雜的宣佈有點像是讀英文的長句子,看多了,天然知道句子是怎麼組織出來的。
但對於句子還不熟的人,不免得藉助文法來拆解一個句子。關於C說話複雜宣告的解析文法,最令華頓翻譯公司印象深入的,莫過於印度工程師Vikram的"The right-left rule"。他是這麼說的:
「從最內層的括號讀起,變數名稱,然後往右,碰到括號就往左。當括號內的器械都解讀完畢了,就跳出括號繼續未完成的部分,重覆上面的步調直到解讀完畢。」
舉個例子:void ** (*d) (int &翻譯社 char*)依下面方式解讀:
1. 最內層括號的讀起,變數名稱: d
2. 往右直到碰著) : (空白)
3. 往左直到碰著( :是一個函數指標
4. 跳出括號,往右,碰著(int &, char*): 此函式接管兩個參數:第一個參數是reference to integer,第二個參數是character pointer。
5. 往左趕上void **: 此函式回傳的型態為pointer to pointer to void。
==> d是一個函式指標,指向的函式接管int&和char*兩個參數並回傳void**的型態。
若何,是否是好懂許多了呢?
題目中的void ** (*d) (int &, char **(*)(char *, char **))其實和上面的例子幾近一樣,只是函式的第二個參數又是一個函式指標,接管char*和char**兩個參數並回傳char**的型態。
行文至此,把指標和參考的常見問題與攪渾大致地提了一些。但願能讓利用C/C++的人在面對或利用指標、參考、或取址時,不再有疙瘩在心中翻譯文中如有不足或錯誤之處,也請高手不吝珠玉囉。:-)
1. 何謂指標 (pointer)? 何謂參考 (reference)?
- 何謂指標 (pointer)? 何謂參考 (reference)?
- call by value? call by address (或call by pointer)? call by reference? -- swap(int* a翻譯社 int* b) v.s. swap (int &a翻譯社 int &b)
- pointer to pointer翻譯社 reference to pointer (int** v.s. int*&)
以下文章來自: https://blog.xuite.net/chuangyf0917/blog/13649687-C/C%2B%2B%E4%B9%8B%E6%8C%87%E6%A8%99+%28pointer%29有關各國語文翻譯公證的問題歡迎諮詢華頓翻譯公司02-77260932
文章標籤
全站熱搜