Build is successful, but the test case #2 keep failing. I don't know what to change or fix. The test program says that
Test Case #2 operator <=() FAILED and operator >() Failed.
Here is My header
#ifndef MYSTRING_H
#define MYSTRING_H
#include <iostream>
#include <cstring> //library functions
#include <cstdlib> //exit() function
using namespace std;
// MyString class
class MyString
{
private:
char *str;
int len;
public:
//constructor
MyString()
{
*str = 0;
len = 0;
}
// convert and copy constructors.
MyString(char *);
MyString(MyString &);
// Destructor.
~MyString()
{
if (len != 0)
delete[] str;
str = 0;
len = 0;
}
// operators.
int length() { return len; }
char *getValue() { return str; };
//==
bool operator==(MyString &);
//!=
bool operator!=(MyString &);
//>
bool operator>(MyString &);
//<
bool operator<(MyString &);
//>=
bool operator>=(MyString &);
//<=
bool operator<=(MyString &);
// insertion and extraction operators.
friend ostream &operator<<(ostream &, const MyString &);
};
// NOTE: Below is the implementation for the functions that are declared above
//constructor
MyString::MyString(char *sptr)
{
len = strlen(sptr);
str = new char[len + 1];
strcpy(str, sptr);
}
//Copy Constructor
MyString::MyString(MyString &right)
{
str = new char[right.length() + 1];
strcpy(str, right.getValue());
len = right.length();
}
//==
bool MyString::operator==(MyString &right)
{
return !strcmp(str, right.getValue());
}
//!=
bool MyString::operator!=(MyString &right)
{
return strcmp(str, right.getValue());
}
//>
bool MyString::operator>(MyString &right)
{
if (strcmp(str, right.getValue()) > 0)
return true;
else
return false;
}
//<
bool MyString::operator<(MyString &right)
{
if (strcmp(str, right.getValue()) < 0)
return true;
else
return false;
}
//>=
bool MyString::operator>=(MyString &right)
{
if (strcmp(str, right.getValue()) >= 0)
return true;
else
return false;
}
//<=
bool MyString::operator<=(MyString &right)
{
if (strcmp(str, right.getValue()) <= 0)
return true;
else
return false;
}
//stream operators
ostream &operator<<(ostream &strm, const MyString &obj)
{
strm << obj.str;
return strm;
}
#endif
And here is the test program.
#include "stdafx.h"
#include <iostream>
#include "MyString.h"
using namespace std;
// Declare a new datatype that defines requires test case parameters
typedef struct {
char str1[128];
char str2[128];
bool equalNotEqual;
bool lessThan;
bool lessThanEqual;
bool greaterThan;
bool greaterThanEqual;
bool testPassed;
} TEST_CASE;
// Declare various test cases used to test the MyString object
TEST_CASE testCases[] = {
/* str1 str2 == < <= > >= P/F flag */
{ "test", "test", true, false, true, false, true, true },
{ "test", "Test", false, false, true, false, true, true },
{ "test", "test1", false, true, true, false, false, true },
{ "test ", "test", false, false, false, true, true, true }
};
// Main programentry point
int main()
{
// Flag used to determine if any test case failed
bool failed = false;
// Loop through all test cases
for (int i = 0; i < sizeof(testCases) / sizeof(TEST_CASE); ++i)
{
// Instantiate two MyString objects that will be used to test overloaded operators
MyString myStrObj1(testCases[i].str1);
MyString myStrObj2(testCases[i].str2);
cout << "Test Case #" << i + 1 << endl;
//-------------------------
// Test the operator==()
//vvvvvvvvvvvvvvvvvvvvvvvvv
if ((myStrObj1 == myStrObj2) != testCases[i].equalNotEqual)
{
cout << "\t***** operator==() FAILED" << endl;
testCases[i].testPassed = false;
}
//-------------------------
// Test the operator!=()
//vvvvvvvvvvvvvvvvvvvvvvvvv
if ((myStrObj1 != myStrObj2) == testCases[i].equalNotEqual)
{
cout << "\t***** operator!=() FAILED" << endl;
testCases[i].testPassed = false;
}
//-------------------------
// Test the operator<()
//vvvvvvvvvvvvvvvvvvvvvvvvv
if ((myStrObj1 < myStrObj2) != testCases[i].lessThan)
{
cout << "\t***** operator<() FAILED" << endl;
testCases[i].testPassed = false;
}
//-------------------------
// Test the operator<=()
//vvvvvvvvvvvvvvvvvvvvvvvvv
if ((myStrObj1 <= myStrObj2) != testCases[i].lessThanEqual)
{
cout << "\t***** operator<=() FAILED" << endl;
testCases[i].testPassed = false;
}
//-------------------------
// Test the operator>()
//vvvvvvvvvvvvvvvvvvvvvvvvv
if ((myStrObj1 > myStrObj2) != testCases[i].greaterThan)
{
cout << "\t***** operator>() FAILED" << endl;
testCases[i].testPassed = false;
}
//-------------------------
// Test the operator>=()
//vvvvvvvvvvvvvvvvvvvvvvvvv
if ((myStrObj1 >= myStrObj2) != testCases[i].greaterThanEqual)
{
cout << "\t***** operator>=() FAILED" << endl;
testCases[i].testPassed = false;
}
// Use the ostream operator to display the string stored in the MyString operator
cout << "The string should be \'" << testCases[i].str1 << "\' string returned from MyClass \'" << myStrObj1 << "\'" << endl << endl;
// Did this test case passed?
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvv
if (testCases[i].testPassed)
{
// yes!!!
cout << "Test Case #" << i + 1 << " PASSED!!!!" << endl << endl;
}
else
{
// Nope, set failed flag
failed = true;
}
} /* end of for loop */
//-------------------------
// Display Overall Status
//vvvvvvvvvvvvvvvvvvvvvvvvv
if (!failed)
{
cout << "**************************" << endl;
cout << "***** OVERALL PASSED *****" << endl;
cout << "**************************" << endl;
}
else
{
cout << "**************************" << endl;
cout << "***** OVERALL FAILED *****" << endl;
cout << "**************************" << endl;
}
return 0;
}
Thanks is advance for any help.
"[The strcmp] function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null-character is reached. This function performs a binary comparison of the characters."
Since 't' is greater than 'T', "test" is greater than "Test" by this rule. Perhaps you're expecting strcmp to do something more than it actually does, such as implement English language rules for word comparisons. Have a look at things like std::collate.
Related
Create a class for working with stitches. The maximum length of the sequence is 254. The first byte must contain information about the actual number of array elements. Will perform an overload of operations:
"=" – assignment,
"+" - concatenation (connection) of a term,
"<=" – relation "less than or equal to",
" >= " – relation "greater than or equal to",
"==" - relation "equals",
"!=" – relation "is not equal".
In the class, provide an initialization constructor, a copy constructor, and a destructor.
As a result, the program does not start for some reason
Here is my code
#include <iostream>
#include <string.h>
using namespace std;
class String {
public:
char* str;
String();
~String();
String(const String& other);
String operator = (String& line);
String operator + (String& line);
bool operator <= (String& line);
bool operator >= (String& line);
bool operator == (String& line);
bool operator != (String& line);
friend ostream& operator<<(ostream& stream, String& obj);
friend istream& operator>>(istream& stream, String& obj);
void strcopy(char* str1, char* str2);
char mystrcat(char* str1, const char* str2);
int strlenght(const char* str);
};
String::String() {
str = new char[256];
}
String::~String() {
delete[] str;
}
String::String(const String& other) {
str = new char[256];
strcopy(str, other.str);
}
String String::operator = (String& line) {
strcopy(str, line.str);
return *this;
}
String String::operator + (String& line) {
mystrcat(str, line.str);
return *this;
}
bool String::operator >= (String& line) {
if (strlenght(str) >= strlenght(line.str)) {
return true;
}
else {
return false;
}
}
bool String::operator <= (String& line) {
if (strlenght(str) <= strlenght(line.str)) {
return true;
}
else {
return false;
}
}
bool String::operator != (String& line) {
if (strlenght(str) != strlenght(line.str)) {
return true;
}
else {
return false;
}
}
bool String::operator == (String& line) {
}
ostream& operator<<(ostream& stream, String& obj)
{
stream << obj.str;
return stream;
}
istream& operator>>(istream& stream, String& obj)
{
stream >> obj.str;
return stream;
}
void String::strcopy(char* str1, char* str2) {
while (*str1++ = *str2++);
}
char String::mystrcat(char* str1, const char* str2) {
char* begin = str1;
while (*str1) {
str1++;
}
while (*str1++ = *str2++);
*str1 = '\0';
return *begin;
}
int String::strlenght(const char* str) {
int counter = 0;
while (*str != '\0') {
counter++;
str++;
}
return counter;
}
int main() {
String input1, input2;
int change;
cout << "Enter the first line: ";
cin >> input1;
cout << "Enter the second line: ";
cin >> input2;
cout << "\t\tActions" << endl;
cout << "1. String Assignment;" << endl;
cout << "2. String concatenation;" << endl;
cout << "3.Relationship (greater than or equal to);" << endl;
cout << "4.Relationship (less than or equal to);" << endl;
cout << "5. Attitude (equal to);" << endl;
cout << "6. Attitude (not equal)." << endl;
cout << "Choice: ";
cin >> change;
switch (change) {
case 1: {
input2 = input1;
cout << "Result: " << input2 << endl;;
break;
}
case 2: {
String result = input1 + input2;
cout << "Concatenation result: " << result << endl;
break;
}
case 3: {
bool result = input1 >= input2;
if (result == true) {
cout << "The first string is greater than or equal to the second" << endl;
}
else {
cout << "The first line is less than the second" << endl;
}
break;
}
case 4: {
bool result = input1 <= input2;
if (result == true) {
cout << "The first string is less than or equal to the second" << endl;
}
else {
cout << "The first line is greater than the second" << endl;
}
break;
}
case 5: {
if ((input1 == input2) == true) {
cout << "Are equal" << endl;
}
else {
cout << "Not equal" << endl;
}
break;
}
case 6: {
bool result = input1 != input2;
if (result == true) {
cout << "The first line is not equal to the second" << endl;
}
else {
cout << "The first line is equal to the second" << endl;
}
break;
}
default: {
cout << "Mistake..." << endl;
return 1;
break;
}
}
return 0;
}
The only problem I can see with your code is that you are not returning anything on operator== Depending on your compiling flags this can produce a compilation error because you are not returning anything from the function.
Here is a possible implementation for that function:
bool String::operator == (String& line)
{
if (!strcmp(line.str, this->str))
return true;
else return false;
}
Learning operator overloading in this project, and below in the ship.cpp file is where I think my error is.
This is the test file, I cannot change this:
#include <iostream>
#include "Ship.h"
#include "Ship.h"
#include "Engine.h"
#include "Engine.h"
using namespace std;
using namespace sdds;
void printHeader(const char* title)
{
char oldFill = cout.fill('-');
cout.width(40);
cout << "" << endl;
cout << "|> " << title << endl;
cout.fill('-');
cout.width(40);
cout << "" << endl;
cout.fill(oldFill);
}
int main()
{
{
printHeader("T1: Testing Constants");
cout << "TYPE_MAX_SIZE: " << sdds::TYPE_MAX_SIZE << endl;
cout << "MIN_STD_POWER: " << sdds::MIN_STD_POWER << endl;
cout << "MAX_STD_POWER: " << sdds::MAX_STD_POWER << endl;
cout << endl;
}
{
printHeader("T2: Testing Default Constructor");
Ship invalid;
invalid.display();
invalid += Engine("D2", 2.1);
cout << endl;
}
Engine engines[] = {
Engine("V8", 4.4),
Engine("V8", 5.0),
Engine("Inline", 4.1),
Engine("D3", 7.0),
Engine("D0", 2.0),
Engine("D1", 3.2),
};
{
printHeader("T3: Testing Custom Constructor");
Ship titanic("cruiser", engines, 6);
titanic.display();
cout << endl;
}
{
printHeader("T4: Testing Conversion to Bool Operator");
Ship invalid;
Ship titanic("liner", engines, 1);
if (invalid)
cout << "1. Test Failed! Object should be invalid.\n";
else
cout << "1. Test succeeded!\n";
if (titanic)
cout << "2. Test succeeded!\n";
else
cout << "3. Test Failed! Object should be valid.\n";
cout << endl;
}
{
printHeader("T5: Testing += and < Operators");
Ship titanic("liner", engines, 3);
char type[]{ "D0" };
while (titanic < sdds::MIN_STD_POWER)
{
type[1]++;
cout << "Ship not up to standard. Required power: "
<< sdds::MIN_STD_POWER << endl;
titanic += Engine(type, 2.1);
}
titanic.display();
if (sdds::MAX_STD_POWER < titanic)
cout << "Too much power." << endl;
else
cout << "Ship doesn't exceed power regulation of: "
<< sdds::MAX_STD_POWER << endl;
}
return 0;
}
This is my Ship.cpp file. My error is in the += operator function, where I have to add an engine but don't understand how I should approach it.
#include <iostream>
#include <cstring>
#include "Ship.h"
using namespace std;
namespace sdds {
Ship::Ship(){
m_type[0] = '\0';
m_engCnt = 0;
}
Ship::Ship(const char* type, const Engine engines[], int cnt){
if (type != nullptr && engines != nullptr && cnt > 0) {
// create a valid ship
strncpy(m_type, type, TYPE_MAX_SIZE);
for (int i = 0; i < cnt; i++) {
m_engines[i] = engines[i];
}
m_engCnt = cnt;
}else{
m_type[0] = '\0';
m_engCnt = 0;
}
}
Ship::operator bool() const {
// return true if the ship is valid (not empty)
if(m_type[0] == '\0' || m_engCnt == 0){
return false;
}else{
return true;
}
}
Ship& Ship::operator+=(Engine e){
if (!*this) {
cout << "The Object is not valid! Engine cannot be added!" << endl;
return *this;
}else if (m_engCnt == NUM_OF_ENGINES){
return *this;
}else{
// ERROR I BELIEVE IS HERE --> I dont understand the syntax to add engine here
m_engCnt++;
return *this;
}
}
double Ship::calculatePower() const {
double power = 0;
for (int i = 0; i < m_engCnt; i++) {
power += m_engines[i].get() * 5;
}
return power;
}
void Ship::display()const{
if (*this) {
cout << m_type << " - " << calculatePower() << endl;
Engine e;
for (int i = 0; i < m_engCnt; i++) {
m_engines[i].display();
}
}else{
cout << "No available data" << endl;
}
}
bool Ship::operator<(double power) const{
if (calculatePower() < power) {
return true;
}else{
return false;
}
}
bool operator<(double power, const Ship& theShip){
if (power < theShip.calculatePower()) {
return true;
}else{
return false;
}
}
}
This is my engine.cpp file:
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <string.h>
#include "Engine.h"
using namespace sdds;
using namespace std;
namespace sdds {
Engine::Engine(){
m_type[0] = '\0';
m_size = 0.0;
}
Engine::Engine(const char* type, double size){
strncpy(m_type, type, TYPE_MAX_SIZE);
m_size = size;
}
double Engine::get() const{
return m_size;
}
void Engine::display() const{
cout << m_size << " liters - " << m_type << endl;
}
}
This should be the output, but my function is stuck in the while loop:
|> T5: Testing += and < Operators
----------------------------------------
Ship not up to standard. Required power: 90.111
Ship not up to standard. Required power: 90.111
Ship not up to standard. Required power: 90.111
liner - 99
4.4 liters - V8
5 liters - V8
4.1 liters - Inline
2.1 liters - D1
2.1 liters - D2
2.1 liters - D3
Ship doesn't exceed power regulation of: 99.999
Your operator+= is not doing anything with the Engine that is passed to it. Your Ship class has an m_engines array, which your Ship constructor adds Engines to (without regard to NUM_OF_ENGINES, though), but your operator+= is not.
Your constructor and operator+= should look more like this instead:
Ship::Ship(const char* type, const Engine engines[], int cnt){
if (type != nullptr && engines != nullptr && cnt > 0) {
// create a valid ship
strncpy(m_type, type, TYPE_MAX_SIZE);
if (cnt > NUM_OF_ENGINES) cnt = NUM_OF_ENGINES; // <-- ADD THIS LINE!
for (int i = 0; i < cnt; ++i) {
m_engines[i] = engines[i];
}
m_engCnt = cnt;
}else{
m_type[0] = '\0';
m_engCnt = 0;
}
}
Ship& Ship::operator+=(Engine e){
if (!*this) {
cout << "The Object is not valid! Engine cannot be added!" << endl;
return *this;
}else if (m_engCnt == NUM_OF_ENGINES){
return *this;
}else{
m_engines[m_engCnt] = e; // <-- ADD THIS LINE!!!
m_engCnt++;
return *this;
}
}
I would suggest re-writing the constructor and operator+= to look more like this instead:
Ship::Ship(const char* type, const Engine engines[], int cnt){
strncpy(m_type, type != nullptr ? type : "", TYPE_MAX_SIZE);
if (engines != nullptr && cnt > 0) {
if (cnt > NUM_OF_ENGINES) cnt = NUM_OF_ENGINES;
for (int i = 0; i < cnt; ++i) {
m_engines[i] = engines[i];
}
m_engCnt = cnt;
}
else
m_engCnt = 0;
}
Ship& Ship::operator+=(const Engine &e){
if (m_type[0] != '\0' && m_engCnt < NUM_OF_ENGINES) {
m_engines[m_engCnt] = e;
++m_engCnt;
}
return *this;
}
This code compiles and runs, creating the expected output, except when valgrind is run, then these memory leaks appear. The following code runs on Visual Studio without any warnings or errors coming up.
So my question is, where is this memory leak occurring? I'm relatively new to CPP and have spent hours on this, and so these errors are catching me by surprise.
Is there anything I am doing wrong in terms of the sequence? Am I passing an uninitialized value somewhere? Confused.
I am having trouble figuring out where the memory loss is occurring. Here are the files:
/// Saiyan.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <iostream>
#include "Saiyan.h"
using namespace std;
namespace sdds
{
// CONSTRUCTORS:
Saiyan::Saiyan()
{
// default state
m_name = nullptr; // Dynamic allocation: set to nullptr!
m_dob = 0;
m_power = 0;
m_super = false;
m_level = 0;
}
Saiyan::Saiyan(const char* name, int dob, int power)
{
set(name, dob, power);
}
// MEMBER FUNCTIONS:
void Saiyan::set(const char* name, int dob, int power, int level, bool super)
{
// Check if arguments are valid:
if (name == nullptr || strlen(name) <= 0 || dob > 2020 || power <= 0)
{
*this = Saiyan(); // Calls constructor that creates default.
}
else
{
// Deallocate previosly allocated memory for m_name to avoid memory leak:
if (m_name != nullptr && strlen(name) == 0)
{
delete[] m_name;
m_name = nullptr;
}
// Assign validate values to current object:
m_name = new char[strlen(name) + 1];
strcpy(m_name, name);
m_dob = dob;
m_power = power;
m_super = super;
m_level = level;
}
}
bool Saiyan::isValid() const
{
bool valid_state = m_name != nullptr && strlen(m_name) > 0 && m_dob < 2020 && m_power > 0;
return valid_state;
}
void Saiyan::display() const
{
if (isValid())
{
cout << m_name << endl;
cout.setf(ios::right);
cout.width(10);
cout << "DOB: " << m_dob << endl;
cout.width(10);
cout << "Power: " << m_power << endl;
cout.width(10);
if (m_super == true) {
cout << "Super: " << "yes" << endl;
cout.width(10);
cout << "Level: " << m_level;
}
else
{
cout << "Super: " << "no";
}
cout.unsetf(ios::left);
}
else
{
cout << "Invalid Saiyan!";
}
cout << endl;
}
bool Saiyan::fight(Saiyan& other)
{
// Check both Saiyans for super level and power up accordingly:
if (m_super == true)
{
m_power += int(m_power * (.1 * m_level)); // Cast an int to avoid possible memory loss.
}
if (other.m_super == true)
{
other.m_power += int(other.m_power * (.1 * other.m_level));
}
bool value = m_power > other.m_power;
return value;
}
// DESTRUCTOR:
Saiyan::~Saiyan()
{
if (m_name != nullptr)
{
delete[] m_name; // Deallocate memory of member.
m_name = nullptr;
}
}
}
// Saiyan.h
#pragma once
#ifndef SDDS_SAIYAN_H
#define SDDS_SAIYAN_H
namespace sdds
{
class Saiyan
{
char* m_name; // Dynamically allocated array of chars.
int m_dob; // Year the Saiyan was born.
int m_power; // Integer indicating the strength of the Saiyan (>= 0).
bool m_super; // indicates whether Saiyan can evolve
int m_level; // an integer indicating the level of a SS
/*
***Valid Name*** : a dynamically allocated array of chars.
***Valid Year of Birth***: an integer within the interval[0, 2020].
***Valid Power***: an integer that is greater than 0.
*/
public:
Saiyan();
Saiyan(const char* name, int dob, int power); // Custom constructor
void set(const char* name, int dob, int power, int level = 0, bool super = false);
bool isValid() const;
void display() const;
bool fight(Saiyan& other); // Fight and power up Saiyans.
~Saiyan();
};
}
#endif
// main.cpp
#include <iostream>
#include "Saiyan.h"
#include "Saiyan.h" // this is on purpose
using namespace std;
using namespace sdds;
void printHeader(const char* title)
{
char oldFill = cout.fill('-');
cout.width(40);
cout << "" << endl;
cout << "|> " << title << endl;
cout.fill('-');
cout.width(40);
cout << "" << endl;
cout.fill(oldFill);
}
int main()
{
{
printHeader("T1: Checking default constructor");
Saiyan theSayan;
theSayan.display();
cout << endl;
}
{
printHeader("T2: Checking custom constructor");
Saiyan army[] = {
Saiyan("Nappa", 2025, 1),
Saiyan("Vegeta", 2018, -1),
Saiyan("Goku", 1990, 200),
Saiyan(nullptr, 2015, 1),
Saiyan("", 2018, 5)
};
cout << "Only #2 should be valid:" << endl;
for (int i = 0; i < 5; i++)
{
cout << " Sayan #" << i << ": " << (army[i].isValid() ? "valid" : "invalid") << endl;
}
for (int i = 0; i < 5; i++)
{
army[i].display();
}
cout << endl;
}
// valid saiyans
Saiyan s1("Goku", 1990, 2000);
Saiyan s2;
s2.set("Vegeta", 1989, 2200);
{
printHeader("T3: Checking the fight");
s1.display();
s2.display();
cout << "S1 attacking S2, Battle " << (s1.fight(s2) ? "Won" : "Lost") << endl;
cout << "S2 attacking S1, Battle " << (s2.fight(s1) ? "Won" : "Lost") << endl;
cout << endl;
}
{
printHeader("T4: Checking powerup");
s1.set("Goku", 1990, 1900, 1, true);
int round = 0;
bool gokuWins = false;
while (!gokuWins) // with every fight, the super saiyan should power up
{
cout << "Round #" << ++round << endl;
gokuWins = s1.fight(s2);
s1.display();
s2.display();
}
cout << "Bonus round. Is s2 winning? " << (s2.fight(s1) ? "yes" : "no") << endl;
s1.display();
s2.display();
cout << endl;
}
{
printHeader("T5: Upgrading s2");
s2.set("Vegeta", 1990, 2200, 3, true);
cout << "Super Battle. Is s2 winning? " << (s2.fight(s1) ? "yes" : "no") << endl;
s1.display();
s2.display();
cout << endl;
}
return 0;
}
Here is what ended up working:
/// Saiyan.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <iostream>
#include "Saiyan.h"
using namespace std;
namespace sdds
{
Saiyan::Saiyan()
{
}
Saiyan::Saiyan(const char* name, int dob, int power)
{
set(name, dob, power);
}
void Saiyan::set(const char* name, int dob, int power, int level, bool super)
{
if (name != nullptr && name[0] != '\0')
{
if (m_name != nullptr)
{
delete[] m_name;
m_name = nullptr;
}
m_name = new char[strlen(name) + 1];
strcpy(m_name, name);
}
if (dob != 0 && dob < 2020)
{
m_dob = dob;
}
if (power > 0)
{
m_power = power;
}
if (level > 0)
{
m_level = level;
}
m_super = super;
}
bool Saiyan::isValid() const
{
bool valid_state = m_name != nullptr && m_dob != 0 && m_dob < 2020 && m_power > 0 && m_level >= 0;
return valid_state;
}
void Saiyan::display() const
{
if (isValid())
{
cout << m_name << endl;
cout.setf(ios::right);
cout.width(10);
cout << "DOB: " << m_dob << endl;
cout.width(10);
cout << "Power: " << m_power << endl;
cout.width(10);
if (m_super == true) {
cout << "Super: " << "yes" << endl;
cout.width(10);
cout << "Level: " << m_level;
}
else
{
cout << "Super: " << "no";
}
cout.unsetf(ios::left);
}
else
{
cout << "Invalid Saiyan!";
}
cout << endl;
}
bool Saiyan::fight(Saiyan& other)
{
// Check both Saiyans for super level and power up accordingly:
if (m_super == true)
{
m_power += int(m_power * (.1 * m_level)); // Cast an int to avoid possible memory loss.
}
if (other.m_super == true)
{
other.m_power += int(other.m_power * (.1 * other.m_level));
}
bool value = m_power > other.m_power;
return value;
}
Saiyan::~Saiyan()
{
if (m_name != nullptr)
{
delete[] m_name; // Deallocate memory of member.
m_name = nullptr;
}
}
}
// Saiyan.h
#pragma once
#ifndef SDDS_SAIYAN_H
#define SDDS_SAIYAN_H
namespace sdds
{
class Saiyan
{
char* m_name{}; // Dynamically allocated array of chars.
int m_dob{}; // Year the Saiyan was born.
int m_power{}; // Integer indicating the strength of the Saiyan (>= 0).
bool m_super{}; // indicates whether Saiyan can evolve
int m_level{}; // an integer indicating the level of a SS
/*
***Valid Name*** : a dynamically allocated array of chars.
***Valid Year of Birth***: an integer within the interval[0, 2020].
***Valid Power***: an integer that is greater than 0.
*/
public:
Saiyan();
Saiyan(const char* name, int dob, int power); // Custom constructor
void set(const char* name, int dob, int power, int level = 0, bool super = false);
bool isValid() const;
void display() const;
bool fight(Saiyan& other); // Fight and power up Saiyans.
~Saiyan();
};
}
#endif
In general --- avoid manual memory management, why not just use std::string?
Regarding issues in the code.
This part of code is a big no no:
if (name == nullptr || strlen(name) <= 0 || dob > 2020 || power <= 0)
{
*this = Saiyan(); // Calls constructor that creates default.
}
You are actually bypassing destructor here, so if m_name was initialized you will leak memory.
Another problem is in this constructor:
Saiyan::Saiyan(const char* name, int dob, int power)
{
set(name, dob, power);
}
You are not ensuring that your object will be in good state always after calling this constructor.
And last but not least, here:
if (m_name != nullptr && strlen(name) == 0)
{
delete[] m_name;
m_name = nullptr;
}
You deallocate m_name only if new name is short, but you should deallocate regardless of new name length, as you are setting new value to m_name regardless of new name length.
Also in C++11 you can give default values to members outside of constructor and they will be used in each constructor in which you don't explicitly set different value:
class Saiyan
{
char* m_name = nullptr; // Dynamically allocated array of chars.
int m_dob = 0; // Year the Saiyan was born.
int m_power = 0; // Integer indicating the strength of the Saiyan (>= 0).
bool m_super = false; // indicates whether Saiyan can evolve
int m_level = 0; // an integer indicating the level of a SS
public:
Saiyan() {};
...
Works!
char* m_name = nullptr; // Dynamically allocated array of chars.
int m_dob = 0; // Year the Saiyan was born.
int m_power = 0; // Integer indicating the strength of the Saiyan (>= 0).
bool m_super = false; // indicates whether Saiyan can evolve
int m_level = 0; // an integer indicating the level of a SS
main():
char inp[] = "(A+B)/(C*D))";
Infix i;
cout << "In main: " << inp /* + ')' */ << endl << endl;
Here is Infix constructor:
Infix() {
push('(');
cout << "Element In Stack: " << *returnElement(returnTop()) << endl;
outputString = "";
strcpy(operatorArray, "/*-+%");
cout << "Operator Array: " << operatorArray << endl;
}
Infix is inheriting from a class 'Stack':
class Stack{
int top = -1;
char arr[100];
public:
bool push(char);
char pop();
char peek();
bool isEmpty();
void displayAll();
char returnTop() { return top;}
char* returnElement(int i) {
if(i > 98){
cout << "StackOutOfIndex";
return nullptr;
}
return &arr[i];
}
};
When I run the code in main, it displays unusual output:
Element In Stack: (
Operator Array: /*-+%
In main: +%
Stack Object Destroyed!
But, when in main, if the comment the line declaring 'Infix' object declaration, the code runs fine:
In main: (A+B)/(C*D))
EDITS:
Stack Class
#include<iostream>
using namespace std;
class Stack{
int top = -1;
char arr[100];
public:
bool push(char);
char pop();
char peek();
bool isEmpty();
void displayAll();
char returnTop() { return top;}
char* returnElement(int i) {
if(i > 98){
cout << "StackOutOfIndex";
return nullptr;
}
return &arr[i];
}
};
bool Stack:: push(char elementToPush) {
if(top > 98) {
cout << "\nStack Overflow!!";
return false;
} else {
arr[++top] = elementToPush;
return true;
}
}
char Stack:: pop() {
if(top <= -1) {
cout << "\nStack Underflow!!";
return ' ';
} else {
return (arr[top--]);
}
}
char Stack:: peek() {
if(top > 98) {
cout << "\nStack Overflow!!";
return ' ';
} else {
return arr[top];
}
}
bool Stack:: isEmpty() {
return (top <= 0);
}
void Stack:: displayAll() {
if(top <= -1) {
cout << "null";
return;
}
int i = top;
while (i >= 0) {
cout << arr[i] << " ";
--i;
}
cout << "\n";
}
Infix Class
#include<iostream>
#include<cstring>
#include<D:\Programs\11Stack.cpp>
using namespace std;
class Infix : public Stack {
string outputString;
char operatorArray[];
public:
Infix() {
push('(');
cout << "Element In Stack: " << *returnElement(returnTop()) << endl;
outputString = "";
strcpy(operatorArray, "/*-+%");
cout << "Operator Array: " << operatorArray << endl;
}
string infixToPostfix(char *, int);
bool manupulateOperator(char, int);
int checkPrecedence(char);
~Infix() {
cout << "\nStack Object Destroyed!" << endl;
}
};
string Infix:: infixToPostfix(char *str, int size) {
cout << "\nGiven String: " << str << endl;
int x;
for(int i = 0; i < size; ++size) {
x = str[i];
if(x != ' ') {
if(x == ')') {
while(returnTop() != '(') {
cout << pop() << " popped!\n";
}
cout << pop() << " popped!\n";
} else if(isalpha(x)) {
cout << x;
} /* else{ // scanned character is an operator
if(manupulateOperator(x, i)) {
} else {
return " ";
}
} */
}
}
return outputString;
}
bool Infix::manupulateOperator(char c, int position) {
try {
char topElement = *returnElement(returnTop());
if(checkPrecedence(c) == -1) {
cout << "\nErr\n";
}else if((checkPrecedence(c) > checkPrecedence(topElement)) || returnTop() == 0) {
push(c);
cout << c << " pushed!\n";
}
} catch(std::exception e) {
std::cerr << e.what() << '\n';
return false;
} catch (char* Ce) {
cout << Ce << endl;
}
return true;
}
int Infix::checkPrecedence(char c) {
/*
+ -> 1
- -> 1
* -> 2
/ -> 2
% -> 2
*/
switch(c) {
case '+':
return 1;
case '-':
return 1;
case '*':
return 2;
case '/':
return 2;
case '%':
return 2;
default:
// throw "Illegal Operator Detected!";
cout << "Illegal Operator Detected: " << c << endl;
return -1;
}
}
int main() {
cout << endl;
int x = 1;
char inp[] = "(A+B)/(C*D))";
//Infix i;
cout << "In main: " << inp /* + ')' */ << endl << endl;
// cout << i.infixToPostfix(input + ')', sizeof(input));
/* for(int i = 0; i < strlen(inp); ++i) {
cout << inp[i];
}
*/
return 0;
}
You are declaring operatorArray as an array of char but you are not assigning any memory for it! So, when you then call strcpy(operatorArray, "/*-+%"); in your Infix constructor, you are causing undefined behaviour by attempting to copy the given string constant to memory that hasn't been assigned - and this appears to be overwriting the inp[] array declared in your main.
To fix this, I would suggest giving your operatorArray member a specific size, which will be large enough to accommodate whatever string you want to copy to it - 8 characters will work in the sample code you've given:
class Infix : public Stack {
string outputString;
char operatorArray[8]; // Make this member a REAL array of characters.
//..
Your variable char operatorArray[] have no memory allocated when your constructor is called. When you use strcpy, you write to a place where you don't have permissions in your memory, and therefore on other informations.
To find these kinds of mistakes, I recommend using valgrind.
char operatorArray[]; is not allowed in Standard C++.
If you didn't see an error message then I would recommend adjusting compiler settings to follow the standard form of the language, this would have saved you a lot of time.
After a fairly lengthy session with my instructor and not being able to come up with a concrete solution, I figured I'd come back here for help on a homework assignment. We're supposed to translate the string class to our own version that uses a linked list with a few basic functions. Everything seems to work so far except the + operator function (adding two strings together).
string operator +(string& s1, string& s2);
What's strange is that it appears to return the correct result when tested, only to cause a crash with a debug assertion failure. I cannot tell why this would be, since the definition:
string operator +(string& s1, string& s2)
{
s1 += s2;
return s1;
}
relies on +=, but that operator works with no issue with the test code in main(). Here's the full code:
HEADER FILE
#ifndef STRING2_H
#define STRING2_H
#include<iostream>
namespace string2
{
class string
{
private:
struct stringList
{
char character;
stringList* link;
};
stringList* headPtr;
public:
// CONSTRUCTORS AND DESTRUCTOR
string() { headPtr = NULL; };
string(const stringList* sourcePtr);
~string();
// CONSTANT MEMBER FUNCTIONS
char getChar(const size_t position) const;
size_t length() const;
char operator [ ] (size_t position) const;
// MODIFICATION MEMBER FUNCTIONS
void operator += (const string& addend);
void operator += (const char addend[]);
void operator += (char addend);
void operator =(const string& source);
// FRIEND FUNCTIONS
friend bool operator ==(const string& s1, const string& s2);
};
// NONMEMBER FUNCTIONS
string operator +(string& s1, string& s2);
std::ostream& operator <<(std::ostream& outs, const string& source);
}
#endif
IMPLEMENTATION
#include "String2.h"
#include <iostream>
namespace string2
{
string::string(const stringList* sourcePtr)
{
stringList* indexPtr;
if (sourcePtr == NULL)
{
headPtr = NULL;
return;
}
headPtr = new stringList;
indexPtr = headPtr;
indexPtr->character = sourcePtr->character;
indexPtr->link = sourcePtr->link;
sourcePtr = sourcePtr->link;
while (sourcePtr != NULL)
{
indexPtr = indexPtr->link;
indexPtr->character = sourcePtr->character;
indexPtr->link = sourcePtr->link;
sourcePtr = sourcePtr->link;
}
}
string::~string()
{
stringList *removePtr;;
while (headPtr != NULL)
{
removePtr = headPtr;
headPtr = headPtr->link;
delete removePtr;
}
}
char string::getChar(const size_t position) const
{
stringList *indexPtr = headPtr;
for (size_t i = 0; i < position - 1; i++)
indexPtr = indexPtr->link;
return indexPtr->character;
}
size_t string::length() const
{
size_t count = 0;
stringList* indexPtr = headPtr;
while (indexPtr != NULL)
{
count++;
indexPtr = indexPtr->link;
}
return count;
}
char string::operator [ ] (size_t position) const
{
stringList* indexPtr = headPtr;
for (size_t i = 0; i < position; i++)
indexPtr = indexPtr->link;
return indexPtr->character;
}
void string::operator += (const string& addend)
{
for (int index = 0; index < addend.length(); index++)
(*this) += addend[index];
}
void string::operator += (const char addend[])
{
if (addend[0] == NULL)
return;
for (int index = 0; index < (sizeof(addend) / sizeof(addend[0])); index++)
(*this) += addend[index];
}
void string::operator += (char addend)
{
stringList *indexPtr = headPtr;
if (headPtr == NULL)
{
headPtr = new stringList;
headPtr->character = addend;
headPtr->link = NULL;
return;
}
while (indexPtr->link != NULL)
indexPtr = indexPtr->link;
indexPtr->link = new stringList;
indexPtr->link->character = addend;
indexPtr->link->link = NULL;
}
void string::operator =(const string& source)
{
if (headPtr != NULL)
{
delete headPtr;
headPtr = NULL;
}
*this += source;
}
bool operator ==(const string& s1, const string& s2)
{
if (s1.length() != s2.length())
return false;
if (s1.headPtr == NULL && s2.headPtr == NULL)
return true;
for (int index = 0; index < s1.length(); index++)
{
if (s1.headPtr->character != s2.headPtr->character)
return false;
}
return true;
}
string operator +(string& s1, string& s2)
{
s1 += s2;
return s1;
}
std::ostream& operator <<(std::ostream& outs, const string& source)
{
for (int index = 0; index < source.length(); index++)
outs << source.getChar(index + 1);
return outs;
}
}
TEST CODE (final line is where it breaks)
#include "String2.h"
#include <iostream>
#include <fstream>
using namespace string2;
int main()
{
string test, test2, test3;
std::cout << "Current length: " << test.length() << std::endl;
char add[4] = { 'a', 'b', 'c', 'd' };
test += 's'; // testing third (lowest) += operator
std::cout << "First char in string: " << test.getChar(1) << std::endl;
test += 'd';
std::cout << "Current length: " << test.length() << std::endl;
std::cout << "Second char in string: " << test.getChar(2) << std::endl;
std::cout << "Second char in string testing [] operator: " << test[1] << std::endl;
std::cout << "Current string: " << test << std::endl;
test += add; // testing second (middle) += operator
std::cout << "Current length: " << test.length() << std::endl;
std::cout << "Current string: " << test << std::endl;
test2 += 'z';
test2 += 'y';
test += test2; // testing first (top) += operator
std::cout << "Current string: " << test << std::endl;
test = test2; // testing = operator
std::cout << "\nCurrent string: " << test << std::endl;
std::cout << "Compared to string: " << test2 << std::endl;
if (test == test2) // testing == operator
std::cout << "\nStrings are equal" << std::endl;
else
std::cout << "\nStrings are not equal." << std::endl;
test += 'f';
std::cout << "\nCurrent string: " << test << std::endl;
std::cout << "Compared to string: " << test2 << std::endl;
if (test == test2) // testing == operator
std::cout << "\nStrings are equal" << std::endl;
else
std::cout << "\nStrings are not equal." << std::endl;
std::cout << "\nTwo strings added together: " << test + test2 << std::endl; // testing + operator
}
Thank you for your help
Your problem is reproducible with this
int main()
{
string test, test2;
test += 'h';
std::cout << "\nTwo strings added together: " << test + test2 << std::endl; // testing + operator
}
string operator +(string& s1, string& s2)
{
s1 += s2;
return s1;
}
In operator +, return s1 returns a shallow copy of s1.So now the internal memory is being occupied by s1 as well as the returned string from operator+(). At the end of main() ~string() is triggered for s1 which frees the internal memory and then for the returned string from operator+() as well which tries to delete the already deleted memory causing double free.
You need a deep copy in operator+() or better, a rethink in design of operator+().