private member data not being available to public member function [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have the code below.
When I have main Run() function run the ResetTrackingTable() function. The ResetTrackingTable() calls 0 for my_n_rows and my_n_cols instead of accessing the existing numbers stored in the private member data.
Why is that? It seems like it's making a new instance of the function...
public:
WordGame();
void Run(Board &gameBoard, Trie &library, int wordlengthlim);
void CheckNode(int row, int col, Board & gameBoard, Trie &Library);
void ExitNode();
void ResetTrackingTable(int rows, int cols);
void PrintWordList();
private:
std::vector<std::string> my_WordList;
int my_wordlength;
int my_wordlengthlimit;
std::stringstream currentword;
int my_n_cols;
int my_n_rows;
std::vector<std::vector<bool>> my_TrackingTable;
};
void WordGame::Run(Board & gameBoard, Trie &Library, int wordlengthlim)
{
//std::stringstream word;
//std::string tempword;
//word.str("");
currentword.str(""); //Clear current word
int my_wordlengthlimit = wordlengthlim; //Import limit word length
int my_wordlength = 0; //Set current word length
int my_n_rows = gameBoard.numRows(); //Import number of rows
int my_n_cols = gameBoard.numCols(); //Import number of cols
for (int i_row = 0; i_row < my_n_rows; ++i_row)
{
for (int i_col = 0; i_col < my_n_cols; ++i_col)
{
//Actually, when should it be reset?
this->ResetTrackingTable(); //Initialize the tracking table as all false before each new starting char.
CheckNode(i_row, i_col,gameBoard,Library); //Check each beginning node.
}
}
}
void WordGame::ResetTrackingTable()
{
for (int i_row = 0; i_row < my_n_rows; ++i_row)
{
my_TrackingTable.push_back(std::vector<bool> {false});
for (int i_col = 1; i_col < my_n_cols; ++i_col)
{
my_TrackingTable[i_row].push_back(false); //Initialize the tracking table as all false.
}
}
}

These lines of code:
int my_n_rows = gameBoard.numRows(); //Import number of rows
int my_n_cols = gameBoard.numCols(); //Import number of cols
are declaring new variables inside the Run function.
If you want to refer to the member variables instead, drop the int declarator:
my_n_rows = gameBoard.numRows(); //Import number of rows
my_n_cols = gameBoard.numCols(); //Import number of cols
You need to do this for all your member variables that you want to use.
Also, your declaration:
void ResetTrackingTable(int rows, int cols);
doesn't match its definition:
void WordGame::ResetTrackingTable() { // ...
you need to have the same number of parameters of the same type.

Related

C++ Declaring arrays in class and declaring 2d arrays in class

I'm new with using classes and I encountered a problem while delcaring an array into a class. I want to initialize a char array for text limited to 50 characters and then replace the text with a function.
#ifndef MAP_H
#define MAP_H
#include "Sprite.h"
#include <SFML/Graphics.hpp>
#include <iostream>
class Map : public sprite
{
private:
char mapname[50];
int columnnumber;
int linenumber;
char casestatematricia[];
public:
void setmapname(char newmapname[50]);
void battlespace(int column, int line);
void setcasevalue(int col, int line, char value);
void printcasematricia();
};
#endif
By the way I could initialize my 2d array like that
char casestatematricia[][];
I want later to make this 2d array dynamic where I enter a column number and a line number like that
casestatematricia[linenumber][columnnumber]
to create a battlefield.
this is the cpp code so that you have an idea of what I want to do.
#include "Map.h"
#include <SFML/Graphics.hpp>
#include <iostream>
using namespace sf;
void Map::setmapname(char newmapname[50])
{
this->mapname = newmapname;
}
void Map::battlespace(int column, int line)
{
}
void Map::setcasevalue(int col, int line, char value)
{
}
void Map::printcasematricia()
{
}
thank you in advance.
Consider following common practice on this one.
Most (e.g. numerical) libraries don't use 2D arrays inside classes.
They use dynamically allocated 1D arrays and overload the () or [] operator to access the right elements in a 2D-like fashion.
So on the outside you never can tell that you're actually dealing with consecutive storage, it looks like a 2D array.
In this way arrays are easier to resize, more efficient to store, transpose and reshape.
Just a proposition for your problem:
class Map : public sprite
{
private:
std::string mapname;
int columnnumber;
int linenumber;
std::vector<char> casestatematricia;
static constexpr std::size_t maxRow = 50;
static constexpr std::size_t maxCol = 50;
public:
Map():
casestatematricia(maxRow * maxCol, 0)
{}
void setmapname(std::string newmapname)
{
if (newmapname.size() > 50)
{
// Manage error if you really need no more 50 characters..
// Or just troncate when you serialize!
}
mapname = newmapname;
}
void battlespace(int col, int row);
void setcasevalue(int col, int row, char value)
{
// check that col and line are between 0 and max{Row|Column} - 1
casestatematricia[row * maxRow + col] = value;
}
void printcasematricia()
{
for (std::size_t row = 0; row < maxRow; ++row)
{
for (std::size_t col = 0; col < maxCol; ++col)
{
char currentCell = casestatematricia[row * maxRow + col];
}
}
}
};
For access to 1D array like a 2D array, take a look at Access a 1D array as a 2D array in C++.
When you think about serialization, I guess you want to save it to a file. Just a advice: don't store raw memory to a file just to "save" time when your relaunch your soft. You just have a non portable solution! And seriously, with power of your computer, you don't have to be worry about time to load from file!
I propose you to add 2 methods in your class to save Map into file
void dump(std::ostream &os)
{
os << mapname << "\n";
std::size_t currentRow = 0;
for(auto c: casestatematricia)
{
os << static_cast<int>(c) << " ";
++currentRow;
if (currentRow >= maxRow)
{
currentRow = 0;
os << "\n";
}
}
}
void load(std::istream &is)
{
std::string line;
std::getline(is, line);
mapname = line;
std::size_t current_cell = 0;
while(std::getline(is, line))
{
std::istringstream is(line);
while(!is.eof())
{
char c;
is >> c;
casestatematricia[current_cell] = c;
++current_cell;
}
}
}
This solution is only given for example. They doesn't manage error and I have choose to store it in ASCII in file. You can change to store in binary, but, don't use direct write of raw memory. You can take a look at C - serialization techniques (just have to translate to C++). But please, don't use memcpy or similar technique to serialize
I hope I get this right. You have two questions. You want know how to assign the value of char mapname[50]; via void setmapname(char newmapname[50]);. And you want to know how to create a dynamic size 2D array.
I hope you are comfortable with pointers because in both cases, you need it.
For the first question, I would like to first correct your understanding of void setmapname(char newmapname[50]);. C++ functions do not take in array. It take in the pointer to the array. So it is as good as writing void setmapname(char *newmapname);. For better understanding, go to Passing Arrays to Function in C++
With that, I am going to change the function to read in the length of the new map name. And to assign mapname, just use a loop to copy each of the char.
void setmapname(char *newmapname, int length) {
// ensure that the string passing in is not
// more that what mapname can hold.
length = length < 50 ? length : 50;
// loop each value and assign one by one.
for(int i = 0; i < length; ++i) {
mapname[i] = newmapname[i];
}
}
For the second question, you can use vector like what was proposed by Garf365 need to use but I prefer to just use pointer and I will use 1D array to represent 2d battlefield. (You can read the link Garf365 provide).
// Declare like this
char *casestatematricia; // remember to initialize this to 0.
// Create the battlefield
void Map::battlespace(int column, int line) {
columnnumber = column;
linenumber = line;
// Clear the previous battlefield.
clearspace();
// Creating the battlefield
casestatematricia = new char[column * line];
// initialise casestatematricia...
}
// Call this after you done using the battlefield
void Map::clearspace() {
if (!casestatematricia) return;
delete [] casestatematricia;
casestatematricia = 0;
}
Just remember to call clearspace() when you are no longer using it.
Just for your benefit, this is how you create a dynamic size 2D array
// Declare like this
char **casestatematricia; // remember to initialize this to 0.
// Create the battlefield
void Map::battlespace(int column, int line) {
columnnumber = column;
linenumber = line;
// Clear the previous battlefield.
clearspace();
// Creating the battlefield
casestatematricia = new char*[column];
for (int i = 0; i < column; ++i) {
casestatematricia[i] = new char[line];
}
// initialise casestatematricia...
}
// Call this after you done using the battlefield
void Map::clearspace() {
if (!casestatematricia) return;
for(int i = 0; i < columnnumber; ++i) {
delete [] casestatematricia[i];
}
delete [][] casestatematricia;
casestatematricia = 0;
}
Hope this help.
PS: If you need to serialize the string, you can to use pascal string format so that you can support string with variable length. e.g. "11hello world", or "3foo".

Updating an array using a function c++ [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm having a very nooby problem.
void update(node city, int costpath) {
int i;
for (i = 1; i < city.concity.size(); i++) {
city.costcity[i] = city.costcity[i] + costpath;
}
// Updates the sorrounding paths with the cost path of the previous one
}
node is a struct. It has vectors concity and costcity. When I call this function to update the values in the main, it doesn't work! When I print it out, it still shows the same old values…
Two problems:
void update(node city, int costpath) {
// ^^^^ 1) You're taking your node by-value. So it's a copy
// Internal to this function, you're just modifying the local city
int i;
for (i=1;i<city.concity.size();i++) {
// ^^^ 2) C++ is zero-indexed, so this loop skips the first element
The correct implementation would be:
void update(node& city, int costpath) {
for (int i = 0; i < city.concity.size(); ++i) {
city.costcity[i] += costpath;
}
}
C and C++ pass parameter by value when call function.
void update(node* city, int costpath) {
int i;
for (i=1;i<city->concity.size();i++) {
city->costcity[i] = city->costcity[i] + costpath;
}
}
See http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_value
and http://clc-wiki.net/wiki/C_language:Terms:Pass_by_value
pass node city as a pointer or reference to the function.
c++ is 0 indexed thus start with 0 and increment till the array size.
void update(node& city, int costpath) {
or
void update(node* city, int costpath) {
and
for (int i = 0; i < city.concity.size(); ++i) {

Array without parameters in c++

I'm pretty new in c++ althought a bit experienced in java, and my problem it's the next one:
I'm doing a sudoku project where I'm creating an abstract data type of the box and the board. In the board one, I'm creating a bidimesional array of boxes, but when I want to create it as a public data so I can use it in the whole class and not only in the board constructor.
I'm creating it in the board constructor because If I don't create it there, I have no way of knowing the value of each dimension, and if I create the variable Box box[int][int] where I can use it in the class, I've got no way of knowing the dimensions. It'll be better understandable with some code.
This code allows me to create the Box array with the dimensions I want, because it's in the board constructor than when it's created it has as a parameters the number of boxes, but it don't let me use the "casilla" variable in the other part of the class nor other classes:
class tablero{
int filas;
int columnas;
public:
tablero (int filas, int columnas){
this->filas = filas;
this->columnas =columnas;
Casilla casilla[filas][columnas];
}
Casilla getCasilla(int n, int m){
return casilla[n][m]; <- Here shows an error because casilla cannot be resolved.
}
And this other code lets me use the casilla variable, but I have to give it the parameters to the dimensions before I know them:
class tablero{
int filas;
int columnas;
public:
Casilla casilla[0][0];
tablero (int filas, int columnas){
this->filas = filas;
this->columnas =columnas;
}
Casilla getCasilla(int n, int m){
return casilla[n][m];
}
No error, but the dimensions of the casilla array have to be given before I know them, and so, they may be the wrong ones (because the board may have different dimensions.
It's the first time I'm programming in c++, and I'm really frustated with this problem, can anyone help me to find a way to make it so it works both ways? (I already tried to leave both dimensions empty and then in the constructor put casilla[][] = Casilla cas[filas] [columnas] but it gives me an error..)
Thanks for the help everyone. Also, If you think the title is not clear enough, you can suggest one and I'll change it.
The Casilla code is this one:
class Casilla{
int fila;
int columna;
int numero;
public:
// constructor
Casilla(int fila, int columna,int numero)
{
this->fila = fila;
this->columna = columna;
this->numero = numero;
}
};
Thanks everyone for your answers, I've already found the answer I needed from 3 different people. I can't upvote all of you because I still don't have 15 reputation, but when I have it i'll upvote you all. Thanks for all your answers, really. I just need to know what I commented on the checked answer and it'll be all answered.
A solution with an array
//----------------------------------------------------------------------------
#include <iostream>
#include <iomanip>
//----------------------------------------------------------------------------
class Casilla
{
int fila;
int columna;
int numero;
public:
// default constructor
Casilla()
{
this->fila = -1;
this->columna = -1;
this->numero = 0;
}
int GetNumero() {return numero;}
void SetCasilla (int _fila, int _columna) //set a cell position
{
fila = _fila;
columna = _columna;
}
void SetCasilla (int _numero) //set a cell value
{
numero = _numero;
}
void SetCasilla (int _fila, int _columna, int _numero) //set a cell position and value
{
fila = _fila;
columna = _columna;
numero = _numero;
}
};
class Tablero
{
int filas;
int columnas;
Casilla **casilla;
public:
Tablero (int filas, int columnas)
{
this->filas = filas;
this->columnas =columnas;
casilla = new Casilla* [filas];
for (int i = 0; i<filas; i++)
casilla[i] = new Casilla [columnas];
for (int i = 0; i<filas; i++)
for (int j = 0; j<columnas; j++)
casilla[i][j].SetCasilla(i,j); //set the right position for each cell
//the values = 0 by default
}
//destructor
~Tablero()
{
for (int i = 0; i<filas; i++)
delete [] casilla[i];
delete [] casilla;
}
//set a cell value in the table
void ChangeCasillaValue (int _fila, int _columna, int _numero)
{
casilla[_fila][_columna].SetCasilla (_numero);
}
Casilla getCasilla(int n, int m)
{
return casilla[n][m];
}
void PrintTablero ()
{
for (int i = 0; i<filas; i++)
{
for (int j = 0; j<columnas; j++)
std::cout << std::setw(5)<<casilla[i][j].GetNumero();
std::cout << "\n";
}
std::cout << "\n";
}
};
//----------------------------------------------------------------------------
int main()
{
int N = 5, M = 6;
Tablero table(N, M);
table.PrintTablero();
table.ChangeCasillaValue(1,1,-5); //change value in cell(1,1)
table.PrintTablero();
std::cin.get();
return 0;
}
//-----------------------------------------------------------------------------
You have to add a bunch of setters and getters of your own.
But, as a draft, it works.
C-style array dimensions must be known at compile-time in C++. So there is no variant of Casilla casilla[filas][columnas]; that will work.
Instead you should use a container which can hold the data you want to put in it. Use of C-style arrays in C++ is discouraged because they have some strange behaviour and rules, they are mainly there for backwards compatibility.
The simplest option is a 1-dimensional array with runtime size, that is called vector:
class tablero{
int filas;
int columnas;
std::vector<Casilla> casilla;
public:
tablero (int filas, int columnas)
: filas(filas), columnas(columnas), casilla(filas * columnas)
{ }
Casilla getCasilla(int f, int c) const
{
return casilla[f * columnas + c];
}
};
Note the use of the constructor initializer list. You should provide initial values for class members this way, instead of using assignment statements inside the constructor.
In your first example, in your constructor, the line
Casilla casilla[filas][columnas];
declares casilla an array of arrays of Casilla objects local to your constructor. Once your constructor returns, casilla goes out of scope. There is no casilla member variable or local variable in your getCasilla function, so of course it cannot be resolved.
In your second example, your class has a public member casilla declared as 0 by 0 array of Casilla objects. Your getCasilla function would return the item in the nth row and mth column of the 0 by 0 array. In C++, there is no bound checking on array dereferences, so this is returning some out of bounds memory location and is very bad.
You can create dynamic C arrays yourself by using malloc and free, but since you are using C++ it will be easier to just use std::vector.
For example, you could use:
#include <iostream>
#include <vector>
class Casilla
{};
class tablero
{
int filas_;
int columnas_;
std::vector<std::vector<Casilla> > casilla_; // a vector of vectors of Casillas
public:
tablero(int filas, int columnas) : filas_(filas), columnas_(columnas),
casilla_(filas, std::vector<Casilla>(columnas))
// The above is an initialization list
// We initialize casilla_ as a vector of filas vectors of columnas Casillas
{}
std::vector<std::vector<Casilla> > getCasilla() const
{
return casilla_;
}
};
int main(int argc, const char* argv[])
{
tablero t(3, 3);
std::cout << "casilla rows: " << t.getCasilla().size() << std::endl;
std::cout << "casilla cols: " << t.getCasilla()[0].size() << std::endl;
return 0;
}
First Casilla casilla[filas][columnas]; needs to be a class variable so it's accessible to all methods.
Second the sizes of rows and columns must be a fixed number e.g Casilla casilla[9][9];
If it need to be dynamically allocated you could you Vectors or Vectors of Vectors.
If it's 2d array, you can still create it as 1d array, but depends which is best for your purposes.

Array of structs declaration

I am trying to write this C++ function in which I am trying to set each Sequence in the array of Sequences, however when I follow the code on debug I notice that the array is not changing. In particular:
compressed.data[compressedDataCounter].c = pic.data[i];
compressed.data[compressedDataCounter].times = counter+1;
don't seem to add any new variables to the array, just override the first one.
I am thinking that the root of the problem is the declaration:
CompressedPic compressed;
compressed.data = new Sequence[pic.height * pic.width];
This is the portion of the code:
struct Sequence
{
char c;
int times;
};
struct CompressedPic
{
int height;
int width;
Sequence* data;
};
struct Picture
{
int height;
int width;
char* data;
};
CompressedPic compressThePicture(Picture pic) {
CompressedPic compressed;
compressed.data = new Sequence[pic.height * pic.width];
compressed.height = pic.height;
compressed.width = pic.width;
int compressedDataCounter=0;
for(int i=0; i<(pic.height * pic.width)-1; i++)
{
int counter = 0;
while(pic.data[i] == pic.data[i+1])
{
i++;
counter++;
}
compressed.data[compressedDataCounter].c = pic.data[i];
compressed.data[compressedDataCounter].times = counter+1;
compressedDataCounter++;
}
compressed.data[compressedDataCounter].times = -1;
return compressed;
}
It would be great if someone could figure out why this is happening.
You might want to change:
compressed.data[compressedDataCounter].c = counter+1;
to:
compressed.data[compressedDataCounter].times = counter+1;
So you can change the .times member otherwise you will be overriding your .c member. Right now you are setting .c to 'a' for example. Then you set .c to 103 (counter+1). Which is an int and likely with your archetecture the high bytes are aligning with .c and setting it to 0 as well.
So .c is getting 0'd and .times is never set

Hash Table of Vectors of Person Objects c

I've been working on a very in depth project for one of my classes. It supposed to read in Person objects and put them into a hash table. I'm still trying to get my head around the concept of a hash table so any help would be appreciated.
It will be hashing based on last name and since some people may have the same last name, I was going to make each bucket a vector of Person objects. I'm trying to test the class by adding a person to the hash function and then returning it. My code compiles successfully but I get a thread error in the put function on this line: table[index].push_back(p);
Could anyone please help me figure out what is going wrong? Thank you!
int main()
{
HashTable ht(10);
ht.put(p1, p1->lName);
ht.getName("Booras");
}
HashTable:
#include "Person.h"
#include <vector>
class HashTable: public DataStructures
{
private:
vector<vector<Person>> table;
public:
HashTable(int tableSize);
~HashTable();
int tableSize;
void getName(string str); //prints out friends with matching name
void put(Person p, string str);
void remove(Person *p, string str);
int hash(string str);
};
HashTable::HashTable(int tableSize)
{
vector< vector<Person> > table(tableSize, vector<Person>(tableSize));
for (int i = 0; i < tableSize; i++) {
table.push_back(vector<Person>()); // Add an empty row
}
}
HashTable::~HashTable()
{
}
//Find a person with the given last name
void HashTable::getName(string key)
{
int index = hash(key);
for(int i=0; i<table[index].size(); i++)
{
if(table[index][i].lName.compare(key) == 0)
std::cout << "Bucket: " << index << "Bin: " << i;
table[index][i].print();
}
//create exception for person not found
}
void HashTable::put(Person p, string str)
{
int index = hash(str);
table[index].push_back(p);
}
void HashTable::remove(Person *p, string str)
{
int index = hash(str);
int i=0;
while(&table[index][i] != p && i<table[index].size())
i++;
for(int j=i; j<table[index].size()-1; j++)
table[index][j] = table[index][j+1];
table[index].pop_back();
}
int HashTable::hash(string str)
{
int hashValue = 0;
for(int i=0; i<str.length(); i++)
{
hashValue = hashValue + int(str[i]);
}
hashValue %= tableSize;
if(hashValue<0) hashValue += tableSize;
return hashValue;
}
Main:
int main() {
Person *p1 = new Person("Kristy", "Booras", "Reston", "03/15");
HashTable ht(10);
ht.put(*p1, p1->lName);
ht.get("Booras");
return 0;
}
You don't show us the HashTable::hash(string) member function, but I'd assume that your problems originate in the HashTableconstructor: You don't initialize the tableSize member variable, which you'll need to calculate a valid hashed index.
While looking at the constructor:
HashTable::HashTable(int tableSize)
{
vector< vector<Person> > table(tableSize, vector<Person>(tableSize));
This has initialized table to have tableSize non-empty elements, for a total of tableSize * tableSizedefault-constructed Person objects.
for (int i = 0; i < tableSize; i++) {
table.push_back(vector<Person>()); // Add an empty row
}
}
Now you have added more rows, so that table.size() == 2*tableSize, with the first half of entries non-empty (as explained above) and the second half holding empty vectors.
That is probably not what you intended.
And in all of that you haven't initialized the member tableSize. It easily gets confusing, if you use local variables or argument names that hide member names.