Create a class for working with stitches. C++ - c++

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;
}

Related

What is causing the abort method to be called when I try to compile and run my "main.cpp" file in c++?

I am currently working on a project in c++ and I have 3 files. A Customer.h, Customer.cpp and Main.cpp, whenever I try to run the main.cpp file I get an error message and the abort method is called. There are no issues or any other error messages with any of the code in my 3 files and i'm unsure of what could be causing the error, any help would be greatly appreciated!
Code from "Main.cpp" is below as I can't upload any images yet
#include "Customer.h"
using namespace std;
int main()
{
Customer cust1;
cust1.setCustomerID(150032);
cust1.setTitle("Mr");
cust1.setName("Joey");
cust1.setNumOfPurchases(3);
cust1.setPurchases(366, 352, 334);
cust1.setType("New");
cout << cust1.getCustomerID() << endl;
cout << cust1.getTitle() << endl;
cout << cust1.getName() << endl;
cout << cust1.getNumOfPurchases() << endl;
cout << cust1.getPurchases() << endl;
cout << cust1.getType() << endl;
return 0;
}
Code from the Customer.h file below
class Customer
{
private:
int customerID;
string title;
string name;
int numOfPurchases;
int* purchases;
string type;
public:
Customer(); // default constructor
Customer(int customerID, string title, string name, int numOfPurchases, int purchase1, int purchase2, int purchase3, string type);
//copy overload assignment
Customer& operator=(Customer& otherCustomer);
Customer(const Customer& source);
~Customer(); //destructor
//Getters and Setters
void setCustomerID(int customerID);
void setTitle(string title);
void setName(string name);
void setNumOfPurchases(int numOfPurchases);
void setPurchases(int purchase1, int purchase2, int purchase3);
void setType(string type);
int getCustomerID();
string getTitle();
string getName();
int getNumOfPurchases();
int* getPurchases();
string getType();
void printCustomer() {
cout << customerID << "," << title << "," << name << "," << numOfPurchases << "," << purchases << "," << type << endl;
}
friend std::ostream& operator<<(std::ostream& out, Customer& customer); // overloaded operator<<
friend istream& operator>> (istream& in, Customer& customer); // overloaded operator >>
};
Code from the Customer.cpp file below
//default constructor
Customer::Customer() {
}
//Full constructor
Customer::Customer(int customerID, string title, string name, int numOfPurchases, int purchase1, int purchase2, int purchase3, string type)
{
customerID = customerID;
title = title;
name = name;
numOfPurchases = numOfPurchases;
purchases = new int[3];
purchases[0] = purchase1;
purchases[1] = purchase2;
purchases[2] = purchase3;
type = type;
}
Customer::Customer(const Customer& source) //copy constructor
{
cout << "copy constructor called" << endl;
this->customerID = source.customerID;
this->title = source.title;
this->name = source.name;
this->numOfPurchases = source.numOfPurchases;
this->purchases = new int[3];
purchases[0] = source.purchases[0];
purchases[1] = source.purchases[1];
purchases[2] = source.purchases[2];
this->type = source.type;
}
//overloaded assignment operator=
Customer& Customer::operator= (Customer& otherCustomer)
{
cout << "Overloaded assignment operator= called" << endl;
//self-assignment guard
if (this == &otherCustomer)
return *this; //refernce to the same object
// copy data from the source (rhs) to this object (the destination)
name = otherCustomer.name;
//must make a new scores object to store a copy of the other student
if (purchases != nullptr)
delete[] purchases;
purchases = new int[3];
for (int i = 0; i < 3; i++) {
purchases[i] = otherCustomer.purchases[i];
}
//return this existing object so we can chain this operator
return *this;
}
Customer::~Customer() {
cout << "Destructor ~Customer called" << endl;
delete[] purchases;
}
// Overloaded insertion operator (Outputs Character object data as an output stream)
// Defined in header file as a "friend" function, as it is not a member function
//
ostream& operator<<(ostream& out, Customer& customer)
{
cout << "Customer details ( output by insertion operator<< )" << endl;
cout << "Customer ID: " << customer.customerID << endl;
cout << "Title: " << customer.title << endl;
cout << "Name: " << customer.name << endl;
cout << "Number of purchases: " << customer.numOfPurchases << endl;
cout << "Purchases: ";
for (int i = 0; i < 3; i++)
{
if (i > 0) cout << ",";
cout << customer.purchases[i];
}
cout << "Type: " << customer.type << endl;
return out;
}
istream& operator>> (istream& in, Customer& customer)
{
cout << "Enter Customer details ( using the extraction operator>> )" << endl;
cout << "Enter Customer ID: " << endl;
cin >> customer.customerID;
cout << "Enter Title: " << endl;
getline(cin, customer.title);
cout << "Enter Name: " << endl;
getline(cin, customer.name);
cout << "Enter Number of Purchases: ";
cin >> customer.numOfPurchases;
cout << "Enter Purchases: ";
cin >> customer.purchases[0];
cin >> customer.purchases[1];
cin >> customer.purchases[2];
cout << "Enter Type";
getline(cin, customer.type);
cout << endl;
return in;
}
int Customer::getCustomerID()
{
return customerID;
}
string Customer::getTitle()
{
return title;
}
string Customer::getName()
{
return name;
}
int Customer::getNumOfPurchases()
{
return numOfPurchases;
}
int* Customer::getPurchases()
{
return purchases;
}
string Customer::getType()
{
return type;
}
void Customer::setCustomerID(int customerID)
{
if (customerID < 1) {
throw invalid_argument("Customer ID has to be equal to 1 or more");
}
this->customerID = customerID;
}
void Customer::setTitle(string title)
{
if (title.length() < 2) {
throw invalid_argument("Title has to be more than or equal to 2 characters");
}
this->title = title;
}
void Customer::setName(string name)
{
if (name.length() < 4) {
throw invalid_argument("Length of name should be more than or equal to 4 characters");
}
this->name = name;
}
void Customer::setNumOfPurchases(int numOfPurchases)
{
if(numOfPurchases > 0 && numOfPurchases < 10000){
throw invalid_argument("Number of purchases should be between 0 to 10000");
}
this->numOfPurchases = numOfPurchases;
}
void Customer::setPurchases(int purchase1, int purchase2, int purchase3)
{
if (purchase1 < 0 || purchase2 < 0 || purchase3 < 0) {
throw invalid_argument("Purchases must be more than or equal to zero");
}
}
void Customer::setType(string type) {
if (type != "New" || type != "Either") {
throw invalid_argument("Type of purchase has to be New or Either");
}
}
You're missing a few directives (namespace std, iostream, etc), but I fixed that and reproduced the issue up to here:
libc++abi.dylib: terminating with uncaught exception of type std::invalid_argument: Number of purchases should be between 0 to 10000 Abort trap: 6
Using the Customer.cpp code you provided (thanks for adding that), I see you have a logic error on line 161
void Customer::setNumOfPurchases(int numOfPurchases)
{
if(numOfPurchases > 0 && numOfPurchases < 10000){
throw invalid_argument("Number of purchases should be between 0 to 10000");
}
this->numOfPurchases = numOfPurchases;
}
Clearly if numOfPurchases is between 0 and 1000 an invalid_argument error is thrown, by your very design. You should change it to something like this:
void Customer::setNumOfPurchases(int numOfPurchases)
{
if(numOfPurchases < 0 || numOfPurchases > 10000){
throw invalid_argument("Number of purchases should be between 0 to 10000");
}
this->numOfPurchases = numOfPurchases;
}
Fixing that revealed another error:
libc++abi.dylib: terminating with uncaught exception of type std::invalid_argument: Type of purchase has to be New or Either Abort trap: 6
This led me to line 176:
void Customer::setType(string type) {
if (type != "New" || type != "Either") {
throw invalid_argument("Type of purchase has to be New or Either");
}
}
Ahh, the classic string comparison issue. This is NOT how you compare strings in C++. Try something like this instead, using the compare method in the string library.
void Customer::setType(string type) {
if (type.compare("New") != 0 && type.compare("Either") != 0) {
throw invalid_argument("Type of purchase has to be New or Either");
}
}
Those changes fixed the issue for me and it runs fine. Also, I asked for the compile command you were using, which doesn't appear to be provided, so I just used g++ main.cpp.

How to use main variable in functions?

I got a function but i can't define any variable inside and global too. This function gets a char value from user. I need to define this value to main function. How can i do it? Thanks for helping guys.
This is my code. I made it like this but I define variables in global but I need to define this variables in only main.
#include <iostream>
using namespace std;
char cName[255], cSurname[255];
bool nameFunc() {
cout << "Whats Your Name ?\n";
cin >> cName;
if (cName != NULL && cName[0] == '\0') {
return false;
}
else {
return true;
}
}
bool surnameFunc() {
cout << "Whats Your Surname ?\n";
cin >> cSurname;
if (cSurname != NULL && cSurname[0] == '\0') {
return false;
}
else {
return true;
}
}
int main() {
if (nameFunc() and surnameFunc()) {
cout << "Hello, " << cName << " " << cSurname << "." << endl;
}
else {
cout << "Error! Name or Surname is empty." << endl;
}
system("PAUSE");
return 0;
}
You could pass references to your variables to the functions. Since the char[] have a fixed length, you need to make sure that you don't write out-of-bounds which complicates things.
Example:
#include <iostream>
template<size_t N>
bool nameFunc(char (&cName)[N]) {
std::cout << "Whats Your Name ?\n";
std::cin.getline(cName, N); // read at most N chars
return cName[0] != '\0';
}
template<size_t N>
bool surnameFunc(char (&cSurname)[N]) {
std::cout << "Whats Your Surname ?\n";
std::cin.getline(cSurname, N); // read at most N chars
return cSurname[0] != '\0';
}
int main() {
char cName[255], cSurname[255];
if (nameFunc(cName) and surnameFunc(cSurname)) {
std::cout << "Hello, " << cName << " " << cSurname << ".\n";
}
else {
std::cout << "Error! Name or Surname is empty.\n";
}
}
A much easier option would be to use std::strings and pass them by reference to the functions.
Is it what you're looking for?
#include <iostream>
using namespace std;
bool nameFunc(char* cName) {
cout << "Whats Your Name ?\n";
cin >> cName;
if (cName != NULL && cName[0] == '\0') {
return false;
}
else {
return true;
}
}
bool surnameFunc(char* cSurname) {
cout << "Whats Your Surname ?\n";
cin >> cSurname;
if (cSurname != NULL && cSurname[0] == '\0') {
return false;
}
else {
return true;
}
}
int main() {
char cName[255], cSurname[255];
if (nameFunc(cName) and surnameFunc(cSurname)) {
cout << "Hello, " << cName << " " << cSurname << "." << endl;
}
else {
cout << "Error! Name or Surname is empty." << endl;
}
system("PAUSE");
return 0;
}

abnormal behaviour while displaying char array in C++ after object initialization

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.

Operator Overloading Test Failure

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.

C++ simple string replace, non complicated code, but producing crazy error

First, thank for you all your help!
The error I am getting is:
Unhandled exception at 0x7c812afb
(kernel32.dll) in Readerboard.exe:
Microsoft C++ exception:
std::out_of_range at memory location
0x0012f8a8..
I have found the problem to be with this line:
str.replace(str.find(sought), sought.size(), replacement);
It is located in this procedure:
void DisplayMessages() {
ifstream myReadFile;
string str;
static string myMessages[10];
static int i; // of course my famous i
static int MyPosition;
string sought;
string replacement;
myReadFile.open("C:\\Documents and Settings\\agerho000\\Desktop\\cms_export_test\\outages.htm",ios::in);
i = 0; //the start of my array
sought = "</td>"; // value that I want to replace with nothing
replacement.clear();
if(!myReadFile) // is there any error?
{
cout << "Error opening the file! Aborting…\n";
exit(1);
}
if (myReadFile.is_open())
{
cout << endl;
while (!myReadFile.eof())
{
getline(myReadFile, str);
if (str == "<tr>")
{
myReadFile.seekg(4,ios::cur);
getline(myReadFile, str);
str.replace(str.find(sought), sought.size(), replacement);
cout << str;
myMessages[i]=str;
i++;
}
}
}
i=0;
while (i < 10)
{
cout << i << ") " << myMessages[i] << endl;
i++;
if (myMessages[i]=="")
{
break;
}
}
myReadFile.close();
mainMenu();
}
The whole cpp file is displayed below:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
void mainMenu();
void DisplayMessages();
void AddMessage();
void DeleteMessage();
void EditMessage();
void RunTests();
void CheckFile();
void CreateHtmlFile(string myMessages[10]);
/*
#define MIN 1
#define MAX 100
#define TRUE 1
#define FALSE 0
*/
int main() {
cout << endl;
cout << endl;
cout << "Hello Andrew.\n";
cout << "First you need some sort of menu.\n";
mainMenu();
return 0;
}
void mainMenu() {
int Command;
cout << endl;
cout << endl;
cout << endl;
cout << "What would you like to do?\n";
// cout << "1) Check that tests work!\n";
// cout << "2) Check that the file exists\n";
cout << "3) Display Messages\n";
// cout << "4) Edit a message\n";
// cout << "5) Add a message\n";
// cout << "6) Delete a message\n";
cout << "7) Exit\n";
cout << "Enter a number: ";
cin >> Command;
if (Command == 3)
{
DisplayMessages();
}
if (Command == 7)
{
cout << "Exiting...";
exit(EXIT_SUCCESS);
}
if (Command == 6)
{
DisplayMessages();
}
}
void DisplayMessages() {
ifstream myReadFile;
string str;
static string myMessages[10];
static int i; // of course my famous i
static int MyPosition;
string sought;
string replacement;
myReadFile.open("C:\\Documents and Settings\\agerho000\\Desktop\\cms_export_test\\outages.htm",ios::in);
i = 0; //the start of my array
sought = "</td>"; // value that I want to replace with nothing
replacement.clear();
if(!myReadFile) // is there any error?
{
cout << "Error opening the file! Aborting…\n";
exit(1);
}
if (myReadFile.is_open())
{
cout << endl;
while (!myReadFile.eof())
{
getline(myReadFile, str);
if (str == "<tr>")
{
myReadFile.seekg(4,ios::cur);
getline(myReadFile, str);
str.replace(str.find(sought), sought.size(), replacement);
cout << str;
myMessages[i]=str;
i++;
}
}
}
i=0;
while (i < 10)
{
cout << i << ") " << myMessages[i] << endl;
i++;
if (myMessages[i]=="")
{
break;
}
}
myReadFile.close();
mainMenu();
}
void AddMessage() {
}
/*
void DeleteMessage() {
ifstream myReadFile;
string str;
static string myMessages[10];
static int i; // of course my famous i
static int MyPosition;
string sought;
string replacement;
static int Command;
myReadFile.open("C:\\Documents and Settings\\agerho000\\Desktop\\cms_export_test\\outages.htm",ios::in);
i = 0; //the start of my array
sought = "</b></td>"; // value that I want to replace with nothing
replacement.clear();
if(!myReadFile) // is there any error?
{
cout << "Error opening the file! Aborting…\n";
exit(1);
}
if (myReadFile.is_open())
{
cout << endl;
while (!myReadFile.eof())
{
getline(myReadFile, str);
if (str == "<tr>")
{
myReadFile.seekg(7,ios::cur);
getline(myReadFile, str);
str.replace(str.find(sought), sought.size(), replacement);
myMessages[i]=str;
i++;
}
}
}
i=0;
while (i < 10)
{
cout << i << ") " << myMessages[i] << endl;
i++;
if (myMessages[i]=="")
{
break;
}
}
myReadFile.close();
cout << "Enter the number of the message you would like to delete?\n";
cout << "Or enter 11 to go back to the main menu.\n";
cin >> Command;
while (Command >= 12)
{
cout << "Invalid number, try again!\n";
cout << endl;
cout << "Enter the number of the message you would like to delete?\n";
cout << "Or enter 11 to go back to the main menu.\n";
cin >> Command;
}
if (Command == 11)
{
mainMenu();
}
myMessages[Command].clear();
//clear the string
//now rebuild the htm file with the new array
CreateHtmlFile(myMessages);
}
void EditMessage() {
}
void RunTests() {
}
void CheckFile() {
}
void CreateHtmlFile(string myMessages[])
{
}
//File.seekg(-5); moves the inside pointer 5 characters back
//File.seekg(40); moves the inside pointer 40 characters forward
//tellg() Returns an int type, that shows the current position of the inside-pointer for reading
//tellp() same as above but for writing
//seekp() just like seekg() but for writing
*/
Please help I am so stumped!
str.replace(str.find(sought), sought.size(), replacement); is wrong when str.find() doesn't find what it's looking for. str.find() will return str::npos, which will not be a valid location in the string. Hence, the call to replace fails with the index out of range exception you're seeing.
Change that to:
std::size_t foundIndex = str.find(sought);
if (foundIndex != str.npos)
str.replace(foundIndex, sought.size(), replacement);
else
std::cout << "Oops.. didn't find " << sought << std::endl;
and let us know if that helps you.
EDIT: You might also want to consider using boost::algorithm::replace_all from the Boost String Algorithms Library
A complete function for replacing strings:
std::string ReplaceString(std::string subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
If you need performance, here is an optimized function that modifies the input string, it does not create a copy of the string:
void ReplaceStringInPlace(std::string& subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
}
Tests:
std::string input = "abc abc def";
std::cout << "Input string: " << input << std::endl;
std::cout << "ReplaceString() return value: "
<< ReplaceString(input, "bc", "!!") << std::endl;
std::cout << "ReplaceString() input string not modified: "
<< input << std::endl;
ReplaceStringInPlace(input, "bc", "??");
std::cout << "ReplaceStringInPlace() input string modified: "
<< input << std::endl;
Output:
Input string: abc abc def
ReplaceString() return value: a!! a!! def
ReplaceString() input string not modified: abc abc def
ReplaceStringInPlace() input string modified: a?? a?? def