1

I'm attempting to make a maze-solving program, and while the algorithm is sound (at least in my head), I've been running into a roadblock with 2D arrays. I'm coming from C# and Java, so the syntax is giving me grief.

Here's an 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]);
}
  • 1
    Wrong pointer type. `Type **` is **not** equivalent to `Type [N][M]` for addressing. `Type (*)[M]` would be better, in your case `char (*maze)[51];`. that said, it (the dimensions) likely would be more robust as template parameters, but that may be a ways off in your studies. Do you want to *copy* the maze on-input, or just point-to/reference the original ? – WhozCraig Feb 10 '14 at 15:08
  • @David: What is the problem with your code ? Does it fail to compile, or do you have unexpected runtime behavior ? – Martin J. Feb 10 '14 at 15:16
  • Just a reference to the original maze such that I can access the values. A full on hard-copy really isn't necessary, I just need a way to access the contents of said array. @WhozCraig I've just tried your fix and it seems to be compiling now, I think I should be good from here. Thanks for the help! – David Griffith Feb 10 '14 at 15:24
  • +1 for SSCCE (though the files could have been merged) – Lightness Races in Orbit Feb 10 '14 at 15:32
  • Use `std::array, 51> maze` in C++11 with a more intuitive syntax. – Jarod42 Feb 10 '14 at 16:15

2 Answers2

2

You cant assign (Or convert) 2d arrays (array[ROWS][COLUMNS]) to pointers to pointers (aka **) because the memory layout of a 2d array is (could be) very different to the memory layout the pointer of pointers could point to.

Check this thread for more info about this topic.

If suggest you to use the de facto C++ standard container, std::vector, instead of a plain array:

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

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

Note that a vector has size 0 by default (At the point of its initialization), so you should fill it with elements:

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( ' ' );
}

However, C++11 (The current iteration of the language) has a std::array container which is like a C array but with the interface of other Standard Library Containers:

std::array<char,ROWS*COLUMNS> maze;
Community
  • 1
  • 1
Manu343726
  • 13,969
  • 4
  • 40
  • 75
  • I would go further and suggest a vector of `ROWS*COLUMNS` (with the 2D indexing overlaid on top by inheritance) – Lightness Races in Orbit Feb 10 '14 at 15:34
  • @LightnessRacesinOrbit I don't wan't to confuse OP with many concepts. OP is clearly a C++ newbie, so I used simple concepts and wording. This answer does not cover technical information or more concise (And/or correct) usage of vector. I'm trying to expose the [][] --> ** problem and suggesting OP to learn about standard library containers instead of using low level features (like pointers or plain arrays). When he understands that, we could show him more tips and usage patterns. – Manu343726 Feb 10 '14 at 15:39
  • But you already introduced an array of size `ROWS*COLUMNS`, and vectors. I don't think it's a reach to combine the two. – Lightness Races in Orbit Feb 10 '14 at 15:42
  • @LightnessRacesinOrbit my fault then. What about a `std::array,ROWS>` and later talk about the better one dimensional alternative? – Manu343726 Feb 10 '14 at 15:44
  • That fits the approach you said you'd take here. but I maintain... ew :) – Lightness Races in Orbit Feb 10 '14 at 16:13
1

<rant>

This is one of the weird quirks of C++.

C++ 2D arrays are NOT jagged arrays. When you declare char maze[51][51], it actually allocates 1 contiguous array 51*51 members long. sizeof(maze) == 51*51. When you dereference a value, maze[a][b], what it actually does is *(maze+51*a+b). All this is under the hood.

A Jagged Array is an array of arrays, a char**. In this case, you have an array of 51 pointers size == (51*sizeof(void*)). In each position, the pointer points to a completely different memory location, allocated to 51 members long.

This is ANNOYING because you can't just convert the two, even by casting. You have to deal with weird syntax, such as char (*maze)[51] to get a pointer to the 2D array.

Whats even more annoying is the following happens:

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*);
}

So it implicitly passes by reference, not by value, which is opposite all the rest of C++.

</rant>

tl;dr;

The correct syntax for a pointer to a 2D array is char (*maze)[51];. Your syntax is for a jagged array (arrays of arrays) which is NOT the same thing in C++.

IdeaHat
  • 7,641
  • 1
  • 22
  • 53
  • 2
    To be fair, for multi-dimensional arrays to be jagged by default would be incredibly inefficient and inappropriate. Also, that's not a reference, but a pointer. In fact, you have no references here whatsoever. Just saying. – Lightness Races in Orbit Feb 10 '14 at 15:33
  • @LightnessRacesinOrbit Completely true, but it would have been nice if we thought of the conflict to begin with, I'm mostly ranting. Your type could be a special type, `int[51,51]` maze, it would at least have different syntax/explicit type. I mean, can't change it now, but yeah. – IdeaHat Feb 10 '14 at 15:36
  • @WhozCraig did fix my issue in a comment, but this should be closed as it is resolved. Your answer though really helped my understanding of the differences (and quirks) of Arrays in C++, so I'll mark this as the answer ;) Thanks for the help!! – David Griffith Feb 10 '14 at 15:38
  • @LightnessRacesinOrbit Also changing the thing about references, cuz while passing around pointers is passing by reference, I agree that the confusion is real. – IdeaHat Feb 10 '14 at 15:39
  • 1
    `passing around pointers is passing by reference` Simply not the case. I mean, for some meaning of "reference", sure, but that term is already taken by something else in C++. If you need a generic term, call it "passing by handle" – Lightness Races in Orbit Feb 10 '14 at 15:40
  • @LightnessRacesinOrbit "Reference Type" is something in C++, but "Passing by Reference" is a general programming concept that is important for all languages, though we are (literally) arguing semantics :-P – IdeaHat Feb 10 '14 at 15:43
  • 2
    @MadScienceDreams Pointers are not passing by reference. They are used **to emulate pass by reference** in languages which don't offer that functionality directly, like C or Java. In Java and C, everything is passed by value, but pointers (aka memory addresses) of things are passed by value to get a handle of the original object. – Manu343726 Feb 10 '14 at 15:46
  • @Manu343726 I'm not sure why if the reference is passed by value, and the reference itself is a value, then the value it is referencing (pointing to) is not passed by reference. We don't call `*(foo_ptr)` the "depointer" operator, we call it "dereference" cuz a pointer is a reference to something else. It just so happens that in C/C++, pointer are references that matches 1 to 1 with a memory location, and thus we can do more with them. – IdeaHat Feb 10 '14 at 15:56
  • C/C++? What language is that? I know C and know C++, which are very different languages... – Manu343726 Feb 10 '14 at 15:59
  • @Manu343726 I can change it to "C and C++" if that'll help your ad hominem – IdeaHat Feb 10 '14 at 16:00
  • The naming of "dereference" is due to legacy, and it does not mean that pointers shall be called references in C++. You are using a generic, high-level term "reference", which is very confusing in C++, which has its own language features called _references_. The introduction of this feature all but demolished the old phrase "pass by reference" when describing the use of pointers. Some 20 years ago. – Lightness Races in Orbit Feb 10 '14 at 16:19
  • In Java it is pass-by-value-reference.. The pointer to the object is passed by value (an opaque copy is made) so you cannot change what it points to (or references) but you can change the properties of the object.. In C++, it just gets out of hand and confusing sometimes.. This is why I hate terminology and language lawyering.. I prefer to say "pass the address". – Brandon Feb 10 '14 at 16:39