C++ : Creating an array of objects - c++

I have the following class:
class student
{
int rol , marks;
char name[20];
public:
student(int r , int m , char n[])
{
rol = r;
marks = m;
strcpy(name,n);
}
int roll()
{
return rol;
}
};
and now I am trying to create an array of objects like so:
student a[]= {(1,10,"AAA"),(2,20,"BBB"),(3,30,"CCC")}; // I get the error on this line
but I get this error message:
Error: testing.cpp(40,56):Cannot convert 'char *' to 'student[]'
When I do this :
student a(1,10,"AAAA");
student b(2,20,"BBBB");
student c(3,30,"CCCC");
student d[3]={a,b,c};
it works perfectly.
#WhozCraig Thx a lot . this is the solution to my problem:
I had to initialize the array as below:
student a[]= {
student(1, 10, "AAA"),
student(2, 20, "BBB"),
student(3, 30, "CCC")
};
My initial code is wrong probably because the constructor cant create more than 1 object at a time.

In an expression (1,10,"AAA") means to apply the comma operator. To initialize an array, you have to provide expressions that can initialize each array member. So one way is:
student a[] = {
student(1, 10, "AAA"), // creates a temporary student to use as initializer
student(2, 20, "BBB"),
student(3, 30, "CCC") };
Since C++11 you can write:
student a[] = { {1, 10, "AAA"}, {2, 20, "BBB"}, {3, 30, "CCC"} };
because C++11 added the feature that an object's constructor can be called via a brace-enclosed initializer list. This is the same reason you could also write afterwards:
a[0] = { 4, 40, "DDD" };
Note: as mentioned in comments, char n[] should be char const n[], and you could improve safety by using std::string name; instead of char name[20];.

Related

Initialization of list of sets of integers in C++98

this might seem trivial but I wasn't able to find it on the web so far, so
I want to initialize a list of sets of integers or a set of sets of integers, like this:
list< set<int> > lsi = {{}};
or maybe like this:
set< set<int> > ssi = {{5}, {6}, {7}};
in C++98. The reason for this is that I have to submit it as an exercise in a submission system that does not accept C++11.
I have found out how to initialize a container in the old syntax from an array of integers, for example
int tmp[] = {1,2,3};
set<int> s (tmp, tmp + sizeof(tmp) / sizeof(tmp));
but not a list< set<int> >.
As mentioned in the comments, this is not possible without c+11 / boost.
That being said, the shortest way to initialize would probably be repeating set's initialization (which you mentioned in your question):
int set1v[] = {10, 20, 30, 40};
int set2v[] = {11, 22, 33, 44};
int set3v[] = {15, 25, 35, 45};
set<int> setV[] = {
set<int>(set1v, set1v + sizeof(set1v) / sizeof(set1v[0])),
set<int>(set2v, set2v + sizeof(set2v) / sizeof(set2v[0])),
set<int>(set3v, set3v + sizeof(set3v) / sizeof(set3v[0]))
};
set< set<int> > mySet(setV, setV + sizeof(setV) / sizeof(setV[0]));
Btw, Since you're checking arrays' sizes so many times I'd suggest you use a count macro:
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
It will look a little better:
#define END_OF(x) (x + COUNT_OF(x))
int set1v[] = {10, 20, 30, 40};
int set2v[] = {11, 22, 33, 44};
int set3v[] = {15, 25, 35, 45};
set<int> setV[] = {
set<int>(set1v, END_OF(set1v)),
set<int>(set2v, END_OF(set2v)),
set<int>(set3v, END_OF(set3v))
};
set< set<int> > mySet(setV, END_OF(setV));
I will give you some approach I have used to initialize static STL storages, but the syntax becomes somewhat obscure for this case:
template <typename Type>
struct SetInit : public std::set<Type> {
SetInit<Type>& operator()(const Type& data) {
this->insert(data);
return *this;
}
};
int main () {
std::set<std::set<int> > test_set = SetInit<std::set<int> >() // Call ctor
(SetInit<int>()(1)(2)(3))(SetInit<int>()(4)(5)(6)); // Each element in () is inserted in the set
return 0;
}
The basic idea is to use an operator() to include elements in the storage. The advantage of this idea is that it can be used to initialize static lists and sets because the expressions can be evaluated at compile time.

cannot print struct contents stored in vector C++

Hello guys I have problem when I have an array of student record which is struct by type. I have randomly assigned numbers to each of student during that I am storing each record in the vector. After that I want to sort it by marks. The problem is that iterator doesn't print the contents of vector. I believe problem is at statementcout<<*RecVectorItr.Marks<<endl; but I cannot figure out why. Can you point out what's wrong. Thank you in advance. Here is code
include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Record
{
int RollNum;
char Name[20];
float Marks;
char Status[10];
};
bool compFunc (struct Record Rec1, struct Record Rec2)
{
return (Rec1.Marks<Rec2.Marks);
}
int main ()
{
struct Record Students[20];
float MarksArray[20]={30.4, 20.1, 11.9, 50.0, 55, 100, 11, 34, 90, 12, 13, 14, 19, 22.4, 88 , 56, 22, 78, 98, 29};
vector<Record> RecVector;
for (int i=1;i<21;i++)
{
Students[i].Marks=MarksArray[i];
RecVector.push_back (Students[i]);
}
sort (RecVector.begin (), RecVector.end (), compFunc);
for (vector<Record>::iterator RecVectorItr=RecVector.begin (); RecVectorItr!=RecVector.end ();RecVectorItr++)
cout<<*RecVectorItr.Marks<<endl;
return 0;
}
Your code is not working due to a problem of Operator Precedence:
When parsing an expression, an operator which is listed on some row
will be bound tighter (as if by parentheses) to its arguments than any
operator that is listed on a row further below it.
Table that list the precedence can be found here
Change your printing line with the following:
cout<<RecVectorItr->Marks<<endl;

Two dimensional array / initialize data in c++ (Arduino)

I think I lost my whole C++ knowledge...
What I want is to initialize a 2D unsigned char array in a proper (readable) way:
My approaches:
#define RADIO_ONOFF 0
#define RADIO_P1 1
#define RADIO_P2 2
...
#define NR_OF_CODES = 5
#define CODE_LENGTH = 10
#1:
unsigned char** codes = new unsigned char*[NR_OF_CODES];
codes[RADIO_ONOFF] = new unsigned char[CODE_LENGTH]{ 9,180,88,11,33,4,0,255,64,191 }; // does not work
...
#2:
unsigned char ICODES[NR_OF_CODES][CODE_LENGTH];
ICODES[RADIO_ONOFF] = { 9,180,88,11,33,4,0,255,64,191 }; // same as above
...
#3:
class Test {
private:
unsigned char data[CODE_LENGTH];
public:
Test(unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4, unsigned char a5, unsigned char a6, unsigned char a7, unsigned char a8, unsigned char a9, unsigned char a10);
unsigned char* getData(void);
};
Test::Test(unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4, unsigned char a5, unsigned char a6, unsigned char a7, unsigned char a8, unsigned char a9, unsigned char a10) {
this->data[0] = a1;
this->data[1] = a2;
this->data[2] = a3;
this->data[3] = a4;
this->data[4] = a5;
this->data[5] = a6;
this->data[6] = a7;
this->data[7] = a8;
this->data[8] = a9;
this->data[9] = a10;
}
unsigned char* Test::getData(void) {
return data;
}
void setup() {
test[RADIO_ONOFF] = new Test( 9,180,88,11,33,4,0,255,64,191 );
test[RADIO_P1] = new Test( 9,180,88,11,33,4,0,255,64,192 );
...
}
#4
const unsigned char RADIO_ONOFF[] = { 9,180,88,11,33,4,0,255,64,191 };
const unsigned char RADIO_P1[] = { 9,180,88,11,33,4,0,255,64,192 };
...
Error message I get for #1 and #2: (code should compile for Arduino and it needs a setup-function)
In function 'void setup()':
revTest:58: error: expected primary-expression before '{' token
revTest:58: error: expected `;' before '{' token
OK - my questions:
To me - #3 and #4 are nice and readable. Effort for #3 is the highest - but I think it´s the
fastest way if I want do uses the array in a switch statement. - True?
I thought array initialization in #1 and #2 should work this way????
Very Arduino specific:
I am not sure what has to be defined inside of setup() and what should go outside of setup(). static initialization and global outside, dynamic inside or what?
I have red about PROGMEM for Arduino - I think it´s not worth the effort in this case. I am right? (I think I`ll have about 50 different codes...)
thx!
Before answering your questions, let's look at what's going wrong with solutions 1 and 2.
The problem with solutions 1 and 2 is that you're using an initialiser ( i.e. the `{} syntax ), where your compiler is expecting an assignment expression.
Initialisation syntax can only be used at the point where the variable is declared. Roughly speaking, initialisation should be understood as giving a value to a variable as soon as it is constructed. Assignment should be understood as giving a value to a variable that has already been constructed somewhere else.
So when you do:
unsigned char** codes = new unsigned char*[NR_OF_CODES];
You are doing initialisation. You are initialising the variable codes to a freshly allocated array of pointers to unsigned char.
On the next line, you are then telling the compiler you are doing an assignment. You're using the = sign and assigning to codes, which was declared on the previous line - compiler sees this as assignment.
codes[RADIO_ONOFF] = new unsigned char[CODE_LENGTH] ...
But then, immediately afterwards, you attempt to use initialisation syntax.
Your compiler is complaining because it's read this:
codes[RADIO_ONOFF] = new unsigned char[CODE_LENGTH] ...
as a complete expression. It read that as you're allocating an array of CODE_LENGTH bytes and assigning it to the RADIO_ONOFF th member of codes.
And it expected you to stop there, with a semi colon but you continued and added the initalisation syntax {}. It doesn't understand, because you are mixing assignment and initialisation together - which are two separate things. That's why you're getting the "I expect a semi colon" type error from the compiler.
To answer your questions, both solution 3 and 4 are taking the long way round. There are quicker ways of initialising a 2D array in C++. I also agree with previous answer about using uint8_t.
Would something like this be more suitable?
uint8_t codes[CODE_LENGTH][NR_OF_CODES] =
{{0, 1, 2, 3, 4, 5, 6, 7},
{0, 1, 2, 3, 4, 5, 6, 7},
{0, 1, 2, 3, 4, 5, 6, 7},
{0, 1, 2, 3, 4, 5, 6, 7} };
A good way to read array syntax is to take the final (rightmost) value in the square brackets [] as the size of some array, and then work backwards.
So uint8_t codes[CODE_LENGTH][NR_OF_CODES] will decode out to an array of size NR_OF_CODES of something. And to get that something go left, and we see uint8_t codes[CODE_LENGTH] - so it's an array of length NR_OF_CODES of arrays of uint8_t, each of length CODE_LENGTH.
I hope that helps.
NB. In answer to your comment about needing to index the array with named indices - there's nothing stopping you from referring to the individual members of codes via an index.
What you can do is initialise the whole thing via {0} - shorthand for initialising all members to 0.
And you can assign members of the RADIO_ONOFF array (or any array for that matter) individually e.g.
codes[RADIO_ONOFF][3] = 255;
Try this example - and note the output:
#include <iostream>
const int NR_OF_CODES = 4;
const int RADIO_ONOFF = 0;
const int CODE_LENGTH = 11;
const unsigned char RADIO_ONOFF_ARR[] = { 180,99,33,11,22,33,55, 22,22,33, 10};
int main()
{
unsigned char codes[CODE_LENGTH][NR_OF_CODES] = {
{0},
};
std::cout << "Before:\n";
for(int x = 0; x < CODE_LENGTH; x++)
{
std::cout << static_cast<int>(codes[RADIO_ONOFF][x]) << ", ";
}
codes[RADIO_ONOFF][3] = 3;
std::cout << "\nAfter:\n";
for(int x = 0; x < CODE_LENGTH; x++)
{
std::cout << static_cast<int>(codes[RADIO_ONOFF][x]) << ", ";
}
// or try memcpy
memcpy(codes[RADIO_ONOFF], RADIO_ONOFF_ARR, sizeof RADIO_ONOFF_ARR);
std::cout << "\nAfter Memcpy:\n";
for(int x = 0; x < CODE_LENGTH; x++)
{
std::cout << static_cast<int>(codes[RADIO_ONOFF][x]) << ", ";
}
char c;
std::cin >> c;
return 0;
}
First off all, since this is tagged C++, I'm going to say that there is no need to do #define. You now have access to static const variables that do the same, but are type safe.
Here's what the Google C++ style guide has to say about braced lists:
http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Braced_Initializer_Lists
I generally follow this guide when I'm not working on a project with an already setup style. Also, I should mention that style is really subjective, so you may end up getting a wide range of answers.
Also, don't use char, where you just want to store byte data. That's what uint8_t is for.
Also, see this SO thread for all your options of how to initialize your arrays: How to initialize all members of an array to the same value? In most of your cases since they are just holding non-changing constants, you can get away with making them static const.
Like this:
static const size_t kMyCodeArraySize = 14; // an example
static const uint8_t[kMyCodeArraySize] = {1, 2, 3, 4}; // example intialization

C++ Class, Assigning values during Constructor initialization

I have a 2D array which I declared part of the classes private members. When I call the constructor, I start assigning values to the 2D array. But every time I do so, I'm hit with an error C2059. To make sure nothing else was causing that error I commented out that line and the compiler finished putting together a binary file.
tried:
Variable[row] = { 0, 1, 2, 3};
Variable[row][] = { 0, 1, 2, 3};
Variable[row][4] = { 0, 1, 2, 3};
No luck, any clues. Thanks in advance.
This syntax is only to be used for the creation of the object.
int array[4] = {1, 2, 3, 4};
Once the array is created, you have to use a loop to assign values to it.
Here's a short example :
class A
{
int array[4];
public:
A()
{
// Here, array is already created
// You can _assign_ values to it
}
};
If you want to give it values when it's instantiated in the constructor, the only way is to use initialization lists. Unfortunatly, you can't do this with a static array.
See this this thread.
Unfortunately, we can't yet properly initialize arrays that are members of classes. I don't know exactly how yours is declared, but here's an example of what to do:
class X
{
int Variable[3][4];
public:
X()
{
const int temp[][4] = { { 1, 2, 3, 4}, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
const int sz = sizeof(Variable)/sizeof(**Variable);
std::copy(*temp, (*temp) + sz, *Variable);
}
};
Since your question is not clear enough, all I can do is demonstrating a simple example.
2D array is initialized as,
//you may "optionally" provide the size of first dimension
int arr[][4] = {
{1,2,3,4},
{11,12,13,14},
{21,22,23,24}
};
And is acessed as,
for ( int i = 0 ; i < 3 ; ++i )
{
for ( int j = 0 ; j < 4 ; ++j )
{
cout << arr[i][j] << endl;
}
}
Online demonstration at ideone : http://www.ideone.com/KmwOg
Are you doing similarly?

What is the easiest way to set the value of an entire array?

My current project requires me to fill an array based upon some other values. I know there's the shortcut:
int arr[4][4] = { {0,0,0,0} , {0,0,0,0} , {0,0,0,0} , {0,0,0,0} };
But in this case, I need to fill the array after its declaration. I currently have my code formatted like this:
int arr[4][4];
if(someothervariable == 1){
arr = { {1,1,1,1},
{1,2,3,4},
{2,,3,4,5},
{3,4,5,6} };
}
But it won't compile. Is there a way to make use of the mentioned shortcut in my case? If not, whats the best fix available? I'd appreciate a way to set it without explicitly assigning each element? ie: arr[0][0] = ...
How about using std::copy() ?
int arr[4][4];
if(someothervariable == 1){
const static int a2[4][4] = { {1,1,1,1},
{1,2,3,4},
{2,3,4,5},
{3,4,5,6} };
std::copy(&a2[0][0], &a2[0][0]+16, &arr[0][0]);
}
No, array initialization syntax is for array initialization. Although, you can use memset if all the values are the same byte.
The boost.assign library adds some interesting syntax for modifying/filling collections, but AFAIK it doesn't support C style arrays (only C++ and Boost containers).
In the current version of C++ language the only way to do it is to copy it from some original
int arr[4][4];
if (someothervariable == 1)
{
const int SOURCE[4][4] = // make it `static` if you prefer
{
{1, 1, 1, 1},
{1, 2, 3, 4},
{2, 3, 4, 5},
{3, 4, 5, 6}
};
assert(sizeof arr == sizeof SOURCE); // static assert is more appropriate
memcpy(&arr, &SOURCE, sizeof arr);
}
The source "constant" can be declared as static in order to avoid re-initialization, if the compiler is not smart enough to optimize it by itself.
In the future version of the language a feature similar to C's compound literals is planned, which will provide support for immediate initialization (basically what you tried to do in your original post).
If you wish to fill the array with a single value:
#include<algorithm>
#include<vector>
// ...
std::vector<int> arr;
std::fill(arr.begin(), arr.end(), VALUE); // VALUE is an integer
If you wish to calculate the value for each element:
struct get_value {
int operator()() const { /* calculate and return value ... */ }
};
std::generate(arr.begin(), arr.end(), get_value());
If you are setting everything to the same value (such as zero), you may be able to get away with ...
memset (arr, 0, sizeof (arr));
Note that this is fraught with perils. You have to know your type sizes and all that jazz.
However, it appears that that will not suffice for you. If you want to fill the array with different values, I can only only think of two ways of doing this.
Method #1. (Can be a pain the butt)
arr[0][0] = 1;
...
arr[0][3] = 1;
arr[1][0] = 1;
...
arr[1][3] = 4;
arr[2][0] = 2;
...
arr[2][3] = 5;
arr[3][0] = 3;
...
arr[3][3] = 6;
Method #2.
Predefine a set of arrays and switch between them using a pointer;
int arr1[4][4] = {
{0,0,0,0},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0} };
int arr2[4][4] = {
{1,1,1,1},
{1,2,3,4},
{2,,3,4,5},
{3,4,5,6} };
int *arr[4];
Now you only have the four (4) values of *arr[] to set instead of setting everything. Of course, this really only works if your arrays will be filled with predetermined constants.
Hope this helps.
I'm not sure if I like this solution or not, but C/C++ will give you assignment convenience if you wrap the array inside a struct with the minor cost of then having to use the struct name to get at the array:
typedef struct {
int data[4][4];
} info_t;
info_t arr;
if (someothervariable == 1){
static const info_t newdata = {{ // since this is static const, there generally
// won't be a copy - that data will be 'baked'
// into the binary image (or at worst a
// single copy will occur)
{1,1,1,1},
{1,2,3,4},
{2,3,4,5},
{3,4,5,6}
}};
arr = newdata; // easy to assign new data to the array
}
int somethingelse = arr.data[1][2]; // a tiny bit less convenient to get
// to the array data
int arr[4][4];
if (someothervariable == 1) {
int tmp[4][4] = { {1, 1, 1, 1}, {1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6} };
arr = tmp;
}