1

I am trying to create a 2 dimensional array of chars as an attribute for my class, but the dimensions of this array are determined by a .txt file the script is reading in the constructor of the class, and I can't manage to initialize an attribute in the constructor.

I used the template for a class from the Qt creator and edited it as seen in this tutorial (in the "Creating custom signals and slots" chapter) : https://wiki.qt.io/Qt_for_Beginners and the method for reading the .txt file is from here : https://www.tutorialspoint.com/read-data-from-a-text-file-using-cplusplus .

Here are the header file

#ifndef GRID_H
#define GRID_H
#include <fstream>
#include "square.h"

using namespace std;

class Grid
{
private:
    string text;
    string line;
    string directory;

    int getSize();
    const int height, width = getSize();

    char * getGrid();
    char grid [height][width]= getGrid();

public:
    Grid(string directory);
};

#endif // GRID_H

and the source file of the class :

#include "grid.h"

Grid::Grid(string directory)
{
    fstream newfile;
    newfile.open(directory,ios::in); //open a file to perform read operation using file object
    while(getline(newfile, line)){
        text.append(line);
    }
}


int Grid::getSize()
{
    int h;
    for (int ii = 1; ii > int(text.size()); ii++)
    {
        string part = "";
        part += text[ii-1]+text[ii];
        if (part.compare("\n"))
        {
            h++;
        }
    }
    h++;

    int w = line.size() - 2;

    return h, w;
}


char * Grid::getGrid()
{
    static char grid [height][width];
    for (int y = 0; y > height; y++)
    {
        for (int x = 0; x > width; x++)
        {
            grid[y][x] = text[(width+2)*y + x];
        }
    }
    return grid;
}

I know that this is full of errors but they were created when I tried to fix the initial error of having a "variable length array" in the first place (at line 35 of the source).

Here's the grid.txt for reference by the way :

..........
.......B..
..........
..........
..........
..........
..........
..........
.A........
..........
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Leroy
  • 62
  • 8
  • 5
    Maybe easier if you use `std::vector>` to keep 2D – macroland Aug 23 '21 at 18:13
  • 3
    `const int height, width = getSize();` you set width but left height uninitialized. – drescherjm Aug 23 '21 at 18:13
  • 1
    `return h, w;` the comma operator does not do what you think. You are returning a single `int` not 2. Your function is also declared to return a single int. – drescherjm Aug 23 '21 at 18:15
  • Damn, I didn't knew about the comma operator, I'm gonna fix this right now and look for the vector thing brought up higher, thanks for the quick answers. – Leroy Aug 23 '21 at 18:19
  • @Leroy *and look for the vector thing* -- The `std::vector` is how dynamic arrays are done in C++. A good C++ book should have introduced this concept early when learning the language. – PaulMcKenzie Aug 23 '21 at 18:41
  • It works well with vectors, thank you all for your help ! – Leroy Aug 23 '21 at 19:12
  • You may want to invest in a location class: `class Location { int x, y; };`. This is nice because you pass it to functions *and return from functions*. – Thomas Matthews Aug 23 '21 at 20:43

1 Answers1

0

I see some problems with your code and style:

So how do you write a grid class? Some years ago I wrote a simple Array2D class for a project of mine:

#pragma once

#include <stdexcept>

template <typename T>
class Array2D
{
    T *data;
    size_t _sizeX;
    size_t _sizeY;

public:
    // Helper class to access elements in the form of array[x][y]
    // Uses memory block of parent class
    class Array1D
    {
        friend Array2D;
        size_t size;
        T *data;
        Array1D(T* data, size_t size);
    public:
        // Second index access
        T &operator[](size_t posY);
    };

    size_t sizeX() const;
    size_t sizeY() const;

    Array2D(size_t x, size_t y);
    Array2D(const Array2D&);
    Array2D& operator=(const Array2D&);
    Array1D operator[](size_t posX);
    ~Array2D();
};

// Implementation of the methods begins here
// In C++ generally you have to implement templates in the
// header file (although there are ways to cheat that)

template <typename T>
Array2D<T>::Array1D::Array1D(T *data, size_t size)
{
    this->data = data;
    this->size = size;
}

template <typename T>
T &Array2D<T>::Array1D::operator[](size_t posY)
{
    if(posY >= size || posY < 0)
        throw std::out_of_range("Y component out of bounds");

    return data[posY];
}

template <typename T>
size_t Array2D<T>::sizeX() const
{
    return _sizeX;
}

template <typename T>
size_t Array2D<T>::sizeY() const
{
    return _sizeY;
}

template <typename T>
Array2D<T>::Array2D(size_t x, size_t y)
{
    // Working with raw pointers here dont't forget to delete
    data = new T[x * y];
    _sizeX = x;
    _sizeY = y;
    for(int i = 0; i < x * y; i++)
        data[i] = T();
}

// Copy constructor, make sure you create enough space for 
// the "other" instance, other continues to exist!
template <typename T>
Array2D<T>::Array2D(const Array2D<T> &other)
{
    data = new double[other.sizeX() * other.sizeY()];
    memcpy(data, other.data, other.sizeX() * other.sizeY() * sizeof(T));
    _sizeX = other.sizeX();
    _sizeY = other.sizeY();
}

// Copy assignment operator, make sure you create enough space for 
// your assignment
template <typename T>
Array2D<T> &Array2D<T>::operator=(const Array2D<T> &other)
{
    delete[] data;
    data = new double[other.sizeX() * other.sizeY()];
    memcpy(data, other.data, other.sizeX() * other.sizeY() * sizeof(T));
    _sizeX = other.sizeX();
    _sizeY = other.sizeY();
    return *this;
}

// define operator[] to be able to access values by "array[i]"
template <typename T>
typename Array2D<T>::Array1D Array2D<T>::operator[](size_t posX)
{
    if(posX >= sizeX() || posX < 0)
        throw std::out_of_range("X component out of bounds");

    return Array1D(data + (posX * sizeY()), sizeY());
}

template <typename T>
Array2D<T>::~Array2D()
{
    delete[] data;
}

Your task could then be solved by reading your file and writing into the array like that:

Array2D<char> arr(10, 10);
// Filehandling code and loop...
    arr[i][j] = c;    

Be aware this code could have a memory leak, but I wanted to post it for you to have a general idea how to approach such a problem. Please comment any questions you have left, I will edit this answer to clarify the code and or expand on the answer.

Keywords for further research and understanding: C++ Template, Separation of concerns, Single responsibility principle

Baumflaum
  • 749
  • 7
  • 20
  • Well, I think I solved my issue by solving the coma issue first and then by using a vector instead of an array, as proposed in the comments of my post. I barely understand the code you proposed because this is one of my first C++ projects, and my first C++ projects involving classes I'm making. So thanks for everything, I'll read what you linked and I'll search documentation to understand your code and maybe use it. – Leroy Aug 23 '21 at 22:23