PDA

View Full Version : deleting invalid pointer



hollowhead
28th April 2010, 11:43
This is a C++ issue rather than a QT issue in my view hence the post here.

When I run the functions below I get

"Program received signal SIGABRT, Aborted.
free(): invalid next size (fast): 0x083101b0 ***"
plus a hundred or so lines of related errors.

I believe I am deleting an invalid pointer but cannot see where I am going wrong. What I'm trying to do is write two functions that gathers the non empty and non txt containing cells from my spreadsheet selected range then sums the numbers and puts the answer in the cell below the selected range. If there is only one number the functions work, if the range has two or more cells than I get the crash above. Can anyone help sort this out?




void Spreadsheet::sumColumn() // sums selected cells and dumps answer below lowest cell
{
QTableWidgetSelectionRange range = selectedRange(); // get selected range
int col=currentColumn(); //get current column position
int rowcount= range.rowCount(); // work out number of rows selected
int *number= new int; // create pointer to number of items to be collected
double *dataSet = new double; // create pointer for array of data to be collected
double total=0; // initialise total
collectData(number, dataSet); // get data from sheet see next function
int numberOfItems=0; // set this to zero just in case
numberOfItems=(int) *number; // cast to make numberOfItems = number of filled cells from collect function

for (int n=0; n<numberOfItems; n++)

total= total+ dataSet[n]; // calculate sum

QString num = QString::number(total); // converts any number type to string -very easy!

setFormula(rowcount, col, num); // put sum on sheet in cell below selected range this works

// in future preferably needs check for overwriting of cell if not empty
// also needs to add row if all rows in sheet are selected

delete number; // clean up memory
delete dataSet;
}




void Spreadsheet::collectData(int *count, double *data)
{

QList<QTableWidgetItem *> items = selectedItems();

int totalcount=0;

foreach (QTableWidgetItem *item, items) // loop through sheet selected items
{
bool ok;
double value = item->text().toDouble(&ok);

if (ok && !item->text().isEmpty()) // ignore empty cells and cells with anything but 0-9. in
{
//data[totalcount]=0.0; // set each element to zero just in case
data[totalcount]=value; // now fill array with values from sheet
totalcount++; //increment count for only filled cells with numbers in
}

}
*count=totalcount; // set pointer to total count
}

Kumosan
28th April 2010, 11:54
Congratulations. You 'newed' memory for exactly one double value. And filled it with totalcount values. Nice example of memory corruption.

hollowhead
28th April 2010, 12:37
Thanks for your reply I thought pointers and arrays were the same thing? What do I do instead?

squidge
28th April 2010, 12:53
You still have to tell the compiler how much memory to allocate. If you intend on using 1 double your code is fine. If you intend on using 2 doubles, you would have to use "double *dataSet = new double[2];" and so on. Your delete code would then change too from "delete dataSet" to "delete[] dataSet".

hollowhead
28th April 2010, 13:13
Thanks for your reply. I'm aware of how to declare the size for known size, but the problem is the size is unknown before I pass the pointer into the collect function. I can think of one way around this which is to use rowcount (and columncount) from the range to set the array size but this would allocate more memory than I need since it counts empty cells.

Kumosan
28th April 2010, 13:19
Thanks for your reply. I'm aware of how to declare the size for known size, but the problem is the size is unknown before I pass the pointer into the collect function. I can think of one way around this which is to use rowcount (and columncount) from the range to set the array size but this would allocate more memory than I need since it counts empty cells.

Why not use QVector?

hollowhead
28th April 2010, 14:52
That's a brilliant idea Kumosan since it can declared at one size and dynamically resized. However, I've not used anything like this before. C++ GUI Programming with Qt 4 shows how to declare it and use it a bit. Any advice on its use in this case would be most welcome....

Declare it thus as a pointer? in my main class declaration? and how do I pass it into my collectData function?



QVector<double> *myArray(10);


Presumably I can do something like this to fill it.




foreach (QTableWidgetItem *item, items) // loop through sheet selected items

{

bool ok;

double value = item->text().toDouble(&ok);

if (ok && !item->text().isEmpty()) // ignore empty cells and cells with anything but 0-9. in

{

//data[totalcount]=0.0; // set each element to zero just in case

myArray.append(value); // now fill array with values from sheet
//or
myArray[totalcount]=value; // now fill array with values from sheet

totalcount++; //increment count for only filled cells with numbers in

}

}

Kumosan
28th April 2010, 15:15
Nope, though you can use it as pointer, it is not too good.

In your .h file:
QVector<double> myArray;

In your .cpp:

myArray.append(value);

Do not:
myArray[totalcount]=value; // now fill array with values from sheet
With the append you already have added the values.

You don't need totalcount at all.
Below how your collectData could look like



void Spreadsheet::collectData(QVector<double> &arr) {
QList<QTableWidgetItem *> items = selectedItems();
foreach (QTableWidgetItem *item, items) // loop through sheet selected items {
bool ok;
double value = item->text().toDouble(&ok);
if (ok && !item->text().isEmpty()) // ignore empty cells and cells with anything but 0-9. in {
arr.append(value);
}
}
}

You don't need totalcount. You can always get the count from myArray.size();

hollowhead
28th April 2010, 20:17
Cheers mate makes sense. Thanks for your help have programmed in C but not C++ until recently. Hence never used the std C++ vector either. You learn from your mistakes.....

hollowhead
29th April 2010, 12:18
Thanks worked like a dream two things I discovered which I will add for those who maybe interested in the future in this thread.
The easiest way to iterate over the vectors filled range is to use the count() function


for (int n=0; n<myArray.count(); n++)

total+=myArray[n]; // calculate sum


In addition using append on its own in the collect function meant the answer was only correct the first time subsequent time the answer was wrong since more and more data was being added to the array and non was being deleted. The way round this is when you have finished with the data in the vector



myArray.clear();


This seems according to the documentation to clear everything and release the memory.

Kumosan
29th April 2010, 12:42
Thanks worked like a dream two things I discovered which I will add for those who maybe interested in the future in this thread.
The easiest way to iterate over the vectors filled range is to use the count() function


for (int n=0; n<myArray.count(); n++)

total+=myArray[n]; // calculate sum



Easiest way?
What about:



foreach(double v, myArray)
total += v;

hollowhead
30th April 2010, 10:47
Fantastic I'm a fan of QVector, already its really powerful. I'll change the code below I know it worked with foreach but not how. I have posted a follow-up question following on from above I hope you don't mind... All the code below works but I don't fully understand why and I think there is a better way of doing things but all attempts to do so have failed hence the post. I wanted to put my sum() function in a separate source file so I created a stats.cpp and stats.h thus;




#ifndef STATS_H
#define STATS_H

class Stats
{
public:

double sum(QVector<double> &dataArray);

private:

QVector<double> dataArray;

};

#endif


and stats.cpp file



#include "stats.h" /* contains function prototypes and class defition */

/*Stats::Stats()
{

}

*/

/* first sum */

double Stats::sum(QVector<double> &dataArray)

{

double sum=0.0;

for (int n=0; n<dataArray.count(); n++)
sum+=dataArray[n]; // calculate sum
// dataArray.clear();
return sum;

}

then modified my sumColumn() function to


double total=0; // initialise total
collectData(myArray); // get data from sheet see next function
Stats myStats;
total=myStats.sum(myArray);
// etc as before


It works but I am unhappy about two things.
The first is that I've instantiated an object of the Stats class in my sumColumn() function which works but seems clumsy. However, I try declaring it anywhere else it won't compile. I've tried spreadsheet class definition (since sumColumn() is called within this class) and the spreadsheet header file (Public:) also stats.h (same). I also created a stats constructor but it won't compile with it there. If I write more functions in stats I will have to do this each time within each function and that is naff.

The second question is do I need a stats constructor? Its just a library with a math function in. If I create a minimalist one commented out in the code above it won't compile. My understanding is that C++ creates one with everything public if non is declared?