program crashes after assigning values to array elements - c++

I have a class with name setaddress containing a structure that contains a 2D array:int WaterMeterIDs[20][2];
namespace Ui {
class SetAddress;
}
class SetAddress : public QDialog
{
Q_OBJECT
public:
struct AddressList{
int WaterMeterIDs[20][2];
};
explicit SetAddress(QWidget *parent = 0);
~SetAddress();
etc...
private:
Ui::SetAddress *ui;
AddressList m_address;
I want to save my data that is in a qtablewidget cells using this commands
in my .cpp file:
void SetAddress::on_pushButton_apply_clicked()
{
int rowscount = ui->tableWidget->rowCount();
//rowscount is always less than 20
for(int j = 0; j < 2; j++){
for(int i = 0; i < rowscount; i++){
if(ui->tableWidget->item(i,j) != 0x0 ){//if cell is not empty
m_address.WaterMeterIDs[i][j] = ui->tableWidget->item(i,j)->text().toInt();//convert data to int and put it in array
qDebug()<<m_address.WaterMeterIDs[i][j];
}
}
}
}
when I click on apply button the program works good(I can see array elements using qDebug()).
but after I pressed the apply button if I press any other key even the close button(or even if I want to resize the window) program crashes!

can you see any mistake in my code?
Even if you are sure that your indexes are within range, there's nothing in the code you've shown us that makes really sure that's the case, so I'd replace your array with this:
#include <array>
class AddressList{
std::array<std::array<int, 2>, 20> WaterMeterIDs;
public:
inline constexpr int& at(size_t row, size_t col) {
return WaterMeterIDs.at(row).at(col);
}
inline constexpr int const& at(size_t row, size_t col) const {
return WaterMeterIDs.at(row).at(col);
}
};
Then access the array via the at() function:
// set value
m_address.at(i,j) = ...
// log value
qDebug() << m_address.at(i,j);
That should make you sure that nothing slipped through the cracks regarding your 2D array.
And I'd check that ui->tableWidget->columnCount() >= 2 before the loop, just to rule that out too:
int colcount = std::min(2, ui->tableWidget->columnCount());
for(int j = 0; j < colcount; ++j) {
...

Related

Arrays with unknown size on Arduino

I'm doing an Arduino project and I need to pass arrays with different sizes as parameter to my function.
The problem is that std::vector is not an option.
How can I do that?
The fallback is to pass a pointer to the first element in the array and the size:
void foo(int* arr, size_t size);
The reason for std::vector not being available on some platforms is that on some platforms dynamic allocations is a bad idea. However, once you are dynamically allocating arrays:
int* x = new int[42];
foo(arr,42); // array decays to pointer
delete[] x;
then you could as well use std::vector.
If std::vector is not available to you, then either search for an alternative (maybe this?) or write your own. The pointer + size approach is fragile and not recommended unless absolutely necessary. The power of std::vector is from the abstract concept to encapsulate the array, its size and capacity. Nobody can prevent you to apply that concept even if you cannot use std::vector.
In case you are talking about statically sized arrays, then thats not quite the use case for std::vector. You do not need dynamic allocation, and you can pass arrays by reference. I won't repeat here what you can find in this answer (std::array) or here (c-arrays).
Something like this should work
template<size_t N>
void DaFunction(std::array<int, N>& daArray)
you can do it without having to deal with memory allocation or pointers just by creating a string variable and a limited size array and then you start shifting
#include <Arduino.h>
class ArrayShifter
{
private:
// String Reservoire Tank
String _text;
// a fixed size array of 5 in my case (depending on the amount of data you expect)
String _viewPortArray[5];
int _size = 0;
// Methode to fill the array
bool shiftArray(int position);
public:
ArrayShifter(/* args */);
// Method that gets the text from Serial
String getSerialText();
// get data from the array
String getArrayData(int index);
// array size getter
int getSize();
//clear the array
void clearArray();
//remove item
void removeArrayItem(int index);
};
ArrayShifter::ArrayShifter(/* args */)
{
}
String ArrayShifter::getSerialText()
{
// lesteing to the serial and returning the value
_text = Serial.readString();
return _text;
}
bool ArrayShifter::shiftArray(int position)
{
/*Assuming that the data is comming separated with ";" for each row and ":" for each value
to optimize the size of array in this way :
name:value;age:value;gender:value;
*/
String text = getSerialText();
int index = 0;
_size = 0;
if (text.length() > 0) // text isn't empty
{
if (position <= 5) // if the data belongs to the first 5 range
{
for (int i = 0; i < 5; i++)
{
// get the index of our separator that we've chosed to be ";"
index = text.indexOf(";");
if (index > 0)
{
// index found
_size++;
// putting the value before ";" in the array
_viewPortArray[i] = text.substring(0, index);
// deleting the value from the tank
text = text.substring(index + 1);
}
}
}
else
{
_size = 0;
// to wich range the desired index belongs
unsigned int dataRange = ((position - position % 5));
int ghostIndex = 0;
// looping throught all ";" to get indexes
for (int i = 0; i < dataRange; i++)
{
ghostIndex = text.indexOf(";");
if (ghostIndex > 0)
{
_size++;
text = text.substring(ghostIndex + 1);
}
}
// grabing just 5 of the data
for (int i = 0; i < 5; i++)
{
if (ghostIndex > 0)
{
_size++;
_viewPortArray[i] = text.substring(0, ghostIndex);
text = text.substring(ghostIndex + 1);
}
// updating ghost index
ghostIndex = text.indexOf(';');
}
}
return true;
}
return false;
}
String ArrayShifter::getArrayData(int index)
{
// turn the roulette
if (shiftArray(index))
{
if (index <= 5)
{
// yes we have this
return _viewPortArray[index];
}
else
{
// but we have to put it in the range of 5
index = index - 5;
return _viewPortArray[index];
}
}
}
int ArrayShifter::getSize()
{
return _size;
}
void ArrayShifter::clearArray()
{
for(int i = 0 ; i <5 ; i ++)
{
_viewPortArray->remove(i);
_size = 0;
}
}
void ArrayShifter::removeArrayItem(int index)
{
_viewPortArray->remove(index);
_size--;
}
main class :
#include <Arduino.h>
#include <ArrayShifter.h>
ArrayShifter array;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while (!Serial){}
}
void loop() {
if(Serial.available()>0)
{
Serial.println(array.getArrayData(7));
int sizeOption2 = array.getSize();
Serial.println(sizeOption2);
array.removeArrayItem(7);
Serial.println(array.getArrayData(7));
}
}
please check my github repository
https://github.com/Riadam/ViewPort-Array-Shifter-for-Arduino-Uno.git

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".

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.

Resetting array using indices

I have an array whose size and values keep changing during execution all the time.
I want to do that with minimum possible performance overhead.
Instead ochanging array size I simply have member int variables indicating start and end Index and I expect consumer of this array to use these indices in the foor loop. The risk is, if the consumer does not use the start and endindex it may end up causing error. Is there a better way of doing that?
So what I have is:
MyClass
{
public:
BusinessClass myArray[MAX_COUNT];//the array
int StartIndex; //start index
int EndIndex; //End index
Logic()
{
//modified the array and changes start and end index
}
}
MyConsumer
{
MyClass obj;
public:
void ReadArray()
{
for (int i = obj.StartIndex ; i <obj.EndIndex; i++)
{
//perform logic
}
}
}
Instead of exposing the underlying array, you could have a length method that returns EndIndex-StartIndex, and an array operator that returns an item from the array offset by the value of the StartIndex.
The you would access the items in the array like this:
for (int i = 0; i < obj.length(); i++) {
BusinessClass &item = obj[i];
}
The MyClass class would look something like this:
class MyClass {
public:
size_t length() const {
return EndIndex - StartIndex;
};
BusinessClass &operator[](size_t off) {
return myArray[StartIndex+off];
};
private:
BusinessClass myArray[MAX_COUNT];
int StartIndex; //start index
int EndIndex; //End index
};

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.