c++ polynomial copy-constructor and ostream override cause memeory leaks?! - c++

Hi there I am working on a polynomial class in c++. So far everything works very well. But now I encountered an error I simply cannot spot :/
polynomial.cpp
// copy-constructor
Polynomial::Polynomial(const Polynomial &p){
size = p.size;
buffer = p.buffer;
poly = new double(buffer);
for (int i = 0; i < size; ++i) poly[i] = p[i];
for (int i = size; i < buffer; ++i) poly[i] = 0;
}
// output stream override | it's a non-member function
ostream& operator<<(ostream& os, const v1::Polynomial& p){
int degree = p.degree();
stringstream ss;
if (degree == 0) ss << '0';
else if (degree > 0){
ss << '(';
for (int i = degree; i >= 0; --i){
ss << p[i];
ss << "x^";
ss << i;
if (i > 0)
ss << " + ";
}
ss << ')' << endl;
}
os << ss.str();
return os;
}
So this is how I call the copy-constructor:
// note: printing 'a' itself does not cause problems...
v1::Polynomial b(a);
cout << "Polynomial b: " << b << " degree: " << b.degree() << endl;;
The stack-log from Visual Studio says it's in Line 23 (here: the line above this one, where I actually want to print 'b') and then it continues to call some heap functions etc..
Running the program without debug (via cmd) results in an APPCRASH, with "Polynomial b: " being the last thing displayed.
I unfortunately don't know how to debug in Visual Studio, I was used to valgrind in linux, which i currently don't have set up :/
Anyone any idea? Or do you need additional info?
Regardless, many thanks in advance =)

poly = new double(buffer);
Here you allocate a single double and set it to buffer. You probably mean
poly = new double[buffer];
or whatever size you desire.
A much better solution would be using std::vector instead of raw arrays. You can copy it with =, resize it with std::vector::resize and reserve more space with std::vector::reserve.

Related

How can I make a vector with all the video modes in SFML?

I have this:
std::vector <sf::VideoMode> *screenResolution = new std::vector<sf::VideoMode>;
*screenResolution = sf::VideoMode::getFullscreenModes();
for (std::size_t i = 0; i < screenResolution->size(); ++i)
{
std::cout << screenResolution[i]->width << ":" << screenResolution[i]->height <<std::endl;
}
And for some reason an error appears in the cout that says "the expresion must be a type of pointer".
You have to carefuly read error message. Your vector is of sf::VideoMode which doesn't look like pointer. Only -> can dereference pointers, so you can't use it in your loop. You also probably don't need dynamic allocation for your vector.
The following code should work for you:
std::vector<sf::VideoMode> screenResolution = sf::VideoMode::getFullscreenModes();
for (std::size_t i = 0; i < screenResolution.size(); ++i)
{
std::cout << screenResolution[i].width << ":" << screenResolution[i].height << std::endl;
}

Reading into an Array Multiple Times

I'm having a little trouble with my code. It's pretty much supposed to open two files, and compare the first twenty line of the file "StudentAnswers.txt" [inputted as a char into a char array] against a char value in (each line of another file) "CorrectAnswers.txt" in another array at the same position (index). It's like a linear search, but the same position in the arrays. Then a report should be displayed, detailing which question the student missed, the given answer, the correct answer, and if the student passed (got >= 70%) or not, like the following:
Report for Student X:
2 (A/D), 3 (C/D), 5(D/A)
This student passed the exam!
Then it should clear the SAArray, and feed the next twenty lines from StudentAnswers.txt, and start the process all over again. I guess the program has to determine the number of students from (lines of 'StudentAnswers.txt' file / 20).
I'm having trouble displaying the report, and having the array clear itself after the program. I'm guessing this can be done with a while loop and an accumulator for the number of students (to be determined by above equation).
Also, Visual Studio seems to go to "Missed __ questions for a total of ___ %", and then keep looping -858993460.
Any help would be appreciated.
#include <iostream>
#include <fstream>
#include <string>
#include <array>
#include <algorithm>
using namespace std;
void GradeReturn(char[], char[], int, int, int);
string PassFail(float);
int main()
{
ifstream SA("StudentAnswers.txt");
ifstream CA("CorrectAnswers.txt");char CAArray[20];
char SAArray[20];
// char SA2Array[20];
bool isCorrect;
int correct;
int incorrect;
int counter;
correct = 0;incorrect = 0;
counter = 0;
cout << endl;
if (!SA.fail())
{
cout << "'StudentAnswers.txt' file opened successfully." << endl;
cout << "'CorrectAnswers.txt' file opened successfully." << endl << endl;
int a = 0;
int b = 0;
while (a < 20)
{
CA >> CAArray[a];
a++;
} // while loop to feed char into the array
while (b < 20)
{
SA >> SAArray[b];
b++;
}
} // while loop to feed char into array
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter);
return 0;
}
void GradeReturn(char CAArray[], char SAArray[], int correct, int incorrect, int counter)
{
float percent;
float hundred;
int student;
int catcher[20];
int writeCatcher; int starter;
int catcher_size;
student = 0;
writeCatcher = 0;
catcher_size = ((sizeof catcher) / 4);
while (counter < 20)
{
if ((CAArray[counter]) == (SAArray[counter]))
{
correct++;
cout << "Good job!" << endl;
} // correct handling
else
{
incorrect++;
cout << "You got question " << counter << " wrong." << endl;
counter >> catcher[writeCatcher];
writeCatcher++;
} // incorrect handling
counter++;
} // while loop to determine if a student got a question right or wrong
static_cast <float> (incorrect); // float conversion
cout << endl; // for cleanliness
percent = ((static_cast <float> (correct)) / 20); // percentage
hundred = percent * 100;
PassFail(percent);
if (PassFail(percent) == "pass")
{
student++;
cout << "Report for Student " << student << ":" << endl;
cout << "-----------------------------" << endl;
cout << "Missed " << incorrect << " questions out of 20 for ";
cout << hundred << " % correct." << endl << endl;
starter = 0;
while (starter < (sizeof catcher)
{
if(1=1)
{
catcher_size
}
else
{
cout << "";
starter++;
}
}
}
else if (PassFail(percent) == "fail")
{
student++;
cout << "Missed " << incorrect << " questions out of 20 for ";
cout << hundred << " % correct." << endl << endl;
while (starter < catcher_size)
{
if ((catcher[starter]) == -858993460)
{
starter++;
}
else
{
cout << "";
starter++;
}
}
}
return;
}
string PassFail(float percent)
{
if (percent >= 0.70) // if <pass>
{
return "pass";
}
else // if <fail>
{
return "fail";
}
cout << endl;
}
To get a loop you should keep streams open instead of closing them after reading 20 lines.
As pseudo code that would be:
a = 0;
while(streams_not_empty)
{
CA >> CAArray[a];
SA >> SAArray[a];
++a;
if (a == 20)
{
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter);
a = 0; // Reset a
}
}
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
You would also need to pass correct, incorrect, counter by reference so that the GradeReturn can change their value and their by do the accumulation.
Like:
void GradeReturn(char CAArray[], char SAArray[], int& correct, int& incorrect, int& counter)
Further you shouldn't rely on being able to read exactly Nx20 lines from the files every time. A file could have, e.g. 108 (5x20 + 8) lines, so you code should be able to handle the with only 8 lines. In other words, don't hard code 20 in your function like while (counter < 20). Instead pass the number of lines to be handled and do while (counter < number_to_handle).
Something like this as pseudo code:
a = 0;
while(streams_not_empty)
{
CA >> CAArray[a];
SA >> SAArray[a];
++a;
if (a == 20)
{
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter, a);
// ^
a = 0; // Reset a
}
}
if (a != 0)
{
// Process the rest
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter, a);
}
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
One problem you have is you're trying to compare C-style strings with the == operator. This will compare them essentially as if they were pointers to char, i.e. compare whether they point at the same location in memory, not compare the contents of the string. I urge you to look up array-decay and c-string variables to understand more.
Specifically, if (PassFail(percent) == "pass") isn't going to do what you want it to. strcomp doc, strncmp doc using std::string variables instead of c-style strings would all work, but it would be better simply to compare percent to a value, i.e. if(percent >= 0.70 directly instead of calling PassFail and comparing a string.
There are many other issues here also, you at one point call PassFail but do nothing with the return value. The only side affect of PassFail is cout << endl, if that's what you intend, it's a poor decision and hard to read way to put a newline on the console.
Try asking your compiler for more warnings, that's often helpful in finding these types of issues. -Wall -Wextra work for gcc, you may have to read your compiler manual...

Why does my vector size keep resetting to 0? (currently using classes)

I've been trying to make a polynomial class, and I've got almost half of it done. However, my vectors keep resetting to 0 after "polynomial q(coeff, expo);", can anyone tell me why?
class polynomial {
public:
polynomial();
polynomial(vector<float> coefficient, vector<int> degree);
friend ostream& operator<<(ostream& os, const polynomial& y);
private:
vector<float> coeff1;
vector<int> expo1;
};
polynomial::polynomial(){
coeff1.clear();
expo1.clear();
coeff1.push_back(1);
}
polynomial::polynomial(vector<float> coefficient, vector<int> degree){
if (coefficient.size() != degree.size()){
cout << "Error. The number of coefficients are not the same as the number of exponents. Polynomial will be set to 1." << endl;
polynomial();
}
else {
for (int b = 0; b<degree.size(); b++) {
for (int c = 0; c<b; c++){
if (degree[b] > degree[c]){
int holder = degree[b];
degree[b] = degree[c];
degree[c] = holder;
float holder1 = coefficient[b];
coefficient[b] = coefficient[c];
coefficient[c] = holder1;
}
}
}
for (int a = 0; a<coefficient.size(); a++) {
coeff1.push_back (coefficient[a]);
expo1.push_back (degree[a]);
}
}
}
ostream& operator<<(ostream& os, const polynomial& y){
if (y.coeff1.size() != y.expo1.size()) {
os << 1;
return os;
}
else {
for (int x = 0; x<y.coeff1.size(); x++){
if (y.coeff1[x] != y.coeff1[y.coeff1.size() - 1]) {
if (y.expo1[x] == 1){
os << y.coeff1[x] << "x" << " + ";
}
else if(y.expo1[x] == 0) {
os << y.coeff1[x];
}
else {
os << y.coeff1[x] << "x^" << y.expo1[x] << " + ";
}
}
else {
if (y.expo1[x] == 1){
os << y.coeff1[x] << "x";
}
else if(y.expo1[x] == 0) {
os << y.coeff1[x];
}
}
}
return os;
}
}
int main()
{
vector<float> coeff;
vector<int> expo;
coeff.push_back(3);
coeff.push_back(16);
coeff.push_back(10);
// coeff.push_back(7);
expo.push_back(4);
expo.push_back(1);
expo.push_back(2);
expo.push_back(3);
polynomial p;
cout << "The polynomial is: " << p << endl;
polynomial q(coeff, expo);
cout << "The polynomial is: " << q << endl;
return 0;
}
[there are useless lines of code because i wanted to check where the size of my vector was changing to 0]
This line:
polynomial();
creates an unnamed object and immediately destroys it. It has the same effect as:
{
polynomial x;
}
I guess you were trying to "call the constructor". However this is not possible, constructors are special and can only be 'called' by virtue of the attempt to create an object; or from the ctor-initializer list .
I would suggest redesigning your constructors. Firstly, the copy-constructor is bogus (it doesn't copy any of the fields except ptr, and also int *ptr was not initialized by the normal constructors). In fact int *ptr; should be removed entirely.
In the constructor polynomial() , the calls to clear() are redundant. Vectors start off empty, and since this is a constructor, it's only called on a polynomial that is just in the business of being created for the first time.
I would suggest doing this for the constructor taking two arguments:
polynomial::polynomial(vector<float> coefficient, vector<int> degree)
{
if (coefficient.size() != degree.size())
{
// typically it would be better to just throw an exception here, the caller will not expect a 1-polynomial
std::cerr << "Error. The number of coefficients are not the same as the number of exponents. Polynomial will be set to 1." << std::endl;
coeff1.push_back(1);
wala();
}
else
{
set_polynomial(coefficient, degree);
}
}
and move your other logic for sorting the coefficient and degree into a private function called set_polynomial. This keeps your constructor easy to read and your code tidy; you may want to use this function at a later time to allow the user to change a polynomial.
Pro tip: look into std::tie, you can actually sort coefficient and degree together using a single command.

Access violation error when getting input from a binary file

Okay, so I'm trying to read input from a binary file. I've changed this code a bit, but with this version, I'm getting an access violation error... So it's trying to access something that isn't there. Here's my source code for the problem area:
void HashFile::fileDump (ostream &log)
{
HashNode *temp = new HashNode;
fstream bin_file;
bin_file.open ("storage_file.bin", ios::in | ios::binary);
for(int i = 0; i < table_size; i++)
{
bin_file.seekg( i * sizeof(HashNode) );
bin_file.read( (char *)&temp, sizeof(HashNode) );
printDump(HashNode(temp->title, temp->artist, temp->type, temp->year,
temp->price), log, i);
}
bin_file.close();
}
void HashFile::printDump(HashNode A, ostream &log, int N)
{
log << "(" << N << ") " << A.title << ", " << A.artist
<< ", " << A.type << ", " << A.year << ", $"
<< setprecision(2) << A.price << endl;
}
I know that I should have some kind of error checking. Right now the error is occurring in the printDump function. Whenever I try to output to the log I get an access violation error. However, I change the log to cout and my code will run fine somewhat. It will read the binary file I've created correctly until it gets to the last element. For what I've been testing with, table_size should be equal to 5. So I get into the for loop and i is incremented until it reaches 5 and then it keeps going. table_size is being changed to some random value even though I haven't physically touched it. Am I somehow writing over table_size's address in memory?
Here is the definition of my Node:
class HashNode
{
public:
HashNode();
~HashNode();
HashNode(string title, string artist, string type, int year, float price);
friend class HashFile;
private:
char title [35];
char artist [25];
char type [12];
int year;
float price;
};
This
bin_file.read( (char *)&temp, sizeof(HashNode) );
should be this
bin_file.read( (char *)temp, sizeof(HashNode) );
You are getting confused over pointers.
Whether that code will actually work depends strongly on the definition of Node which you haven't shown.
Also the code leaks memory as temp is never deleted. It would be better not to allocate temp at all, like this
void HashFile::fileDump (ostream &log)
{
HashNode temp;
fstream bin_file("storage_file.bin", ios::in | ios::binary);
for(int i = 0; i < table_size; i++)
{
bin_file.seekg( i * sizeof(HashNode) );
bin_file.read( (char *)&temp, sizeof(HashNode) );
printDump(HashNode(temp.title, temp.artist, temp.type, temp.year, temp.price), log, i);
}
}
Not clear why you feel the need to create a new node from temp, why not just pass temp to printDump? Like this
printDump(temp, log, i);
But without seeing the definition of Node I can't say for sure.
Also no need to close the file, that happens automatically, also opening the file in the constructor is a little cleaner IMHO.
EDIT
OK having seen the definition of Node this would be my recommendation
void HashFile::fileDump(ostream &log)
{
fstream bin_file("storage_file.bin", ios::in | ios::binary);
for(int i = 0; i < table_size; i++)
{
bin_file.seekg(i * sizeof(HashNode));
HashNode temp;
bin_file.read((char *)&temp, sizeof(HashNode));
printDump(temp, log, i);
}
}
Also I would change printDump to use a const reference, this avoids copying a Node object (it is quite big).
void HashFile::printDump(const HashNode& A, ostream &log, int N)
{
log << "(" << N << ") " << A.title << ", " << A.artist
<< ", " << A.type << ", " << A.year << ", $"
<< setprecision(2) << A.price << endl;
}

Split array string in c++

I am new to cpp and have a situation in which I want to split array string
I have
for( i = k = 0; i < points[1].size(); i++ )
{
cout << points[1][k];
}
Output >>
[390.826, 69.2596]
[500.324, 92.9649]
[475.391, 132.093]
[5.60519e-44, 4.62428e-44]
I want
390.826
69.2596
500.324
92.9649
475.391
132.093
5.60519e-44
4.62428e-44
Please help me.Thanks
Assuming the type of point has public members x and y:
for( i = k = 0; i < points[1].size(); i++ )
{
cout << points[1][k].x << endl;
cout << points[1][k].y << endl;
}
If the members are something else, say, X and Y (the uppercase), then use the uppercase instead (or whatever it is).
The reason why you code prints the output that way, because operator<< has been overloaded for the type of the point. Something like:
std::ostream & operator<<(std::ostream & out, const point &p)
{
return out << "[" << p.x << "," << p.y << "]\n";
}
If you can search the above definition (or something similar) somewhere in your project source code, and then can change that to this:
std::ostream & operator<<(std::ostream & out, const point &p)
{
return out << p.x << "\n" << p.y << "\n";
}
then you wouldn't need to change the code in your for loop.
This has nothing to do with string splitting, what does points[1][k] actually return (i.e. it's type). Then look at how it has implemented the stream out operator (operator<<), and you'll see how the above is printed. This should give you a clue about the two individual values (i.e. fields of that *type), and you can simply access them and print them out.