[英]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.