简体   繁体   English

如何在C中使用指向指针的指针分配内存

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

I am trying to understand code snippets in free a double pointer 我试图免费阅读双指针中的代码段

and Why use double pointer? 为什么使用双指针? or Why use pointers to pointers? 或为什么使用指向指针的指针?

I want to understand the difference between the following. 我想了解以下内容之间的区别。 Both snippets are from the above urls 这两个片段均来自上述网址

int** pt; 

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

and

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

Could you elaborate with some examples and drawing 您能否详细说明一些示例和绘图

First of all, the code snippet is bad for several reasons - the first is casting the result of malloc to the wrong type, and is using the wrong type to compute the amount of memory. 首先,由于以下几个原因,代码段很糟糕-首先是将malloc的结果转换为错误的类型,并使用错误的类型来计算内存量。 Fixing the cast and type issues, we have: 解决演员和类型问题,我们有:

int **pt;

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

After executing the first line, you have the following: 执行第一行之后,您将具有以下内容:

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

You've set aside space for 10 int * objects, and pt points to the first of them. 您已经为10个int *对象留出了空间,并且pt指向它们中的第一个。

The next line 下一行

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

allocates space for 10 int objects, and sets pt[0] to point to them: 为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]
                          +---+                +---+

This illustrates one way of allocating a "jagged" array; 这说明了分配“锯齿状”数组的一种方法。 you can still index it as pt[i][j] , but unlike a true 2D array the rows are not adjacent in memory, and each row may be a different length. 您仍然可以将其索引为pt[i][j] ,但是与真正的2D数组不同,行在内存中并不相邻,并且每行的长度可能不同。 You'd normally write that as 您通常将其写为

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

When that's all done, you have something like this: 完成这些后,您将获得以下内容:

     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]
                                           +---+---+     +---+

The following is wrong, compiler should complain about types: 以下是错误的,编译器应抱怨类型:

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

This is also wrong for another reason (here pt does not actually point to anything usable): 由于另一个原因,这也是错误的(这里pt实际上并不指向任何可用的东西):

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

A pointer to T is a variable of type T * that may contain address of some memory that may contains elements of type T : 指向T的指针是类型T *的变量,它可能包含某些可能包含类型T元素的内存地址:

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

For example, in C, to obtain what is drawn, you can write: 例如,在C中,要获取绘制的内容,可以编写:

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

If you have a pointer to pointer to T then then diagram could be something like: 如果您有一个指向T指针,则图表可能类似于:

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

and the code could be: 代码可能是:

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);

Of course, malloc could fail and return value should be tested against failure. 当然, malloc可能失败,并且应该测试返回值是否失败。

Using the casting you helped the compiler to find an error in this code snippet 使用强制转换可以帮助编译器在此代码片段中找到错误

int** pt; 

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

For example the error message can look like 例如,错误消息可能看起来像

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

Without the casting the compiler could accept this evidently invalid code because the return type of the function malloc is void * and a pointer of the type void * may be assigned to a pointer to object of any other type. 如果不进行强制转换,则编译器可以接受此明显无效的代码,因为函数malloc的返回类型为void *且类型void *的指针可以分配给任何其他类型的对象的指针。

That is in the right side of the assignment the evaluated expression has the type int * while in the left side of the assignment there is an object of the type int ** and there is no implicit conversion from the type int * to the type int ** . 也就是说,在赋值的右侧,求值表达式的类型为int *而在赋值的左侧,则为int **类型的对象,并且没有从int *类型到int **类型的隐式转换。 int **

This code snippet 此代码段

int** pt; 

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

is invalid by another reason. 因其他原因无效。 The pointer pt is not initialized by a valid address of an object. 指针pt未被对象的有效地址初始化。 It has either indeterminate value if the pointer has automatic storage duration or NULL if the pointer has static storage duration. 如果指针具有自动存储持续时间,则其值为不确定;如果指针具有静态存储持续时间,则其值为NULL。 In any case its dereferencing results in undefined behavior. 在任何情况下,其取消引用都会导致未定义的行为。

So it would be correctly to write 所以写是正确的

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

However this construction 但是这个构造

int** pt; 

//...

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

can be made valid in some context. 在某些情况下可以有效。

Let's assume that you declared a pointer 假设您声明了一个指针

int *pt;

and want to initialize it in a function. 并希望在函数中对其进行初始化。 In this case you have to pass the pointer to the function by reference. 在这种情况下,您必须通过引用将指针传递给函数。 Otherwise the function will deal with a copy of the pointer and in this case the original pointer will not be assigned in the function. 否则,函数将处理指针的副本,在这种情况下,原始指针将不会在函数中分配。

So the corresponding code snippet can look as it is shown in the demonstrative program 因此,相应的代码段可以像在演示程序中所示

#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 );
}

The program output is 程序输出为

0 1 2 3 4 5 6 7 8 9

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM