structure array won't initialize - c++

I'm trying to initialize the members of candy like this.
#include <iostream>
#include <string>
struct CandyBar
{
std::string Brand;
float weight;
int cal;
};
int main()
{
CandyBar candy[3];
candy[0] = {"toe foe", 30.2f, 500};
candy[1] = {"lays", 2.1f, 10};
candy[2] = {"fin", 40.5f, 1000};
return 0;
}
But it gives me a syntax error near the opening brace
i know this is wrong but is there a way like this to initialize a array of struct.
And can someone explain why is the above code wrong.

You're not initializing the array, you're making assignments to its elements. If you do use an initializer, it will work fine:
CandyBar candy[3] = {
{"toe foe", 30.2f, 500},
{"lays", 2.1f, 10},
{"fin", 40.5f, 1000}
};

CandyBar candy[3] = {
{"toe foe", 30.2f, 500},
{"lays", 2.1f, 10},
{"fin", 40.5f, 1000}};
You can do this.
This style can only be used in the initialization stage, i.e when you create the variable. It cannot be used to assign the value later. (pre C++11)

Related

Return a pointer to 2D array from a function - C++

So what I am trying to achieve is to return a pointer to a 2D array from the function so it could accessed in main(). I know there are some C++ libraries that does it for you like std::vector but I am trying to avoid dynamic memory allocation since I am working on embedded board (STM32) so I will stick to just normal pointers and arrays. (ALSO for some reason I can't use std::array in KEIL uVision, which is also why I am forced to work with pointers/arrays)
In addition, I understand that returning a pointer to a local array int arr[2][2] defined inside the function is not a good idea since it will no longer be valid after the function returns, which is why I creating test_array, declaring it inside a class and defining it in a function (acting as a global variable) so I assume this shouldn't be a problem. What do you guys think? However, doing it this way gives an error "Excess elements in scalar initializer"
#include <iostream>
#include "file.hpp"
int main() {
myClass class_object;
class_object.value = class_object.foo();
}
//file.hpp
#include <stdio.h>
class myClass{
int array[2][2];
int (*foo())[2];
int (*value)[2];
int test_array[2][2]; //declaring here!
};
//file.cpp
#include "file.hpp"
int (*myClass::foo())[2]{
test_array[2][2]={ {10,20}, {30, 40} }; //defining here - ERROR!!
int arr[2][2]= {
{1, 10},
{20, 30}
};
return arr;
}
The immediate problem:
test_array[2][2]={ {10,20}, {30, 40} }; //defining here - ERROR!!
is not defining. test_array was defined up in myClass. This is attempting to assign to a single element of test_array, specifically [2][2] which does not exist. What particularly offends the compiler is not the out of bounds access, but that ={ {10,20}, {30, 40} }; is trying to stuff an array into a single array element. The compiler is expecting a single number, so four numbers is definitely in excess.
Unfortunately I don't know of a good way to do what you want to do. You can initialize an array with an initializer list, but you can't assign from one.
So
class myClass{
public:
myClass();
void foo();
int test_array[2][2]; //declaring here!
};
// you can do this:
myClass::myClass(): test_array{ {10,20}, {30, 40} }
{
}
void myClass::foo()
{
// but you can't do this:
test_array = { {10,20}, {30, 40} };
}
Depending on what you do with test_array, initializing in the constructor may work for you. If you have to reset the array on every call to foo, perhaps an Automatic variable is a better fit for you
void myClass::foo()
{
int temp_array[2][2] = { {10,20}, {30, 40} };
// use temp_array
// maybe copy temp_array to test_array with good ol' memcpy here if you
// need to carry the state for some reason.
}
To silence the elephant in the room and gain access to std::array, give this a try. Note: I've never done this. It could be an utter freaking disaster for all I know, so take it with a grain of salt.
If you really want to work with C-Array, use typedef to have normal syntax:
class myClass{
public:
using array2 = int[2][2];
myClass() {
test_array[0][0] = 0;
test_array[0][1] = 1;
test_array[1][0] = 2;
test_array[1][1] = 3;
}
const array2& getArray() const { return test_array; }
array2& getArray() { return test_array; }
private:
array2 test_array;
};

Why does array size initialization differ inside or outside a class/struct/...?

The first example will automagically know it's size by the elements it is initialized with.
The second example requires you to explicitly define the length of the array (to get it working).
Why is this the case? Is there a reason behind this?
Array initialization outside a class/struct/...
const int intArray[] = { 0, 1, 2 };
struct Example
{
int SizeOfArray()
{
return sizeof(intArray);
}
};
Array initialization inside a class/struct/...
Faulting
struct Example
{
const int intArray[] = { 0, 1, 2 };
int SizeOfArray()
{
return sizeof(intArray);
}
};
Error: cannot specify explicit initializer for arrays
Solution
struct Example
{
const int intArray[3] = { 0, 1, 2 };
int SizeOfArray()
{
return sizeof(intArray);
}
};
I think it's because in-class/struct initialization is just syntactic sugar for writing part of initializer list in a different place. According to this, your faulting example is equal to the following:
struct Example
{
const int intArray[];
Example() :
// start of compiler-generated pseudo code
intArray[0](0),
intArray[1](1),
intArray[2](2)
// end of compiler-generated pseudo code
{
}
int SizeOfArray()
{
return sizeof(intArray);
}
};
The code above obviously defines an incomplete structure of unknown size, just as #harper said in his comment.
P.S. Couldn't find proof in the standard, but I'm pretty sure that it covers this case, probably implicitly.

Using a list inside a struct c++

I´m starting with the programming and i speak bad english sorry for that.
I like to use a list instead of an array, inside of a struct, something like this:
#include <iostream>
#include <list>
using namespace std;
struct Market {
string b;
list <int> prices;
};
int main()
{ list <int> precios;
Market m1 = {"a",NULL};
return 0;
}
but i get this error conversion from int' to non-scalar type std::list<int, std::allocator<int> > requested|
Is this possible? maybe with malloc or free?
You should define a constructor
struct Market {
Market(string val){b=val;}
// or like this:
// Market(string val):b(val){}
string b;
list <int> prices;
};
Then you will be able to create objects like:
Market a("A");
As lists default constructor creates empty list, you dont need to pass it any parametrs.
A good read about basics of classes: http://www.cplusplus.com/doc/tutorial/classes/
NULL is not of the type std::list<int>, that's why you are getting this error.
Are you using a C++11 compiler?
If yes then try:
Market m1 = {"a", { NULL } };
Otherwise:
list<int> prices;
Market m1;
m1.b = "a";
m1.prices = prices;
You are attemping to initialize the list with a null pointer value (actually an int type). If you need to store the list by value you can initialize 'm1' like so
Market m1 = {"a", std::list<int>()};

Vector of structs initialization

I want know how I can add values to my vector of structs using the push_back method
struct subject
{
string name;
int marks;
int credits;
};
vector<subject> sub;
So now how can I add elements to it?
I have function that initializes string name(subject name to it)
void setName(string s1, string s2, ...... string s6)
{
// how can i set name too sub[0].name= "english", sub[1].name = "math" etc
sub[0].name = s1 // gives segmentation fault; so how do I use push_back method?
sub.name.push_back(s1);
sub.name.push_back(s2);
sub.name.push_back(s3);
sub.name.push_back(s4);
sub.name.push_back(s6);
}
Function call
setName("english", "math", "physics" ... "economics");
Create vector, push_back element, then modify it as so:
struct subject {
string name;
int marks;
int credits;
};
int main() {
vector<subject> sub;
//Push back new subject created with default constructor.
sub.push_back(subject());
//Vector now has 1 element # index 0, so modify it.
sub[0].name = "english";
//Add a new element if you want another:
sub.push_back(subject());
//Modify its name and marks.
sub[1].name = "math";
sub[1].marks = 90;
}
You cant access a vector with [#] until an element exists in the vector at that index. This example populates the [#] and then modifies it afterward.
If you want to use the new current standard, you can do so:
sub.emplace_back ("Math", 70, 0); // requires a fitting constructor, though
or
sub.push_back ({"Math", 70, 0}); // works without constructor
.
You may also which to use aggregate initialization from a braced initialization list for situations like these.
#include <vector>
using namespace std;
struct subject {
string name;
int marks;
int credits;
};
int main() {
vector<subject> sub {
{"english", 10, 0},
{"math" , 20, 5}
};
}
Sometimes however, the members of a struct may not be so simple, so you must give the compiler a hand in deducing its types.
So extending on the above.
#include <vector>
using namespace std;
struct assessment {
int points;
int total;
float percentage;
};
struct subject {
string name;
int marks;
int credits;
vector<assessment> assessments;
};
int main() {
vector<subject> sub {
{"english", 10, 0, {
assessment{1,3,0.33f},
assessment{2,3,0.66f},
assessment{3,3,1.00f}
}},
{"math" , 20, 5, {
assessment{2,4,0.50f}
}}
};
}
Without the assessment in the braced initializer the compiler will fail when attempting to deduce the type.
The above has been compiled and tested with gcc in c++17. It should however work from c++11 and onward. In c++20 we may see the designator syntax, my hope is that it will allow for for the following
{"english", 10, 0, .assessments{
{1,3,0.33f},
{2,3,0.66f},
{3,3,1.00f}
}},
source: http://en.cppreference.com/w/cpp/language/aggregate_initialization
You cannot access elements of an empty vector by subscript.
Always check that the vector is not empty & the index is valid while using the [] operator on std::vector.
[] does not add elements if none exists, but it causes an Undefined Behavior if the index is invalid.
You should create a temporary object of your structure, fill it up and then add it to the vector, using vector::push_back()
subject subObj;
subObj.name = s1;
sub.push_back(subObj);
After looking on the accepted answer I realized that if know size of required vector then we have to use a loop to initialize every element
But I found new to do this using default_structure_element like following...
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
typedef struct subject {
string name;
int marks;
int credits;
}subject;
int main(){
subject default_subject;
default_subject.name="NONE";
default_subject.marks = 0;
default_subject.credits = 0;
vector <subject> sub(10,default_subject); // default_subject to initialize
//to check is it initialised
for(ll i=0;i<sub.size();i++) {
cout << sub[i].name << " " << sub[i].marks << " " << sub[i].credits << endl;
}
}
Then I think its good to way to initialize a vector of the struct, isn't it?

Initialisation of static vector

I wonder if there is the "nicer" way of initialising a static vector than below?
class Foo
{
static std::vector<int> MyVector;
Foo()
{
if (MyVector.empty())
{
MyVector.push_back(4);
MyVector.push_back(17);
MyVector.push_back(20);
}
}
}
It's an example code :)
The values in push_back() are declared independly; not in array or something.
Edit: if it isn't possible, tell me that also :)
In C++03, the easiest way was to use a factory function:
std::vector<int> MakeVector()
{
std::vector v;
v.push_back(4);
v.push_back(17);
v.push_back(20);
return v;
}
std::vector Foo::MyVector = MakeVector(); // can be const if you like
"Return value optimisation" should mean that the array is filled in place, and not copied, if that is a concern. Alternatively, you could initialise from an array:
int a[] = {4,17,20};
std::vector Foo::MyVector(a, a + (sizeof a / sizeof a[0]));
If you don't mind using a non-standard library, you can use Boost.Assignment:
#include <boost/assign/list_of.hpp>
std::vector Foo::MyVector = boost::list_of(4,17,20);
In C++11 or later, you can use brace-initialisation:
std::vector Foo::MyVector = {4,17,20};
With C++11:
//The static keyword is only used with the declaration of a static member,
//inside the class definition, not with the definition of that static member:
std::vector<int> Foo::MyVector = {4, 17, 20};
Typically, I have a class for constructing containers that I use (like this one from boost), such that you can do:
const list<int> primes = list_of(2)(3)(5)(7)(11);
That way, you can make the static const as well, to avoid accidental modifications.
For a static, you could define this in the .cc file:
// Foo.h
class Foo {
static const vector<int> something;
}
// Foo.cc
const vector<int> Foo::something = list_of(3)(5);
In C++Ox, we'll have a language mechanism to do this, using initializer lists, so you could just do:
const vector<int> primes({2, 3, 5, 7, 11});
See here.
You could try this one:
int arr[] = { 1,2,3,4,5,6,7,8,9 };
MyVector.insert(MyVector.begin(), arr, &arr[sizeof(arr)/ sizeof(*arr)]);
But it's probably only worth when you have a really long vector, and it doesn't look much nicer, either. However, you get rid of the repeated push_back() calls. Of course, if your values are "not in an array" you'd have to put them into there first, but you'd be able to do that statically (or at least references/pointers), depending on the context.
How about initializing using a static object. In its constuctor it
could call a static function in the object to do the initalization.
with boost you can use the +=() operator defined in the boost::assign namespace.
#include <boost/assign.hpp>
using namespace boost::assign;
int main()
{
static std::vector<int> MyVector;
MyVector += 4,17,20;
return 0;
}
or with static initialization:
#include <boost/assign.hpp>
using namespace boost::assign;
static std::vector<int> myVector = list_of(4)(17)(2);
int main()
{
return 0;
}
or even better, if your compiler supports C++ 11, use initialization lists.