[爆卦]c指標是什麼?優點缺點精華區懶人包

為什麼這篇c指標鄉民發文收入到精華區:因為在c指標這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者khoguan (Khoguan Phuann)看板C_and_CPP標題Re: [討論] 關於...

c指標 在 Amber Physiotherapist, MSc Instagram 的最佳解答

2021-09-16 07:45:34

哈囉各位大家好,我是魍魅物理治療師Amber~ ⁡ 📱使用手機真的會讓你姿勢變差嗎? ⁡ 🤘🏻先評估你的脖子是否有姿勢變差以及前傾問題? ⁡ 臨床上會測量顱頸角度(craniovertebral angle, CVA)來當作頭部前傾的指標。小於50-53度則代表有頭部前傾的問題,角度越小,代表脖子障...


※ 引述《gocpp (cpp)》之銘言:
: 一般有幾種習慣:
: T* p; // 向型別 T 看齊
: T *p; // 向變量 p 看齊
: T * p; // 不偏不倚

這的確是見仁見智,style 一致就好。

像是 int* p; 和 int *p;
第一種是強調 type,也就是說 p 的 type 是 int*,
第二種是強調 syntax, * 和 p 都是 "declarator" 的一部份。
int 則是 "type specifier" 的一部份,C 和 C++ 的 syntax
分類的定義都如此。

: 似乎用第一種寫法的人比較多,很多 C++ 大師都是如此。
: 我個人是比較習慣第二種寫法,原因是當有兩個以上的指標:
: T *p1, *p2;
: 第二種寫法顯然比較合理,這時如果這樣寫:
: T* p1, p2;
: 那 p2 就不是指標而是物件了。

以下連結是真正的 C++ 大師(也就是 C++ 發明者本人啦)的說明,
為什麼他個人採用 T* p; 的寫法,他也提到了相反立場者所持包括
上面引文的理由。

http://www.research.att.com/~bs/bs_faq2.html#whitespace

: 個人認為第二種寫法的最大好處,就是便於理解:

我個人是 T* p; 派的,下面這些例子,採用 T* p; 的寫法,
對我來說,反而能看得更清楚。

: 例如(一律由右往左看):
: T *p; // p 是一個指標,指向一個型別 T 的物件
: T &r; // r 是一個 reference,參用一個型別 T 的物件
: 又(同樣一律由右往左看):
: T *f(); // f 回傳一個指標,指向型別 T 的物件
: T &g(); // g 回傳一個 reference,參用一型別 T 的物件
: 又(同樣一律由右往左看):
: T *const p; // p 是一個 const 指標,指向型別 T 的物件
: T const *p; // p 是一個指標,指向型別 T 的 const 物件
: T const *const p; // p 是一個 const 指標,指向型別 T 的 const 物件
: const T *const p; // 同上(只要保持由右往左讀的習慣,就不會昏頭弄錯)
: 甚至(還是由右往左看):
: T *const f(); // f 回傳一個 const 指標,指向型別 T 的物件
: T const &g(); // g 回傳一個 reference,參用一個型別 T 的 const 物件
: T *&h(); // h 回傳一個 reference to pointer,參用一指標,該指標指向
: // 一型別 T 的物件

--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 220.130.208.168

> -------------------------------------------------------------------------- <

作者: renderer (rendering) 看板: C_and_CPP
標題: Re: [討論] 關於指標記號 * 的位置
時間: Fri Aug 19 22:21:05 2005

※ 引述《gocpp (cpp)》之銘言:
: 一般有幾種習慣:
: T* p; // 向型別 T 看齊
: T *p; // 向變量 p 看齊
: T * p; // 不偏不倚


個人比較習慣 T* p;
理由是在「視覺上」對於「型別的識別」會比較清楚而快速 而且比較不會誤看



: 似乎用第一種寫法的人比較多,很多 C++ 大師都是如此。
: 我個人是比較習慣第二種寫法,原因是當有兩個以上的指標:
: T *p1, *p2;
: 第二種寫法顯然比較合理,這時如果這樣寫:
: T* p1, p2;
: 那 p2 就不是指標而是物件了。


我會儘量避免合在一起寫 而改成:

T* p1;
T* p2;



: 個人認為第二種寫法的最大好處,就是便於理解:
: 例如(一律由右往左看):
: T *p; // p 是一個指標,指向一個型別 T 的物件
: T &r; // r 是一個 reference,參用一個型別 T 的物件
: 又(同樣一律由右往左看):
: T *f(); // f 回傳一個指標,指向型別 T 的物件
: T &g(); // g 回傳一個 reference,參用一型別 T 的物件
: 又(同樣一律由右往左看):
: T *const p; // p 是一個 const 指標,指向型別 T 的物件
: T const *p; // p 是一個指標,指向型別 T 的 const 物件
: T const *const p; // p 是一個 const 指標,指向型別 T 的 const 物件
: const T *const p; // 同上(只要保持由右往左讀的習慣,就不會昏頭弄錯)
: 甚至(還是由右往左看):
: T *const f(); // f 回傳一個 const 指標,指向型別 T 的物件
: T const &g(); // g 回傳一個 reference,參用一個型別 T 的 const 物件
: T *&h(); // h 回傳一個 reference to pointer,參用一指標,該指標指向
: // 一型別 T 的物件


由左往右讀也可以 尤其是以中文思考的時候

int p;

int p

int* p;

int 的指標 p

int& p;

int 的參考 p

int const * p;

int constant 的指標 p ( constant 解讀成名詞:常數 )
int 常數的指標 p

int* const p;

int 指標的常數 p

int const * const p;

((int 常數) 指標) 的常數 p

int* p[5];

==> int*[5] p; // 以 p 為軸將 [5] 搬到左邊

(int 指標) 的陣列 p
共5個

int* p[5][3];

==> int*[3][5] p;

((int 指標) 的陣列) 的陣列 p
共3個
共5個

int (* p)[5];

==> int[5]* p; // 以 (* p) 為軸

int 陣列的指標 p



習慣由右往左讀的同學別被我誤了

C/C++ 本身就是一種語言

能直接解讀程式本身是最好的 不必翻成英文或中文解讀



--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.228.217.108
※ 編輯: renderer 來自: 61.228.217.108 (08/19 22:26)
※ 編輯: renderer 來自: 61.228.217.108 (08/19 22:30)
drkkimo:我也是慣用Type* 變數名稱 218.164.24.136 08/19
clifflu:我喜歡 T * p; 因為 * 不是 CDATA, 看起來怪怪的140.112.212.129 08/19
khoguan:呵呵 :-) renderer大大有在擔任教職嗎?220.130.208.168 08/20
renderer:沒有耶 程度不夠呀 61.228.217.108 08/20
renderer:像 k大對 C++有很清楚的瞭解 就滿適合教 C++ 的 61.228.217.108 08/20
khoguan:r大 才有循循善誘、誨人不倦的教師風範呀 :-)220.130.208.168 08/20

> -------------------------------------------------------------------------- <

作者: UNARYvvv (有趣生活) 看板: C_and_CPP
標題: Re: [討論] 關於指標記號 * 的位置
時間: Fri Aug 19 23:12:24 2005

※ 引述《gocpp (cpp)》之銘言:
: 一般有幾種習慣:
: T* p; // 向型別 T 看齊
: T *p; // 向變量 p 看齊
: T * p; // 不偏不倚

我習慣用 T *p;
而對型別的辨認,因為我的解讀是看到 *p 先知道 p 是個指標
然後再往回找它指向什麼
而且有時候不只一個指標變數的時候
我可能也會用 T *p1, *p2; 寫在同個 statement 而不是兩個
用到現在也就是都這樣寫了
也由於習慣,所以在閱讀上也並未覺得麻煩

以前是看
The C Programming Language & C++ Primer 這兩本書
分別作為學習 C/C++ 的入門書
裡面的 code 也是用 char *p; 這樣
C++ Primer 有特別提到要注意這點 (忘記 K&R 有沒有)
然後我認同了(偏好) T *p; 這種 * 號靠著變數名的寫法
到現在習慣也就是這樣了。好像跟前面幾位都不同XD

題外話
講到這個就想起以前修 OOP (其實內容是在教 C++ 語言) 的課時
某次上機考,老師出一個 binary tree 的題目
代表 node 的 structure 如下:


struct TreeNode {
TreeNode* left,right;
}


然後一些對宣告指標相關語法不太熟的同學
每次編譯的時候就都會發現
為什麼建立 tree 或是做 traversal 的程式碼
總是往左的可以,而往右的部分總是有很奇怪的錯誤.....


: 似乎用第一種寫法的人比較多,很多 C++ 大師都是如此。
: 我個人是比較習慣第二種寫法,原因是當有兩個以上的指標:
: T *p1, *p2;
: 第二種寫法顯然比較合理,這時如果這樣寫:
: T* p1, p2;
: 那 p2 就不是指標而是物件了。
: 個人認為第二種寫法的最大好處,就是便於理解:
: 例如(一律由右往左看):
: T *p; // p 是一個指標,指向一個型別 T 的物件
: T &r; // r 是一個 reference,參用一個型別 T 的物件
: 又(同樣一律由右往左看):
: T *f(); // f 回傳一個指標,指向型別 T 的物件
: T &g(); // g 回傳一個 reference,參用一型別 T 的物件
: 又(同樣一律由右往左看):
: T *const p; // p 是一個 const 指標,指向型別 T 的物件
: T const *p; // p 是一個指標,指向型別 T 的 const 物件
: T const *const p; // p 是一個 const 指標,指向型別 T 的 const 物件
: const T *const p; // 同上(只要保持由右往左讀的習慣,就不會昏頭弄錯)
: 甚至(還是由右往左看):
: T *const f(); // f 回傳一個 const 指標,指向型別 T 的物件
: T const &g(); // g 回傳一個 reference,參用一個型別 T 的 const 物件
: T *&h(); // h 回傳一個 reference to pointer,參用一指標,該指標指向
: // 一型別 T 的物件

--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.70.137.117
sekya:我也是支持T *p,*p2; :p 59.104.35.116 08/20

> -------------------------------------------------------------------------- <

作者: tomex (tomex_ou) 看板: C_and_CPP
標題: Re: [討論] 關於指標記號 * 的位置
時間: Sat Aug 20 23:10:54 2005

C#廢了指標,而用ref變數來取代
強型別的時代是趨勢,也是避免糊模不清的治本方法。

C++喜歡用同個關鍵字代表不同的意義
例如*代表是指標,也代表取值子
對於宣告來說,我是覺得*該偏在type那邊,而不該偏在變數。

重型別的人,將來到java或c#等強型別的語言
是比較容易轉化的。

有人說:
int* p1, p2; // p2不是指標
以完全不會語法的人,很容易聯想這語法是要造2個指標的意思
那麼問題並不在於否認人的直觀看法
而是compiler該去修正這樣的宣告誤解才對。

我是從高階語言往低階去學習的
往往能了解高階語言在語意上就是要解決以前不清模糊的地方
或許無法改變低階的現況
但我們學習到新的思想,即使現況作不到,也該堅持正確的直覺宣告法。

compiler並非永遠不標,標準也非永遠不變
而科技始終來自人性,人的直觀法才是取決一切的考量。

--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.119.52.211
drkkimo:推個 218.164.44.125 08/20
UNARYvvv:最後一行有句話很眼熟 好久沒看到了 61.70.137.117 08/20

> -------------------------------------------------------------------------- <

作者: clifflu (缺錢啦 @@) 看板: C_and_CPP
標題: Re: [討論] 關於指標記號 * 的位置
時間: Sat Aug 20 23:40:05 2005

※ 引述《tomex (tomex_ou)》之銘言:
: 有人說:
: int* p1, p2; // p2不是指標
: 以完全不會語法的人,很容易聯想這語法是要造2個指標的意思
: 那麼問題並不在於否認人的直觀看法
: 而是compiler該去修正這樣的宣告誤解才對。

這我就想到一個很好的例子.
在 VB 6.0 中, 如果你使用 Dim Var1, Var2 as String
的話, 你會得到 Var1 (Variant), Var2 (String)
(VB 6.0 的 Variant 是種很神妙的型別, 功能和 C: void 或 VB.NET Object 相近)

然而這樣的寫法在 VB.Net 中做了修正,
也就是會將 Var1 和 Var2 的的型態皆設定為 String.
這確實就是 compiler 向某種使用者 "可能" 的習慣作修正.

然而在反面來看, 將 Dim Var1, Var2 as String
^^^^^^^^^^^^^^
後區視為一個整體, 而前面則是使用預設型別也是有它的道理在.
由此而論, VB.Net 將 Var1, Var2 來視為一個整體反而才是異端邪說了.

所以雖然這樣的寫法可能會比較快, 比較省, 比較優雅, 或甚至有千百種其他的優點,
當一段 code 潛在會被誤認 (ambiguous) 時, 這些寫法都 *應當* 要被其他較不易
出錯, 不容易被誤認, 而能正確執行的碼取代.

畢竟程式碼是給人看的.

--

鬼壓床怎麼辦
騎上去啊

--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.112.212.129
tomex:微軟常常作出貼心的設計,programmer感受的到! 140.119.52.211 08/21
clifflu:XD 貼心是一回事 不過使用者也該自己注意 ^^;;140.112.212.129 08/21
UNARYvvv:這樣看起來應該是一行Dim宣告只能用一種型態囉? 61.70.137.117 08/21
khoguan:VB.Net和舊VB不再相容。MS越來越強勢了 XD220.130.208.168 08/21
clifflu:可以寫成 Dim a as String, b as Integer140.112.212.129 08/21

> -------------------------------------------------------------------------- <

作者: khoguan (Khoguan Phuann) 看板: C_and_CPP
標題: Re: [討論] 關於指標記號 * 的位置
時間: Sun Aug 21 10:16:02 2005

※ 引述《tomex (tomex_ou)》之銘言:
: C++喜歡用同個關鍵字代表不同的意義
: 例如*代表是指標,也代表取值子

C/C++ 關鍵字一字多用的情形,一個明顯的例子就是 static.
在 C 的時代,當他出現在 local scope 的變數宣告前面時,
代表的是 static storage class, 這是 static能夠讓人顧名
思義的用法。但是當它出現在 file scope 的變數宣告前面時,
卻又代表了 internal linkage, 和 static 這個名字難以產生
聯想(file scope 的變數不加 static 本來就已經是 static
storage 了,加上 static 對 static storage 並無影響)。
當初如果多個 intern 關鍵字來表示,似乎還比較好。還可以
和 extern 做對比。但 extern 的用法本身似乎也有問題,而且
C++ 的 extern 除了 scope linkage 的用法,還多了 language
linkage的用法,就是 extern "C" 這種東東 ..Orz..

到了 C++ 時代,為了相容,上述用法仍然承襲下來,但是 C++
標準,已將上述第二種用法標為 deprecated 要人避免使用。
可是另一方面,C++ 又加入了 static 的第三種用法,放在
class member(包含 data 和 function)的宣告前面,表示
它是屬於 class 的 member, 而非屬於個別 class object
的 member. 這和 static 的聯想性也很模糊 ..Orz..

至於 C++ 所 deprecate 的第二種用法,在 C++ 裡是建議宣告
在 unnamed namespace 來取代。

/* internal.c */
static int internal;

// internal.cpp
namespace {
//...
int internal;

}

這種 unnamed namespace 似乎很少人想去利用。

--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 220.130.208.168
UNARYvvv:我剛想到class,typename不同地方也有不同用處XD 61.70.137.117 08/21
khoguan:嗯,是的。我也有想到 ^_^220.130.208.168 08/21

> -------------------------------------------------------------------------- <

作者: renderer (rendering) 看板: C_and_CPP
標題: Re: [討論] 關於指標記號 * 的位置
時間: Sun Aug 21 11:33:40 2005



關於指標記號 * 的位置


在這個地方:

unsigned int value;

int* v = (int*) &value;
~~~~~~
int* 是個型別 所以好像 * 向型別靠比較好


但在這個地方:

void (*fun_ptr) ();
~~~~~~~~~~
fun_ptr 是個指標 所以好像 * 向變數靠比較好


呵呵 一笑
看來向哪邊靠似乎都不會有一個比較統一的標準思維



--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.228.217.108
※ 編輯: renderer 來自: 61.228.217.108 (08/21 11:34)

> -------------------------------------------------------------------------- <

作者: renderer (rendering) 看板: C_and_CPP
標題: Re: [討論] 關於指標記號 * 的位置
時間: Sun Aug 21 11:42:13 2005



又想到一些例子

int* const value; // 向型別靠好 向變數沒得靠

int (*value)[10]; // 向變數靠好 向型別沒得靠



--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.228.217.108
khoguan:適合靠哪邊就靠哪邊,沒得靠就靠自己。正所謂220.130.208.168 08/21
khoguan:此身飲罷無歸處,獨立蒼茫自詠詩。220.130.208.168 08/21
renderer:大概就是這樣了: 61.228.217.108 08/21
renderer:int const * const value; 61.228.217.108 08/21
renderer:k大是讀什麼科系的呢 感覺頗有文才 61.228.217.108 08/21
khoguan:摭拾古人牙慧,褻瀆了詩聖,真不好意思。220.130.208.168 08/21
simata:可以改成 int* value const; 嗎??? 59.112.230.24 08/25
simata:若可..即可以變成 int *value const; :P 59.112.230.24 08/25

> -------------------------------------------------------------------------- <

作者: renderer (rendering) 看板: C_and_CPP
標題: Re: [討論] 關於指標記號 * 的位置
時間: Sun Aug 21 16:55:55 2005



「T* d」 說不清楚的例子:

int *data0, *data1;


「T *d」 說不清楚的例子:

int* data[2];



C++ 的變數宣告語法是強調 usage 而不是 type
例如:

int * data [3][5];

其 usage 修飾強度順序是:

int * data [3][5];
4 3 0 1 2

所以使用時:

data 的型別是 int * [3][5]
data[0] 的型別是 int * [5]
data[0][1] 的型別是 int *
*data[0][1] 的型別是 int

又例如:

void (*fun_ptr) (int, int);

使用時:

fun_ptr 的型別是 void (*) (int, int)
*fun_ptr 的型別是 void () (int, int)


強調 usage 的宣告語法暗示了我們要怎麼去使用變數
基於這一點寫 int *data; 是合理的
因為 *data 代表 int 而讓 * 靠著 data 似乎滿好的


然而強調 type 的宣告方式似乎也滿自然的
如果使用

型別 變數;

這樣子的宣告格式 會讓我們清楚地知道變數的型別
而在 型別轉換 與 new 的使用時 會得到一個型別清晰的方便性
如:

int* data;
data = (int*) value;



int** data;
data = new int*;

基於這點:想清楚地表達型別
而讓 * 靠著型別似乎也是出乎天性


語言本身似乎無意讓 * 偏靠哪一邊
而人卻有心要讓 * 偏靠哪一邊
畢竟

int * data;

的宣告似乎多用了個 ' '
要少用一個 ' '
不靠型別 就得靠變數了




----------------- 以下是閒談 ------------------


小弟個人目前的結論是:

看哪樣子好看、清楚,就那麼靠吧;都不好看的話,就都不靠啦。

如:

int *data0, *data1;

int* data[2];

int const * const data;



--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.228.217.108

你可能也想看看

搜尋相關網站