我一直在嘗試撰寫一個函式來對通用二進制搜索函式進行字串比較。但是,在撰寫函式時,我意識到我的指標取消參考不起作用。
本質上,這是行不通的:
printf("***a[0] = %c\n", (*(char **)(void *)&"a")[0]);
我運行了除錯器,它告訴我 EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
但是,這個極其相似的代碼(我認為與我之前的代碼相同)確實有效。
char * stringa = "a";
printf("***stringa[0] = %c\n", (*(char **)(void *)&stringa)[0]);
我不明白為什么第二個有效,但第一個無效。我的理解是“a”和stringa都表示字符陣列開頭的記憶體地址。
先感謝您。
uj5u.com熱心網友回復:
指標不是陣列。陣列不是指標。
&stringa導致指向型別為 的指標的指標char**。&"a"結果是一個型別為 的陣列指標char(*)[2]。它與char**.
您嘗試char(*)[2]通過將其視為char**無效來取消參考- 它們是不兼容的型別,實際上實際的陣列指標表示“在地址 x 處有資料”,但在轉換時您說“在地址 x 處有資料”有一個指標”。
如果您嘗試列印,printf("%p\n", *(char **)(void *)&"a");您將不會獲得地址而是資料。我得到類似的東西<garbage> 0061,這是一個小端機器,試圖將字串轉換為更大的整數。在記憶體中,您將有 0x61 ( 'a') 然后是 0x00 (空項) - 字串本身,而不是您可以取消參考的地址。
uj5u.com熱心網友回復:
首先,檢查此規則 - 來自 C11 Standard#6.3.2.1p3 [強調已添加]:
3除非它是 sizeof 運算子、_Alignof 運算子或一元 & 運算子的運算元,或者是用于初始化陣列的字串文字,否則型別為“array of type”的運算式將轉換為運算式型別為 ''pointer to type'' 指向陣列物件的初始元素,而不是左值。如果陣列物件具有暫存器存盤類,則行為未定義。
從字串文字 [強調添加]:
就地構造指定字符陣列型別的未命名物件,當需要在源代碼中嵌入字串時使用。
讓我們先解碼:
char * stringa = "a";
printf("***stringa[0] = %c\n", (*(char **)(void *)&stringa)[0]);
在此陳述句中char * stringa = "a";,字串"a"將轉換為指向char字串初始元素的型別的指標"a"。因此,初始化后,stringa將指向字串文字的第一個元素"a"。
&stringa是 型別char **。取消參考它會給出char *type ,它只是 string"a"并且應用[0]到它會給出 character 'a'。
現在,讓我們解碼:
printf("***a[0] = %c\n", (*(char **)(void *)&"a")[0]);
因為,在這里你給一元運算子&,因此在這種表情,(*(char **)(void *)&"a")[0],字串"a"將不會轉換為指標,它的初始元素,&"a"會給型別的指標const char (*)[2]和該指標將型別強制轉換為char **型別。
取消參考此指標將在 address 處給出值,該值只是 string "a",它將被視為型別指標char(因為型別轉換char **)并應用于[0]它。這意味著,它試圖做這樣的事情((char *)0x0000000000000061)[0](0x61是字符的十六進制值'a'),這導致錯誤 EXC_BAD_ACCESS。
相反,你應該做
printf("***a[0] = %c\n", (*(const char (*)[2])(void *)&"a")[0]);
編輯:
OP還是一頭霧水。此編輯試圖以不同的方式解釋運算式(在帖子上方)。
來自評論:
OP:But you wrote ((const char ()[2])(void )&"a")[0] works! There are two dereferencing operations ( and [0]) going on here!
不確定你是否知道它,但我認為[],從 C11 標準#6.5.2.1p2共享運算子的定義是很好的:
下標運算子[]的定義是E1[E2]等同于(*((E1) (E2)))。
表達(*(char **)(void *)&stringa)[0]:
(*(char **)(void *)&stringa)[0]
| | |
| ----------------------
| |
| this will result in
| type casting a pointer
| of type char ** to char **
|
|
This dereferencing
will be applied on result of &stringa
i.e. ( * ( &stringa ) )
and result in stringa
i.e. this
|
|
| &stringa (its type is char **)
| -------
| | 800 |---
| ------- |
| |
-------> stringa |
/ ------- (pointer stringa pointing to first char of string "a"
/ | 200 |--- (type of stringa is char *)
| ------- |
now apply [0] 800 |
to it |
i.e. stringa[0]. -------
stringa[0] is -> | a | 0 | (string literal - "a")
equivalent to | -------
*((stringa) (0)) | 200 ---> address of "a"
i.e. |
*(200 0), |
add 0 to address 200 |
and dereference it. |
*(200 0) => *(200) |
dereferencing address |
200 will result in |
value at that address |
which is character |
'a', that means, |
*(200) result in -------
表達(*(char **)(void *)&"a")[0]:
(*(char **)(void *)&"a")[0]
| | |
| ------------------
| |
| this will result in
| type casting a pointer
| of type const char (*)[2] to char **
|
|
this dereferencing will be
applied to pointer of type
char ** which is actually a
pointer of type char (*)[2]
i.e. *(&"a").
It will result in value at address 200
which is nothing but string "a"
but since we are type casting
&"a" with double pointer (char **)
so single dereference result
will be considered as pointer of
type char i.e. char *.
*(char **)(void *)&"a"
|
|
| &"a" (its type is const char (*)[2] because type of "a" is
| ------- const char [2] i.e. array of 2 characters)
| | 200 |---
| ------- |
| |
| |
| |
| -------
------------------> | a | 0 | (string literal - "a")
/ -------
/ 200 ---> address of "a"
|
|
The content at this location will be
treated as pointer (of type char *)
i.e. the hex of "a" (0x0061) [because the string has character `a` followed by null character]
will be treated as pointer.
Applying [0] to this pointer
i.e. (0x0061)[0], which is
equivalent to (* ((0x0061) 0)).
(* ((0x0061) 0)) => *(0x0061)
i.e. trying to dereference 0x0061
Hence, resulting in bad access error.
表達(*(const char (*)[2])(void *)&"a")[0]:
(*(const char (*)[2])(void *)&"a")[0]
| | |
| ----------------------------
| |
| this will result in
| type casting a pointer
| of type const char (*)[2] to const char (*)[2]
|
|
this dereferencing will be
applied to pointer of type
const char (*)[2]
i.e. *(&"a")
and result string "a"
whose type is const char [2]
|
|
| &"a" (its type is const char (*)[2] because type of "a" is
| ------- const char [2] i.e. array of 2 characters)
| | 200 |---
| ------- |
| |
| |
| |
| -------
------------------> | a | 0 | (string literal - "a")
/ -------
/ 200 ---> address of "a"
|
|
Apply [0] to "a"
i.e. "a"[0].
Now, scroll to the top of my post
and check string literal definition -
string literal constructs unnamed object of character array type.....
also, read rule 6.3.2.1p3
(which is applicable for an array of type) -
....an expression that has type 'array of type' is converted
to an expression with type 'pointer to type' that points to
the initial element of the array object. ....
So, "a" (in expression "a"[0]) will be converted to pointer
to initial element i.e. pointer to character `a` which is
nothing but address 200.
"a"[0] -> (* ((a) (0))) -> (* ((200) (0)))
-> (* (200)) -> 'a'
來自評論:
OP:there is no such thing as an object in C ....
不要將 word object與 objectC 或其他面向物件的語言混淆。
這是 C 標準定義物件的方式:
來自 C11 標準#3.15p1
1
執行環境中資料存盤的物件區域,其中的內容可以表示值
例如-- int x; > x是一個型別的物件int。
如果您還有其他問題,請告訴我。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/392922.html
上一篇:我在C中的結構鏈表有問題
下一篇:無法發布供應商組態檔
