如何在C/C++中获取多维数组的列?

4
int matrix[9][9],*p;
p=matrix[0]; 

这段代码可以获取matrix的第一行,但是如何获取第一列呢?我试过使用p=matrix[][0];,但是不行。另外,我不理解为什么下面的代码会出现编译错误?

int matrix[9][9],p[9];  // it looks really ugly, byt why it doesn't work ?
p=matrix[0];            // compiler gives "invalid array assigment"

这是因为多维数组是数组的数组,我们应该将matrix [i] [j]解释为第i个嵌套数组中的第j个元素。

9个回答

16
在C/C++中,多维数组实际上是作为一维数组来存储的(在内存中)。你的二维矩阵以行优先的顺序存储为一维数组。这就是为什么提取其中一列不容易并且默认情况下不提供的原因。在内存中没有一个连续的数组,你可以得到一个指向它的指针,表示多维数组的一列。参见下面的代码:
当你执行p=matrix[0]时,你只是获取第一个元素matrix[0][0]的指针,这使你认为你获得了指向第一行的指针。实际上,它是指向存储matrix的整个连续数组的指针,如下所示:
matrix[0][0]
matrix[0][1]
matrix[0][2]
.
.
matrix[1][0]
matrix[1][1]
matrix[1][2]
.
.
matrix[8][0]
matrix[8][1]
matrix[8][2]
.
.
matrix[8][8]

如上所示,任何一列的元素都是由相应行中的其他元素分隔开的。

因此,顺便提一下,使用指针p,您可以遍历整个矩阵的81个元素(如果您愿意的话)。


“存储为一维数组”这种说法有点奇怪。它们只是数组的数组,所以我承认内存布局相似,但语义有些不同。 - Carl Norum
语义确实不同,我指的是内存布局。我会重新编写那部分内容。 - meyumer
1
@meyumer 错误了,抱歉,它们确实在内存中相邻。 - Qbik

8
您可以使用循环来获取第一列,例如:
for(int i = 0; i < 9; i++)
{
    printf("Element %d: %d", i, matrix[i][0]);
}

我认为这个任务无法正常运行,因为你试图将不是地址的东西赋给指针。(抱歉,这是c代码)

1
抱歉,但我想要通用的解决方案,不过你的第一篇帖子值得鼓励。+1 - Qbik
我认为应该是 matrix[i][0],因为 C 和 C++ 将 0 作为第一个元素。 - Thomas Matthews
这是做法。你必须循环遍历数组以获取所需的元素。没有简单的方法,因为如上所述,这些元素不位于连续的内存位置中。 - KeyC0de

4
指定 matrix[81]matrix[9][9] 没有区别。 matrix[r][c] 意思与 matrix[9*r+c] 相同。 还有其他更适合多维数组的容器,例如 boost::multi_array 。 请参阅http://www.boost.org/doc/libs/1_53_0/libs/multi_array/doc/index.html。 将裸数组视为分配一段连续的内存。程序员需要自己处理这块内存。数组的名称,例如 matrix 是指向这个分配的内存块的第一个元素的指针。然后,*(matrix+1) 相当于 matrix[0][1]matrix[1]

你确定 matrix[81]matrix[9][9] 是一样的吗?我的理解是 matrix[9][9] 相当于 int * matrix[9],这意味着它是指针的容器,而不是连续的内存位置。 - Thomas Matthews
1
当你问的时候,我变得不确定了。所以我查了一下,现在我很确定了。例如,请参见此处:https://dev59.com/62sz5IYBdhLWcg3wmpBb - AxelOmega
1
我需要对此进行小修正。从内存布局的角度来看,没有区别。但是如果编译器有关于原始数组声明的信息,则在解释方式上会有所不同。例如,matrix[R][C]可以从指针int* mp (int*)matrix线性访问,需要进行转换以避免警告。您可以将行访问为int (row_ptr*)[C] = matrix,然后指针算术运算将确保您移动整个行,例如(row_ptr+1)将指向第二行。还要注意值的访问必须是**(row_ptr+1)。但是,在内存中没有指针。 - AxelOmega

2

p是一个整型数组,matrix[0]是一个指针..


@Qbik *(matrix[0]) 是一个整数,你不能将整数赋值给整数数组。 - zzk
现在我明白了!我已经打印了*p并且数据是正确的,但它只是指向单个整数的指针。 - Qbik

1

matrix本身就是数组中最接近列的东西,因为(matrix + 1)[0][0]matrix[1][0]是相同的。


1
这是一个建立10x10数组并打印第二列的程序:
#include <iostream>

using namespace std;

int main()
{
   int aa[10][10];

   for(int i = 0; i<10; i++)
       for(int j = 0; j<10; j++)
           aa[i][j] = i*10+j;
   
   int col = 2;

   // pointer to a length-10 1d array
   int (*p)[10] = (int (*)[10])&(aa[0][col]);

   for(int i =0; i<10; i++)
      cout << *(p[i]) << endl;

   return 0;
}

与 `aa[row][2]` 的区别在于使用指向长度为10的一维int数组的指针 `int (*p)[10]`。有关 `int (*p)[10]` 的更多上下文,请参见 此答案
`p` 保存了一维数组 `{2, 3, 4, 5, 6, 7, 8, 9, 10, 11}` 的地址。而 `p+1` 则保存了一维数组 `{12, 13, 14, 15, 16, 17, 18, 19, 20, 21}` 的地址。`*(p[1])` 或 `*(*(p+1))` 可以访问一维数组的第一个值。

1
能够简要解释一下这个程序是如何工作的/如何解决问题,以及它与现有答案的不同之处,会很好。 - starball

0

对于静态声明的数组,您可以像连续的1D数组一样访问它们,p = matrix[0]将给您第一行的第一列。然后可以像 p[i]*(p+i) 或者 p[current_raw * raw_size + current_column] 一样访问1D数组。

如果用 **p 表示2D数组,则会被解释为指向1D数组的指针数组,这时情况会变得棘手。


0
如果您想让矩阵在连续的位置上,将其声明为一维数组,并自行执行行和列计算:
int contiguous_matrix[81];

int& location(int row, int column)
{
  return contiguous_matrix[row * 9 + column];
}

您也可以迭代每一行的每一列:

typedef void (*Function_Pointer)(int&);

void Column_Iteration(Function_Pointer p_func, int row)
{
  row = row * MAXIMUM_COLUMNS;
  for (unsigned int column = 0; column < 9; ++column)
  {
    p_func(contiguous_matrix[row + column]);
  }
}

0

我不知道这是否是一种高效的解决方案,但通过这种方式我能够获取该列的数据。

int arr[9][2] = { {2,  57}, {3,  66}, {4,  73}, {5,  76}, {6,  79}, {7,  81}, {8,  90}, {9,  96}, {10, 100}};

int c[18];
int co = 0;
for (auto & i : arr) {
    for (int j : i) {
        c[co++] = j;
    }
}

for (int i = 0; i < co; ++i) {
    if (i % 2 != 0)
        std::cout << c[i] << " ";
}

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