简体   繁体   English

C-指向指针数组的指针

[英]C - pointer to pointer array

I am learning C and as I got stuck at the pointer chapter. 我正在学习C,因为我陷入了指针章节。 Particullary at the pointer to pointer ( **p ) part, used with processing 2 dimensional arrays. 指向指针(** p)的指针的部分,用于处理2维数组。

The following function generates a 2 dimmensional array with all its elements equal to 0 . 以下函数生成一个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;}

Is the tr returned by the function a "double pointer" to the first element of the tr array ? 函数返回的tr是指向tr数组第一个元素的“双指针”吗? Or to its value ? 还是要其价值? Also, now (after the the function was called) how do I access the elements of the array at the part of memory where **tr points to ? 另外,现在(在调用函数之后)如何在** tr指向的内存部分访问数组的元素?

Can someone explain me how this all works ? 有人可以解释一下这一切如何运作吗? Or suggest me an article or a chapter in a book that does ? 还是建议我在其中写一篇文章或一章呢?

In C, functions will have to return a value/variable of the same type as the function. 在C语言中,函数必须返回与函数类型相同的值/变量。 In this example, tr would be a double pointer, which is pointing to the first row. 在此示例中,tr将是一个双指针,它指向第一行。

When using double pointers to create 2D arrays, you're actually creating an pointer that points to an array of pointers, with the pointers within the array pointing to strings/values stored in each row. 当使用双指针创建2D数组时,实际上是在创建一个指向指针数组的指针,该数组内的指针指向存储在每一行中的字符串/值。 The double pointer would be pointing to the first pointer in the pointer array, which will point to the first element in the first row. 双指针将指向指针数组中的第一个指针,该指针数组将指向第一行中的第一个元素。

You can access values in 2D arrays using bracket notation such as tr[row][column] , or as *(*(tr + row) + column) . 您可以使用括号符号(例如tr[row][column]*(*(tr + row) + column)来访问2D数组中的值。 For the second notation, *(tr + row) will access the pointer pointing to the row you want, which you can then reference the value by using *(found_row + column) , giving you the element in the column you want. 对于第二种表示法, *(tr + row)将访问指向所需行的指针,然后可以使用*(found_row + column)引用该值,从而在所需列中提供元素。

The presented program is totally incorrect. 提出的程序是完全不正确的。 A variable length array may not have static storage duration/ According to the C Standard (6.7.6.2 Array declarators) 可变长度数组可能没有静态存储持续时间/根据C标准(6.7.6.2数组声明符)

2 If an identifier is declared as having a variably modified type, it shall be an ordinary identifier (as defined in 6.2.3), have no linkage, and have either block scope or function prototype scope. 2如果一个标识符被声明为具有可变修改的类型,则它应该是一个普通标识符(如6.2.3中所定义),没有链接,并且具有块范围或函数原型范围。 If an identifier is declared to be an object with static or thread storage duration, it shall not have a variable length array type. 如果一个标识符被声明为具有静态或线程存储持续时间的对象,则该标识符不得具有可变长度的数组类型。

Moreover the pointer types double ** and double ( * )[cols] (to which the array provided that it was declared correctly is converted in expressions) are not compatible. 此外,指针类型double **double ( * )[cols] (假定正确声明的数组将在表达式中转换为指针类型)不兼容。 So the function is wrong. 所以功能是错误的。

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

Here is a demonstrative program that shows how to deal with variable length arrays. 这是一个演示程序,显示了如何处理可变长度数组。

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

Its output might look like 它的输出可能看起来像

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

Within the both functions the third parameter is adjusted to the pointer type double ( *a )[cols] . 在这两个函数中,第三个参数被调整为指针类型double ( *a )[cols] It is not the same as double **a . 它与double **a

If you will write for example the following program 例如,如果您要编写以下程序

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

then it will have undefined behavior because p[0] considers the value stored in the element a[0][0] (or the combined value stored in elements a[0][0] and a[0][1] depending on the size of the pointer) that is the value 1 as a pointer value and try to access the memory at address 1 in the expression p[0][0] . 那么它将具有未定义的行为,因为p[0]考虑存储在元素a[0][0]的值(或存储在元素a[0][0]a[0][1]的组合值,具体取决于指针的大小)(即指针的值1)作为指针值,并尝试访问表达式p[0][0]中地址1的内存。

Throw away the book that contains this code - it doesn't even compile properly. 扔掉包含此代码的书-它甚至无法正确编译 I get the following errors: 我收到以下错误:

[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

You cannot create a variable-length array with static storage duration. 您不能创建具有static存储持续时间的可变长度数组。 Objects with static storage duration are allocated at program startup , so their sizes need to be known at compile time. 具有static存储持续时间的对象是在程序启动时分配的,因此需要在编译时知道它们的大小。 A VLA cannot be instantiated until you know the size of its dimensions at runtime. 除非您在运行时知道其尺寸大小,否则无法实例化VLA。

Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T " will be converted ("decay") to an expression of type "pointer to T ", and the value of the expression will be the address of the first element of the array. 除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则类型“ T N元素数组”的表达式将被转换(“ decay”)为类型为“指向T指针”的表达式,该表达式的值将是数组第一个元素的地址。

The expression tr has type " rows -element array of cols -element array of double "; 表达 tr具有类型“ rows的阵列-元素cols的-元素阵列double ”; in the return statement, this expression will "decay" to type "pointer to cols -element array of double ", or double (*)[cols] . return语句,这种表达将“衰变”输入“指针cols的-元素阵列double ”,或double (*)[cols] This is a completely different type from double ** . 这是与double ** 完全不同的类型

Multiple indirection shows up a lot, but this isn't a valid example. 多重间接显示了很多东西,但这不是一个有效的例子。

You would normally see multiple indirection when you want a function to write to a parameter of pointer type: 当您希望函数写入指针类型的参数时,通常会看到多个间接寻址:

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
}

You can use multiple indirection to create a structure that kinda-sorta looks and behaves like a 2D array, but it's not the same thing as a 2D array: 您可以使用多种间接创建一种有点像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
  }
}

When you're done, you have a structure that looks like this: 完成后,您将具有如下结构:

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

You can access elements using regular subscript notation ( a[i][j] ) like a 2D array, but the memory for this structure is not allocated contiguously like it would be for a 2D array: 您可以使用常规下标符号( a[i][j] )来访问元素,例如2D数组,但是此结构的内存不会像2D数组那样连续分配:

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

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

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