C语言 如何使用指针表达式访问 C 中二维数组的元素?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13554244/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:34:30  来源:igfitidea点击:

How to use pointer expressions to access elements of a two-dimensional array in C?

cpointersmultidimensional-array

提问by Tudor Ciotlos

I know that for single-dimensional arrays x=a[i]is equivalent to x=*(a+i), but how can I access elements of a two-dimensional arrays using pointers?

我知道对于一维数组 x=a[i]等价于x=*(a+i),但是如何使用指针访问二维数组的元素?

回答by antonijn

Summary:If you have a multidimensional array defined as int [][], then x = y[a][b]is equivalent to x = *((int *)y + a * NUMBER_OF_COLUMNS + b);

总结:如果你有一个多维数组定义为int [][],那么x = y[a][b]等价于x = *((int *)y + a * NUMBER_OF_COLUMNS + b);



Boring Details:

无聊的细节:

The (int *)cast of yabove deserves some explanation, as its necessity may not be at-first intuitive. To understand why it must be there consider the following:

上面的(int *)演员y阵容值得一些解释,因为它的必要性起初可能并不直观。要理解为什么它必须存在,请考虑以下几点:

  1. Typed pointer arithmetic in C/C++ always adjusts the typed pointer value (which is an address) by the size of the typein bytes when adding/subtracting/incrementing/decrementing by scalar.

  2. The fundamental typeof a multi-dimensional array declaration (not the element type; the variabletype) is an array-type of one-less dimension than the final dimension.

  1. 在C / C ++类型指针算法总是由大小调整类型化指针值(这是一个地址)类型以字节加法/减法/递增/标量递减时。

  2. 多维数组声明的基本类型(不是元素类型;变量类型)是比最终维度少一维的数组类型。

The latter (#2) of these really needs an example to solidify. In the following, variables ar1and ar2are equivalent declarations.

后者(#2)确实需要一个例子来巩固。在下面,变量ar1ar2是等价的声明。

int ar1[5][5]; // an array of 5 rows of 5 ints.

typedef int Int5Array[5];  // type is an array of 5 ints
Int5Array ar2[5];          // an array of 5 Int5Arrays.

Now the pointer arithmetic part. Just as a typed structure pointer can be advanced by the size of the structure in bytes, so can a full dimension of an array be hopped over. This is easier to understand if you think of the multi-dimensioned array as I declared ar2 above:

现在是指针算术部分。正如类型化结构指针可以按结构的大小(以字节为单位)前进一样,数组的整个维度也可以跳过。如果您考虑我上面声明的 ar2 的多维数组,这将更容易理解:

int (*arptr)[5] = ar1; // first row, address of ar1[0][0].
++arptr;               // second row, address of ar[1][0].

All of this goes away with a bare pointer:

所有这些都用一个裸指针消失了:

int *ptr = ar1; // first row, address of ar1[0][0].
++ptr;          // first row, address of ar1[0][1].

Therefore, when doing the pointer arithmetic for two-dimensional array, the following would NOT work in getting the element at [2][2]of a multi-dimensioned array:

因此,在对二维数组进行指针运算时,以下方法无法获取[2][2]多维数组的元素:

#define NUMBER_OF_COLUMNS   5
int y[5][NUMBER_OF_COLUMNS];
int x = *(y + 2 * NUMBER_OF_COLUMNS + 2); // WRONG

The reason is hopefully obvious when you remember that yis an array of arrays (declaratively speaking). The pointer arithmetic of adding the scaler (2*5 + 2)to ywill add 12 rows, thereby computing and address equivalent to &(y[12]), which is clearly not right, and in fact, will either throw a fat warning at compile time or outright fail to compile altogether. This is avoided with the cast of (int*)yand the resulting type of the expression being based on an bare pointer-to-int:

当您记得这y是一个数组数组时(声明性地说),原因很明显。加上scaler (2*5 + 2)to的指针算法y会相加12,从而计算和地址等价于&(y[12]),这显然是不对的,实际上,要么在编译时抛出一个fat警告,要么完全编译失败。这可以通过强制转换(int*)y和表达式的结果类型基于裸指针到 int 来避免:

#define NUMBER_OF_COLUMNS   5
int y[5][NUMBER_OF_COLUMNS];
int x = *((int *)y + 2 * NUMBER_OF_COLUMNS + 2); // Right!

回答by totymedli

The table

桌子

In C 2D arrays are continuous series of lines (not like in Pascal).
When we crate a table of integers with 4 rows and 5 columns: A 5*4 integer table.

在 C 中,二维数组是一系列连续的线(不像在 Pascal 中)。
当我们创建一个 4 行 5 列的整数表时: 一个 5*4 的整数表。

Reaching the elements

到达元素

We can reach the elemnts with:

我们可以通过以下方式到达元素:

int element = table[row-1][column-1];

But we can also do this with the following code:

但是我们也可以使用以下代码来做到这一点:

int element = *(*(table+row-1)+column-1);

In these examples rowand columnis counted from 1, thats the reason for the -1.
In the following code you can test that both technique is correct. In this case we count the rows and columns from 0.

在这些示例中rowcolumn从 1 开始计数,这就是 -1 的原因。
在下面的代码中,您可以测试这两种技术是否正确。在这种情况下,我们从 0 开始计算行和列。

Example

例子

#include <stdio.h>
#include <stdlib.h>
#define HEIGHT 4
#define WIDTH 5

int main()
{
    int table[HEIGHT][WIDTH] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
    int row = 2;
    int column = 2;
    int a = *(*(table+row)+column);
    printf("%d\n",a);//13
    printf("%d\n",table[row][column]);//13
    return 0;
}

Explanation

解释

This is a double poiner arithmetic, so tablepoints to the first row and *tablepoints to the first element, if you derefer it than **tablewill return the value of the first element. In the following example you can see that *tableand tableis pointing to the same memory address.

这是一个双指针算术,因此table指向第一行并*table指向第一个元素,如果您取消引用它,**table则将返回第一个元素的值。在下面的示例中,您可以看到*tabletable指向相同的内存地址。

printf("%d\n",table);//2293476
printf("%d\n",*table);//2293476
printf("%d\n",**table);//1

In the memory all the rows of the table are following eachother. Because tablepointing to the first row if we add the row number where the needed element is in the table, we will get a pointer that points to that row. In this case *(table+row)will contain an address to the first element of the given row. Now we just have to add the column number like *(table+row)+column, and we get the adress of the element in the given row and column. If we derefer this, we get the exact value of this element.
So if we count the rows and columns from zero, we can get elements fromt the table like this:

在内存中,表的所有行都互相跟随。因为table如果我们在表中所需元素所在的位置添加行号,则指向第一行,我们将得到一个指向该行的指针。在这种情况下,*(table+row)将包含给定行的第一个元素的地址。现在我们只需要像 一样添加列号*(table+row)+column,我们就可以得到给定行和列中元素的地址。如果我们取消引用它,我们就会得到这个元素的确切值。
因此,如果我们从零开始计算行和列,我们可以像这样从表中获取元素:

int element = *(*(table+row)+column);

In the memory

记忆中

The table in the memory.

内存中的表。

回答by nbs

A 2D array is viewed as an array of 1D arrays. That is, each row in a 2D array is a 1D array. Therefore given a 2D array A,

二维数组被视为一维数组的数组。也就是说,二维数组中的每一行都是一维数组。因此给定一个二维数组A

int A[m][n].

In general,

一般来说,

A[i][j] = *(A[i]+j) 

also

A[i] = *(A+i)

so,

所以,

A[i][j] = *(A[i]+j) = * ( *(A+i)+j).

回答by Eric Wang

The previous answers already explained very well, I would just list pointer expressions according to my understanding, and compare them with the arr[i][j]format.

前面的回答已经解释的很好了,我就按照自己的理解列出指针表达式,和arr[i][j]格式对比一下。

Pointer expression of 2-D array:
    the array name itself is a pointer to first sub array,

    arr:
        will be pointer to first sub array, not the first element of first sub 
        array, according to relationship of array & pointer, it also represent 
        the array itself,

    arr+1:
        will be pointer to second sub array, not the second element of first sub 
        array,

    *(arr+1):
        will be pointer to first element of second sub array,
        according to relationship of array & pointer, it also represent second
        sub array, same as arr[1],

    *(arr+1)+2:
        will be pointer to third element of second sub array,

    *(*(arr+1)+2):
        will get value of third element of second sub array,
        same as arr[1][2],

Similar to 2-D array, multiple-Darray has similar expression.

与二维数组类似,多维数组也有类似的表达。

回答by CTastan

A practical way to access with a pointer.

一种使用指针访问的实用方法。

typedef struct
{
    int  Array[13][2];
} t2DArray;

t2DArray TwoDArray =
{
   { {12,5},{4,8},{3,6},{7,9},{3,2},{3,3},{3,4},{3,5},{3,6},{3,7},{4,0},{5,0},{5,1} }
};

t2DArray *GetArray;

int main()
{
    GetArray = &TwoDArray;
    printf("\n %d\n %d\n %d\n %d\n %d\n %d\n",
    GetArray->Array[0][0], 
    GetArray->Array[0][1], 
    GetArray->Array[1][0], 
    GetArray->Array[1][1], 
    GetArray->Array[2][0], 
    GetArray->Array[2][1]);

    getchar();
    return 0;
}

OUT

出去

12 5 4 8 3 6

12 5 4 8 3 6

回答by ankit gupta

#include <iostream>
using namespace std;

int main()
{
   //FOR 1-D ARRAY THROUGH ARRAY
   int brr[5]= {1,2,3,4,5};

   for(int i=0; i<5; i++)
   {
      cout<<"address ["<<i<<"] = "  <<&brr[i]<<" and value = "<<brr[i]<<endl;        
   }

   //FOR 1-D ARRAY THROUGH POINTER
   cout<<endl;  //  endl TO MAKE OUT PUT LOOK CLEAR AND COOL :)
   int (*q)=brr;

   for(int i=0; i<5; i++)
   {
      cout<<"address ["<<i<<"] = "  <<&brr[i]<<" and value = "<<*(q+i)<<endl; //(p[i][j])
   }

   cout<<endl;

   //FOR 2-D ARRAY THROUGH ARRAY        
   int arr[2][3] = {1,2,3,4,5,6};

   for(int i=0; i<2; i++)
   {
      for(int j=0; j<3; j++)
      {
         cout<<"address ["<<i<<"]["<<j<<"] = "  <<&arr[i][j]<<" and value = "<<arr[i][j]<<endl;
      }
   }

   //FOR 2-D ARRAY THROUGH POINTER        
   int (*p)[3]=arr; //  j value we give
   cout<<endl;

   for(int i=0; i<2; i++)
   {
      for(int j=0; j<3; j++)
      {
         cout<<"address ["<<i<<"]["<<j<<"] = "  <<(*(p+i)+j)<<" and value = "<<(*(*(p+i)+j))<<endl; //(p[i][j])
      }
   }
   return 0;
}

==============OUT PUT======================

//FOR 1-D ARRAY THROUGH ARRAY

address [0] = 0x28fed4 and value = 1
address [1] = 0x28fed8 and value = 2
address [2] = 0x28fedc and value = 3
address [3] = 0x28fee0 and value = 4
address [4] = 0x28fee4 and value = 5

//FOR 1-D ARRAY THROUGH POINTER

address [0] = 0x28fed4 and value = 1
address [1] = 0x28fed8 and value = 2
address [2] = 0x28fedc and value = 3
address [3] = 0x28fee0 and value = 4
address [4] = 0x28fee4 and value = 5

//FOR 2-D ARRAY THROUGH ARRAY

address [0][0] = 0x28fee8 and value = 1
address [0][1] = 0x28feec and value = 2
address [0][2] = 0x28fef0 and value = 3
address [1][0] = 0x28fef4 and value = 4
address [1][1] = 0x28fef8 and value = 5
address [1][2] = 0x28fefc and value = 6

//FOR 2-D ARRAY THROUGH POINTER

address [0][0] = 0x28fee8 and value = 1
address [0][1] = 0x28feec and value = 2
address [0][2] = 0x28fef0 and value = 3
address [1][0] = 0x28fef4 and value = 4
address [1][1] = 0x28fef8 and value = 5
address [1][2] = 0x28fefc and value = 6