討論區快速選單
知識庫快速選單
掌握Salesforce雲端管理秘訣 討論區最近新進100則主題 政府補助!學嵌入式+物聯網
[ 回上頁 ] [ 討論區發言規則 ]
為何函式參數的型態無法轉換呢?
更改我的閱讀文章字型大小
作者 : hgffly(飛) 貼文超過200則人氣指數超過10000點
[ 貼文 246 | 人氣 23261 | 評價 290 | 評價/貼文 1.18 | 送出評價 11 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/11/27 下午 05:46:29
void test1(const int *a)
{
...
}

void test2(const int **a)
{
...
}

void main()
{
  int *a, **b;
  test1(a);
  test2(b); //編譯錯誤:Cannot convert "int **" to "const int **"
}

各位大大好,小弟在寫函式的參數定義有遇到一點小困惑,像上面的兩個函式 test1 和 test2 的參數都有加 const,那為何參數宣告成一維指標的函式可以通過編譯,而宣告成二維指標的函式就無法通過編譯呢?
希望大大們能幫小弟解惑一下!感激不盡!!!
作者 : chiuinan2(青衫)討論區板主 Visual C++ .NET卓越專家VC++一代宗師Visual Basic優秀好手資訊類作業求救卓越專家一般曠世奇才程式設計甘苦談優秀好手C++ Builder優秀好手上班族的哈拉園地優秀好手C++頂尖高手Assembly優秀好手貼文超過3000則人氣指數超過150000點
[ 貼文 3732 | 人氣 170106 | 評價 34520 | 評價/貼文 9.25 | 送出評價 125 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/11/27 下午 08:33:21
能呼叫進去的只有兩種情況:

1. 呼叫參數的資料形態與函數定義的資料形態完全一致
2. 函數定義的資料形態為完全const, 亦即完全無法修改, 以此例而言便是const int* const*

這樣的限制, 主要是避免潛在隱藏的誤變更. 舉一個例子來說:

const int c[] = {1,2};
int **a = NULL;
const int **b = a; // 如果int**可轉為const int**的話 //
b[0] = c; // 因為b[0]是const int*, 故c的形態可填入 //
a[0][0] = 5; // 因a[0]的指標同b[0]的指標, 原本const int*不可變更值的形態, 變成了int*可變更值的形態, 這樣就違反了const的精神 //

作者 : hgffly(飛) 貼文超過200則人氣指數超過10000點
[ 貼文 246 | 人氣 23261 | 評價 290 | 評價/貼文 1.18 | 送出評價 11 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/11/28 下午 03:00:58
非常謝謝青杉大大的回答…
小弟的功力還不太夠…還不是很懂大大的解答…
想請問 一下您所謂的 " 以此例而言便是const int* const* " 是什意思?
還有 const int* const* 和 const int ** 是同型態嗎?
我又試了下面一個例子:
  int **a;
  const int **b;
  const int * const *c;
  b = a; //編譯過不了,同樣的錯誤
  c = a; //編譯 ok
// b 和 c 的差異在哪呢?兩個應該都是二維指標吧…
因為我原 po 的寫法,想法只是單純地想讓我那些參數在函式保證不會去變更到而已…
因為如果參數是一維的話,是 ok 的…但還是不懂為何改成二維就不行了…
我想是我對 const int ** 所代表的涵意還不夠了解…
小弟不才…麻煩大大了!謝謝!
作者 : chiuinan2(青衫)討論區板主 Visual C++ .NET卓越專家VC++一代宗師Visual Basic優秀好手資訊類作業求救卓越專家一般曠世奇才程式設計甘苦談優秀好手C++ Builder優秀好手上班族的哈拉園地優秀好手C++頂尖高手Assembly優秀好手貼文超過3000則人氣指數超過150000點
[ 貼文 3732 | 人氣 170106 | 評價 34520 | 評價/貼文 9.25 | 送出評價 125 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人hgffly註記此篇回應為最佳解答 2009/11/28 下午 06:33:38
const右邊若有*, 表示該位址指向的值是不可改變的. 因此const int* const*, 二維皆不能改變. const int**, 第一維([i])可以變更值, 但第二維([i][j])不可以變更值, int* const*, 第一維不可變更值, 第二維可以變更值.

完全const便是所有*都有const限制不得變更值. 三維便是const int* const* const*.
作者 : kenneth_deng(Kenneth_Deng)
[ 貼文 12 | 人氣 0 | 評價 0 | 評價/貼文 0 | 送出評價 8 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/12/10 上午 10:14:02
請問一下前輩
const int *a

int *a

test1(a)

型態不同為什麼可以通過編輯
int *a .............指向的是一個非const int
const int *a.....指向的是一個const int
作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/12/10 上午 10:42:17
>const int *a.....指向的是一個const int

const int *a 並不意味著 'a' 指向 const int, 它的意思是: 你不能透過 'a' 來更改所指向的 int 物件.

作者 : kenneth_deng(Kenneth_Deng)
[ 貼文 12 | 人氣 0 | 評價 0 | 評價/貼文 0 | 送出評價 8 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/12/10 上午 11:14:32

>const int *a 並不意味著 'a' 指向 const int, 它的意思是: 你不能透過 'a' 來更改所指向的 int 物件.

謝謝前輩幫我指正觀念上的錯誤
作者 : hgffly(飛) 貼文超過200則人氣指數超過10000點
[ 貼文 246 | 人氣 23261 | 評價 290 | 評價/貼文 1.18 | 送出評價 11 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/12/18 下午 01:17:34
不好意思…又有新的困惑…

  int a[2];
  int *b1 = a;
  const int *b2 = a;
  int *const b3 = a;
  const int *const b4 = a;
  //針對以上一維的陣列的四種轉換,編譯都 ok

  int aa[2][3]; //因為是靜態陣列,所以 aa、aa[0] 和 aa[1] 指標的值是無法變更的
  int *const *bb1 = aa;
  int *const *const bb2 = aa;
  const int *const *const bb3 = aa;
  //而以上針對二維陣列的三種轉換,不懂為什編譯都過不了,如果只是怕變數可以指定到二維陣列,使用者不知維度的大小而預防使用時超過其範圍,那同樣的道理,一維陣列應該也沒有理由可以轉換過去吧…,因為現在這個問題也是延續之前函式參數型態轉換的問題,我只是希望函式能接受二維以上任意大小的陣列的目的。不知這是否有好的方案可解決,希望哪位大大能給小弟指點迷津一下!感激不盡!!!謝謝!
作者 : chiuinan2(青衫)討論區板主 Visual C++ .NET卓越專家VC++一代宗師Visual Basic優秀好手資訊類作業求救卓越專家一般曠世奇才程式設計甘苦談優秀好手C++ Builder優秀好手上班族的哈拉園地優秀好手C++頂尖高手Assembly優秀好手貼文超過3000則人氣指數超過150000點
[ 貼文 3732 | 人氣 170106 | 評價 34520 | 評價/貼文 9.25 | 送出評價 125 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/12/18 下午 06:20:07
一維陣列, int*和int[]基本上是一樣的.

二維以上, int**和int[][]是不同的, 前者是多個記憶體(一維陣列)所組成, 後者是一個記憶體(二維陣列)所組成, 其中的差異, 可以參考下列這篇Raymond所畫的圖:

http://www.programmer-club.com.tw/ShowSameTitleN/c/40141.html

二維例子比較多人舉例, 我另用三維的例子來說明, 應該更有助於了解.

int***其實應該看成是(int**)*, 它本身是一個一維空間, 每個空間記錄的, 是int**形態的位址值, 也就是各自指向一個元素為int*的一維空間. int**當然也應該看成是(int*)*, 就像前面說的, 它也是一維空間, 記錄int*形態的位址值. 最後的int*, 指向的是元素為int的一維空間, 和int[]是相同的. 所以這種形態都是一維串一維, 運用多個一維空間共同組成多維的空間 (多半使用動態記憶體).

int[][][]是一個一整塊的記憶體, 從int[i], 或int[i][j]取得的位址值, 都是"計算"出來, 且不能變更, 和int***可以改變位址值是不同的. 也因為所有的存取, 都必須經過計算, 因此compiler必須知道每個維度的大小, 以便配置空間. 例如:

int a[2][3][4];

就會配置2x3x4=24個空間. 而在計算a[i][j][k]時, 便可以按照各維大小算得對應的位置 (未必按下列公式, 這裡有row-based或column-based的差異, 要看compiler):

i*3*4+j*4+k

如果要傳進函數中處理, 也是需要知道各維度的大小(第一維除外), 例如:

test(int b[][3][4])
{
 ...
}

這樣才能將a傳進test函數. 由於這種方式必須事先得知維度大小, 且在執行過程中都無法改變, 因此運用機會其實比int***低.

既然int**和int[][]是不同的形態, 你的那些=運算, 當然就不可能會過.
作者 : hgffly(飛) 貼文超過200則人氣指數超過10000點
[ 貼文 246 | 人氣 23261 | 評價 290 | 評價/貼文 1.18 | 送出評價 11 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2009/12/19 下午 10:58:59
非常謝謝青衫大大詳細的解釋,那所以如果我想寫一個能接收二維以上且大小不定的靜態陣列變數的函式是不可能的囉?
 板主 : simula
 > C++ - 討論區
 - 最近熱門問答精華集
 - 全部歷史問答精華集
 - C++ - 知識庫
  ■ 全站最新Post列表
  ■ 我的文章收藏
  ■ 我最愛的作者
  ■ 全站文章收藏排行榜
  ■ 全站最愛作者排行榜
  ■  月熱門主題
  ■  季熱門主題
  ■  熱門主題Top 20
  ■  本區Post排行榜
  ■  本區評價排行榜
  ■  全站專家名人榜
  ■  全站Post排行榜
  ■  全站評價排行榜
  ■  全站人氣排行榜
 請輸入關鍵字 
  開始搜尋
 
Top 10
評價排行
C++
1 Raymond 13050 
2 青衫 4760 
3 simula 4690 
4 coco 4030 
5 白老鼠(Gary) 3670 
6 ozzy 2540 
7 Ben 2250 
8 Anderson 1960 
9 windblown 1650 
10 Kenny 1560 
C++
  專家等級 評價  
  一代宗師 10000  
  曠世奇才 5000  
  頂尖高手 3000  
  卓越專家 1500  
  優秀好手 750  
Microsoft Internet Explorer 6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2019 程式設計俱樂部 http://www.programmer-club.com.tw/
0.1875