How to initialize string array in Classes? - c++

how to initialize this string array consisting for four elements. Like i know how to initialize but i don't know Where?? I mean where in the classes. Its giving me error in the constructor. Help needed.
class Water :public Element
{
public:
Water () { }
Water(string n): Element (n)
{
water = n;
i=-1;
//Error Message: expected an expression
Elements [4] = {"Steam", "Mud", "Sea", "Rain"};
}
string water;
int i;
bool elementexists;
string Elements [4];//how to initialize this and where?
};

You can initialize it in constructor initialization list:
Water(string n)
: Element(n)
, water(n)
, i(-1)
, Elements{"Steam", "Mud", "Sea", "Rain"} // <- Note the curly braces here.
{}
Raw (C style) arrays cannot be assigned directly using assignment operator (=). An std::array<string, 4> Elements could be assigned, but the syntax would be Elements = {"Steam", "Mud", "Sea", "Rain"}.

It is important to note that this line:
Elements [4] = {"Steam", "Mud", "Sea", "Rain"};
does not mean 'assign these strings to the 4-element long array, Elements'. Elements [4] refers to a specific item in that array. Given that Elements is only 4 items long, attempting to write to the fifth item would be bad. To refer to the array as a whole (as you would do for modifying the whole array at once), just use Elements.
Now, plain old C-style arrays don't support initialising in quite the way you're trying to do there.
I'd recommend using a std::array... they are somewhat easier to work with than C-style arrays as you are using. If you might have different numbers of elements, you should use std::vector instead.
class Water :public Element
{
public:
Water () { }
Water(std::string n): Element (n)
{
water = n;
i=-1;
elements = {{"Steam", "Mud", "Sea", "Rain"}};
}
std::string water;
int i;
bool elementexists;
std::array<std::string, 4> elements;
};
or alternatively,
Water(std::string n): Element(n), elements{{"Steam", "Mud", "Sea", "Rain"}}
{
water = n;
i=-1;
}
Note the double braces around the array initialisers; they're required for std::array by some older compilers. Newer ones may work just fine with a single set, {"Steam", "Mud", "Sea", "Rain"}.

Elements[0] = "Steam";
Elements[1] = "Mud";
Elements[2] = "Sea";
Elements[3] = "Rain";
should be the easiest way.

Related

Default value of a integer or character array in C++ [duplicate]

If I were to create an array with int* array = new int[10]; and fill part of the array with values, how can I check how much of the array is filled? I want to loop through and check if each value is the default value but I'm not sure what the default value of each array element is. Would it be null 0 or garbage values?
This is how to set a default value in C++ when making an array.
int array[100] = {0};
Now every element is set to 0. Without doing this every element it garbage and will be undefined behavior if used.
Not all languages are like this. Java has default values when declaring a data structure but C++ does not.
There is no default value so it's garbage.
You can't do what are you hoping to, not when the type is int.
The uninitialized elements of the array will have unpredictable values. In addition, accessing those elements is cause for undefined behavior.
You can initialize the elements of the array to a sentinel value at the time of allocation using:
int* ptr = new int[10]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
Use whatever sentinel value works for you if -1 does not.
The default value of array is indeterminate means garbage.
how can I check how much of the array is filled?
You cannot check, C/C++ has no array bounds check. You have to do it yourself.You need to keep track of the data inserted by a user. When your counter reaches the size of the array, the array is full
You can solve your problem by a more C++ way. You can create struct or class, which contain your value and bool flag. Bool flag must be set to false in default constructor and set to true in operator=. There is ready implementation of such class - boost.optional. std::optional will be in C++17.
#include <boost/optional.hpp>
#include <iostream>
int main()
{
const size_t nArr = 100;
auto pArr = new boost::optional<int>[nArr];
const size_t nInit = 30;
for (size_t i = 0; i < nInit; ++i)
{
pArr[i] = i; //initialize nInit first values of pArr
}
size_t n = 0;
for (; n < nArr; ++n)
{
if (!pArr[n].is_initialized()) break;
// or more compact form:
//if(!pArr[n]) break;
assert(*pArr[n] == n);
}
std::cout << "nInit = " << nInit << ", n = " << n << std::endl;
assert(nInit == n);
delete[] pArr;
}
It should be pointed out the default is uninitialized only for basic types like int. classes will use their defined parameterless constructor. Here is a MWE that wraps an int in such a class. OP also asked about checking the values so that is here too:
#include <iostream>
struct Element {
int Value;
Element() : Value{42} {}
};
struct Array {
Element Values[10];
};
int main() {
Array array;
for(Element element: array.Values)
std::cout << element.Value << " ";
}
Note: POD (or record) classes, which have no custom constructor, will remain uninitialised. Non-POD classes that have no parameterless constructor cannot usually be held in arrays.
I don't know if this helps but in c++17 onwards there's the std::array class that can be used. In this class you have the option to use class functions such as std::array.fill(...)
std::array<int, 10> arr;
arr.fill(-1);
cpp docs: cpp-docs
This get's you closer to the experience from other languages such as Java and Python both having Arrays.fill(arr, -1); and arr = [-1]*N respectively to fill the array with non-default values.
By default, the objects allocated by new are default initialized. This mean when you wrote:
int* array = new int[10]; //block of 10 uninitialized ints
Here, all of the 10 ints are uninitialized. That is, they have indeterminate value.
It is possible to value initialize the elements by adding an empty pair of parenthesis as shown below:
int* array = new int[10](); //block of 10 ints value initialized to 0
Here all of the 10 ints are initialized to 0.
But note that although we can use empty parentheses to value initialize the elements of an array, we cannot supply an element initializer inside the parentheses. This means for example,
int* array = new int[10](55); // INVALID
The above statement is invalid because we cannot supply an element initializer inside the parenthesize.
You can use std::fill_n instead of supplying an element initializer inside the parentheses as shown below:
int* array = new int[10]; //block of 10 uninitialized ints
std::fill_n(array, 10, 55); // all elements will now hold 55

How to get the length of a class array in C++, without hardcoding?

I have a class array in C++. I have defined it as such:
Student* pliststudent = new Student[2]{ 3,5 };
I know that the class array decays into a pointer when we assign it to Student* pliststudent.
It becomes difficult to extract the length of the class array, without hardcoding it.
I implemented the code, such that it is not hardcoded (using friend function). But I think, a better solution must exist.
Following is my full code:
class Student
{
private:
int marks;
int counter=0;
public:
Student(int marks) : marks(marks)
{}
int FinalMarks()
{
marks *=2;
return marks;
}
friend int Length(Student ob1, Student ob2);
};
int Length(Student ob1, Student ob2)
{
int i = ++ob1.counter + ++ob2.counter;
return i;
}
int main()
{
Student* pliststudent = new Student[2]{ 3,5 };
//int length = sizeof(*pliststudent) / sizeof(pliststudent[0]); //This does not work.
int length = Length(pliststudent[0], pliststudent[1]);
for (int i = 0; i < length; i++)
{
cout << (pliststudent+i)->FinalMarks() << endl;
}
return 0;
}
Is there a better solution to this? I don't want to hardcode the size of the Student class array.
You cannot get the length of an array from a pointer to the array's first element. That information is lost when the array decays to a pointer.
You need to keep the length information somewhere, either yourself:
int length = 2;
Student* pliststudent = new Student[length]{ 3,5 };
or by using a container that tracks the length for you:
std::vector<Student> students{3, 5};
// students.size() returns the number of Student objects in the vector
Live Demo
If you must use a dynamic array, there is no way to automatically determine the size of the array. That information is "lost" when storing the array in a pointer as you have done.
There are several ways to work around this, the preferred one is the one already suggested in the comments, use std::vector<Student> instead. Vector is the standard library's dynamic array and is almost always what you want. And since it takes care of the memory management automatically, it is much simpler to work with.
However, if you must use dynamic arrays, (because this is a school assignment and you are not allowed to use std::vector), then you should store the size of the array in a separate variable, and pass that together with whatever you need to do.
const int nStudents = 2;
Student* pliststudents = new Student[nStudents]{3, 5};

what is the default value of an array in C++?

If I were to create an array with int* array = new int[10]; and fill part of the array with values, how can I check how much of the array is filled? I want to loop through and check if each value is the default value but I'm not sure what the default value of each array element is. Would it be null 0 or garbage values?
This is how to set a default value in C++ when making an array.
int array[100] = {0};
Now every element is set to 0. Without doing this every element it garbage and will be undefined behavior if used.
Not all languages are like this. Java has default values when declaring a data structure but C++ does not.
There is no default value so it's garbage.
You can't do what are you hoping to, not when the type is int.
The uninitialized elements of the array will have unpredictable values. In addition, accessing those elements is cause for undefined behavior.
You can initialize the elements of the array to a sentinel value at the time of allocation using:
int* ptr = new int[10]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
Use whatever sentinel value works for you if -1 does not.
The default value of array is indeterminate means garbage.
how can I check how much of the array is filled?
You cannot check, C/C++ has no array bounds check. You have to do it yourself.You need to keep track of the data inserted by a user. When your counter reaches the size of the array, the array is full
You can solve your problem by a more C++ way. You can create struct or class, which contain your value and bool flag. Bool flag must be set to false in default constructor and set to true in operator=. There is ready implementation of such class - boost.optional. std::optional will be in C++17.
#include <boost/optional.hpp>
#include <iostream>
int main()
{
const size_t nArr = 100;
auto pArr = new boost::optional<int>[nArr];
const size_t nInit = 30;
for (size_t i = 0; i < nInit; ++i)
{
pArr[i] = i; //initialize nInit first values of pArr
}
size_t n = 0;
for (; n < nArr; ++n)
{
if (!pArr[n].is_initialized()) break;
// or more compact form:
//if(!pArr[n]) break;
assert(*pArr[n] == n);
}
std::cout << "nInit = " << nInit << ", n = " << n << std::endl;
assert(nInit == n);
delete[] pArr;
}
It should be pointed out the default is uninitialized only for basic types like int. classes will use their defined parameterless constructor. Here is a MWE that wraps an int in such a class. OP also asked about checking the values so that is here too:
#include <iostream>
struct Element {
int Value;
Element() : Value{42} {}
};
struct Array {
Element Values[10];
};
int main() {
Array array;
for(Element element: array.Values)
std::cout << element.Value << " ";
}
Note: POD (or record) classes, which have no custom constructor, will remain uninitialised. Non-POD classes that have no parameterless constructor cannot usually be held in arrays.
I don't know if this helps but in c++17 onwards there's the std::array class that can be used. In this class you have the option to use class functions such as std::array.fill(...)
std::array<int, 10> arr;
arr.fill(-1);
cpp docs: cpp-docs
This get's you closer to the experience from other languages such as Java and Python both having Arrays.fill(arr, -1); and arr = [-1]*N respectively to fill the array with non-default values.
By default, the objects allocated by new are default initialized. This mean when you wrote:
int* array = new int[10]; //block of 10 uninitialized ints
Here, all of the 10 ints are uninitialized. That is, they have indeterminate value.
It is possible to value initialize the elements by adding an empty pair of parenthesis as shown below:
int* array = new int[10](); //block of 10 ints value initialized to 0
Here all of the 10 ints are initialized to 0.
But note that although we can use empty parentheses to value initialize the elements of an array, we cannot supply an element initializer inside the parentheses. This means for example,
int* array = new int[10](55); // INVALID
The above statement is invalid because we cannot supply an element initializer inside the parenthesize.
You can use std::fill_n instead of supplying an element initializer inside the parentheses as shown below:
int* array = new int[10]; //block of 10 uninitialized ints
std::fill_n(array, 10, 55); // all elements will now hold 55

How to have a 2-dimensional array as a private variable in a class, and then set it in the constructor

In my platformer game which I'm writing in Visual C++, each level will initially be stored as a 2-dimensional array of ints. I decided it would make more sense to store this array in a class, so I created a class called Level. It looks like this:
class Level {
private:
int map[20][30];
public:
Level(int a[20][30]) {
map = a;
}
int getcell(int row, int column) {
return map[row][column];
}
};
As far as I can see - from looking up tutorials on class constructors, and passing 2-dimensional arrays as parameters, this should work, so I really don't understand why it doesn't.
On the line where I do map = a, I get an error: Error: expression must be a modifiable lvalue. I've looked this error up on stackoverflow, but I can't find any answers which relate to my problem.
So, how can I fix this error?
This doesn't really have anything to do with a constructor. You cannot assign arrays in C++. Whether in the constructor, or anywhere else.
There are two ways to work around it. The first way is the brute force way. Instead of
map = a;
write a loop to copy the contents of the array from the constructor's parameter into the class member array.
The second way is to stuff the array into an intermediate class:
class Level {
public:
struct level_map {
int map[20][30];
};
private:
level_map map;
public:
Level(const level_map &initial_map) : map(initial_map)
{
}
int getcell(int row, int column) {
return level_map.map[row][column];
}
};
This may or may not be practical, and introduces a little bit more complexity.
But the real answer here is to use std::vectors instead of plain arrays, which will solve all of these problems.
Others have already mentioned the real reason: you cannot assign an array to another using = operator. My two cents about your class:
map is not a good name, it may get conflict with std::map if using namespace std; or using std::map was specified somewhere.
The constant array sizes make this class non-reusable. Class should be flexible to allow any N*M sized 2D array. For this, better to use vector<vector<int>>.
getcell should be a const method, and it should do error checking with row and column numbers passed.
If you want this class to have static-sized array sizes and compile time, you may use class templates with row and column sizes as non type template arguments.
template<size_t row, size_t column>
class Level
{
int _map[row][column];
public:
Level(int src[row][column])
{
memcpy(_map, src, sizeof(_map)); // why not simply 'memcpy' ?
}
};
int main()
{
int source[10][2] = { {1, 2}, {3,4} };
Level<10, 2> ten_by_2(source);
}
Here the map is a constant value, which could not been assigned as an lvalue. This could be fixed by iterating the element of the array, and assign a[i][j] to map[i][j].
class Level {
private:
int map[20][30];
public:
Level(int a[20][30]) {
for(int i = 0; i < 20; ++i)
for(int j = 0; j < 30; ++j)
map[i][j] = a[i][j];
}
int getcell(int row, int column) {
return map[row][column];
}
};

Choose at runtime array or vector in C++

I have a problem described as below ::
class datad {
private:
int *a;
int _size;
vector<int> v;
public:
datad(int arr[], int size) {
_size = size;
for (int i = 0; i < size; i++)
a[i] = arr[i];
}
datad(vector<int> ve)
{
v = ve;
_size = ve.size();
}
void printdata()
{
// print data which the object has been initialized with
// if object is initialized with vector then print vector
// array print array
}
};
int main()
{
// print only vector data
int a[] = { 9,4,8,3,1,6,5 };
datad d(v1);
d.printdata();
// print only array data
datad d1(a, 7);
d1.printdata();
}
I need to find the way the object is initialized and then based on the same should be able to printdata accrodingly.
Can someone help me understand if it is possible at all?
Add a bool usesVector to your class and set it to true or false in each constructor as appropriate. Then, in printdata, simply check the value of the boolean.
Or you can set size to -1 in the vector case (as it's otherwise unused) and just check for that.
By the way, your array implementation is broken, because you never allocate any memory for it. You'd be much better off using only the vector version. You can still initialise that vector from array data if you wish.
You can set a flag in respective constructor and check that flag during the printing method.
I hope this is for learning purposes, otherwise as noted you maybe better of using just the vector version. When using dynamic memory management in class you need to be aware of things like rule of three and I guess there is also rule of five.