2017-10-11 12 views
3

指針檢索2D陣列我嘗試以下代碼從用C

char arr[5] = {'A', 'E', 'I', 'O', 'U'}; 
    char (*p_arr)[1] = &arr; 
    printf("%c\n", p_arr[0][4]); //returns 'U' 

this計算器螺紋,

char (*p_arr2D)[m] = &arr2D //or arr2D 

也是用於n*m 2D陣列arr2D衰變語法,返回一個指向其第一個元素的指針,一個m元素的數組。

p_arr[0]似乎是「反向」數組衰減,從指針到數組檢索二維數組。這怎麼可能發生?在上面的代碼片段中,將p_arr解釋爲1*5數組(來自具有5個元素的原始1D數組)?

+0

我的不好,我把原來的問題分成兩部分,忘記把'char(* p_arr)[1] = &arr;'改成'char(* p_arr)[5] = &arr;'這個部分。但是,'char(* p_arr)[1] = &arr;'不會產生任何編譯錯誤(請參閱我的[其他問題](https://stackoverflow.com/questions/46687759/pointer-to-2d-array-with - 不兼容的行長度)),我不明白爲什麼。 –

+0

(C編譯器不會阻止你想做什麼。)用'-Wall'選項編譯它。 – BLUEPIXY

+0

我做了代碼更改的回滾。答案發布後請不要修復你的代碼。通過修復它,你使大多數答案無關緊要。相反,如果您有後續問題,請提出一個新問題(與您一樣)。 – Lundin

回答

1

首先,行char (*p_arr)[1] = &arr;無效C.您的編譯器必須提供診斷消息。 p_arr是一個數組指針,指向1個字符的數組,但您將其指定爲指向5個字符的數組。

至於爲什麼看起來你有一個二維數組 - 你有一個 - 就是因爲p_arr[0]像任何其他指針運算,給你指出的,在項目「偏移+ 0」。這是陣列。然後你訪問數組中的第4項。

的非常相同的指針運算原理的簡單的例子是這樣的:

int a; 
int* ptr = &a; 
ptr[0] = whatever; // perfectly valid C 

ptr[0]保證是相當於*(ptr+0)

正確使用數組指針應該是printf("%c\n", (*p_arr)[4])。在這種情況下,它恰好工作,但在其他情況下,您可能會調用未定義的行爲,因爲p_arr不允許超出分配的內存。

+0

我的不好,我把原來的問題分爲兩部分,並忘記在本部分(現在完成)中將char(* p_arr)[1] = &arr;更改爲char(* p_arr)[5] = &arr;。然而,char(* p_arr)[1] = &arr;不會產生任何編譯錯誤(請參閱我的其他問題),我不明白爲什麼。我已經把這個評論放在我的問題之下,告訴我在這裏複製它是好的還是不好的做法。如果需要,我將刪除它 –

0

您正在聲明p_arr是一個指向字符數組的指針(並且該數組長度爲1,這確實是一個問題的標誌)。

您可能要簡單得多的語法:

char *p_arr = arr; 

或可能:

#include <stdio.h> 

int main() { 
    char arr[] = {"Hello world"}; 
    char *p[3] = {NULL, arr, NULL}; 

    printf("%s %c\n", p[1], p[1][3]); 
} 

約翰

+0

我的不好,我把原來的問題分成兩部分,並忘記在這部分中將char(* p_arr)[1] = &arr;改爲char(* p_arr)[5] = &arr;(現在完成)。然而,char(* p_arr)[1] = &arr;不會產生任何編譯錯誤(請參閱我的其他問題),我不明白爲什麼。我已經把這個評論放在我的問題之下,告訴我在這裏複製它是好的還是不好的做法。如果需要,我將刪除它 –

1

一個二維數組存儲在內存中像一維數組How are multi-dimensional arrays formatted in memory?

char (*p_arr)[1] = &arr;創建一個指向數組的指針指針具有一個元件((*p_arr)[1])和由分配&arr這個指針得到一個已經存在的陣列的具有5個元素

地址,以便printf("%c\n", p_arr[0][4]);打印的第五元件(U),因爲通過p_arr[0][4]不會忽略在第1行

所述第五元件

printf("%c\n", p_arr[1][4]);會給出錯誤

所以爲什麼這個代碼工作的原因是一個二維數組存儲在內存中像一維數組

+0

「並通過賦值&arr該指針獲取已存在數組的地址」否,因爲該部分無效C.這不是有效的賦值。 – Lundin

1

這個聲明

char (*p_arr)[1] = &arr; 

不正確,因爲聲明的指針和初始值設定項具有不兼容的類型。沒有從類型char (*)[5](初始化程序的類型)到類型char (*)[1](已聲明指針的類型)的隱式轉換。所以你需要一個明確鑄造,重新詮釋一個類型的指針作爲另一種類型的指針,例如

char (*p_arr)[1] = (char (*)[1])&arr; 

至於那麼你的問題,如果你有T類型的對象,其中T是某種類型的

T obj; 

和一個指向對象像

T *ptr = &obj; 

然後表達*ptrptr[0]產生T類型的參考對象。

因此,讓我們假設你有下面的聲明

char arr[5] = {'A', 'E', 'I', 'O', 'U'}; 
char (*p_arr)[5] = &arr; 

對於類型char[5]即變量arr你可以引入一個typedef名稱的類型。

typedef char T[5]; 

然後聲明將看起來像

T arr = {'A', 'E', 'I', 'O', 'U'}; 
T *p_arr = &arr; 

,因爲它是表達*p_arrp_arr[0]產生類型T即類型char[5]的被引用對象如上所述。

來自C標準(6.5.3。2地址和間接運算符)

4一元*運算符表示間接。如果操作數指向一個 函數,則結果是一個函數指示符;如果它指向一個 對象,則結果是指定該對象的左值。如果操作數 的類型爲''指向類型'',則結果的類型爲''type''。如果 無效值已分配給指針,則一元運算符*的操作未定義。

和(6.5.2.1數組下標)

2後綴表達式,隨後在方括號表達式[]是一個數組對象的元素的下標指定。 下標運算符[]的定義是E1 [E2]等於(*((E1)+(E2)))。由於適用於二元運算符的轉換規則,如果E1是一個數組對象(等同於一個指向數組對象的初始元素的指針)並且E2是一個整數,則E1 [E2]指定第E2個元素的E1(從零開始計數)。

,最後(6.5.6加法運算符)

7對於這些操作符的目的,的指針的對象 不是數組的元素的行爲相同的指針 長度爲1的數組的第一個元素與對象的類型爲 其元素類型爲

所以在此聲明

char arr[5] = {'A', 'E', 'I', 'O', 'U'}; 
char (*p_arr)[5] = &arr; 

指針p_arr不指向的數組元素。然而,它可以表現爲它指向長度1的陣列的第一個元素可以想像它通過以下方式

char arr[1][5] = { {'A', 'E', 'I', 'O', 'U'} }; 
char (*p_arr)[5] = arr; 

所以表達式p_arr[0]給出了設想的二維數組,它是一個的第一個元素char[5]類型的元素。

+0

我的不好,我把我原來的問題分爲兩部分,並忘記在這部分(現在完成)中將char(* p_arr)[1] = &arr;更改爲char(* p_arr)[5] = &arr;。然而,char(* p_arr)[1] = &arr;不會產生任何編譯錯誤(請參閱我的其他問題),我不明白爲什麼。我已經把這個評論放在我的問題之下,告訴我在這裏複製它是好的還是不好的做法。如果需要,我會將其刪除 –