#include <iostream>
using namespace std;
class MyClass
{
private :
char str[848];
public :
MyClass()
{
}
MyClass(char a[])
{
str[848] = a[848];
}
MyClass operator () (char a[])
{
str[848] = a[848];
}
void myFunction(MyClass m)
{
}
void display()
{
cout << str[848];
}
};
int main()
{
MyClass m1; //MyClass has just one data member i.e. character array named str of size X
//where X is a constant integer and have value equal to your last 3 digit of arid number
MyClass m2("COVID-19") , m3("Mid2020");
m2.display(); //will display COVID-19
cout<<endl;
m2.myFunction(m3);
m2.display(); //now it will display Mid2020
cout<<endl;
m3.display(); //now it will display COVID-19
//if your array size is even then you will add myEvenFn() in class with empty body else add myOddFn()
return 0;
}
I cannot use string because I'm told not to, therefore, I need to know how I can make it such that it displays the desired output
How to initialize char array in constructor?
Use a loop to copy element by element:
MyClass(char a[])
{
//make sure that sizeof(a) <= to sizeof(str);
// you can not do sizeof(a) here, because it is
// not an array, it has been decayed to a pointer
for (int i = 0; i < sizeof(str); ++i) {
str[i] = a[i];
}
}
Use std::copy from <algorithm>
const int size = 848;
std::copy(a, a + size, str);
Prefer std::copy over strcpy, if you have to use strcpy, prefer strncpy instead. You can give size to it, so it can help prevent errors and buffer overflows.
MyClass(char a[])
{
strncpy(str, a, sizeof(str));
}
Use std::array from the library. It has various advantages, for e.g you can directly assign it like normal variables. Example:
std::array<char, 848> str = {/*some data*/};
std::array<char, 848> str1;
str1 = str;
To copy a string you have to use std::strcpy, not str[848] = a[848].
str[848] = a[848] copy only one element, but in your case it's a mistake, becasue your array has indexes [0, 847].
Try
class MyClass
{
private :
char str[848];
public :
MyClass()
{
}
MyClass(char a[])
{
std::strcpy(src, a);
}
MyClass operator () (char a[])
{
std::strcpy(src, a);
}
void myFunction(MyClass m)
{
}
void display()
{
cout << str;
}
};
Related
I need to make an array of string where I can store either 3 or 5 words like {"banana, peach, pear"}, or {"orange", "pear", "silantro", "ginger", "mandarine"}.
I'm confused if I should make an array of string pointer(to dynamically allocate the memory depending on the size of the array-3 or 5), or just have an array of string with the statically allocated memory of 5. And how to initialize it/set it to null/use it in the constructors.
I'm not allowed to use vector.
When I declared an array of size 5, the problem started in the default constructor.
I don't know how to set it to null...
// string multiple_fruits[5]
// multiple_fruits[] = { nullptr, };
So I'm using an array of string pointer here, is there a better way?
What am I doing wrong?? HAAAALP
//.h file
class Fruit {
char* single_fruit;
string* multiple_fruits;
int num_Fruits;
};
//.cpp file
Fruit::Fruit() {
single_fruit = nullptr;
multiple_fruits = nullptr;
num_Fruits = 0;
}
Fruit::Fruit(const char* singlefruit, string* multiplefruits, int numFruits) {
single_fruit = new char[strlen(singlefruit) + 1];
strcpy_s(single_fruit, strlen(singlefruit) + 1, singlefruit);
multiple_fruits = new string[numFruits];
for (int i = 0; i < numFruits; i++) {
multiple_fruits[i] = multiplefruits[i];
}
num_fruits = numFruits;
}
int main() {
Fruit A;
A("apple", {"banana", "peach", "pear"}, 3)
Fruit B;
B("lemon", {"orange", "pear", "silantro", "ginger", "mandarine"}, 5);
return 0;
}
My approach is to use std::string and std::initializer_list for this:
#include <string>
#include <initializer_list>
class Fruit {
public:
Fruit(const std::string &singlefruit, const std::initializer_list<std::string> &multiplefruits) : single_fruit{singlefruit}, multiple_fruits{new std::string[multiplefruits.size()]}, num_Fruits{multiplefruits.size()} {
for (std::size_t i = 0; i < num_Fruits; ++i) {
multiple_fruits[i] = *(multiplefruits.begin() + i);
}
}
~Fruit() {
delete[] multiple_fruits;
}
private:
std::string single_fruit;
std::string *multiple_fruits;
std::size_t num_Fruits;
};
int main() {
Fruit A("apple", {"banana", "peach", "pear"});
Fruit B("lemon", {"orange", "pear", "silantro", "ginger", "mandarine"});
}
I allocated memory for the elements and deleted the memory in the destructor.
You can't declare a variable in one line and call the constructor in the next line.
Here's one way using a proper declaration of the array argument to the constructor.
#include <algorithm> // std::copy
#include <iterator> // std::begin, std::end
#include <string>
#include <iostream>
template<size_t N>
class Fruit {
public:
Fruit();
Fruit(const std::string& singlefruit, const std::string (&multiplefruits)[N]);
size_t size() const;
private:
std::string single_fruit;
std::string multiple_fruits[N];
};
template<size_t N>
Fruit<N>::Fruit() {}
template<size_t N>
Fruit<N>::Fruit(const std::string& singlefruit, const std::string (&multiplefruits)[N])
: // colon indicates the start of the member initializer list
single_fruit(singlefruit)
{
std::copy(std::begin(multiplefruits), std::end(multiplefruits), multiple_fruits);
}
template<size_t N>
size_t Fruit<N>::size() const { return N; }
int main() {
Fruit A("apple", {"banana", "peach", "pear"});
std::cout << A.size() << '\n';
Fruit B("lemon", {"orange", "pear", "silantro", "ginger", "mandarine"});
std::cout << B.size() << '\n';
}
Output:
3
5
I'm using the following example from Stroustrup C++ 4th Ed. Page 218. My question is regarding the destructor.
Questions:
How does placement new(&s) string{ss} allocate room for the new string when it's my understanding that union size is fixed to the largest member? Is string s not a 0 element string? If so, how does the placement new create a larger string if there is not enough space in the union?
#include <iostream>
#include <string>
using namespace std;
class Entry2 { // two alternative representations represented as a union
private:
enum class Tag { number, text };
Tag type; // discriminant
union { // representation
int i;
string s; // string has default constructor, copy operations, and destructor
};
public:
struct Bad_entry { }; // used for exceptions
string name;
Entry2(int n) : type{Tag::number}, i{n} { };
Entry2(string ss) : type{Tag::number} { new(&s) string{ss}; };
~Entry2();
Entry2& operator=(const Entry2&); Entry2(const Entry2&);
// ...
int number() const; string text() const;
void set_number(int n);
void set_text(const string&); // ...
};
Entry2::~Entry2()
{
if (type==Tag::text)
s.~string();
}
int Entry2::number() const
{
if (type!=Tag::number) throw Bad_entry{};
return i;
}
string Entry2::text() const
{
if (type!=Tag::text) throw Bad_entry{};
return s;
}
void Entry2::set_number(int n)
{
if (type==Tag::text) {
s.~string();
type = Tag::number;
}
i = n;
}
void Entry2::set_text(const string& ss)
{
if (type==Tag::text)
s = ss;
else {
new(&s) string{ss};
type = Tag::text;
}
}
Entry2& Entry2::operator=(const Entry2& e)
{
if (type==Tag::text && e.type==Tag::text) {
s = e.s; // usual string assignment
return *this;
}
if (type==Tag::text)
s.~string(); // explicit destroy (ยง11.2.4)
switch (e.type) {
case Tag::number:
i = e.i;
break;
case Tag::text:
new(&s) string{e.s};
type = e.type;
}
return *this;
}
int main(int argc, char *argv[])
{
Entry2 e0(0);
cout << e0.number() << endl;
try {
e0.text();
} catch (...) {
cout << "caught except" << endl;
}
e0.set_text("abcd");
cout << e0.text() << endl;
return 0;
}
No, the destructor should not always do this. Remember that in a union, only one of the fields is actually active at any one time. If the std::string member of the union isn't active, then calling its destructor would be a Bad Thing (cause undefined behavior) because there wasn't a string there to destroy. Instead, we instead only call the destructor on that std::string member if at some previous point in time we activated the std::string there.
Hope this helps!
I have class XOBoard that present an array that is size n*n,each cell of the array is an Object called Cell.
Each Cell object is defined by
class Cell {
private:
char ch;
public:
Cell(char ch = '.');
char getCellValue();
void setCellValue(char nch);
};
Board is defined this way:
class XOBoard {
private:
int n;
Cell **Board;
};
XOBoard::XOBoard(int n) { //constructor
this->n = (n >= 3) ? n : 3;
Board = new Cell*[n];
for (int i = 0; i < n; i++) {
Board[i] = new Cell[n];
}
}
I wanted to get to a specific Cell value by using this method: board1[{1,2}], but I want to check if the values that sent to me is withing the range(n), but unfortantly I was unable to get to the Board array, and to n variable.
Here is the code:
XOBoard& operator[](list<int> list){
int x = list.front(), y = list.back();
return Board[x][y].getCellValue();
}
Thanks a head!
As mentioned in the comments, using operator[] for multidimensional subscripting is unconventional, but if you want that, you should make sure you get the correct amount of values (2 in this case) and that you return the correct type (a Cell& in this case).
Also be aware of shadowing. If you try to construct a Board with a value less than 3, you'll set this->n to 3 but go on with the construction using the erroneous n (that may even be a negative value).
More comments inline:
#include <iostream>
#include <stdexcept>
#include <tuple>
class Cell {
private:
char ch;
public:
Cell(char nch = '.') : // after the colon comes the member initializer list
ch(nch) // which is usually good to use
{
// if(ch is not valid) throw ...
}
char getCellValue() const { return ch; }
// a convenient conversion operator to automatically
// convert a Cell to a char where a char is needed
// (like when streaming a Cell to std::cout)
operator char() const { return ch; }
// void setCellValue(char nch); // replaced by operator=
Cell& operator=(char nch) {
// if(nch is not valid) throw ...
ch = nch;
return *this;
}
};
class XOBoard {
private:
size_t n; // use an unsigned type for sizes/indices
Cell** Board;
public:
// constructor
XOBoard(size_t xy_size) : // a member initializer list again
n(xy_size >= 3 ? xy_size : 3), // assign to "n" here
Board(new Cell*[n]) // the correct n is now used
{
// if the below construction fails, a bad_alloc will be thrown.
// you need to add code to clean up what you've already allocated to take
// care of that situation.
for(size_t i = 0; i < n; i++) {
Board[i] = new Cell[n];
}
}
// Copying or moving need careful handling of the pointers.
// Read "The rule of three/five/zero". Until then, disable it.
XOBoard(const XOBoard&) = delete;
XOBoard& operator=(const XOBoard&) = delete;
// destructor
~XOBoard() {
for(size_t i = 0; i < n; i++) delete[] Board[i];
delete[] Board;
}
// added for convenience
size_t size() const { return n; }
// return a Cell& and use a std::pair since you
// expect exactly 2 values
Cell& operator[](std::pair<size_t, size_t> pos) {
auto& [x, y] = pos;
if(x>=n || y>=n)
throw std::out_of_range("{"+std::to_string(x)+","+std::to_string(y)+"}");
return Board[x][y];
}
};
int main() {
try {
XOBoard a{2}; // trying an invalid size
std::cout << a.size() << '\n';
a[{2, 2}] = 'a';
std::cout << a[{2, 2}] << '\n';
Cell x = 'b';
a[{2, 2}] = x;
std::cout << a[{2, 2}] << '\n';
a[{2, 3}] = 'c'; // index out of bounds
} catch(const std::out_of_range& ex) {
std::cerr << "out_of_range exception: " << ex.what() << '\n';
}
}
Output:
3
a
b
out_of_range exception: {2,3}
You should try to avoid raw pointers and actual multidimensional arrays. It's often better to emulate dimensionality by allocating a 1d array and provide an interface to the user that calculates the correct element to work on.
I have made a class String which has two private members int length and a character pointer.
There are two constructors which initialize these members.
My question why s1.print() is not working in my code?
#include <iostream>
#include <string.h>
using namespace std;
class String {
int length;
char * ptr;
public:
String(int N, char s[]) {
ptr = new char[N];
strcpy(s, ptr);
}
String(int N) {
ptr = new char[N];
}
String concat(String s2) {
String result(s2.length + length, strcat(ptr, s2.ptr));
}
void print(void) {
cout << ptr << endl;
}
};
int main() {
char temp[50];
cin >> temp;
String s1(strlen(temp) + 1, temp);
//String s2(strlen(temp)+1, temp);
s1.print();
//s1.concat(s2);
//s1.print();
return 0;
}
In order to print the char* you need to cast it to string and than print.
Another thing I suggest that your array size will be N + 1 and add a NULL-terminate at ptr[N] = '\0'
Hey i'm new to c++ and still working out its perticularities. I'm having the darnedest time trying to figure out whats going wrong with this code. I've stepped through it and everything is calculating correctly. The issue is that value_array in the base class doesn't seem to be retaining the values once the derived class Calculate function ends. I think i've declared and allocated the array properly. I'm stumped...
#include <iostream>
class Indicator
{
protected:
double * value_array;
double * input_array;
int input_size;
public:
Indicator(double input[], int size)
{
input_array = input;
input_size = size;
value_array = new double[size]; // issue with value_array
}
double operator[] (int index) { return value_array[index]; }
void virtual Calculate() {}
~Indicator() { delete[] value_array; }
};
class SMA : public Indicator
{
private:
int nperiod;
double sum;
public:
SMA(double input[], int size, int period) : Indicator(input, size)
{
nperiod = period;
sum = 0;
Calculate();
}
void Calculate();
};
void SMA::Calculate()
{
for (int i=0; i<input_size; i++)
{
if (i > nperiod - 1)
{
sum += input_array[i] - input_array[i-nperiod];
value_array[i] = sum / nperiod;
}
else
{
sum += input_array[i];
value_array[i] = sum / (i+1);
}
}
}
int main(int argc, const char *argv[]) {
double input[] = {1,2,3,4,5,6,7,8,9,10};
Indicator indicator = SMA(input,10,5);
double value = indicator[0];
std::cout << "value: " << value << std::endl;
std::cin.get();
exit(0);
}
Update:
Here is the code implemented with vectors. I wanted to leave the input as double[] to be consistent with other libraries, any other potential issues I should be aware of?
#include <iostream>
#include <vector>
class Indicator
{
protected:
std::vector<double> value_vector;
double * input_array;
int input_size;
public:
Indicator(double input[], int size)
{
input_array = input;
input_size = size;
value_vector.reserve(size);
}
double operator[] (int index) { return value_vector[index]; }
void virtual Calculate() {}
};
class SMA : public Indicator
{
private:
int nperiod;
double sum;
public:
SMA(double input[], int size, int period) : Indicator(input, size)
{
nperiod = period;
sum = 0;
Calculate();
}
void Calculate();
};
void SMA::Calculate()
{
for (int i=0; i<input_size; i++)
{
if (i > nperiod - 1)
{
sum += input_array[i] - input_array[i-nperiod];
value_vector.push_back(sum / nperiod);
}
else
{
sum += input_array[i];
value_vector.push_back(sum / (i+1));
}
std::cout << "sma: " << value_vector[i] << std::endl;
}
}
int main(int argc, const char *argv[]) {
double input[] = {1,2,3,4,5,6,7,8,9,10};
Indicator indicator = SMA(input,10,5);
for (int i=0; i<10; i++)
{
std::cout << "main: " << indicator[i] << std::endl;
}
std::cin.get();
exit(0);
}
That's because you're violating the Rule of Three. Since your class manages a resource, it needs a copy constructor and an assignment operator. I strongly suggest replacing any T* data member with a std::vector<T> data member. Then you don't need to write those special member functions manually.
Hia,
a few things are wrong.
As FredOverflow says you need a copy constructor and assignment, something like:
Indicator::Indicator(const Indicator& other)
{
input_size = other.input_size;
//direct copy of reference as indicator doesn't own this data
//Note a shared pointer (such as boost::shared_ptr) would be better than a naked reference
input_array = other.input_array;
//construct a new set of data
value_array = new double[input_size];
//do you want to copy the data too? maybe a memcpy follows?
memcpy(value_array, other.value_array, input_size*sizeof(double));
}
Then you need an assignment
Indicator&
Indicator::operator=(const Indicator& other)
{
//make sure you are not assigning itself
if(this != &other)
{
input_size = other.input_size;
//direct copy of reference as indicator doesn't own this data
//Note a shared pointer (such as boost::shared_ptr) would be better than a naked reference
input_array = other.input_array;
//destroy old data and construct a new set of data
delete[] value_array;
value_array = new double[input_size];
//do you want to copy the data too? maybe a memcpy follows?
memcpy(value_array, other.value_array, input_size*sizeof(double));
}
return *this;
}
You probably also want to make the destructor virtual - see here for why -
it helps prevent memory leaks in the destructor of SMA
virtual ~Indicator() { delete[] value_array; }
Use std::vector instead of raw arrays.
std::vector handles all the memory management and copying and so forth.
Cheers & hth.,