Segmentation fault error with structures - c++

I have no idea where the segmentation error is coming from ... Any ideas?
I am working with structures for an assignment
TestResult testResultFactory(std::string name, double mark)
{
//creating an object of TestResult
TestResult car;
car.name = name;
car.mark = mark;
return car;
}
Student studentFactrory(std::string name)
{
//Creating an object of student
Student house;
house.name = name;
house.testResults = 0;
house.numTestResults = 0;
return house;
}
void addTestResult(Student * student, std::string testName, double testMark)
{
//First we need to create a new array
(student->numTestResults)+=1;
TestResult *newTestArray = new TestResult[(student->numTestResults)];
//Now we loop through the old array and add it to the new one
int index = (student->numTestResults);
for (size_t i = 0; i < (index-1); i++)
{
newTestArray[i] = testResultFactory((student->testResults[i].name),(student->testResults[i].mark));
}
//Now we need to add the new student to the end of the array
newTestArray[index] = testResultFactory(testName, testMark);
(student->testResults) = newTestArray;
}
string studentBest(Student const * student)
{
//create variables as temps
string highestName;
double highestMark;
int index = (student->numTestResults);
//Setting the two variables to the first value
highestName = (student->testResults[0].name);
highestMark = (student->testResults[0].mark);
//Using a while loop to compare and get the best
for (size_t i = 0; i < index; i++)
{
if((student->testResults[i].mark)> highestMark)
{
highestMark = (student->testResults[i].mark);
highestName = (student->testResults[i].name);
}
}
//returning the string they want
string send = (highestName)+ " "+ doubleToString(highestMark)+ "%";
return send;
}
double studentAverage(Student const * student)
{
//Variables used as temps
double average = 0;
double counter = 0.0;
double running = 0;
int index = (student->numTestResults);
//Now we need to loop through each one and add to running and counter
for (size_t i = 0; i < index; i++)
{
counter++;
running += (student->testResults[i].mark);
}
//calculating the average;
average = (running)/counter;
return average;
}
void destroyStudent(Student * student)
{
delete [] (student->testResults);
(student->testResults)=0;
}
Subject subjectFactory(std::string name)
{
//Creating an object to use in subject factory
Subject lamp;
lamp.name = name;
lamp.numStudents = 0;
lamp.studentsAllocated = 0;
lamp.students = 0;
return lamp;
}
MY guess is that the error occurs because of an out of bounds array or an pointer not worked with correctly .
int getStudentIndex(Subject const * subject, std::string studentName)
{
int index;
int count = (subject->numStudents);
//loop to find the names and set index
for (size_t i = 0; i < count; i++)
{
if(studentName == ((subject->students[i].name)))
{
index = i;
}
else index = -1;
}
return index;
}
void addStudent(Subject * subject, std::string studentName)
{
//Variables as temps
Student *pointer =0;
int index = getStudentIndex(subject,studentName);
if(index != -1)
{
//Now we need to see if they are large enough
if((subject->studentsAllocated)==0)
{
//Set the allocated to 2
(subject->studentsAllocated) = 2;
pointer = new Student[2];
//Figure this out later
pointer[1] = studentFactrory(studentName);
(subject->students) = pointer;
}
else
{
//increase SA with 1.5
(subject->studentsAllocated) = (subject->studentsAllocated) * 1.5;
pointer = new Student[(subject->studentsAllocated)+1];
int count = (subject->studentsAllocated);
//Now we need to put all the other students in
for (size_t i = 0; i < count-1; i++)
{
pointer[i] = (subject->students[i]);
}
pointer[(subject->studentsAllocated)+1] = studentFactrory(studentName);
(subject->studentsAllocated) += 1 ;
}
//Once done just seet one equal to
(subject->students) = pointer;
}
else return;
}
void removeStudent(Subject * subject, std::string studentName)
{
//First get temps
int index = getStudentIndex(subject ,studentName);
int number = (subject->studentsAllocated);
int i = index;
//delete student
if(index == -1) return;
destroyStudent(&(subject->students)[index]);
//loop to shift the things
while (i<(number -1))
{
(subject->students)[i] = (subject-> students[i+1]);
}
//Removing the last one
(subject->numStudents) -= 1;
}
bool addTestResult(Subject * subject, std::string studentName, std::string testName, double testMark)
{
int index = getStudentIndex(subject ,studentName);
if(index != -1)
{
addTestResult(&(subject->students [index]),testName,testMark);
return true;
}
else
return false;
}
void printSubjectSummary(Subject const * subject)
{
cout<<(subject->name)<< ": with "<<(subject->numStudents)<<" students"<<endl;
//Variables to use in the loop
size_t indexLoop = subject->numStudents;
int i=0;
while (i< indexLoop)
{
cout<<(subject->students[i].name)<<" Average: "<<studentAverage(&(subject->students[i]))<<", Best: "<<studentBest(&(subject->students[i]))<<endl;
}
}
void destroySubject(Subject * subject)
{
//Variables
size_t indexLoop = subject->numStudents;
for (size_t i = 0; i < indexLoop; i++)
{
destroyStudent(&(subject->students[i]));
}
delete [] subject->students;
subject->students =0;
}
I can not seem to find where the segmentation error is coming from. Even restarted the whole assignment from scratch and still seem to get errors.
Can someone please help or indicate where the fault could be coming from.
Over here we have the structs.h file that is included in my code above
#ifndef STRUCTS_H
#define STRUCTS_H
struct TestResult{
double mark;//the test mark as a percentage
std::string name;//the test name
};
struct Student{
std::string name;
TestResult * testResults;//an arry of TestResults
size_t numTestResults;//the number of results for this student (also the size of the array)
};
struct Subject{
std::string name;
Student * students;//an array of Students
size_t numStudents;//the number of students added to the subject
size_t studentsAllocated;//the size of the Student arry(must never be smaller that numStudents)
};
#endif

There are so many logical errors in there that the root cause (or causes; there are quite a few candidates) could be pretty much anywhere.
getStudentIndex returns -1 unless the student is the last one in the array, and an indeterminate value for the first one you add, so adding the first student to a subject is undefined.
addStudent only adds a student if they're already taking the subject.
It also (for some inexplicable reason) allocates an array of two Students, leaving the first element uninitialised.
Using this first element is, of course, undefined.
In the other branch, it first claims that the number of allocated students is * 1.5, but then only allocates + 1.
This will undoubtedly lead to problems.
There is a recursion in addTestResult that will never terminate.
There are most likely other problems as well – this was just a quick glance.
Start with fixing these.
And do learn about constructors and destructors so you can get rid of those "factory" and "destroy" functions.

Related

Std::bad_alloc thrown in the middle of While Loop

I'm writing a function that handles an order input file (csv) using a while loops to iterate though it.
762212,1,2020-03-15,10951-3,64612-2,57544-1,80145-1,27515-2,16736-1,79758-2,29286-2,51822-3,39096-1,32641-3,63725-3,64007-2,23022-1,16974-3,26860-2,75536-2,26461-1
1,373975319551257,12-2023
258572,2,2020-03-15,96497-1,70616-1,80237-2,22248-2,56107-1,59695-1,37948-3,21316-3,63498-1,18329-1,56833-1,66295-1,47680-3,30346-1
1,201741963232463,02-2022
857003,3,2020-03-15,16655-1,88019-3,75069-3,96017-2,46883-2,15138-1,77316-1,70063-3,54452-3,86429-2,15134-2,60176-1,12946-3
2,cfeeham3s
747893,4,2020-03-17,48520-1,93268-2,63636-1,23750-2,99771-3,83203-1,21316-3,89921-2,15134-3,82831-1,30346-2,54044-3,28561-1,14792-2,23523-3,56826-2
1,3571379825697064,04-2025
Every two lines represents an input. I have the following function that handles this input:
list<Order> orders;
void read_orders(string file_name) {
fstream read_file;
read_file.open(file_name, ios::in);
if (read_file.is_open()) {
string s;
int line_num = 1; // keeps track of line number in input file
int o_id;
string o_date;
int c_id;
vector<LineItem> itms;
while (getline(read_file, s)) {
cout << orders.size(); // shows that only two objects are added before failure
if (line_num % 2 == 1) { // handle odd numbered lines of input
auto data = split(s, ',');
int o_id = stoi(data[0]);
string o_date = data[1];
int c_id = stoi(data[2]);
vector<LineItem> itms;
// get line items
int n_line_items = data.size() - 3;
vector<string> end_data(data.end() - n_line_items, data.end());
for (string x: end_data) {
auto parts = split(x, '-');
LineItem* it = new LineItem(stoi(parts[0]), stoi(parts[1]));
itms.push_back(*it);
delete it;
}
} else { // handle even numbered lines of input
auto data = split(s, ',');
Credit* pay_credit = new Credit(0.0, data[1], data[2]); // initialize each type of payment
PayPal* pay_paypal = new PayPal(0.0, data[1]);
WireTransfer* pay_wire = new WireTransfer(0.0, data[1], data[2]);
if (data[0] == "1") {
Order* ordr = new Order(o_id, o_date, c_id, itms, *pay_credit);
orders.push_back(*ordr);
delete ordr;
} else if (data[0] == "2") {
Order* orr = new Order(o_id, o_date, c_id, itms, *pay_paypal);
orders.push_back(*orr);
delete orr;
} else if (data[0] == "3") {
Order* odr = new Order(o_id, o_date, c_id, itms, *pay_wire);
orders.push_back(*odr);
delete odr;
}
delete pay_credit; // trying to clean up memory
delete pay_paypal;
delete pay_wire;
}
line_num += 1;
}
read_file.close();
}
}
Because of my cout statement, I can tell that it only adds two items to the list before running into the std::bad_alloc error. It seems to happen when it switches from adding a Credit object to adding a PayPal object into the Order(...) when it's initialized. I did a lot of research into why this might happen, so I tried to clean up as much as I knew how to (I'm new to C++) but the same error kept popping up. Does the error happen when I'm adding things to the list or is it when I'm creating these new objects?/How could I fix something like that?
Here are my class definitions in case that's important:
class Payment {
public:
double amount;
string print_detail() {
return "hey";
};
};
class Credit: public Payment {
private:
string card_number;
string expiration;
public:
Credit(double amt, string cn, string exp) {
this->amount = amt;
this->card_number = cn;
this->expiration = exp;
}
string print_detail() {
return "Credit card " + this->card_number + ", exp. " + this->expiration;
}
};
class PayPal: public Payment {
private:
string paypal_id;
public:
PayPal(double amt, string pp_id) {
this->amount = amt;
this->paypal_id = pp_id;
}
virtual string print_detail() {
return "Paypal ID: " + this->paypal_id;
}
};
class WireTransfer: public Payment {
private:
string bank_id;
string account_id;
public:
WireTransfer(double amt, string b_id, string a_id) {
this->amount = amt;
this->bank_id = b_id;
this->account_id = a_id;
}
string print_detail() {
return "Wire transfer from Bank ID " + this->bank_id + ", Account# " + this->account_id;
}
};
class LineItem {
private:
int item_id;
int qty;
public:
LineItem(int i_id, int qt) {
this->item_id = i_id;
this->qty = qt;
}
double subtotal() {
double subtot = 0.0;
for (auto x: items) {
if (x.item_id == this->item_id) {
subtot += x.price * this->qty;
}
}
return subtot;
};
};
class Order {
private:
int order_id;
string order_date;
int cust_id;
vector<LineItem> line_items;
Payment payment;
public:
Order(int o_id, string o_date, int c_id, vector<LineItem> li, Payment pay) {
this->order_id = o_id;
this->order_date = o_date;
this->cust_id = c_id;
this->line_items = li;
this->payment = pay;
}
string pay_type = "";
double total() {
double result = 0.0;
for (auto li: line_items) {
result += li.subtotal();
}
return result;
}
string print_order() {
string text = "===========================\nOrder #";
text += to_string(this->order_id) + ", Date: " + this->order_date + "\nAmount: $";
text += to_string(this->total()) + ", Paid by ";
text += payment.print_detail();
return text;
}
};
And this was the error message showing that it did insert two items:
001122terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Process returned 3 (0x3)
std::bad_alloc is often thrown when there is not enough memory to be allocated. I can't say if this will solve the problem, but your repeated allocations and deallocations of objects are both unnecessary and harmful (causing memory fragmentation).
Instead of
LineItem* it = new LineItem(stoi(parts[0]), stoi(parts[1]));
itms.push_back(*it);
delete it;
you should do
itms.push_back(LineItem(stoi(parts[0]), stoi(parts[1]));
or
itms.emplace_back(stoi(parts[0]), stoi(parts[1]));
The same applies to every occurence of new in read_orders. You don't need any of them.
Another helpful thing you can do is to preallocate memory for std::vector. If you don't know how many items it will have, do an educated guess (100, 1000, 10000, etc.).
itms.reserve(1000); //before you start to push_back() to it
Also, make sure to std::move your vectors if you want to transfer the whole content of it and not make a copy.

C++ memory leak, where?

I'm having a problem with the code attached below. Essentially it generates a huge memory leak but I can't see where it happens.
What the code does is receiving an array of strings, called prints, containing numbers (nodes) separated by ',' (ordered by desc number of nodes), finding other compatible prints (compatible means that the other string has no overlapping nodes 0 excluded because every print contains it) and when all nodes are covered it calculates a risk function on the basis of a weighted graph. In the end it retains the solution having the lowest risk.
The problem is that leak you see in the picture. I really can't get where it comes from.
Here's the code:
#include "Analyzer.h"
#define INFINITY 999999999
// functions prototypes
bool areFullyCompatible(int *, int, string);
bool contains(int *, int, int);
bool selectionComplete(int , int);
void extractNodes(string , int *, int &, int);
void addNodes(int *, int &, string);
Analyzer::Analyzer(Graph *graph, string *prints, int printsLen) {
this->graph = graph;
this->prints = prints;
this->printsLen = printsLen;
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
this->bestReSize = INFINITY;
this->bestRisk = INFINITY;
this-> actualSize = -1;
}
void Analyzer::getBestResult(int &size) {
for (int i = 0; i < bestReSize; i++)
cout << bestResult[i] << endl;
}
void Analyzer::analyze() {
// the number of selected paths is at most equal to the number of nodes
int maxSize = this->graph->nodesNum;
float totRisk;
int *actualNodes = new int[maxSize];
int nodesNum;
bool newCycle = true;
for (int i = 0; i < printsLen - 1; i++) {
for (int j = i + 1; j < printsLen; j++) {
// initializing the current selection
if (newCycle) {
newCycle = false;
nodesNum = 0;
extractNodes(prints[i], actualNodes, nodesNum, maxSize);
this->actualResult[0] = prints[i];
this->actualSize = 1;
}
// adding just fully compatible prints
if (areFullyCompatible(actualNodes, nodesNum, prints[j])) {
this->actualResult[actualSize] = prints[j];
actualSize++;
addNodes(actualNodes, nodesNum, prints[j]);
}
if (selectionComplete(nodesNum, maxSize)) {
// it means it's no more a possible best solution with the minimum number of paths
if (actualSize > bestReSize) {
break;
}
// calculating the risk associated to the current selection of prints
totRisk = calculateRisk();
// saving the best result
if (actualSize <= bestReSize && totRisk < bestRisk) {
bestReSize = actualSize;
bestRisk = totRisk;
for(int k=0;k<actualSize; k++)
bestResult[k] = actualResult[k];
}
}
}
newCycle = true;
}
}
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
int nodesNum = 0;
for (int i = 0; i < actualSize; i++) {
extractNodes(this->actualResult[i], nodes, nodesNum, maxSize);
// now nodes containt all the nodes from the print but 0, so I add it (it's already counted but misses)
nodes[nodesNum-1] = 0;
// at this point I use the graph to calculate the risk
for (int i = 0; i < nodesNum - 1; i++) {
float add = this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
totRisk += this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
//cout << "connecting " << nodes[i] << " to " << nodes[i + 1] << " with risk " << add << endl;
}
}
delete nodes;
return totRisk;
}
// -------------- HELP FUNCTIONS--------------
bool areFullyCompatible(int *nodes, int nodesNum, string print) {
char *node;
char *dup;
int tmp;
bool flag = false;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL && !flag)
{
tmp = atoi(node);
if (contains(nodes, nodesNum, tmp))
flag = true;
node = strtok(NULL, ",");
}
// flag signals whether an element in the print is already contained. If it is, there's no full compatibility
if (flag)
return false;
delete dup;
delete node;
return true;
}
// adds the new nodes to the list
void addNodes(int *nodes, int &nodesNum, string print) {
char *node;
char *dup;
int tmp;
// in this case I must add the new nodes to the list
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
if (tmp != 0) {
nodes[nodesNum] = tmp;
nodesNum++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
}
// verifies whether a node is already contained in the nodes list
bool contains(int *nodes, int nodesNum, int node) {
for (int i = 0; i < nodesNum; i++)
if (nodes[i] == node)
return true;
return false;
}
// verifies if there are no more nodes to be added to the list (0 excluded)
bool selectionComplete(int nodesNum, int maxSize) {
return nodesNum == (maxSize-1);
}
// extracts nodes from a print add adds them to the nodes list
void extractNodes(string print, int *nodes, int &nodesNum, int maxSize) {
char *node;
char *dup;
int idx = 0;
int tmp;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
// not adding 0 because every prints contains it
if (tmp != 0) {
nodes[idx] = tmp;
idx++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
nodesNum = idx;
}
You have forgotten to delete several things and used the wrong form of delete for arrays where you have remembered, e.g.
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
//...
delete [] nodes; //<------- DO THIS not delete nodes
The simplest solution is to avoid using raw pointers and use smart ones instead. Or a std::vector if you just want to store stuff somewhere to index into.
You have new without corresponding delete
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
These should be deleted somewhere using delete [] ...
You allocate actualNodes in analyze() but you don't release the memory anywhere:
int *actualNodes = new int[maxSize];
In Addition, Analyzer::bestResult and Analyzer::actualResult are allocated in the constructor of Analyzer but not deallocated anywhere.
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
If you must use pointers, I really suggest to use smart pointers, e.g. std::unique_ptr and/or std::shared_ptr when using C++11 or later, or a Boost equivalent when using C++03 or earlier. Otherwise, using containers, e.g. std::vector is preferred.
PS: You're code also has a lot of mismatches in terms of allocation and deallocation. If memory is allocated using alloc/calloc/strdup... it must be freed using free. If memory is allocated using operator new it must be allocated with operator delete. If memory is allocated using operator new[] it must be allocated with operator delete[]. And I guess you certainly should not delete the return value of strtok.

Access Object attributes in C++ [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am relatively new to C++ programming and I have done a code which is not performing as expected.
The code is a bit long [pasted at end for reference] but I will just point to my concern in the code:
I define an object of a class inside a while loop:
...
objVec[obj_i] = new ChipSeqRegion(refID, strand, midPoint, start, end, posArray, frac_posArray, negArray, frac_negArray);
//testing
cout<<"printing object number: "<<obj_i<<endl;
objVec[obj_i]->PrintID();
cout<<"printing frac pos array: "<<endl;
objVec[obj_i]->PrintFracPosArray();
obj_i++;
}
objVec[0]->PrintID();
cout<<endl;
objVec[0]->PrintFracPosArray();
cout<<endl;
objVec[1]->PrintID();
objVec[1]->PrintFracPosArray();
cout<<endl;
objVec[2]->PrintID();
objVec[2]->PrintFracPosArray();
}
In the above code fragment PrintID and PrintFracPosArray are just procedures[members of same class] to print contents of the variables/Arrays.
Now, If I try to print the object attributes refID and posArray inside the loop then all printed values come out different and as assigned and expected.
But outside the loop the printID attribute prints values uniquely [as expected] but posArray attributes just repeat the value last assigned in the loop.
I want to access all values uniquely outside the loop which is my concern.
I am sure this might be from a scope conflict or the way the variables are getting passed.
Any help will be great !!!
Thanks in advance.
A quick look on detailed code below can clarify any questions:
Detailed Code:[Apologies for bad presentation]
#include <iostream>
#include <string>
#include <fstream>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <iomanip>
#include <cmath>
#include "api/BamReader.h"
#include "api/BamWriter.h"
#include "api/BamAlignment.h"
#include "api/BamAux.h"
using namespace std;
using namespace BamTools;
BamReader reader;
BamAlignment al;
int const windowSize = 10;
int halfWindowSize = windowSize/2;
int const N = windowSize + 1;
//determine the gap score
float gap = -2;
//default value for matrix F
double negNum = -100000;
float F[N][N];
int xTraceBack[N][N];
int yTraceBack[N][N];
float maxScore;
int x_coord = 0;
int y_coord = 0;
//collections of arrays from chipSeq data after loading data
class ChipSeqRegion{
private:
int ref_id, mid_p, start_p, end_p;
char genomeStrand;
float* pos_array;
float* frac_positiveArray;
float* neg_array;
float* frac_negativeArray;
float* gap;
public:
ChipSeqRegion (int refID, char strand, int midPoint, int start, int end, float* posArray, float* frac_posArray, float* negArray, float* frac_negArray);
//accessors
int GetRefID(){return ref_id;}
int GetMidPoint(){return mid_p;}
void PrintID();
void PrintFracPosArray();
//destructor
~ChipSeqRegion(){
delete [] pos_array;
delete [] frac_positiveArray;
delete [] neg_array;
delete [] frac_negativeArray;
}
};
ChipSeqRegion::ChipSeqRegion(int refID, char strand, int midPoint, int start, int end, float* posArray, float* frac_posArray, float* negArray, float* frac_negArray){
ref_id = refID;
genomeStrand = strand;
mid_p = midPoint;
start_p = start;
end_p = end;
pos_array = posArray;
frac_positiveArray = frac_posArray;
neg_array = negArray;
frac_negativeArray = frac_negArray;
}
void ChipSeqRegion::PrintID(){
cout<<"ref id is: "<<ref_id<<endl;
}
void ChipSeqRegion::PrintFracPosArray(){
cout<<"this is raw pos data"<<endl;
for (int i = 0; i<windowSize; i++){
cout<<pos_array[i]<<'\t';
}
cout<<"this is frac data"<<endl;
for (int i = 0; i<windowSize; i++){
cout<<frac_positiveArray[i]<<'\t';
}
cout<<endl;
}
class ChipSeqLoader{
public:
void LoadData (string bamFileName, string coordFileName);
void GetRegions();
private:
string nameOfBamFile;
string nameOfCoordFile;
};
void ChipSeqLoader::LoadData(string bamFileName, string coordFileName){
nameOfBamFile = bamFileName;
nameOfCoordFile = coordFileName;
int obj_i = 0;
int objSize = 6;
ChipSeqRegion **objVec = new ChipSeqRegion* [objSize];
//reading coordinates
ifstream CoordFile;
char chrom[5], strand;
string sChr1, sChr2, withmotif, dot;
int start, end, midPoint;
float tag;
CoordFile.open(coordFileName.c_str());
if (CoordFile.is_open()){
while (!CoordFile.eof()){
CoordFile>>chrom;
CoordFile>>withmotif;
CoordFile>>dot;
CoordFile>>start;
CoordFile>>end;
CoordFile>>tag;
CoordFile>>strand;
CoordFile.ignore(200,'\n');
midPoint = (start+end)/2;
ostringstream convert1;
ostringstream convert2;
convert1<<chrom[3];
convert2<<chrom[4];
sChr1 = convert1.str();
sChr2 = convert2.str();
string sChrom;
sChrom = sChr1+sChr2;
int refID;
if (sChr1 =="X\0"){
refID = 19;
}else if (sChr1 == "Y\0"){
refID = 20;
}else{
refID = atoi(sChrom.c_str())-1;
}
int intStrand;
if (strand == '+'){
intStrand = 0;
}else if (strand == '-'){
intStrand = 1;
}
cout<<endl;
cout<<sChrom<<'\t'<<refID<<'\t'<<start<<'\t'<<end<<'\t'<<midPoint<<'\t'
<<strand<<'\t'<<intStrand<<endl;
//get information from the coordinates to return array
BamRegion region(refID, midPoint-600, refID, midPoint+600);
reader.SetRegion(region);
if(!reader.SetRegion(region)){
std::cout<<"could not set region."<<endl;
}
float posArray[windowSize];
float negArray[windowSize];
float frac_posArray[windowSize];
float frac_negArray[windowSize];
for (int index = 0; index < windowSize; index ++){
posArray[index] = 0;
negArray[index] = 0;
}
int posPosition;
int negPosition;
//if reverse strand, calculate and return the end position
//if positive strand, return the position
//put them in separate arrays
while (reader.GetNextAlignment(al)){
if (al.MapQuality>0 && al.IsReverseStrand()== true){
negPosition = al.GetEndPosition();
if (negPosition>=midPoint-halfWindowSize && negPosition <midPoint+halfWindowSize){
negArray[negPosition-midPoint+halfWindowSize]++;
}
}else if (al.MapQuality>0){
posPosition = al.Position;
if (posPosition>=midPoint-halfWindowSize && posPosition <midPoint+halfWindowSize){
posArray[posPosition-midPoint+halfWindowSize]++;
}
}
}
float posMax = 0, negMax = 0, max = 0;
float temp;
for (int i= 0; i<windowSize; i++){
temp = posArray[i];
if (temp>posMax){
posMax = temp;
}
}
for (int i = 0; i<windowSize; i++){
temp = negArray[i];
if (temp>negMax){
negMax = temp;
}
}
if (posMax>=negMax){
max = posMax;
}else{
max = negMax;
}
for (int i = 0; i<windowSize; i++){
frac_posArray[i] = posArray[i]/max;
frac_negArray[i] = negArray[i]/max;
}
objVec[obj_i] = new ChipSeqRegion(refID, strand, midPoint, start, end, posArray, frac_posArray, negArray, frac_negArray);
//testing
cout<<"printing object number: "<<obj_i<<endl;
objVec[obj_i]->PrintID();
cout<<"printing frac pos array: "<<endl;
objVec[obj_i]->PrintFracPosArray();
obj_i++;
}
objVec[0]->PrintID();
cout<<endl;
objVec[0]->PrintFracPosArray();
cout<<endl;
objVec[1]->PrintID();
objVec[1]->PrintFracPosArray();
cout<<endl;
objVec[2]->PrintID();
objVec[2]->PrintFracPosArray();
}
}
int main(int argc, char* argv[]) {
string bamFileName, coordFileName;
if (argc == 3){
bamFileName = argv[1];
coordFileName = argv[2];
}else{
std::cout << "Wrong number of arguments." <<endl;
return 1;
}
if (!reader.Open(bamFileName)){
std::cout<< "Could not open input Bam file." <<endl;
return 1;
}
if (!reader.LocateIndex()){
std::cout<<"Could not locate index file."<<endl;
return 1;
}
ChipSeqLoader loader;
loader.LoadData(bamFileName, coordFileName);
return 0;
}
All your objects point to the same piece of data, namely posArray and frac_posArray which are defined in the loop: if you look at the ChipSeqRegion class constructor, it accepts 2 arrays (with the very same names as the arrays cited above), ie. 2 pointers to sequences of data in memory. These pointers in the constructors are simply copied over in the instance fields:
pos_array = posArray;
frac_positiveArray = frac_posArray;
instead of copying the array contents, as it should probably be:
pos_array = new int[windowSize];
memcpy(pos_array,posArray, sizeof(int)*windowSize); // or use std::copy_n
frac_positiveArray = new int[windowSize];
memcpy(frac_positivearray,frac_posArray, sizeof(int)*windowSize); // or use std::copy_n
You probably will have the same issue with other arrays in the class.

I am getting a pointer being free but not allocated error when running make, make test in putty

I am very new to object oriented programming, pointer use and allocating memory in C++. I am working on an assignment for class and initially I had it pass the first three tests listed below by having an array, grade_array, that in the addScore function looked like grade_array[count -1] = grade. Then it would be used in the mean function.
I know this is not the correct way to go about this because I was getting seg faults, so I know I need to have an array, then create a new array (twice the size) that allocates more memory so that I can put the values of the first one into the new one, and then delete to not get memory leaks. The real problem I am having is I do not know if I am even close to correct on the way I am doing this. The error I am getting:
Running cxxtest tests (5 tests)testrunner(85436) malloc: *** error for object 0x107a87970: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
make: *** [test] Abort trap: 6
I have seen a lot of people having similar problems and posting about them on this very site I just cannot seem to fix mine. I saw that it could be that I made a new pointer and tried to them have them point to the same thing so when one deletes the other has nothing to delete or that my initializer is wrong as it doesn't do much. Like I said, very new to the topic so sorry if I have a million questions and so many errors. I have spent a lot of time on this already and was hoping I could maybe get some advice before I waste more time, thanks in advance!
Gradebook.h
#ifndef GRADEBOOK_H
#define GRADEBOOK_H
#include <string>
using namespace std;
class Gradebook {
public:
Gradebook();
Gradebook(const string& filename);
Gradebook(const Gradebook& that);
virtual ~Gradebook();
void initCount();
void addScore(double grade);
double getScoreAt(int i);
int getCount(int i);
string getSourceFile();
double getMean(); // change back to double
double getMin();
double getMax();
double getMedian();
double getStdDev();
int scoresInRange(double low, double high);
private:
string filename;
int* grade_array;
int new_size;
int count;
int count_tracker;
int* grade_point;
};
#endif
Gradebook.cpp
void Gradebook::initCount(){
count = 0;
}
Gradebook::Gradebook() {
}
Gradebook::Gradebook(const string& filename) : filename(filename) {
//this->filename = filename; // i beleive that filename(filename) does this line
//grade_array = new int[this->getCount(0) +1];
}
Gradebook::Gradebook(const Gradebook& that) {
}
Gradebook::~Gradebook() {
for ( int i = 0; i < this->getCount(0); i ++){
delete &grade_array[i];
}
delete grade_array;
}
void Gradebook::addScore(double grade) {
int count_tracker = this->getCount(1); //number of elements in array currently
// grade_array = new int[count_tracker ];
// grade_array = new int[1]; // grade_array is just a *array
grade_array[count_tracker -1 ] = grade; // array[0] is first not array[1]
new_size = count_tracker * 2;
int* new_array = new int[new_size];
for (int i = 0; i < count_tracker ; i++) {
new_array[i] = grade_array[i];
}
delete[] grade_array;
grade_array = new_array;
count_tracker = new_size;
}
double Gradebook::getScoreAt(int i) {
return grade_array[i];
}
int Gradebook::getCount(int i) {
if (i == 1){
count = count + 1;
}
else{
//don't want to add to the actual count
}
return count;
}
string Gradebook::getSourceFile() {
//ifstream foo;
//foo.open(filename);
return filename;
}
double Gradebook::getMean() {
double mean = 0;
count_tracker = this->getCount(0);
for (int i = 0; i < count_tracker ; i++){
//mean = (*(&(grade_array[i])- (bit_count))) + mean;
mean = grade_array[i] + mean;
}
return (mean/count_tracker);
}
GradebookTest.h
#ifndef GRADEBOOK_TEST_H
#define GRADEBOOK_TEST_H
#include <Gradebook.h>
#include <cxxtest/TestSuite.h>
class GradebookTest : public CxxTest::TestSuite {
public:
void testDefaultConstructor(){
string filename = "data1.txt";
Gradebook a(filename);
TS_ASSERT_EQUALS("data1.txt" , a.getSourceFile());
}
void testAddOne() {
Gradebook gb;
gb.initCount();
gb.addScore(110);
TS_ASSERT_EQUALS(120, gb.getScoreAt(1));
TS_ASSERT_DELTA(110, gb.getMean(), 0.001);
TS_ASSERT_EQUALS(4, gb.getCount(0) );
}
void testAddMultiple() {
Gradebook gb;
gb.addScore(75);
TS_ASSERT_EQUALS(1, gb.getCount(0) );
gb.addScore(85);
TS_ASSERT_EQUALS(2, gb.getCount(0));
TS_ASSERT_DELTA(85, gb.getMean(), 0.001);
}
#endif
I think the following is wrong
for ( int i = 0; i < this->getCount(0); i ++){
delete &grade_array[i];
}
You don't need this for loop since you only allocate memory for grad_array. One delete grade_array; is enough.

Sorting a 2D Char and Int Array from class using bubble sort?

I am trying to sort an array of int and chars (from a class) by descending order. These are student names and grades.
The class is defined as:
class Student {
public:
char name[20];
int grades;
};
numCount is the incremental value of number of records.
void bubble_sort(Student theResults[], int numCount)
{
bool swapped = true;
while(swapped)
{
swapped = false;
for(int i=1;i<numCount;i++)
{
if(theResults[i-1].grades < theResults[i].grades)
{
int tempHold = theResults[i-1].grades;
theResults[i-1].grades = theResults[i].grades;
theResults[i].grades = tempHold;
swapped = true;
}
}
}
The issue I am having is that the int values (grades) are sorted correctly after the loop but having difficulty getting the names to be correctly allocated to match with the grades.
I have used the following code but it doesn't work as it displays the incorrect grades for the students.
char* title_temp = theResults[i-1].name;
theResults[i-1].name[20] = theResults[i].name[20];
theResults[i].name[20] = title_temp[20];
I think your problem is here:
if(theResults[i-1].grades < theResults[i].grades)
{
int tempHold = theResults[i-1].grades;
theResults[i-1].grades = theResults[i].grades;
theResults[i].grades = tempHold;
swapped = true;
}
What you really want to do is
if(theResults[i-1].grades < theResults[i].grades)
{
Student tempHold = theResults[i-1];
theResults[i-1] = theResults[i];
theResults[i] = tempHold;
swapped = true;
}
Before all you were changing was the grade value and not the names, this will switch the entire Student object and should produce the output you are looking for
You'd have to copy the entire char block, each element at a time using a loop, or you could use memcpy.
You could also use a shallow copy of your class
void bubble_sort(Student theResults[], int numCount)
{
bool swapped = true;
while(swapped)
{
swapped = false;
for(int i=1;i<numCount;i++)
{
if(theResults[i-1].grades < theResults[i].grades)
{
Student tempHold = theResults[i-1];
theResults[i-1]= theResults[i];
theResults[i] = tempHold;
swapped = true;
}
}
}
}
The problem is that you need to swap the objects, the grades only have to act as a key to guide the sort, try this :
void bubble_sort(Student theResults[], int numCount)
{
Student tempHold;
bool swapped = true;
while(swapped)
{
swapped = false;
for(int i=1;i<numCount;i++)
{
if(theResults[i-1].grades < theResults[i].grades)
{
tempHold = theResults[i-1]; //swap the objects, not just the grades.
theResults[i-1]= theResults[i];
theResults[i] = tempHold;
swapped = true;
}
}
}}
However, if you must copy members, then in addition to swapping grades :
char temp[20];
strcpy(temp ,theResults[i-1].name);
strcpy(theResults[i-1].name,theResults[i].name);
strcpy(theResults[i].name,temp);
Instead of using
char* title_temp = theResults[i-1].name; // <-wrong
theResults[i-1].name[20] = theResults[i].name[20];//20 is invalid index
theResults[i].name[20] = title_temp[20]; //this is just 1 element out of the whole array
which is wrong due to many reasons.