2011-02-14 82 views
9

我想結束與char **字符**和取消引用指針

我的困惑在一次創建字符數組(字符串)數組如何char **真正做到這一點?

我知道char *是一個指向char的指針,char *array[]是一個char指針數組,但char **究竟做了什麼,它是如何做到的?

另外,當我聽到這個詞的解除引用,這讓我覺得指針被刪除了什麼是取消引用指針意味着什麼?更改指針指向的值?

由於

回答

10

「解引用」一個指針裝置訪問所述值的指針指向。假定以下聲明:

int a = 10; 
int *p = &a; 

下面是兩個變量的假想存儲器映射:

 
Item  Address  0x00 0x01 0x02 0x03 
----  -------  ---- ---- ---- ---- 
    a  0x80001000 0x00 0x00 0x00 0x0A 
    p  0x80001004 0x80 0x00 0x10 0x00 

a包含整數值10 p包含a(0x80001000)中的地址。如果我們想要訪問ap的內容,我們使用間接運算符*解除引用p。因此,表達*p等效於表達a。如果我們寫

*p = 16; 

這是相同的書面

a = 16; 

這裏的代碼展示瞭如何使用char **類型的對象來創建一個字符串數組一小片段:

#include <stdlib.h> 
#define N  20 // For this example, we will allocate 20 strings 
#define LENGTH 10 // of 10 characters each (not counting 0 terminator) 
... 
char **arr = malloc(sizeof *arr * N); 
if (arr) 
{ 
    size_t i; 
    for (i = 0; i < N; i++) 
    { 
    arr[i] = malloc(sizeof *arr[i] * (LENGTH + 1)); 
    strcpy(arr[i], "   "); 
    } 
} 

經歷它一行行,

char **arr = malloc(sizeof *arr * N); 

分配N個元素的塊,每個元素的大小足以存儲指向char的指針(sizeof *arr == sizeof (char *),因爲類型爲*arr == char *),並將結果指針值指定爲arr。 IOW,arr指向第一指針char,因此類型char **。請注意,如果分開申報和函數調用,它看起來像

char **arr; 
... 
arr = malloc(sizeof *arr * N); 

我們想要的malloc結果分配給arr,沒有什麼arr

if (arr) 

malloc可能會失敗,所以我們希望在使用它之前檢查結果。在事件malloc失敗,它會返回一個NULL指針值。

{ 
    size_t i; 
    for (i = 0; i < N; i++) 
    { 
    arr[i] = malloc(sizeof *arr[i] * (LENGTH + 1)); 

對於每個字符指針arr[i],我們分配的存儲器足夠大的長度+ 1個元素,每個大到足以容納一個char值的塊(sizeof *arr[i] == sizeof (char),由於類型的*arr[i] == char;請注意,sizeof (char)始終爲1)並將結果分配給arr[i]

由於我們爲每個字符串分配了一個單獨的malloc調用,所以它們不太可能在內存中連續存在。下面是表示上述代碼的可能結果另一個存儲器映射:「 * P1 == C,即解除引用P1允許我們從讀/寫至c」

 
Item   Address  0x00 0x01 0x02 0x03 
----   -------  ---- ---- ---- ---- 
arr   0x80001000  0xA0 0xCC 0x00 0x00 
      ... 
arr[0]  0xA0CC0000  0xA0 0xCC 0x20 0x00  
arr[1]  0xA0CC0004  0xA0 0xCC 0x20 0x40 
arr[2]  0xA0CC0008  0xA0 0xCC 0x21 0x28 
      ... 
arr[19]  0xA0CC0014  0xA0 0xCC 0x23 0x10 
      ... 
arr[0][0] 0xA0CC2000  ' ' ' ' ' ' ' ' 
arr[0][4] 0xA0CC2004  ' ' ' ' ' ' ' ' 
arr[0][8] 0xA0CC2008  ' ' ' ' 0x00 0x?? 
      ... 
arr[1][0] 0xA0CC2040  ' ' ' ' ' ' ' ' 
arr[1][4] 0xA0CC2044  ' ' ' ' ' ' ' ' 
arr[1][8] 0xA0CC2048  ' ' ' ' 0x00 0x?? 
      ... 
+1

對不起,我是一個新手,所以我可能是錯的,但要完全清理分配後,你將不得不遍歷所有字符串和自由arr [我]以及釋放整個數組(arr),是嗎?或者僅僅是「自由(arr)」就足夠了? –

3

解引用一個指針裝置訪問所述值的指針到。例如,

char c = 'c'; // This is a primitive value. You cannot dereference it. 
char* p1 = &c; // A pointer to the address of c 
char** p2 = &p1; // A pointer to the address of p1 
/* Now, the following is true: 
*p1 == c, i.e. dereferencing p1 allows us to read from/write to c. 
*p2 == p1 
**p2 == *(*p2) == *p1 = c - dereferencing p2 twice is c, too */ 

您使用指向c而不是c的指針的原因是指針允許您訪問多個值。以此爲例:

char[4] str; 
char c0 = 'a', c1 = 'b', c3 = 'c', c4 = '\0'; 
str[0] = c0; str[1] = c1; str[2] = c2; str[3] = c3; 
str = "abc"; // Same as the above line 

現在假設我們需要第二個字符。我們可以通過c1訪問它。但正如你所看到的,這個符號非常麻煩。另外,如果我們從文件中讀取字符串而不是寫入字符串,我們就不得不做很複雜的事情。相反,我們只是寫

str[1] /* or */ *(str+1) 

注意,第一個元素的指數 0,第二個1 - 這就是爲什麼我們在這裏使用了1。一個char**把這個變成了十一個 - 我們有一個數組字符。假設我們有這樣一個數組,我們稱之爲input,並且需要找出它中所有字符串的長度。這是我們如何做到這一點:

int lensum(char **input) { 
    int res = 0; 
    while (*input) { // This loops as long as the value input points to is not 0. 
     char* p = *input; // Make a copy of the value input currently points to 
     while (*p != '\0') { // Loop while the copy does not point to a char '\0' 
      res += 1; // We found a character 
      p++; // Check next character in the next iteration 
     } 
     input++; // Check next string in the next iteration 
    } 
    return res; 
} 
+0

這是幹什麼的? char * p1 =&c; ? – jarryd

+0

@alJaree完全正確。 &c是c的地址。 – phihag

9

指針是一個保存了地址的值,而不是控股的實際值的類型。

因此,在char * p的情況下,一旦分配,p將包含地址A.解除引用該指針表示訪問存儲在地址A的值。可以將字符串存儲在char *中的原因是分配的內存是連續的。所以,A是存儲第一個字符的地址,A + 1是存儲第二個字符的地址等等。

在char ** pp的情況下,它存儲char *的地址。調用這個地址B.所以,取消引用pp意味着訪問地址B的值,恰好是一個char *,恰好持有一個字符串。以相同的方式,B + 1(實際上是B + sizeof(char *))存儲下一個值,這是另一個字符串。

解引用pp兩次(即** pp)表示您首先訪問地址B處的值(例如A),然後再次解除引用,以獲取地址A處的值,該值是某個字符。

+0

真的很好的解釋。謝謝。 – jarryd

3

圖表勝過1000字。看一看here

char,char *和char **只是描述變量(內存區域)包含的類型。

使用間接引用,如*變量實際上說的變量作爲內存地址來治療的價值,實際上在該地址返回值。這是間接的。

**變量只是間接的兩個層次。即變量中的值是將要返回的數據的又一存儲器地址的存儲器地址。

地址通常來自操作者,&的地址或從一個存儲器分配功能/操作員等new

+1

謝謝:)另外5個去..:P – jarryd