使用双指针实现二维数组

9
请看下面的代码:

请考虑以下代码:

#include <stdio.h>
#include <stdlib.h>

#define NUM_ARRAYS     4
#define NUM_ELEMENTS   4
#define INVALID_VAL   -1

int main()
{
   int index            = INVALID_VAL;
   int array_index      = INVALID_VAL;
   int **ptr            = NULL;

   ptr = malloc(sizeof(int*)*NUM_ARRAYS);

   if (!ptr)
   {
      printf ("\nMemory Allocation Failure !\n\n");
      exit (EXIT_FAILURE);
   }

   for (index=0; index<NUM_ARRAYS; index++)
   {
      *(ptr+index) = malloc(sizeof(int)*NUM_ELEMENTS); 

      if (!*(ptr+index))
      {
         printf ("\nMemory Allocation Failure !\n");
         exit (EXIT_FAILURE);
      }
   }

   /* Fill Elements Into This 2-D Array */
   for (index=0; index<NUM_ARRAYS; index++)
   {
      for (array_index = 0; array_index<NUM_ELEMENTS; array_index++)
      {
         *(*(ptr+index)+array_index) = (array_index+1)*(index+1);
      }
   }

   /* Print Array Elements */
   for (index = 0; index<NUM_ARRAYS; index++)
   {
      printf ("\nArray %d Elements:\n", index);
      for (array_index = 0; array_index<NUM_ELEMENTS; array_index++)
      {
         printf (" %d ", *(*(ptr+index)+array_index));
      }
      printf ("\n\n");
   }

   return 0;
}

我的代码没有问题,它运行良好。

Output:

Array 0 Elements:
 1  2  3  4 


Array 1 Elements:
 2  4  6  8 


Array 2 Elements:
 3  6  9  12 


Array 3 Elements:
 4  8  12  16 

我有一个关于指针算术的问题:

*(ptr+0) = 指向完整块(第一个数组)的指针
*(ptr+1) = 指向完整块(第二个数组)的指针。

但是(*ptr+1)是什么意思?

GDB 输出:

(gdb) p *(*ptr+1)
$1 = 2
(gdb) p *(*ptr+2)
$2 = 3
(gdb) p *(*ptr+3)
$3 = 4
(gdb) p *(*ptr+4)
$4 = 0

我对此感到困惑,请给我一些解释以解决这个疑问。

我在这段代码中没有看到 (*ptr+1) - Kiril Kirov
不,它不在那里。这是我在编写此代码后的概念疑问。 - Sandeep Singh
5个回答

28
                                 (*ptr)      (*ptr+1)     (*ptr+2)
                                   |            |            |
             __________      ______v____________v____________v____________
  ptr------>|   *ptr   |--->|  *(*ptr)   |  *(*ptr+1)  |*(*ptr+2) |       |
            |__________|    |____________|_____________|__________|_______|
 (ptr+1)--->| *(ptr+1) |     ____________ _____________ __________________
            |__________|--->|*(*(ptr+1)) |*(*(ptr+1)+1)|          |       |
            |          |    |____________|_____________|__________|_______|
            |__________|          ^             ^
                                  |             |
                              *(ptr+1)     *(ptr+1)+1

使用双指针的2D数组意味着您有一个主数组,而主数组的元素是指向子数组的指针(或地址)。如上图所示。

如果您已将双指针定义为这个2D数组的指针,比如int **ptr

那么ptr指向包含指向子数组的指针的主数组。 ptr指向主数组的第一个元素,因此ptr + 1指向主数组的第二个元素。

*ptr表示ptr指向的第一个元素的内容。它是指向子数组的指针(子数组是一个int数组)。因此,*ptr指向第一个子数组的第一个元素。所以*ptr + 1是指向第一个子数组的第二个元素的指针。


2
+1,你的图比我的清晰。Kallel,你是如何画这个图的?你用了什么工具吗? - Grijesh Chauhan

9

*(ptr+i)等同于ptr[i],而*(ptr+1)等同于ptr[1]

你可以把一个二维数组看作是由多个一维数组组成的数组。

  • ptr指向完整的二维数组,因此ptr+1指向下一个二维数组。

在下图中,ptr为二维数组,列数为3

原图由Kerrek SB先生制作,在这里查看!

+===============================+==============================+====
|+---------+----------+--------+|+----------+---------+--------+|
||ptr[0,0] | ptr[0,1] | ptr[0,2]|||ptr[1,0] |ptr[1,1] | ptr[1,2]|| ...
|+---------+----------+--------+++----------+---------+--------++ ...
|            ptr[0]             |           ptr[1]              |
+===============================+===============================+====
   ptr

*(*ptr+1) = *( ptr[0] + 1 ) = ptr[0][1]

理解以下内容:

ptr 指向完整的二维数组。

*ptr = *(ptr + 0) = ptr[0] 即第一行。

*ptr + 1 = ptr[1] 表示第二行

*(*ptr+1) = *(*(ptr + 0) + 1 ) = *(ptr[0] + 1) = ptr[0][1]

Array 0 Elements:
1  2  3  4 

同时,GDB 的输出如下:

(gdb) p *(*ptr+1)
$1 = 2  

没错,2 可以使用 ptr[0][1] 进行读取。


我理解*(ptr+1)没有问题。事实上,上面的代码是我自己写的。我的问题是{*(ptr)+1}。 - Sandeep Singh
谢谢Grijesh。但是gdb显示了不同的输出。我正在更新我的问题,以包括对ptr + 1)的GDB O / P。 - Sandeep Singh
不,这对我还不清楚。我也期望(*ptr)+1 可能会到达第二个数组块,但它实际上到达的是第一个数组的第二个元素(在上面的问题中添加了GDB输出)。 - Sandeep Singh
@SandeepSingh:请检查一下,我希望现在你已经明白了。 - Grijesh Chauhan
@SandeepSingh 现在的状态是什么? - Grijesh Chauhan
@SandeepSingh:欢迎,Sandeep。一开始是我的错误,我写错了,对此感到抱歉。谢谢你。如果你还有其他疑问,请告诉我。 - Grijesh Chauhan

3

使用指针创建二维数组、为数组赋值以及访问数组元素的最简单方法。

#include<stdio.h>
#include<stdlib.h>

int main()
{
int i,j;
int row,col;
printf("Enter the values for row and col:\n");
scanf("%d%d",&row,&col);
int **arr=(int**)malloc(row*(sizeof(int*)));
for(i=0;i<row;i++)
{
    *(arr+i)=(int*)malloc(sizeof(int)*col);
            //You can use this also. Meaning of both is same.
            //arr[i]=(int*)malloc(sizeof(int)*col);
}
for(i=0;i<row;i++)
for(j=0;j<col;j++)
{
    arr[i][j]=0;
}
for(i=0;i<row;i++)
{
    for(j=0;j<col;j++)
    {
        printf("%d ",arr[i][j]);
    }
    printf("\n");
}
}

是的,您已经简化了将值分配给双指针的任务。但是,在理解双指针时,这种简单性存在很大的危险。从查看此代码,许多人可以得出结论:指向变量的双指针就像二维数组一样。但是,指向变量的双指针与二维数组不同。 - Nguai al

2
除非您输入错误,(*ptr + 1) 等同于 *(ptr + 0) + 1,它是指向第一个块中第二个元素的指针。

不,我没有打错字。我对 {(ptr)+1} 有些困惑。你的解释是正确的(已由GDB验证)。但根据我的理解,ptr = 指向第一个数组块,而不是任何单个元素。那么,(*ptr+1) 可能已经到了第二个数组的开头。请澄清这个疑问。 - Sandeep Singh

1

*ptr + 1 is address of ptr[0][1]

Because, we know

ptr[0][1] == *(*(ptr+0)+1)

现在在两侧放置“&”符号。
&ptr[0][1] == &*(*(ptr+0)+1)

你知道带星号的&符号就像加号和减号一样吗?它们会相互抵消。所以这就变成了:
&ptr[0][1] == (*(ptr+0)+1)

这与以下内容相同:

&ptr[0][1] == *(ptr+0)+1

这再次与之前相同

&ptr[0][1] == *ptr+1

这是我的第一个声明。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接