【问题标题】:Can't understand exactly the pointers in 2d array无法准确理解二维数组中的指针
【发布时间】:2020-02-20 14:21:13
【问题描述】:

我通过查看互联网做了一些事情,但这里缺少的是我的代码

void draw_way(int *arr,int lenght_row,int lenght_column) {
int s1 = 0, s2 = 0;
for (s1 = 0; s1 < lenght_row; s1++)
{
    for (s2 = 0; s2 < lenght_column; s2++) {
        if (*((arr + s1 * lenght_row) + s2) == 1)
        {
            printf("S");
        }
        else if (*((arr + s1 * lenght_row) + s2) == 2)
        {
            printf("G");
        }
        else if(*((arr + s1 * lenght_row) + s2) == 3)
        {
            printf("#");
        }
        else if (*((arr + s1 * lenght_row) + s2) == 4)
        {
            printf(".");
        }
    }
    printf("\n");
}

它实际上是在打印一个迷宫,但这并不重要。我想了解的是为什么我必须使用*((arr + s1 * lenght_row) + s2),为什么如果我使用*(*(arr+s1)+s2) 'lenght_row' 会做什么,这不起作用。

【问题讨论】:

    标签: c pointers multidimensional-array


    【解决方案1】:

    对于任何数组或指针arr 和索引i,表达式*(arr + i) 完全等于arr[i]

    如果我们为*(*(arr+s1)+s2) 进行此翻译,那将是(arr[s1])[s2](或arr[s1][s2])。因为arr 不是指向指针(或数组数组)的指针,所以arr[s1][s2] 没有意义。

    相反,您可以使用数组(arr 指向其第一个元素)模拟二维数组(数组的数组),并使用算术计算该数组的单个索引。

    这对于动态分配的内存非常常见,其中不使用 jagged array(使用指向指针的指针),而是使用单个连续区域或内存。


    用插图可能更容易理解...

    假设我们想要一个由 2 x 3 个元素组成的二维数组。我们可以使用动态分配将其创建为锯齿状数组:

    int **arr;
    arr = malloc(2 * sizeof *arr);  // First dimension
    for (size_t i = 0; i < 2; ++i)
        arr[i] = malloc(3 * sizeof *arr[i]);  // Second dimension
    

    由于我们有多个分配,数组中没有位置,arr[0][2] 后面可能没有arr[1][0]。局部性和连续的二维数组可能对某些算法和用例有好处。

    一个连续的二维数组将是一个数组的数组,如

    int arr[2][3];
    

    但这更难动态处理,因此我们分配了2 * 3元素的单个连续内存区域:

    int *arr;
    arr = malloc(2 * 3 * sizeof *arr);
    

    不幸的是,它不能以与锯齿状数组或数组数组相同的直观方式被索引(即arr[0][1] 是不可能的)。但通过一些巧妙的算术,它是可能的:arr[row_index * row_length + column_index] 将类似于 arr[row_index][column_index](用于锯齿状数组或数组数组)。

    【讨论】:

      【解决方案2】:

      arr 是一个平面数组,而不是多维数组。它通过传入网格大小来模拟多维数组。因此,如果它是 5x2,那么作为平面数组的 arr 将是 10 个整数,而不是另一个 2 列数组的 5 行数组。

      因此,它使用简单的指针算法通过平面数组索引计算来模拟 r,c 维度

      ((arr + s1 * lenght_row) + s2)

      【讨论】:

      • 顺便说一句,从“length_row”的角度来看,代码变量名称没有意义,应该设置为“列数”​​(我猜技术上是行的长度),同样,“length_column”应设置为“行数”,这在技术上是正确的。我建议将它们更改为 num_rows 和 num_columns 以减少混乱。
      • 此外,编译器在处理“真实”二维数组时会悄悄地做同样的事情。与“数组的数组”不同(并不总是连续的,地址是通过从第一个数组获取指针并将其用作第二个数组的基数来计算的,这需要额外的内存访问操作而不是简单的乘法操作)。
      • 虽然说 arr 是一个平面数组,而不是一个多维数组,你的意思是 你不是指向二维数组。它只是一个数组
      • @nbr 是的,这就是我的意思
      【解决方案3】:

      如果你减少 paranthises 的数量,它会更容易理解:if (*(arr + s1 * lenght_row + s2) == 2)

      二维数组有c 列和r 行。它们连续存储在内存中 row0 然后 row 1 它们 row2 ...

      因此,要访问特定元素(行、列),您需要将行乘以“r”(即我们在行中拥有多少个元素并添加列。

      【讨论】:

        【解决方案4】:

        对于初学者来说,像这样的 if-else 语句中的表达式

        if (*((arr + s1 * lenght_row) + s2) == 1)
        

        不正确。应该有

        if (*((arr + s1 * lenght_column) + s2) == 1)
        

        参数arr声明为

        int *arr
        

        类型为int *。因此,像 *arr 这样解引用指针,您将获得一个 int 类型的对象,您可能不会对其应用解引用运算符。

        所以这个表达式

        *(*(arr+s1)+s2)
        

        不正确。子表达式*(arr+s1) 的类型为int。所以第二次使用 * 会产生编译错误。

        在所示函数中,使用指向一维数组的指针模拟了一个二维数组。即一维数组通过 length_column 元素在逻辑上分成块。

        这是一个演示程序。

        #include <stdio.h>
        
        #define ROW_LENGTH      2
        #define COLUMN_LENGTH   3
        
        void display( const int *arr, size_t row_length, size_t column_length )
        {
            for ( size_t i = 0; i < row_length; i++ )
            {
                for ( size_t j = 0; j < column_length; j++ )
                {
                    printf( "%d ", *( arr + i * column_length + j ) );
                }
                putchar( '\n' );
            }
        }
        
        int main(void) 
        {
            int arr[ROW_LENGTH * COLUMN_LENGTH] = { 1, 2, 3, 4, 5, 6 };
        
            display( arr, ROW_LENGTH, COLUMN_LENGTH );
        
            return 0;
        }
        

        它的输出是

        1 2 3 
        4 5 6 
        

        【讨论】:

        • 不需要让我的代码完美运行,但就像我说的我无法理解我做了什么。以一种有趣的方式更改 row_lenght 和 column_lenght 不会影响任何事情
        • @NBR 无效代码会引起问题并使读者感到困惑。您应该始终提供用户专注于问题的正确代码..
        猜你喜欢
        • 2021-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-17
        • 2014-04-12
        相关资源
        最近更新 更多