In c++, when I use operator = , destructor is automatically called? - c++

I made a class str for practice, and I use operator = to
assign an object into another.
I make like this.
#include <string.h>
class Str{
private:
char *str;
int len;
int num;
public:
Str(int leng);
Str(char *neyong);
~Str();
int length(void);
char *contents(void);
int compare(Str a);
int compare(char *a);
void operator=(char *a);
void operator=(Str a);
};
Str::Str(char *neyong){
len = strlen(neyong);
str = new char[len + 1];
strcpy(str, neyong);
}
Str::~Str(){
delete[] str;
}
int Str::length(void){
return len;
}
char* Str::contents(void){
return str;
}
void Str::operator=(Str a){
len = a.length();
str = new char[len+1];
strcpy(str, a.contents());
}
(I skip some functions for ease of reading)
And I execute this like below code.
Str a("hahahaha"), b("hihihihihihi");
cout << a.contents() << endl;
cout << b.contents() << endl;
a = b;
cout << b.contents() << endl;
cout << a.contents() << endl;
Problem: When I assign a = b, then destructors of b is
automatically called. Probably b.~Str() erases all its content and hence b.contents() doesn't return proper value.
How can I solve this problem????

Related

How to write c++ code to reverse a string without using inbuilt function?

I have write this code. It does not show any error but string is not reversed.please let me know where i have made the mistake?
I'm using codeblock to write code and GCC compiler. I have created two functions reverseString and printString, the printString function is working but reverseString is not working. what can i do?
#include <iostream>
#include<string>
using namespace std;
void reverseString(string s, int iNode, int lNode){
while(iNode < lNode){
char temp = s[iNode];
s[iNode] = s[lNode];
s[lNode] = temp;
iNode++;
lNode--;
}
}
void printString(string s, int n){
for(int i=0; i<n; i++){
cout << s[i];
cout << endl;
}
}
int main() {
string s;
cout << "Type String To Reverse: \n";
cin >> s;
cout << "String In Actual Order: \n";
printString(s,s.length());
reverseString(s, 0, s.length()-1);
cout << "String In Reverse Order: \n";
printString(s,s.length());
return 0;
}
This function accepts an object of the type std::string by value
void reverseString(string s, int iNode, int lNode){
while(iNode < lNode){
char temp = s[iNode];
s[iNode] = s[lNode];
s[lNode] = temp;
iNode++;
lNode--;
}
}
It means that it deals with a copy of the string used as an argument and changes the copy instead of the original string.
You have to declare the parameter as having reference type
void reverseString(string &s, int iNode, int lNode){
while(iNode < lNode){
char temp = s[iNode];
s[iNode] = s[lNode];
s[lNode] = temp;
iNode++;
lNode--;
}
}
The function could be defined simpler (without using standard features as for example std::swap) the following way
std::string & reverseString( std::string &s )
{
for ( std::string::size_type i = 0, n = s.size(); i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n - i - 1];
s[n - i - 1] = c;
}
return s;
}
And the function can be called like
cout << "String In Reverse Order: \n";
std::cout << reverseString( s ) << '\n';
Without using the loop you could define the function just the following way
std::string & reverseString( std::string &s )
{
return s.assign( s.rbegin(), s.rend() );
}
As for your own function printString then it could be defined at least like
std::ostream & printString( const std::string &s, std::ostream &os = std::cout )
{
for ( char c : s )
{
os << c;
}
return os;
}
and can be called like
printString( s ) << '\n';

Difference in allocating char type and int type in C++

I have a class foo like this:
class foo
{
private:
int* a;
public:
foo()
{
a = new int[4];
cout << "a" << endl;
}
};
When I create new object named foo1 and then I debug, after the allocating line, it yields the result: a 0x005a4580 {-842150451}.
But when I replace all int-s by char-s in class definition, it yields an undesired result:
a 0x005694a0 "ÍÍÍÍýýýý\x6ŒÒ•\x5Ÿ"
that the size of a is now greater than 4.
I dont know what happened. Could you please give me an explanation?
Full code:
#include <iostream>
#include <string>
using namespace std;
class String
{
public:
String(char* data)
{
setSize(0);
while (*(data + size) != '\0')
size++;
this->data = new char[size];
//need to allocate memory for 'data' pointer because 'data' pointer is now on the stack and the data must be on the heap
memcpy(this->data, data, size * sizeof(char));
}
void operator=(String rhs)
{
if (this->data != NULL)
delete[] this->data, data = NULL;
this->data = new char[rhs.getSize()]; //allocate
memcpy(this->data, data, size * sizeof(char));
}
int getSize()
{
setSize(0);
while (*(data + size))
size++;
return size;
}
void setSize(int size)
{
this->size = size;
}
void display()
{
for (int i = 0; i < size; i++)
cout << *(data + i);
}
~String()
{
if (data != NULL)
delete[] data, data = NULL;
}
private:
char* data;
int size;
};
void main()
{
String a("abcd");
String b("1");
a.display();
cout << endl;
cout << b.getSize() << endl;
a = b;
cout << a.getSize() << endl;
system("pause");
}
Whatever you're using to look at a doesn't know how much you allocated. It just knows the type.
In the first version it sees int *, so it shows a single int.
In the second version it sees char *, so it assumes it's a C string and prints whatever is in memory up to the first '\0' byte.

String & String::Concat(const char Str[])

I decided to code all assignments from last semesters c++ class over summer in order to better prepare for c++ 3 but I don't understand how to pass through a String class or what steps are even needed in order to concatenate two strings and the display the result in the main cpp file.
In my Main.cpp:
#include <iostream>
using namespace std;
#include "String.h"
int main()
{
String Str1;
String Str2("this is a test");
String Str3(Str2);
String Str4("bruh");
int result;
cout << "Testing Display: " << endl;
Str2.Display();
cout << endl;
cout << "Testing displayLine: " << endl;
Str2.displayLine();
cout << endl;
result = Str2.Compare(Str3);
if (result < 0)
{
Str2.Display();
cout << " comes before " << endl;
Str3.Display();
cout << endl;
}
else
if (result > 0)
{
Str3.Display();
cout << " comes before " << endl;
Str2.Display();
}
else
{
Str3.Display();
cout << " is equal to " << endl;
Str2.Display();
}
cout << endl;
result = Str2.Compare("wxyz");
Str1.Copy(Str3);
cout << "Str1 contains " << Str1.length() <<" characters"<< endl;
cout << "Concatenation: ";
Str2.Concat(Str4);
cout << endl;
return 0;
}
In my String.cpp:
#include <iostream>
using namespace std;
#include <string.h>
#include "String.h"
#pragma warning(disable:4996)
String::String()
{
NumChars = 0;
MaxSlots = 0;
pChar = new char[NumChars+1];
pChar[0] = '\0';
}
String::String(const char Str[])
{
NumChars = strlen(Str);
pChar = new char[NumChars + 1];
strcpy(pChar, Str);
}
String::String(const String & Str)
{
NumChars = Str.NumChars;
pChar = new char[NumChars + 1];
strcpy(pChar, Str.pChar);
}
String::~String()
{
delete[] pChar;
}
int String::Compare(const String & Str) const
{
return strcmp(pChar, Str.pChar); //case sensitive
}
int String::Compare(const char Str[]) const
{
return strcmp(pChar, Str); //case sensitive
}
String& String::Copy(const String & Str)
{
if (this != &Str)
{
if (MaxSlots < Str.NumChars)
{
delete[]pChar;
MaxSlots = Str.NumChars;
pChar = new char[NumChars + 1];
}
else;
NumChars = Str.NumChars;
strcpy(pChar, Str.pChar);
}
else;
return *this;
}
String& String::Copy(const char Str[])
{
delete[] pChar;
NumChars = strlen(Str);
MaxSlots = NumChars;
pChar = new char[MaxSlots + 1];
return *this;
}
String& String::Concat(const String & Str)
{
pTemp = new char[NumChars+1];
strcpy(pTemp, pChar);
strcat(pTemp, Str.pChar);
delete[]pChar;
pChar = pTemp;
return *this;
}
String & String::Concat(const char Str[])
{
return *this;
/*
NumChars = strlen(Str);
MaxSlots = NumChars;
delete[] pChar;
MaxSlots = MaxSlots + NumChars;
NumChars = NumChars + strlen(Str);
pChar = new char[MaxSlots + 1]; */
}
void String::Display() const
{
cout << pChar;
}
void String::displayLine() const
{
cout << pChar;
}
In my String.h:
#ifndef STRING_H
#define STRING_H
class String
{
public:
String(); //default constructor
String(const char[]);
String(const String &); //copy constructor
~String();
int Compare(const String &) const;
int Compare(const char[])const;
String& Copy(const String&);
String& Copy(const char[]);
String& Concat(const String&);
String& Concat(const char[]);
void Display()const;
void displayLine() const;
int length() const;
private:
char * pChar;
char *pTemp;
int NumChars;
int MaxSlots;
};
inline int String::length() const
{
return NumChars;
};
#endif
You expect the length of the concatenated string to be the sum of the length of the two strings. Therefore:
String& String::Concat(const String & Str)
{
pTemp = new char[NumChars + Str.NumChars + 1];
strcpy(pTemp, pChar);
strcat(pTemp, Str.pChar);
delete[]pChar;
pChar = pTemp;
return *this;
}
You can optimize this further by not strcat()-ing but strcpy()-ing twice (with an offset added to pTemp second time), as you already know the string length.
I'm not sure to understand the use of your MaxSlots; it's the size of allocated pChar (minus 1)? If so, there are points in your code where you forget to set/update/use.
And I don't understand what do you mean with "how to pass through a String class", but regarding "what steps are even needed in order to concatenate two strings", you've forgotten to take in count the number of chars already present in the object.
First of all, I suggest to create e Reserve() method; something like [caution: code not tested]
String& String::Reserve (int n)
{
if ( n > MaxSlots )
{
MaxSlots = n;
pTemp = new char[MaxSlots+1];
strcpy(pTemp, pChar);
delete[]pChar;
pChar = pTemp;
}
}
Next, rewrite your Concat() methods in this way
String& String::Concat(const String & Str)
{
NumChars += Str.NumChars;
Reserve(NumChars);
strcat(pChar, Str.pChar);
return *this;
}
String & String::Concat(const char * Str)
{
if ( Str )
{
NumChars += strlen(Str);
Reserve(NumChars);
strcat(pChar, Str);
}
return *this;
}
p.s.: sorry for my bad English

Combining two const char* together

I've tried many ways to do that, I got a void which is static and is on Console class i made, Void it self works fine:
Console::WriteLine(const char* msg)
On the other side, I got another const char* non static void which calls the Console::WriteLine void from It, I've been working on C# for around a year and on C# I can easily do something like this:
string a = "Start ";
string b = a + "End";
When i call this on C++, it gives me bunch of errors:
Player::Kill(const char* Message)
{
Console::WriteLine("> " + Message + " <");
}
I've also tried the strcat thing and put, But it tells me to use strcat_s which doesn't really work, And also I've tried to do string instead of const char*, And tried char*, But all of them give errors for the thing I'm trying to do.
"const" means "cannot be changed(*1)". So you cannot simply "add" one const char string to another (*2). What you can do is copy them into a non-const character buffer.
const char* a = ...;
const char* b = ...;
char buffer[256]; // <- danger, only storage for 256 characters.
strncpy(buffer, a, sizeof(buffer));
strncat(buffer, b, sizeof(buffer));
// now buffer has the two strings joined together.
Your attempt to use std::string failed for a similar reason. You said:
std::string a = "Start";
std::string b = a + " End";
This translates to
b = (std::string)a + (const char*)" End";
Which should be ok except that it creates an extra string, what you probably wanted is
std::string a = "Start";
a += " End";
If you are getting compile errors doing this, please post them (Make sure you #include ).
Or you could do something like:
std::string addTwoStrings(const std::string& a, const std::string& b)
{
return a + b; // works because they are both strings.
}
All of the following work: (see live demo http://ideone.com/Ytohgs)
#include <iostream>
#include <string>
std::string addTwoStrings(const std::string& a, const std::string& b)
{
return a + b; // works because they are both strings.
}
void foo(const char* a, const char* b)
{
std::string str = a;
std::cout << "1st str = [" << str << "]" << std::endl;
str += " ";
std::cout << "2nd str = [" << str << "]" << std::endl;
str += b;
std::cout << "3rd str = [" << str << "]" << std::endl;
str = addTwoStrings(a, " ");
std::cout << "4th str = [" << str << "]" << std::endl;
str = addTwoStrings(str, b);
std::cout << "5th str = [" << str << "]" << std::endl;
}
int main()
{
foo("hello", "world");
}
*1 Or more accurately, "cannot be changed in-situ" - you can use it in expressions, etc, so for example, e.g.
const size_t len = strlen("hello");
size_t newLen = len + strlen("world");
// but this would not be legal:
len += 2; // error: len is const.
2 "const char a + const char* b" is actually trying to add two pointers not two strings, the result would be the address of string a plus the address of string b, the sum of which would be some random memory location
char * is a pointer (so are "> " and " <"), you cannot add pointers together.
However you can concatenate C++ strings using the + operator:
Player::Kill(const std::string& Message)
{
Console::WriteLine(("> " + Message + " <").c_str());
}
Instead of concatenating the strings and creating an extra temporary object, why not just output the 3 strings separately?
Player::Kill(const char* Message)
{
Console::Write("> ");
Console::Write(Message);
Console::WriteLine(" <");
}
Since you say it's C++ code, just just this:
void Player::Kill(std::string const& Message)
{
Console::WriteLine(("> " + Message + " <").c_str());
}
Ideally, your Console::WriteLine() is declared to also take a std::string const& in which case you don't need to do the .c_str()-dance.
#include <iostream>
using namespace std;
string string1 = "John";
string string2 = "Smith";
float string1Len = string1.length();
float combinedLen = string1.length() + string2.length();
char combine[string2.length() + string1.length()];
for(int i = 0; i < string1Len; ++i){
combine[i] = string1[i];
}
for(int i = string1Len; i < combinedLen; ++i){
combine[i] = string2[i - string1Len];
}
const char * combined = combine;
well, it is possible to make changes with const char* ,even thought it is const we cannot change its value but can change its address ,check below class for reference
class String
{
private:
const char* m_Name;
int m_Size;
public:
String() :m_Name(" "), m_Size(0) { m_Size = 0; }
String(const char* name , int size) :m_Name(name),m_Size(size) {}
String(const char* name) :m_Name(name) {}
void Display()
{
LOG(m_Name);
}
int GetSize()
{
while (m_Name[m_Size] != '\0')
{
m_Size++;
}
return m_Size;
}
void Append(const char* nameToAppend)
{
//Create an empty char array pointer "*tempPtr" of size = existing const
//char name pointer "m_Name" + const char pointer appending name
//"*nameExtention"
//this array can store both the names
int totalSize = 0;
int nameToAppendSize = 0, existingNameSize = 0;
while (nameToAppend[nameToAppendSize] != '\0')
{nameToAppendSize++;}
existingNameSize = this->GetSize();
totalSize = nameToAppendSize + existingNameSize;
char* tempPtr = new char[totalSize+1];
//Add existing const char name pointer "*m_Name" + const char pointer
//appending name "*nameExtention" to tempPtr, using a loop
int currentSize = 0;
for (int i = 0; i < existingNameSize; i++)
{
tempPtr[currentSize] = m_Name[i];
currentSize++;
}
for (int i = 0; i <= nameToAppendSize; i++)
{
if (i == nameToAppendSize)
{
tempPtr[currentSize] = '\0'; // this line tells compiler to stop
// writting inside tempPtr
}
else
{
tempPtr[currentSize] = nameToAppend[i];
currentSize++;
}
}
//--------------------------------
//Now change the address of your const char* with tempPtr
//This will change the contents of the const char*
//--------------------------------
m_Name = (char*)tempPtr;
}
};

Odd output from program when entering operator?

I'm probably missing something obvious here. This is my code (I'm just learning true C++, and I want to get some practice):
#include <iostream>
#include <cstring>
using namespace std;
class String {
private:
char * value;
int len;
friend ostream & operator<<(ostream & os, String s);
public:
String();
String(const char * base);
~String();
String operator+(String s);
String operator*(int n);
int length();
};
String::String() {
this->value = new char[0];
this->len = 0;
}
String::String(const char * base) {
this->value = new char[this->len = strlen(base)];
strcpy(this->value, base);
}
String::~String() {
delete [] this->value;
}
int String::length() {
return this->len;
}
String String::operator+(String s) {
String n;
delete [] n.value;
cout << "Upon entering, I am: \"" << *this << "\"\n";
n.value = new char[this->len + s.len];
for(int i = 0; i < this->len; i++) {
n.value[i] = this->value[i];
}
for(int i = 0; i < s.len; i++) {
n.value[i + this->len] = s.value[i];
}
n.len = this->len + s.len;
cout << "String::operator+(" << *this << ", " << s << ") succeeded with new value = \"" << n << "\"\n";
return n;
}
String String::operator*(int n) {
String s;
delete [] s.value;
s.value = new char[this->len * n];
for(int i = 0; i < this->len * n; i++) {
s.value[i] = this->value[i % this->len];
}
cout << "String::operator* succeeded with new value = \"" << s << "\"\n";
return s;
}
ostream & operator<<(ostream & os, String s) {
return os << s.value;
}
int main() {
String s("Hello, world!");
cout << s << "\nLength = " << s.length() << "\n\n";
cout << (s + String("\n")) * 5;
return 0;
}
And the string initializes and displays correctly, but my output is really strange; it seems that upon entering the operator+, "Hello, world!" suddenly becomes "x%r"?
C:\Users\Ryan\Documents\My Dropbox\C++ Projects>strings
Hello, world!
Length = 13
Upon entering, I am: "x%r"
String::operator+(x%r,
) succeeded with new value = "x%r"
String::operator* succeeded with new value = "╚%r"
─
Try this:
ostream & operator<<(ostream & os, const String& s) {
return os << s.value;
}
otherwise your should define copy constructor for your String class.
You need to provide copy constructor and assignment operator.
There are a lot of problems with your code.
You are managing your own memory. You should avoid doing this if at all possible.
You are consitantly forgetting that strings have a null terminator. In order to accomodate the strin Hello, world! you need a char buffer that is 14 bytes, not 13.
You have a len member variable that does effectively the same thing as the strlen function, except for the inconsistent consideration of #1 above.
Your string class does not have a copy constructor, which results in wild pointers and eventually crashes.
Here is a refactoring of your code that pretty much works.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;
class String {
private:
char * value;
// size_t len;
friend ostream & operator<<(ostream & os, String s);
public:
String();
String(const char * base);
String(const String& rhs)
{
value = new char[strlen(rhs.value)+1];
strcpy(value,rhs.value);
}
~String();
String operator+(String s);
String operator*(int n);
size_t length();
};
String::String() {
this->value = new char[0];
}
String::String(const char * base) {
this->value = new char[strlen(base)+1];
strcpy(this->value, base);
}
String::~String() {
delete [] this->value;
}
size_t String::length() {
return strlen(value);
}
String String::operator+(String s) {
String n;
delete [] n.value;
cout << "Upon entering, I am: \"" << *this << "\"\n";
n.value = new char[strlen(value)+strlen(s.value)+1];
for(int i = 0; i < strlen(value); i++) {
n.value[i] = this->value[i];
}
for(int i = 0; i < strlen(s.value); i++) {
n.value[i + strlen(value)] = s.value[i];
}
n.value[strlen(value)+strlen(s.value)] = '\0';
cout << "String::operator+(" << *this << ", " << s << ") succeeded with new value = \"" << n << "\"\n";
return n;
}
String String::operator*(int n) {
String s;
delete [] s.value;
s.value = new char[(strlen(value)*n)+1];
for(int i = 0; i < strlen(value) * n; i++) {
s.value[i] = this->value[i % strlen(value)];
}
s.value[strlen(value)*n] = '\0';
cout << "String::operator* succeeded with new value = \"" << s << "\"\n";
return s;
}
ostream & operator<<(ostream & os, String s) {
return os << s.value;
}
int main() {
String s("Hello, world!");
cout << s << "\nLength = " << s.length() << "\n\n";
cout << (s + String("\n")) * 5;
return 0;
}