Error when attempting to change value of float? - c++

Trying to change the value of a certain float which is used to define the RGBA of an element. The problem is when I try to change the value of the float an error occurs. Here's an example:
float ColorForScrollbar[4] = {1,0,0,.8};
// Set the value for ColorForScrollbar
ColorForScrollbar[4] = {0,1,0,.8};
// "Error: Expected an expression"
ColorForScrollbar = {0,1,0,.8};
// "Error: Expression must be a modifiable value"

float ColorForScrollbar[4] = {1,0,0,.8};
This is valid. The {1,0,0,.8} is an initializer. It is not, however, an expression. It can only be used after the = in an object declaration.
ColorForScrollbar[4] = {0,1,0,.8};
If this were legal, then it would (attempt to) change the value of ColorForScrollbar[4], not of the entire array. Since the only elements that exist have indices 0, 1, 2, and 3, this would have undefined behavior. But again, {0,1,0,.8} is not an expression, so it can't be used on the RHS of an assignment.
This is closer, but it has the same problem as before. Furthermore, there is no assignment operator for array types.
You can change one element at a time:
ColorForScrollbar[0] = 0;
ColorForScrollbar[1] = 1;
ColorForScrollbar[2] = 0;
ColorForScrollbar[3] = 0.8;
Or, if you want to use the initializer syntax, you can use a temporary object:
#include <cstring>
const float new_value[4] = { 0, 1, 0, 0.8 };
std::memcpy((void*)ColorForScrollbar, (void*)new_value), sizeof ColorForScrollbar);
However, this is all rather low-level. You're probably better off using one of the C++ container classes from the standard library. Which one is best (std::vector, std::array) probably depends on just what you're doing.

An array is really just an address for a contiguous, fixed, area of memory. You can't change it any more than you can change your own street address (unless you move, of course).
What you can change, though, are the contents of an array:
ColorForScrollbar[0]=0;
ColorForScrollbar[1]=1;
ColorForScrollbar[2]=0;
ColorForScrollbar[3]=.8;
You don't have to change every value in the array, just what you need to change.
You can also do an explicit copy:
float NewColorForScrollBar[4] = {0,1,0,.8};
for (i=0; i<4; ++i)
ColorForScrollbar[i]=NewColorForScrollbar[i];

Related

Find End of Array Declared as Struct Type C++

I was recently learning to use struct datatype in c++. I know how the basics of struct datatype work and how to manipulate its variables. But I was wondering how would I determine the end of struct datatype array. For example consider the code below:
struct PersonDetails
{
string name, address;
int age, number;
}
Now in c++ program I create an array of struct type as follows:
PersonDetails Data[500];
Now consider that I have 30 records in data array and I have to display these records by looping through data array's index. So how would I determine that I have to loop through only first 30 indexes as the data is only stored in these indexes. As in char array we compare all indexes with '\0' to determine the end of array. Then what method will we use for Data[] array?
An edit that I have no idea about Vectors and the project i am working on requires me to use basics of c++(functions, control structures, loops, etc.).
It's not feasible.
For char[], back in times of C standardization, developers agreed to use \0 (integer value 0) as a special character marking end-of-string. Everything works as long as everyone is following this convention (i.e. both standard library functions and developers using those functions).
If you wanted to have such a convention for your type, you could just write down "Data object with both strings empty and both ints equal to 0 is array terminator", but you would have to follow this convention. You'd have to write functions that would stop processing array upon finding such an object. You'd have to make sure that in every array there is at least one such object.
Instead
You should use std::vector<Data> which can automatically accomodate for any number of Data objects and will now precisely how many of them are currently stored (using size() method)
or
use std::array<Data, 30>, which can store exactly 30 objects and you can assume all of them are valid objects.
IMHO the correct way to solve this is to not use a C-style array, but instead use a std::array or std::vector that knows it's .size().
Iterating a std::vector or std::array is trivial:
for (const auto& element : Data_array) {
// Do something with the array element
}
See also:
https://en.cppreference.com/w/cpp/container/array
https://en.cppreference.com/w/cpp/container/vector
https://en.cppreference.com/w/cpp/language/for
https://en.cppreference.com/w/cpp/language/range-for
The simplest solution is to just have a separate variable specifying how many array elements are filled in.
PersonDetails Data[500];
int numPersons = 0;
Data[0].name = ... ;
Data[0].address = ...;
Data[0].age = ...;
Data[0].number = ...;
numPersons = 1;
Data[1].name = ... ;
Data[1].address = ...;
Data[1].age = ...;
Data[1].number = ...;
numPersons = 2;
...
Then you use that variable when looping through the array.
for (int i = 0; i < numPersons; ++i)
{
// use Data[i] as needed...
}
I don't really agree using std::array makes any difference.
The problem you currently have doesn't occur in whether we have such an element in the container, but whether the element we are inspecting useful.
Consider the example you gave, for an array of chars, we simply check whether one of the elements is \0 to decide whether or not we should halt the iteration.
How does that work? The ramaining elements, of course, default initialized to be \0, they exist, but of no use.
Similarly, you can check, in this example, whether
name.empty()
Or, in order to avoid any possible exception, as mentioned in the comment section, do this:
add user-defined constructor to the class ( or struct, they are same actually.) which initialize age to -1 and then check if age == -1.
because it's impossible for a people not having any name, that means, you have not assign to any of the remaining elements. Thus, stop iteration.
As a supplement, using std::vector makes sense, but if that isn't a option for you for the time being, you don't need to consider it.

How to convert between flat and multidimensional arrays without copying data?

I've got some data structured as a multi-dimensional array, i.e. double[][], and I need to pass it to a function that expects a single linear array of double[] along with dimensional metadata for the multi-dimensional representation.
For example, I might have a 3 x 5 multidimensional array, which I need to pass as a 15-element flat array along with height and width parameters so that the function knows it is a 3x5 array rather than a 5x3 array.
The function will then return a flat array and size metadata, which I need to use to convert the data back into a multidimensional type.
I believe the data layout in memory is exactly the same for both the flat and multi-dimensional representations; the only difference is how the indexing operations are performed. So I'd like to do the "conversion" with typecasting rather than copying the array values.
What's the most correct and readable way to typecast between multidimensional and flat arrays of the same total size?
I actually know what the dimensions of the multi-dimensional array will be at compile time. The array sizes aren't dynamic.
The most correct way has been given by #Maxim Egorushkin and #ypnos: double *flat = &multi[0][0];. And it will work fine with any decent compiler. But unfortunately is not valid C++ code and invokes Undefined Bahaviour.
The problem is that for an array double multi[N][M]; (N and M being compile time contant expressions), &multi[0][0] is the address of the first element of an array of size M. So it is legal to do pointer arithmetics only up to M. See this other question of mine for more details.
What's the most correct and readable way to typecast between multidimensional and flat arrays of the same total size?
The address of the first array element coincides with the address of the array. You can pass around the address of the first element, no casting is necessary.
I would assume the most popular way to do it is:
double *flat = &multi[0][0];
This is how it is done in C, and you do operate with simple C arrays.
You could also have a look at std::array in your use case (dimensions known at compile time), but that one is not multi-dimensional, so if you would cascade it, you would lose the contiguous layout.
You can use cast to a reference to an array. This require to use some fancy C++ type syntax but in return it allows to use all features that work on arrays, like for each loop.
#include <iostream>
using namespace std;
int main()
{
static constexpr size_t x = 5, y = 3;
unsigned multiArray[x][y];
for (size_t i = 0; i != x; ++i)
for (size_t j = 0; j != y; ++j)
multiArray[i][j] = i * j;
static constexpr size_t z = x * y;
unsigned (&singleArray)[z] = (unsigned (&)[z])multiArray[0][0];
for (const unsigned value : singleArray)
cout << value << ' ';
cout << endl;
return 0;
}
Take into account that this and other methods basing on casts work only with real multi-dimensional arrays. If it is an array of arrays (like unsigned **multiArray;), it isn't allocated in a continuous block of memory and a cast cannot bypass that.

Check if vector is uninitialised at a certain position

This seems like a really basic thing to do, but anyway I couldn't manage to find a solution to it so far, because I always find only questions that are asking how to check if the vector is actually empty, which is not what I want to check for.
Consider this code example:
#include <iostream>
#include <vector>
using namespace std;
struct Atom {
int x,y;
int pol;
};
int main() {
vector<vector<Atom>> vec=vector<vector<Atom>>(5,vector<Atom>(5));
cout<<(vec[0][0]==nullptr); // this line doesn't compile, because the vector doesn't hold pointers.
return 0;
}
I'm trying to declare a vector of vectors of objects of a custom type. At the beginning of the Programm I will initialise the vector so that it has a specific size, but without assigning an actual object to it. Now I want to be able to check if I already assigned an object to a specific position of the vector. I would've liked to use something like vec==nullptr but this doesn't work, because the objects in the vector aren't pointers. Unfortunately I can't just change the structs standard constructor to put some indicator value that I can check for like Atom.pol==-2, because the class is created by ROS messages. Any other suggestions on how to check if I already assigned an object?
EDIT: pol will always be either -1 or 1 after I assigned an object. So is it safe to check Atom.pol==0? When I tried to do this on ideone.com it always worked, but I assume that it's not guaranteed to be 0, right?!
There is no way to check whether an object has been initialised. That said, elements of std::vector are always initialised, so there is never a need to check either.
It seems that you want to represent an "unassigned" object. The standard library has a template for you: std::optional. If you create a vector optional objects, those objects, when value-initialized, will be in "unassigned" state.
EDIT: pol will always be either -1 or 1 after I assigned an object. So is it safe to check Atom.pol==0?
Yes, that would be safe, since the constructor that you use initialises the elments using a value initialised argument.
If you can assume that some states of the object are "not valid", then you don't necessarily need to use std::optional. If the value initialised state is such invalid state, then you don't need to add a default constructor to the class either. Just like a value initialised pointer compares equal to nullptr, so too the integer members of the value initialised Atom compare equal to 0.
but I assume that it's not guaranteed to be 0, right?!
It is guaranteed to be 0.
The solution to use pol == 0 should be fine, provided that pol == 0 is in fact not a normal state for that object to be in and that you don't try it with an uninitialized instance.
The std::vector constructor you are using guaranties that the new elements are default inserted. If you are using the default allocator (which you are) then that performs value initialization of those new elements. Since Atom is a class type with a default constructor that is neither user-provided nor deleted, then your instance of Atom are zero initialized. That means each of Atom's members' value is initialized to zero.
Beware that this is something std::vector does. You need your Atoms to be initialized to zero for this approach to work. If you tried the following, it would be undefined behavior. The Atom members are not initialized, much less guaranteed to be zero :
int main()
{
Atom a;
std::cout << (a.pol == 0); // <- Not okay
}
You can force value initialization by adding {} though :
int main()
{
Atom a{};
std::cout << (a.pol == 0); // <- Okay now
}
Edit : Accidentally used the same code sample for both examples.
One way to do this is to change the signature of vec to,
vector<vector<Atom*>> vec=vector<vector<Atom*>>(5,vector<Atom*>(5));
Then you can do the null ptr check to see if a given element has been initialized. This does add some complexity though, as you have to handle the memory allocation yourself.
If you want to initialize the members of Atom to specific values and check if they are initialized, you can do this.
vector<vector<Atom>> vec=vector<vector<Atom>>(5,vector<Atom>(5, {1, 2, 3}));
This initializes x, y, pol to 1, 2 and 3 respectively.
Minimal Example:
int main() {
using std::cout;
using std::vector;
vector<vector<Atom>> vec=vector<vector<Atom>>(5,vector<Atom>(5, {1, 2, 3}));
cout<<((vec[0][0]).x == 1) << "\n";
cout<<((vec[0][0]).y == 2) << "\n";
cout<<((vec[0][0]).pol == 3) << "\n";
cout<<((vec[0][0]).x == -1) << "\n";
cout<<((vec[0][0]).y == -1) << "\n";
cout<<((vec[0][0]).pol == -1) << "\n";
return 0;
}
See Demo

Dynamic memory allocation...how about this type of inititlization?

To create an integer on heap and initialize it to a value 5, we do:
int* a = new int(5);
To create an array of 5 integers on the heap, we do:
int* a = new int[5];
But, if we want to create an array of 5 integers and initialize each of them to 10 in one single instruction, is it possible?
To make things more interesting, let us say that the array size will only be known at run time. How about then?
Also, I know this is a very trivial question, but I'm making this transition from Java and get confused at times with C++, so... if not initialized during declaration, then unlike in Java, C++ primitive data types are not initialized with default values, and contain garbage values, right?
But someone told me that if they are declared as global variables, then they are initialized to default values like in Java...is that true as well? Why?
I prefer:
std::vector<int> a = {10,10,10,10,10};
C++ is a very complex language, with many different (even contradicting) goals.
One of the ideas behind it was that you should not pay in efficiency what you don't need and this is what is behind the concept of uninitialized values.
When you write
int x;
the variable x is initialized if it's at global/namespace scope and instead is not initialized when the definition is in a local scope.
This happens not because who designed C is crazy (of course an initialized value is better) but because initialization at global/namespace scope is free from an efficiency point of view as it's done compile/link/loading time, not at runtime.
Initializing a variable in local scope instead has a cost (small, but non-zero) and C++ inherited from C the idea that shouldn't pay for it if you don't need it, thus if you want your variable initialized to any value simply says so with:
int x = 42;
Note however that an uninitialized variable is not simply "containing a garbage value", it's uninitialized and you are not allowed to read its content as such an operation is "undefined behavior".
There are platforms in which just reading the content of an uninitialized variable may crash ("trap representations": for example hardware with dedicated registers for pointers in which just placing an invalid address in a register - not doing anything with it - provokes an hardware exception).
No, it is not possible to allocate an array with new[] and specify an initial value for the array elements. You have to fill in the array after the allocation is finished, eg:
int count = 5;
int* a = new int[count];
for (int i = 0; i < count; ++i)
a[i] = 10;
...
delete[] a;
That is not very C++-ish. You could use std::fill() to get rid of the loop, at least:
int count = 5;
int* a = new int[count];
std::fill(a, a+count, 10);
...
delete[] a;
A better option is to switch to a std::vector instead, which has a constructor that does exactly what you are looking for:
std::vector<int> a(5, 10); // create 5 elements initialized to value 10
std::vector has a constructor where you can specify the initial size and initial value:
std::vector<int> an_array(size, init_value);
If you want to use a dynamic array using new[], you have to assign the initial value to each element:
int* array = new a[size];
for(int i = 0; i < size; ++i)
array[i] = init_value;
...
delete[] array;
Use std::array if the size is known at compile-time:
std::array<int, 5> myArray = { 1, 2, 3, 4, 5 };
Which is RAII-conform and safe.
You just have to include <array> and <initializer_list>.
In other cases, use std::vector.
This works for me with g++ 4.8.2.
#include <iostream>
int main()
{
int* a = new int[5]{10, 10, 10, 10, 10};
for ( int i = 0; i < 5; ++i )
{
std::cout << a[i] << " ";
}
std::cout << std::endl;
}
Output:
10 10 10 10 10
Update, in response to OP's comment
When you use
std::vector<int> v(5, 10);
the constructor of std::vector used is:
vector( size_type count,
const T& value,
const Allocator& alloc = Allocator());
Let's say you have a class
class MyClass
{
public:
MyClass(int ) {}
};
You can construct a std::vector<MyClass> using:
std::vector<MyClass> v(10, MyClass(50));
or
std::vector<MyClass> v(10, 50);
In the second case, the compiler knows how to implicitly construct a temporary MyClass object given the argument 50 alone. But either way, a temporary MyClass object is being passed to the vector, and that is OK because the argument type of that parameter is const MyClass&, which can bind to a temporary object.

std::vector's push_back does not add the supplied value

I have the following function
std::vector<bool> buildBoolList(node* n)
{
std::vector<bool> boolList;
for(int i = 0; i < n->next.size(); i++)
{
int ival = atoi(n->next[i]->val.c_str());
bool b = !!ival;
boolList.push_back(b);
}
return boolList;
}
However every time I run my code boolList is always returned with a size of 0. I've run the debugger to ensure that atoi is returning a valid numeric and I've also ensured that b becomes the appropriate boolean value, however I can't seem to figure out why boolList is not populated.
std::vector<bool> has been a kind of experiment by the C++ committee. It is actually a template specialization that stores the bool values tightly packed in memory: one bit per value.
And since you cannot have a reference to a bit, so you might be seeing the size as 0.
Why vector<bool>::reference doesn't return reference to bool?
There's nothing wrong with vector<bool>, except that it isn't equivalent to a vector were T is the integer type equivalent to bool. This only shows in performance (CPUs only access bytes at a time, where in a vector<bool> every element is stored in one bit) and memory access (a reference to a first element of a vector is not equivalent to an array like with any other vector<T>. It is part of the Standard, unfortunately: see section 23.3.7 (C++0x FDIS)
I think your problem is with:
for(int i = 0; i < n->next.size(); i++)
{
int ival = atoi(n->next[i]->val.c_str());
I am almost certain you meant something along the lines of:
for(node* i = n; i->next != NULL; i=i->next)
{
int ival = atoi(i->val.c_str());