C ++通过指针访问2D数组中的连续值

时间:2016-03-05 06:11:10

标签: c++ arrays pointers multidimensional-array

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

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;

它指向下一个元素,它本身就是数组中的下一行,因为它是一个2D数组。我理解,但我想知道是否有任何可以做的事情,以便指针指向当前行中的下一个“元素”,而不是指向下一行?

5 个答案:

答案 0 :(得分:3)

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

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

enter image description here

正如我经常想解释的那样,C ++中的多维数组只是一维数组的特殊情况,只是它的元素类型本身就是一个数组类型。

在您的情况下,int是一个大小为3的数组,其元素类型为numbers。整个事物在记忆中是连续的,这意味着所有元素彼此相邻放置而两者之间没有任何孔。 “行”和“列”的概念实际上只是一种错觉,它是由int[3]符号如何通过在引擎盖下执行指针算术来访问各个数组元素而提供的。

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

enter image description here

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

因此,“列”的概念只能通过首先遍历“行”,在非常间接的情况下通过操作而不是通过数据类型在非常间接的情况下实现。例如:

int[3]

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

这是一个相当简单的示例(没有错误处理,硬编码值和没有// 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]; } 操作):

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才能创建该类的新对象。

结合C ++运算符重载,您甚至可以实现原始的Matrix表示法。您实际上只是为[][]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: Column(Column const&) = delete; Column& operator=(Column const&) = delete; Column(Column&& src) = default; 返回get_columnColumn&&返回值以使其编译。

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

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] << " "; } 这样的大评论在实践中同样有效。

答案 1 :(得分:1)

要通过指针访问第二列的值,您可以使用指向数组第一个元素的指针和公式 *(row*numberofelementsinarow+(pointer+column) 来访问数组中所需的任何内容,仅更改所需的行和列那个公式:

const int rows=3;
const int columns=3;
int numbers[rows][columns] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
int * p_numbers;
p_numbers=&numbers[0][0];
for (int i=0; i<=rows-1; i++) {std::cout << *(i*columns+(p_numbers+1)) <<"\n";};

输出为: 2 5 8

答案 2 :(得分:0)

试试这段代码:

int numbers[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
cout << *(*(numbers+2) + 1); 

答案 3 :(得分:0)

据我所知,您在访问多维数组的所有成员时遇到问题。以下是您如何访问所有这些内容的示例,您可以根据自己的使用情况进行调整。

#include <iostream>

int main() {
    int numbers[3][3] = {1, 30, 3,
                         4, 40, 6,
                         7, 50, 9};

    for(int x=0;x<3;x++) {

        int* row = numbers[x]; // Decay array to int pointer, pointing to numbers[x][0]

        for(int y=0;y<3;y++) {

            std::cout<<row[y]<<" ";

        }
        std::cout<<"\n";
    }
}

输出:

1 30 3
4 40 6
7 50 9

答案 4 :(得分:-1)

数字是整数的二维数组,这意味着它是3个1D 子数组的1D数组。您应该使用p访问子数组,然后访问该1D数组中的第二个元素。下面的代码段应该解释这个想法:

int * p = 0;
p = numbers[0]; // Now array p = {1, 2, 3}
std::cout << p[1] << std::endl; // '2'

p = numbers[1]; // Now array p = {4, 5, 6}
std::cout << p[1] << std::endl; // '5'

p = numbers[2]; // Now array p = {7, 8, 9}
std::cout << p[1] << std::endl; // '8'