【问题标题】:Setting class level 2D Array variable to passed in value - C++将类级别 2D 数组变量设置为传入值 - C++
【发布时间】:2014-02-10 15:06:45
【问题描述】:

我正在尝试制作一个解决迷宫的程序,虽然算法是正确的(至少在我的脑海中),但我遇到了二维数组的障碍。我来自 C# 和 Java,所以语法让我很伤心。

这是一个 SSCCE:

//Main.cpp

#include "MazeSolver.h"

int main()
{
     MazeSolver mazeSolver;

     char maze[51][51] = { }; // Not bothering to show code for populating the array

     mazeSolver.setMaze(maze);
}

//MazeSolver.cpp

#include "MazeSolver.h"

MazeSolver::MazeSolver() { }

void MazeSolver::setMaze(char maze[51][51])
{
     this->maze = maze;
}

//MazeSolver.h

#ifndef _MAZESOLVER_H
#define _MAZESOLVER_H

class MazeSolver
{
private:
     char **maze; // This is likely the problem, I'm at wits end in regards to
                  // what notation is needed here.  I do not want to hard-copy
                  // the entire array, I just need to access it (via pointer)
                  // I've also tried just using char maze[51][51] here, char *maze, etc...
public:
      MazeSolver();
      void setMaze(char maze[51][51]);
}

【问题讨论】:

  • 错误的指针类型。 Type ** 在寻址方面等同于 Type [N][M]Type (*)[M] 会更好,在你的情况下 char (*maze)[51];。也就是说,它(维度)作为模板参数可能会更稳健,但这可能是您研究的一个方法。您是要复制输入时的迷宫,还是只是指向/引用原始迷宫?
  • @David:你的代码有什么问题?是编译失败,还是有意外的运行时行为?
  • 只是对原始迷宫的引用,以便我可以访问这些值。真的不需要完整的硬拷贝,我只需要一种访问所述数组内容的方法。 @WhozCraig 我刚刚尝试了您的修复,现在似乎正在编译,我想我应该从这里开始。感谢您的帮助!
  • SSCCE +1(尽管文件可能已合并)
  • 在 C++11 中以更直观的语法使用 std::array<std::array<char, 51>, 51> maze

标签: c++ arrays pointers 2d


【解决方案1】:

您不能将二维数组 (array[ROWS][COLUMNS]) 分配(或转换)到指向指针的指针(又名 **),因为二维数组的内存布局(可能)与指针的指针的内存布局非常不同可以指向。

查看this thread 了解有关此主题的更多信息。

如果建议您使用事实上的 C++ 标准容器 std::vector,而不是普通数组:

class MazeSolver
{
    std::vector<std::vector<char>> maze;

    void setMaze( const std::vector<std::vector<char>>& new_maze )
    {
        maze = new_maze;
    }
};

请注意,向量的大小默认为 0(在其初始化时),因此您应该用元素填充它:

for( std::size_t i = 0 i < ROWS ; ++i )
{
    maze.push_back( std::vector<char>() );

    for( std::size_t j = 0 ; j < COLUMNS ; ++j )
       maze[i].push_back( ' ' );
}

但是,C++11(该语言的当前迭代)有一个 std::array 容器,它类似于 C 数组,但具有其他标准库容器的接口:

std::array<char,ROWS*COLUMNS> maze;

【讨论】:

  • 我会更进一步,建议ROWS*COLUMNS 的向量(2D 索引通过继承覆盖在顶部)
  • @LightnessRacesinOrbit 我不想将 OP 与许多概念混淆。 OP 显然是 C++ 新手,所以我使用了简单的概念和措辞。这个答案不包括技术信息或更简洁(和/或正确)的矢量用法。我试图揭露 [][] --> ** 问题并建议 OP 了解标准库容器,而不是使用低级功能(如指针或普通数组)。当他明白这一点时,我们可以向他展示更多的技巧和使用模式。
  • 但是您已经引入了一个大小为ROWS*COLUMNS 的数组和向量。我认为将两者结合起来并不容易。
  • @LightnessRacesinOrbit 那是我的错。 std::array&lt;std::array&lt;char,COLUMNS&gt;,ROWS&gt; 和稍后谈论更好的一维替代方案怎么样?
  • 这符合您所说的方法。但我坚持... ew :)
【解决方案2】:

&lt;rant&gt;

这是 C++ 的怪癖之一。

C++ 2D 数组不是锯齿状数组。当您声明 char maze[51][51] 时,它实际上分配了 1 个 51*51 成员长的连续数组。 sizeof(maze) == 51*51。当您取消引用一个值maze[a][b] 时,它实际上所做的是*(maze+51*a+b)。这一切都在幕后。

Jagged Array 是一个数组数组,一个 char**。在这种情况下,您有一个包含 51 个指针大小 == (51*sizeof(void*)) 的数组。在每个位置,指针指向一个完全不同的内存位置,分配给 51 个成员。

这很烦人,因为您不能只转换两者,即使通过强制转换也是如此。您必须处理奇怪的语法,例如char (*maze)[51] 才能获得指向二维数组的指针。

更烦人的是以下情况:

int foo(int maze[51][51])
{
   return sizeof(maze);
}

int maze[51][51];

int main(int argc, char** argv)
{
   std::cout << sizeof(maze) << std::endl;//return 51*51*sizeof(int);
   std::cout << foo(maze) << std::endl;//return 8, sizeof(void*);
}

所以它隐式地通过引用而不是值传递,这与 C++ 的所有其余部分相反。

&lt;/rant&gt;

tl;博士;

指向二维数组的指针的正确语法是char (*maze)[51];。您的语法适用于锯齿状数组(数组的数组),这在 C++ 中是不同的。

【讨论】:

  • 公平地说,多维数组默认为锯齿状是非常低效和不合适的。另外,这不是参考,而是指针。事实上,你在这里没有任何参考资料。只是说。
  • @LightnessRacesinOrbit 完全正确,但如果我们一开始就想到冲突就好了,我主要是在咆哮。您的类型可能是一种特殊类型,int[51,51] maze,它至少具有不同的语法/显式类型。我的意思是,现在不能改变它,但是是的。
  • @WhozCraig 确实在评论中解决了我的问题,但应该在解决后关闭。虽然您的回答确实帮助我理解了 C++ 中数组的差异(和怪癖),所以我将其标记为答案;)感谢您的帮助!
  • passing around pointers is passing by reference 根本不是这样。我的意思是,对于“参考”的某些含义,当然,但该术语已经被 C++ 中的其他东西所采用。如果你需要一个通用术语,就叫它“通过句柄”
  • @MadScienceDreams 指针未通过引用传递。它们用于在不直接提供该功能的语言(如 C 或 Java)中模拟按引用传递。在 Java 和 C 中,一切都是按值传递的,但事物的指针(也称为内存地址)是按值传递的,以获取原始对象的句柄。
猜你喜欢
  • 2021-10-04
  • 1970-01-01
  • 2017-04-14
  • 1970-01-01
  • 2016-10-05
  • 2021-08-05
  • 1970-01-01
  • 2018-10-31
  • 2013-05-19
相关资源
最近更新 更多