C - 指向指针数组的指针

时间:2017-03-31 15:51:49

标签: c arrays pointers memory-management types

我正在学习C,因为我被困在指针章节。指向指针(** p)部分的指针,用于处理2维数组。

以下函数生成一个2维数组,其所有元素都等于0。

double** example(int rows, int cols){
    static double tr[rows][cols];
    for(int i = 0; i < rows; i++)
       for(int j = 0; j < cols; j++)
            tr[j][i] = 0;
    return tr;
    }
int main(void){

    double **tr;
    int m = 2 ;
    int n = 2 ;

    tr = transpose(m, n);
    return 0;}

函数返回的trtr数组的第一个元素的“双指针”吗?或者它的价值?此外,现在(在调用函数之后)如何访问** tr指向的内存部分的数组元素?

有人可以解释一下这一切是如何运作的吗?或者向我推荐一本书中的文章或章节?

3 个答案:

答案 0 :(得分:4)

在C中,函数必须返回与函数相同类型的值/变量。在这个例子中,tr将是一个双指针,指向第一行。

当使用双指针创建2D数组时,实际上是在创建一个指向指针数组的指针,数组中的指针指向存储在每一行中的字符串/值。双指针将指向指针数组中的第一个指针,指针将指向第一行中的第一个元素。

您可以使用括号表示法访问2D数组中的值,例如 tr[row][column]*(*(tr + row) + column)。对于第二种表示法,*(tr + row)将访问指向所需行的指针,然后您可以使用*(found_row + column)引用该值,从而为您提供所需列中的元素。

答案 1 :(得分:2)

提供的程序完全不正确。可变长度数组可能没有静态存储持续时间/根据C标准(6.7.6.2数组声明符)

  

2如果标识符被声明为具有可变修改类型,则为   应为普通标识符(如6.2.3中所定义),没有联系,   并具有块范围或功能原型范围。 如果是   标识符被声明为具有静态或线程存储的对象   持续时间,它不应具有可变长度数组类型。

此外,指针类型double **double ( * )[cols](数组提供正确声明的指针在表达式中转换)不兼容。所以功能错了。

double** example(int rows, int cols){
    static double tr[rows][cols];
    for(int i = 0; i < rows; i++)
       for(int j = 0; j < cols; j++)
            tr[j][i] = 0;
    return tr;
    }

这是一个演示程序,展示了如何处理可变长度数组。

#include <stdio.h>

void init( size_t rows, size_t cols, double a[rows][cols] )
//  or
//  void init( size_t rows, size_t cols, double a[][cols] )
//  or
//  void init( size_t rows, size_t cols, double ( *a )[cols] )
{
    for ( size_t i = 0; i < rows; i++ )
    {
        for ( size_t j = 0; j < cols; j++ ) a[i][j] = 0.0;
    }
}

void display( size_t rows, size_t cols, double a[rows][cols] )
//  or
//  void display( size_t rows, size_t cols, double a[][cols] )
//  or
//  void display( size_t rows, size_t cols, double ( *a )[cols] )
{
    for ( size_t i = 0; i < rows; i++ )
    {
        for ( size_t j = 0; j < cols; j++ ) printf( "%lf", a[i][j] );
        putchar( '\n' );
    }
}

int main(void) 
{
    while ( 1 )
    {
        size_t m, n;

        printf( "Enter numbers of rows and columns (0 - exit): " );

        if ( scanf( "%zu%zu", &m, &n ) != 2 || m == 0 || n == 0 ) break;

        double a[m][n];

        putchar( '\n' );

        init( m, n, a );
        display( m, n, a );

        putchar( '\n' );
    }

    return 0;
}

它的输出可能看起来像

Enter numbers of rows and columns (0 - exit): 2 3

0.0000000.0000000.000000
0.0000000.0000000.000000

Enter numbers of rows and columns (0 - exit): 3 4

0.0000000.0000000.0000000.000000
0.0000000.0000000.0000000.000000
0.0000000.0000000.0000000.000000

Enter numbers of rows and columns (0 - exit): 0 0

在这两个函数中,第三个参数被调整为指针类型double ( *a )[cols]。它与double **a不同。

如果您要编写以下程序

#include <stdio.h>

#define M   2
#define N   3

int main(void) 
{
    int a[M][N] =
    {
        { 1, 2, 3 },
        { 4, 5, 6 }
    };

    int **p = ( int ** )a;

    p[0][0] = 10;

    return 0;
}

然后它会有未定义的行为,因为p[0]会考虑元素a[0][0]中存储的值(或元素a[0][0]a[0][1]中存储的组合值,具体取决于大小指针的值为1作为指针值,并尝试访问表达式p[0][0]中地址1的内存。

答案 2 :(得分:0)

丢掉包含此代码的书 - 它甚至不能编译。我收到以下错误:

[fbgo448@n9dvap997]~/prototypes/buf: gcc -o stack -std=c99 -pedantic-errors -Wall stack.c
stack.c: In function âexampleâ:
stack.c:2: error: storage size of âtrâ isnât constant
stack.c:6: error: return from incompatible pointer type

您无法创建具有static存储持续时间的可变长度数组。具有static存储持续时间的对象在程序启动时分配 ,因此需要在编译时知道它们的大小。在运行时知道其维度的大小之前,无法实例化VLA。

除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,表达式为类型&#34; T&#34;的N元素数组;将被转换(&#34;衰减&#34;)到类型为&#34的表达式;指向T&#34;的指针,并且表达式的值将是第一个元素的地址。阵列。

表达式 tr的类型为&#34; rows - cols的元素数组 - double的元素数组&#34; ;在return语句中,此表达式将“衰减”#34;输入&#34;指向cols的指针 - double&#34;或double (*)[cols]的元素数组。这是来自double **完全不同的类型。

多个间接显示了很多,但这不是一个有效的例子。

当您希望函数写入指针类型的参数时,通常会看到多个间接:

void bar( T **p ) // for any type T
{
  *p = new_pointer_value();  // write a new value to the thing p points to
}

void foo( void )
{
   T *ptr;

   bar( &ptr ); // bar writes a value to ptr
}

您可以使用多个间接来创建一个有点排序的结构,其行为类似于2D数组,但它与2D数组不同:

double **arr;
size_t rows = some_number_of_rows();
size_t cols = sime_number_of_cols();

arr = malloc( sizeof *arr * rows ); // allocates an array of pointers to double
if ( arr )
{
  for ( size_t i = 0; i < rows; i++ )
  {
    arr[i] = malloc( sizeof *arr[i] * cols ); // allocates an array of double
  }
}

当你完成后,你的结构看起来像这样:

   +---+       +---+      +---+---+---+     +---+
a: |   |  ---> |   | ---> |   |   |   | ... |   |
   +---+       +---+      +---+---+---+     +---+
               |   | -+
               +---+  |   +---+---+---+     +---+
                ...   +-> |   |   |   | ... |   |
               +---+      +---+---+---+     +---+
               |   | -+
               +---+  |   +---+---+---+     +---+
                      +-> |   |   |   | ... |   |
                          +---+---+---+     +---+

您可以使用常规下标表示法(a[i][j])来访问元素,就像2D数组一样,但是这个结构的内存不像二维数组那样连续分配:

   +---+---+---+---+---+ 
a: |   |   |   |   |   |
   +---+---+---+---+---+
   |   |   |   |   |   |
   +---+---+---+---+---+
   |   |   |   |   |   |
   +---+---+---+---+---+
   ...