Error with my assignment [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I had one assignment from my prof., but after coding, I got over 40 errors but don't know why :(
My assignment:
" Build CHAR and STRING class (STRING is a string of CHAR) with these samples:
class CHAR
{
private:
char content;
/* Insert more codes here */
};
class STRING
{
private:
CHAR * content;
int length;
/* Insert more codes here */
};
and then test with this main function:
int main()
{
CHAR c1, c2('c');
STRING s1, s2("s2"), s3('a'), s4(c1);
s1.expand(c2).expand('a').expand(s2).expand("abc");//s1: "cas2abc"
s1.remove(c2).remove('d');//remove all character c2 in s1 -- s1: "as2ab"
s1.input();//insert new string from keyboard
cout<<s1.getContent();// export content of s1
cout<<c1.getContent();// export content of c1
return 0;
}
My code link here: https://bugs.vn/10670
Thank you.

Check compiler errors!
Your STRING class does not have methods: remove, input, getContent. You can not call methods which you have not defined.
This will compile and run.
// CHAR.h
#include <iostream>
// STRING.h
#include <iostream>
#include <string>
#include <string.h> //sg7
using namespace std;
class CHAR
{
private:
char content;
public:
CHAR();
CHAR(char);
char GetContent();
void SetContent(char);
};
class STRING
{
private:
CHAR * content;
int length;
public:
STRING();
STRING(const char*);
STRING(char);
STRING(const CHAR&);
STRING& expand(const CHAR&);
~STRING();
};
// CHAR.cpp
// #include "CHAR.h"
CHAR::CHAR()
{
this->content = '\0';
}
CHAR::CHAR(char)
{
this->content = 'c';
}
char CHAR::GetContent()
{
return content;
}
void CHAR::SetContent(char C)
{
content = C;
}
// STRING.cpp
//#include "STRING.h"
//#include "CHAR.h"
STRING::STRING()
{
this->content = NULL;
this->length = 0;
}
STRING::STRING(const char *c)
{
this->length = strlen(c);
this->content = new CHAR[this->length];
for (int i = 0; i < this->length; i++)
{
this->content[i] = CHAR(c[i]);
}
}
STRING::STRING(char c)
{
this->length = 1;
this->content = new CHAR[1];
this->content[0] = CHAR(c);
}
STRING::STRING(const CHAR &c)
{
this->length = 1;
this->content = new CHAR[1];
this->content[0] = c; //.SetContent(c.GetContent());
}
STRING& STRING::expand(const CHAR &c)
{
CHAR *new_content = new CHAR[this->length + 1];
for (int i = 0; i < this->length; i++)
{
new_content[i] = this->content[i];
}
new_content[this->length] = c;
if(this->content!=NULL)
{
delete[] this->content;
}
this->content = new_content;
this->length++;
return *this;
}
STRING::~STRING()
{
if (this->content != NULL)
delete[]this->content;
}
int main()
{
CHAR c1, c2('c');
STRING s1, s2("s2"), s3('a'), s4(c1);
s1.expand('a');
return 0;
}

Related

Why isn't my char* shrinking after popping a char

For context, I'm rewriting the string class in C++ to use on microcontrollers, specifically Arduino, so that it doesn't use the standard library functions not supported by Arduino.
I've looked at several answers here that show how to pop a char off a char*. However, within my function it doesn't seem to correctly edit the char*.
My string class
#include <stdlib.h> // malloc
namespace micro_std {
class string {
private:
const int MAX_SIZE = 4096; // Maximum size on 16bit controllers.
char* data = nullptr;
int _length = 0;
public:
string(char* data) {
this->data = data;
for (int i = 0; data[i] != '\0'; i++)
_length++;
}
int size(void) const { return _length; }
int length(void) const { return _length; }
int max_size(void) const { return MAX_SIZE; }
bool empty(void) const { return _length == 0; }
char at(int index) const { return data[index]; }
char back(void) const { return data[_length - 1]; }
char front(void) const { return data[0]; }
char* str(void) const { return data; }
void clear(void) { _length = 0; data = nullptr; }
// removed for brevity //
char pop_back(void) {
_length--;
char character = data[_length];
data[_length] = '\0';
return character;
}
// removed for brevity //
};
}
And how I'm testing my code, specifically the pop_back function.
#include <stdio.h> // printf
#include "micro_std/string.h"
int main(int argc, char** argv) {
micro_std::string x = "abcdef";
// Testing pop_back function
printf("%d %s\n", x.length(), x.str());
for (int i = 0; i < 5; i++) {
char res = x.pop_back();
printf("%d %c %s\n", x.length(), res, x.str());
}
//printf("%s\n", x.str());
return 0;
}
And, if needed, my compiler arguments
g++ -w -std=c++2a -O3 program.cpp -o program
Running this program gives me the following output:
6 abcdef
5 f abcdef
4 e abcdef
3 d abcdef
2 c abcdef
1 b abcdef
Instead of the output I want:
6 abcdef
5 f abcde
4 e abcd
3 d abc
2 c ab
1 b a
Where the output is formatted like "(length) (char popped) (result string)". Why isn't the data member data being altered when calling the pop_back function?
Why isn't the data member data being altered when calling the pop_back function?
Even if the code compiles (which it shouldn't, since you are trying to construct x with a string literal, which is a const char[] array that cannot be assigned to a non-const char*), x would be pointing its data member at a string literal, thus data[_length] = '\0'; inside of pop_back() would invoke Undefined Behavior trying to alter read-only memory.
To make your code work, you MUST make a copy of the input data, eg:
#include <stdlib.h> // malloc
namespace micro_std {
class string {
private:
const int MAX_SIZE = 4096; // Maximum size on 16bit controllers.
char _data[MAX_SIZE];
int _length = 0;
public:
string(const char* str) {
for (int i = 0; str[i] != '\0'; ++i) {
data[i] = str[i];
++_length;
}
data[_length] = '\0';
}
...
void clear(void) { _length = 0; }
...
};
}

Trace/Breakpoint trap:delete []

I use VScode, and it shows "trace/breakpoint trap" on line:delete [] str;
Here is my code:
#include <iostream>
#include <cstring>
using namespace std;
class String
{
private:
char *str;
public:
String() : str(new char[1]) { str[0] = 0; }
const char *c_str() { return str; }
String operator=(const char *s);
~String()
{
delete[] str;
}
};
String String::operator=(const char *s)
{
delete[] str;
str = new char[strlen(s) + 1];
strcpy_s(str, strlen(s) + 1, s);
return *this;
}
int main()
{
String s;
s = "abc";
cout << s.c_str() << endl;
return 0;
}
the code stops at the destructor :
delete [] str;
I wonder what is going on.

error: conversion from ‘const char [5]’ to non-scalar type ‘String’ requested

I am trying to create a class String which can be assigned by operator=. But the compiler shows an error:
error: conversion from ‘const char [5]’ to non-scalar type ‘String’ requested
Can anyone help me to fix it?
#include <iostream>
using namespace std;
class String
{
private:
char string[];
public:
void operator=(const char str[])
{
for (int i = 0; ; i++) {
if (str[i] == '\0') {
string[i] = str[i];
break;
} else {
string[i] = str[i];
}
}
}
friend ostream &operator<<(ostream &output, const String& str)
{
output << str.string;
return output;
}
};
int main()
{
String str1 = "test";
cout << str1 << endl;
}
String str1 = "test"; does not use operator= at all. It is just syntax sugar for String str1("test");, which uses a conversion constructor that you have not defined yet, hence the compiler error. You need to add such a constructor.
Also, char string[]; is not a valid variable declaration for an array. You need to specify a size for the array, and then make sure the class never exceeds that size.
For example
#include <iostream>
#include <cstring>
using namespace std;
class String {
private:
char string[256];
public:
String(const char *str = NULL) {
if (str) strncpy(string, str, sizeof(string)-1);
string[sizeof(string)-1] = '\0';
}
String& operator=(const String &str) {
if (this != &str) {
memcpy(string, str.string, sizeof(string));
}
return *this;
}
friend ostream& operator<<(ostream &output, const String& str) {
output << str.string;
return output;
}
};
int main() {
String str1 = "test";
cout << str1 << endl;
}
However, in this situation, using a dynamically allocated array makes more sense than using a fixed array. Just be sure to follow the Rule of 3 for proper memory management.
Try this instead:
#include <iostream>
#include <cstring>
using namespace std;
class String {
private:
char *string;
int length;
int capacity;
public:
String(const char *str = NULL)
: string(NULL), length(0), capacity(0)
{
if ((str) && (*str != '\0')) {
length = capacity = strlen(str);
string = new char[length + 1];
memcpy(string, str, length + 1);
}
}
String(const String &str)
: string(NULL), length(0), capacity(0)
{
if (str.string) {
length = capacity = str.length;
string = new char[length + 1];
memcpy(string, str.string, length + 1);
}
}
~String() {
delete[] string;
}
String& operator=(const String &str) {
if (this != &str) {
int len = str.length;
if (capacity >= len) {
memcpy(string, str.string, len + 1);
}
else {
int cap = int(double(len) * 1.5);
char *temp = new char[cap + 1];
memcpy(temp, str.string, len + 1);
delete[] string;
string = temp;
capacity = cap;
}
length = len;
}
return *this;
}
friend ostream& operator<<(ostream &output, const String& str) {
if (str.string) {
output.write(str.string, str.length);
}
return output;
}
};
int main() {
String str1 = "test";
cout << str1 << endl;
}
You need to add a ctor to your class. You are using the assignment operator to try to construct your String object. Add this to your class.
String(const char str[]) {
for (int i = 0; ; i++) {
if (str[i] == '\0') {
string[i] = str[i];
break;
} else {
string[i] = str[i];
}
}
}

c++ deep copy constructor [duplicate]

This question already has answers here:
Rule-of-Three becomes Rule-of-Five with C++11? [closed]
(9 answers)
Closed 5 years ago.
this is my code:
#include<iostream>
#include<cstring>
using namespace std;
class String
{
private:
char *s;
int size;
public:
String(const char *str = NULL); // constructor
String& operator=(String &c){
size = strlen(c.s);
s = new char[size+1];
strcpy(s, c.s);
}
~String() { delete [] s; }// destructor
void print() { cout << s << endl; }
void change(const char *); // Function to change
};
String::String(const char *str)
{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
void String::change(const char *str)
{
delete [] s;
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
int main()
{
String str1("learnc++");
String str2 = str1;
str1.print(); // what is printed ?
str2.print();
str2.change("learnjava");
str1.print(); // what is printed now ?
str2.print();
return 0;
}
it can be compiled, and the result is:
learnc++
learnc++
learnjava
learnjava
in addition to that,there is:
*** Error in `./code': double free or corruption (fasttop): 0x0000000000f7f010 ***
BTY, if I delete "delete [] s;" in String::change,the result just becomes:
learnc++
learnc++
learnc++
learnjava
and no error appers, and why ?
the code is from geek foe feeks, I have changes some strings, and the code can be run in its IDE, but in my ubuntu 14.04, it cannot.
Your class is not following the Rule of Three because it is missing a proper copy constructor.
String str2 = str1; is just syntax sugar for String str2(str1);, so it uses the copy constructor, not your operator= (which has a memory leak, BTW).
Since you did not provide a copy constructor, the compiler provided one for you, but it does not make a deep copy of the char* data. It just copies the pointer itself, which causes the behaviors you are seeing.
A proper implementation would look more like this:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
class String
{
private:
char *s;
int size;
public:
String(const char *str = NULL);
String(const String &src);
~String();
String& operator=(const String &rhs);
void print() const;
};
String::String(const char *str)
{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
String::String(const String &src)
{
size = src.size;
s = new char[size+1];
strcpy(s, src.s);
}
String::~String()
{
delete [] s;
}
void String::print() const
{
cout << s << endl;
}
String& String::operator=(const String &rhs)
{
if (&rhs != this)
{
String tmp(rhs);
swap(s, tmp.s);
swap(size, tmp.size);
}
return *this;
}
int main()
{
String str1("learnc++");
String str2 = str1;
str1.print();
str2.print();
//str2.change("learnjava");
str2 = "learnjava";
str1.print();
str2.print();
return 0;
}
If you are using C++11 or later, you can use this implementation instead, which follows the Rule of Five by adding move semantics:
#include <iostream>
#include <cstring>
#include <utility>
using namespace std;
class String
{
private:
char *s;
int size;
public:
String(const char *str = nullptr);
String(const String &src);
String(String &&src);
~String();
String& operator=(String rhs);
void print() const;
};
String::String(const char *str)
{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
String::String(const String &src)
{
size = src.size;
s = new char[size+1];
strcpy(s, src.s);
}
String::String(String &&src)
{
size = src.size;
s = src.s;
src.s = nullptr;
src.size = 0;
}
String::~String()
{
delete [] s;
}
void String::print() const
{
cout << s << endl;
}
String& String::operator=(String rhs)
{
swap(s, rhs.s);
swap(size, rhs.size);
return *this;
}
Add a copy constructor.
String(const String& c){
size = strlen(c.s);
s = new char[size+1];
strcpy(s, c.s);
}

Can not delete char pointer in C++

Why can not I perform the following line?
delete [] target;
in my case?
Here is the code:
main.cpp
#include <iostream>
using namespace std;
#include "Char.h"
int main()
{
char * text = "qwerty";
char * a = new char[charlen(text)+1];
copyon(a,text);
cout<<a<<endl;
char * test = "asdfghjkl";
assign(&a, test);
assign(&a, a);
char * test1 = new char[26];
for (int i(0); i < 26; i++)
{
test1[i] = char(i+65);
}
test1[26] = '\0';
anotherAssign(test1, a);
cout << test1 << endl;
return 0;
}
Char.cpp
#include "Char.h"
#include <iostream>
#include <cassert>
#include <cstring>
size_t charlen(const char * ps)
{
size_t len=0;
while (ps[len++]);
assert(len-1==strlen(ps));
return len;
}
void assign(char** target, const char* source)
{
if (*target==source)
return;
delete [] *target;
*target = new char[charlen(source)+1];
copyon(*target, source);
return;
}
void anotherAssign(char* target, const char* source)
{
if (target==source)
return;
delete [] target;
target = new char[charlen(source)+1];
copyon(target, source);
return;
}
void copyon(char* const target, const char* const source)
{
char * t = target;
const char * s = source;
while (*t++ = *s++);
//while(*target++ = *source++)
// ;
std::cout << target << " source = " << source << std::endl;
return;
size_t len = charlen(source);
//for (size_t i=0; i<len; ++i)
// target[i]=source[i];
//target[len]='\0';
}
Here is an exception:
If you do:
char * test1 = new char[26];
then your array will go from test1[0] to test1[25].
That means:
test1[26] = '\0';
is out of bounds. At this point, the head is corrupted, and what happens next is undefined (but rarely desirable).