如何使用指向C

时间:2017-10-10 17:02:25

标签: c pointers malloc

我正在尝试理解代码片段 free a double pointer

Why use double pointer? or Why use pointers to pointers?

我想了解以下内容之间的区别。两个片段都来自上面的网址

int** pt; 

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

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

您能否详细说明一些示例和绘图

3 个答案:

答案 0 :(得分:2)

以下是错误的,编译器应该抱怨类型:

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可能会失败,并且应该针对失败测试返回值。

答案 1 :(得分:1)

首先,代码片段很糟糕有几个原因 - 第一个是将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]
                                           +---+---+     +---+

答案 2 :(得分:1)

使用强制转换帮助编译器在此代码段中找到错误

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 *的{​​{1}}类型。

此代码段

int **

因其他原因无效。指针int** pt; *pt = (int*) malloc(sizeof(int)*10); 未由对象的有效地址初始化。如果指针具有自动存储持续时间,则它具有不确定的值;如果指针具有静态存储持续时间,则具有NULL。在任何情况下,它的解除引用都会导致未定义的行为。

所以编写

是正确的
pt

然而这种结构

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