gpt4 book ai didi

C++ 通过指针访问二维数组中的连续值

转载 作者:行者123 更新时间:2023-11-30 03:43:57 25 4
gpt4 key购买 nike

我了解如何通过指针访问二维数组中的元素,但是在访问数组行中的第二个“元素”并使用它进行比较时遇到了一些麻烦。例如,如果我有数组:

int numbers[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

我需要访问元素 2、5 和 8 来获得另一个功能。但是当我声明一个指针并将其指向数组中的下一个元素时,如下所示:
int (*p)[3] = &(numbers[1]);

或者
int (*p)[3] = numbers + 1;

它指向下一个元素,本身就是数组中的下一行,因为它是一个二维数组。我明白,但我想知道是否有什么可以做的,使指针指向当前行中的下一个“元素”,而不是指向下一行?

最佳答案

首先,让我们了解 C++ 中数组的根本问题。

您的阵列 int numbers[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};在内存中可以这样描绘,假设 sizeof(int)是 4(在您的系统上可能是也可能不是,但 C++ 没有规定 int 的内存大小,并且 4 比 8 更容易绘制):

enter image description here

正如我经常喜欢解释的,C++ 中的多维数组只是一个 一维数组的特例 ,只是它的元素类型本身是一个数组类型。

在您的情况下,numbers是一个大小为 3 且元素类型为 int[3] 的数组.整个事物在内存中是连续的,这意味着所有元素都彼此相邻放置,中间没有任何孔。 “行”和“列”的概念实际上只是一种错觉[] 如何提供表示法通过在后台执行指针运算来访问各个数组元素。

获得指向“行”的指针很容易,因为“行”的元素都彼此相邻。例如,指向第二“行”的指针只是指向“4”元素的指针,因为“4”、“5”和“6”元素构成int[3]。 “行”彼此直接相邻:

enter image description here

现在你想要的是一个指向“列”的指针。如图所示,在如此低的语言水平上,这是完全不可能的。例如,第二个“列”由“2”、“5”和“8”元素组成。但是,很明显,没有一个地方可以让指针指向这三个元素在内存中彼此相邻的位置。

因此,“列”的概念只能在如此低的语言级别上非常间接地实现,通过操作而不是通过数据类型 ,首先遍历“行”。例子:

// print 2nd column:
int const column_index = 1;
for (int row_index = 0; row_index < 3; ++row_index)
{
std::cout << numbers[row_index][column_index];
}

然而,这是 C++,一种能够很好地抽象出这种低级机制的语言。您的问题的一种解决方案是创建一个自定义数据类型,它在内部执行间接并保持“行和列”错觉。你甚至不需要一个二维数组。一维就足够了。

这是一个相当简单的例子(没有错误处理、硬编码值和没有 const 操作):
#include <iostream>

class Column
{
public:
int& element(int row_index)
{
return array[row_index * width + column_index];
}

private:
friend class Matrix;

Column(int width, int(&array)[9], int column_index) :
width(width),
array(array),
column_index(column_index)
{
}

int width;
int(&array)[9];
int column_index;
};

class Matrix
{
public:
Matrix() : width(3), array {1, 2, 3, 4, 5, 6, 7, 8, 9 }
{}

Column column(int column_index)
{
return Column(width, array, column_index);
}

private:
int width;
int array[9];

};

int main()
{
Matrix m;

for (int column_index = 0; column_index < 3; ++column_index)
{
for (int row_index = 0; row_index < 3; ++row_index)
{
std::cout << m.column(column_index).element(row_index) << " ";
}
std::cout << "\n";
}
}
Column在本例中称为 代理类 . friend声明和私有(private)构造函数确保只有 Matrix可以创建类的新对象。

结合C++运算符重载,甚至可以实现原来的 [][]符号。您实际上只是给 column 赋予不同的名称和 element成员函数:
#include <iostream>

class Column
{
public:
int& operator[](int row_index)
{
return array[row_index * width + column_index];
}

private:
friend class Matrix;

Column(int width, int(&array)[9], int column_index) :
width(width),
array(array),
column_index(column_index)
{
}

int width;
int(&array)[9];
int column_index;
};

class Matrix
{
public:
Matrix() : width(3), array {1, 2, 3, 4, 5, 6, 7, 8, 9 }
{}

Column operator[](int column_index)
{
return Column(width, array, column_index);
}

private:
int width;
int array[9];

};

int main()
{
Matrix m;

for (int column_index = 0; column_index < 3; ++column_index)
{
for (int row_index = 0; row_index < 3; ++row_index)
{
std::cout << m[column_index][row_index] << " ";
}
std::cout << "\n";
}
}

你最初的目标现在实现了,因为你可以完美地创建一个对象来代表一整列:
Matrix m;

Column second_column = m[1];

for (int row_index = 0; row_index < 3; ++row_index)
{
std::cout << second_column[row_index] << " ";
}

但我们还没有。 Column目前是一个有点危险的类,因为它不能安全地从函数中返回。对矩阵数组的内部引用很容易变成悬空的:
Column get_column() // dangerous, see below!
{
Matrix m;

Column second_column = m[1];

// m is destroyed, but reference to its array
// member is kept in the returned Column, which
// results in undefined behaviour:
return second_column;
}

这类似于迭代器对象通常不打算保留更长的时间。

您可以为 Column 禁用复制。并给它一个私有(private)的移动构造函数,但是:
private:
Column(Column const&) = delete;
Column& operator=(Column const&) = delete;
Column(Column&& src) = default;

这强烈地阻止了来自上面的不良行为,因为实际上必须使 get_column返回 Column&&std::move使其编译的返回值。

就我们上面的输出循环而言,它看起来像这样:
Matrix m;

auto&& second_column = m[1];

for (int row_index = 0; row_index < 3; ++row_index)
{
std::cout << second_column[row_index] << " ";
}

这一切是否值得麻烦,我不知道。也许像 // treat Column like an iterator, making sure that it never outlives the Matrix it refers to 这样的大胖评论在实践中同样有效。

关于C++ 通过指针访问二维数组中的连续值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35810783/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com