簡體   English   中英

如何在C中使用指向指針的指針分配內存

[英]How to allocate memory using a pointer to pointer in C

我試圖免費閱讀雙指針中的代碼段

為什么使用雙指針? 或為什么使用指向指針的指針?

我想了解以下內容之間的區別。 這兩個片段均來自上述網址

int** pt; 

pt = (int*) malloc(sizeof(int)*10);

*pt = (int*) malloc(sizeof(int)*10);

您能否詳細說明一些示例和繪圖

首先,由於以下幾個原因,代碼段很糟糕-首先是將malloc的結果轉換為錯誤的類型,並使用錯誤的類型來計算內存量。 解決演員和類型問題,我們有:

int **pt;

 pt = malloc( sizeof  *pt * 10 );   // allocate space for 10 int *
*pt = malloc( sizeof **pt * 10 );   // allocate space for 10 int

執行第一行之后,您將具有以下內容:

     int **                int *
    +---+                 +---+
pt: |   | --------------->|   | pt[0]
    +---+                 +---+       
                          |   | pt[1]
                          +---+
                          |   | pt[2]
                          +---+
                           ...
                          +---+
                          |   | pt[9]
                          +---+

您已經為10個int *對象留出了空間,並且pt指向它們中的第一個。

下一行

*pt = malloc( sizeof **pt * 10 ); // allocate space for 10 int

為10個int對象分配空間,並設置pt[0]指向它們:

     int **                int *                int 
    +---+                 +---+                +---+
pt: |   | --------------->|   | pt[0] -------->|   | pt[0][0]
    +---+                 +---+                +---+
                          |   | pt[1]          |   | pt[0][1]
                          +---+                +---+
                          |   | pt[2]          |   | pt[0][2]
                          +---+                +---+
                           ...                  ...
                          +---+                +---+
                          |   | pt[9]          |   | pt[0][9]
                          +---+                +---+

這說明了分配“鋸齒狀”數組的一種方法。 您仍然可以將其索引為pt[i][j] ,但是與真正的2D數組不同,行在內存中並不相鄰,並且每行的長度可能不同。 您通常將其寫為

pt = malloc( sizeof *pt * ROWS );
if ( pt )
{
  for ( size_t r = 0; r < ROWS; r++ )
  {
    pt[r] = malloc( sizeof *pt[r] * COLS );
  }
}

完成這些后,您將獲得以下內容:

     int **           int *                 int
    +---+            +---+                 +---+---+     +---+
pt: |   | ---------> |   | pt[0] --------> |   |   | ... |   | pt[0][0] - pt[0][COLS-1]
    +---+            +---+                 +---+---+     +---+
                     |   | pt[1] ------+
                     +---+             |   +---+---+     +---+
                     |   | pt[2] ---+  +-> |   |   | ... |   | pt[1][0] - pt[1][COLS-1]
                     +---+          |      +---+---+     +---+
                      ...           | 
                                    |      +---+---+     +---+
                                    +----> |   |   | ... |   | pt[2][0] - pt[2][COLS-1]
                                           +---+---+     +---+

以下是錯誤的,編譯器應抱怨類型:

int** pt;     
pt = (int*) malloc(sizeof(int)*10);

由於另一個原因,這也是錯誤的(這里pt實際上並不指向任何可用的東西):

int** pt;     
*pt = (int*) malloc(sizeof(int)*10);

指向T的指針是類型T *的變量,它可能包含某些可能包含類型T元素的內存地址:

+------+
|      | pointer to T 
+------+
    |
    v
+-------------+-------------+-------------+
|             |             |             | elements of type T
+-------------+-------------+-------------+ 

例如,在C中,要獲取繪制的內容,可以編寫:

int *pi;
pi = malloc(sizeof(int)*3);

如果您有一個指向T指針,則圖表可能類似於:

+------+
|      | pointer to pointer to T 
+------+
    |
    v
+------+------+------+
|      |      |      | pointers to T 
+------+------+------+
    |      |      |     +-------------+-------------+-------------+
    |      |      +---->|             |             |             | elements of type T
    |      |            +-------------+-------------+-------------+ 
    |      |     +-------------+-------------+
    |      +---->|             |             | elements of type T
    |            +-------------+-------------+ 
    |
    v
+-------------+-------------+-------------+-------------+
|             |             |             |             | elements of type T
+-------------+-------------+-------------+-------------+ 

代碼可能是:

int **ppi;
ppi = malloc(sizeof(int *)*3);
ppi[0] = malloc(sizeof(int)*3);
ppi[1] = malloc(sizeof(int)*2);
ppi[2] = malloc(sizeof(int)*4);

當然, malloc可能失敗,並且應該測試返回值是否失敗。

使用強制轉換可以幫助編譯器在此代碼片段中找到錯誤

int** pt; 

pt = (int*) malloc(sizeof(int)*10);

例如,錯誤消息可能看起來像

 error: assignment from incompatible pointer type [-Werror=incompatible-pointer-types]
  pt = (int*) malloc(sizeof(int)*10);
     ^

如果不進行強制轉換,則編譯器可以接受此明顯無效的代碼,因為函數malloc的返回類型為void *且類型void *的指針可以分配給任何其他類型的對象的指針。

也就是說,在賦值的右側,求值表達式的類型為int *而在賦值的左側,則為int **類型的對象,並且沒有從int *類型到int **類型的隱式轉換。 int **

此代碼段

int** pt; 

*pt = (int*) malloc(sizeof(int)*10);

因其他原因無效。 指針pt未被對象的有效地址初始化。 如果指針具有自動存儲持續時間,則其值為不確定;如果指針具有靜態存儲持續時間,則其值為NULL。 在任何情況下,其取消引用都會導致未定義的行為。

所以寫是正確的

int* pt; 
^^^^^^^
pt = (int*) malloc(sizeof(int)*10);

但是這個構造

int** pt; 

//...

*pt = (int*) malloc(sizeof(int)*10);

在某些情況下可以有效。

假設您聲明了一個指針

int *pt;

並希望在函數中對其進行初始化。 在這種情況下,您必須通過引用將指針傳遞給函數。 否則,函數將處理指針的副本,在這種情況下,原始指針將不會在函數中分配。

因此,相應的代碼段可以像在演示程序中所示

#include <stdlib.h>
#include <stdio.h>

size_t f( int **pt )
{
    const size_t N = 10;

    *pt = (int*) malloc( sizeof( int ) * N );

    if ( *pt )
    {
        int value = 0;
        for ( size_t i = 0; i < N; i++ ) ( *pt )[i] = value++;
    }

    return *pt == NULL ? 0 : N;
}

int main( void )
{
    int *pt;

    size_t n = f( &pt );

    if ( n )
    {
        for ( size_t i = 0; i < n; i++ ) printf( "%d ", pt[i] );
        putchar( '\n' );
    }

    free( pt );
}

程序輸出為

0 1 2 3 4 5 6 7 8 9

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM