Trouble placing int matrix array in a C++ Object - c++

I need a variable which will hold 22 pairs of ints (positions in a grid) so I was thinking of having a matrix array. So in my header file is:
int points[22][2];
but when I put the following in the constructor of the object:
this->points = {{1,2},{2,3},...};
It says "must be a expression must be a modifiable lvalue" I've tried using the const keyword and making it a pointer in the header file as described here Expression must be a modifiable L-value
I've also tried creating a separate 2d array and then assigning it but this doesn't work either.
int points2 = {{1,2},{2,3},...};
this->points = points2;
I'm used to Java and I'm not too experienced with C++. There is a default constructor that will assign the values as above and a constructor which will have the matrix as parameter.
The following does work:
this->point[1][1] = 4;
But this means I can't pass another value as a parameter and I end up with 44 lines of messy code in the default constructor! And I was going to use a struct with 2 ints and put them in a vector put that seems like a bit of an overkill and would mean I need 22 vector inserts before I even called the constructor with the manual values and I just thought there must be a better way :)
Thanks

Since you're using C++, a much better choice would be to use a vector of pairs of ints.
Declare it like this:
std::vector<std::pair<int, int> > points;
In your constructor you can specify size at initialization
: points(22),
or set it at any point like this:
points.resize(22);
You can access individual coordinates with
points[1].first = 1;
points[1].second = 44;
or with
points[1] = make_pair(1, 44);
or you can build it up without having to worry about exceeding its allocated size with
points.push_back(make_pair(1, 44));
etc

The fundamental cause of your problem is that arrays do not count as real values in C++. They are substandard in many ways- one of which you have just encountered. Any normal type would work as you expect. Unfortunately, to those of us who are not language experts, the error Visual Studio throws is incredibly unhelpful.
You must create an array on the stack and then manually loop through and assign all the values.

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.

Passing a 3-dimensional variable size array by reference in C++

I've been working off of Passing a 2D array to a C++ function , as well as a few other similar articles. However, I'm running into a problem wherein the array I'm creating has two dimensions of variable size.
The initialization looks like:
int** mulePosition;
mulePosition = new int *[boardSize][boardSize][2];
The function looks like:
int moveMule (int boardSize, int ***mulePosition)
And the references look like
moveMule (boardSize, mulePosition)
Boardsize is defined at the beginning of the function, but may change per execution.
The array, properly sized, would be int [boardSize][boardSize][2].
Either use a plain '3-dimensional' array via
int* mulePosition = new int[boardsize*boardsize*2];
and address its elements calculating the offset from the beginning: mulePosition[a][b][c] is mulePosition[boardSize*2*a + 2*b + c],
or use array of arrays of arrays (which would correspond to your int*** declaration) or better (and simpler) vector of vectors of vectors, although the initialization would be a little more complex (you would need to initialize every array/vector).
Either use a std::vector<std::vector<int>> if boardSize is not a const or std::array<std::array<boardSize>, boardSize> (see Multidimensional std::array for how to initialize the std::array).
That being said, it looks like a good idea to hide this in a class Board which provides a nice interface.

How to create variable name with integer appended to the end?

I want to create a for loop that will fill a bunch of arrays with data in c++. Now to save space and in the future once more arrays are added which they will, I have the for loop. Each array for demonstration purposes is called Array# (# being a number) The point of the for loop would be to set a constant with maximum arrays, then cycle through each array filling by appending i to the end of the Array name.
For example in pseudo code:
for (i = 1; i < numberofarrays; i++)
{ fill (Array & i) with ("Array" & i & "-default.txt")}
It is impossible to generate Variable Names by any type of code.
(Meaning it is impossible to generate dynamic variable names on Runtime or on Compiletime)
The best solution possible would be a array of arrays:
int Arrays[][];
Calling Arrays[0] would give you the first array.
If you want to determine the number of arrays during Runtime you need to use pointers!
That would look like that:
(int[])* Arrays = new (int[])[numberofarrays];
Accessing the arrays in the array would work the same!
An alternative would be using the container vector from std.
The code would the look like this:
#include<vector>
// More includes
// Optional
using namespace std;
// Somewhere in your code
vector<vector<int>> Arrays;
You still would acces the elements by using your standard array method (Arrays[15][78] e.g.)
You don't really need the name. You can use an std::vector of arrays. This will not work out of the box, see Correct way to work with vector of arrays
Another approach would be to have an std::map of arrays. You could have the name as the key, if that is what you really want. You will still have to use the same workaround as before to have an array as a value. See Character Array as a value in C++ map for example.

Select a random object from an array of objects

I'd like to implement a function that selects a random object from an array of objects and returns it to me. It should be something like (in C++ instead of psuedocode):
getRandomObject(objectList) {
return objectList[int(random(length of objectList))];
}
My current code looks like this, but doesn't seem to work:
//definition of random selector
object getRandomObject(Object* objectList) {
return objectList[int(ofRandom(0, sizeof(objectList)))];
};
//create a pointer for the listOfObjects
object* listOfObjects;
//create an empty object to put the randomly selected object in
object randomObject;
//later in the code, populate the array:
object* listOfObjects[] = {
new Object(),
new Object(),
new Object()
};
//select random object
randomObject = getRandomObject(listOfObjects);
But this seems to return a segmentation fault. A few problems I've noticed:
sizeof() returns the size of the pointer in getRandomObject, not the size of the array. is there a good way to get the size of the array? It might involves not using a float* pointer for the array. Is this a good use case for vectors?
I think that much of the problem lies in how I'm creating my arrays, and not so much in how I'm selecting the random object from them. I'm relatively new to C++ (coming from a Java background), so much of pointers / references / memory management in general is new to me.
thanks!
I see one definite problem and one possible one. The definite problem is that sizeof(objectList) returns the size of the objectList pointer, which will be 4 or 8 on most platforms. It does not return the number of elements in the array, objectList. Either pass in the length of the array or use std::vector or std::array.
The second possible problem relates to ofRandom. Make sure that ofRandom(a,b) returns numbers >= a, but strictly < b. If it returns values <= b, then you'll need to us ofRandom(0, objectVector.size() - 1). Typically, functions like this are written to return values strictly < b, but you should check.
C++ has an array template class that you may want to consider using. Check out the documentation here:
http://www.cplusplus.com/reference/array/array/
This type has a method, size(), that will return the length of the array.
When the sizeof operator is applied to an array, it yields the total
number of bytes in that array, not the size of the pointer represented
by the array identifier.
Quote
So you take the space alocated for your whole array and divide by the memory need just for one element: sizeof(objectList) / sizeof(*objectList).
Mr Fooz noticed issues that cause a segfault.
Other compilation issues are:
listOfObjects is declared with 2 different types: object* and object*[3] while getRandomObject expects a type Object*.
listOfObjects[] contains elements of type object* while getRandomObject reads elements of type Object and returns object.

assign elements in vector declared with new. C++

I am trying to use a large 2D vector which I want to allocate with new (because it is large).
if I say:
vector< vector<int> > bob;
bob = vector< vector<int> >(16, vector<int>(1<<12,0));
bob[5][5] = 777;
it works. But if I say:
std::vector< std::vector<int> > *mary;
mary = new vector< vector<int> >(16, vector<int>(1<<12, 0));
mary[5][5] = 777;
it doesn't work and I get the error:
Error 1 error C2679: binary '=' : no operator found which takes a right-hand operand of type 'int' (or there is no acceptable conversion) c:\Users\jsparger\Documents\My Dropbox\ARI\VME_0.01\VME_0.01\V965.cpp 11 VME_0.01
Obviously I am new to C++. Could someone explain what syntax I need to use to perform this operation. mary is a pointer, so I can see why this wouldn't work, but *mary[5][5] = whatever is not allowed either because of "new", right?
Thanks for the help. This vector is what I will be using for now because it seems easy enough for my small c++ brain to understand, but feel free to let me know if a large vector like this is a bad idea, etc.
Thanks a bunch.
Edit:
I am mistaken about the "not allowed because of new". I don't know where I misread that, because it obviously works, and wouldn't make too much sense for it not to. Thanks.
If mary is a pointer then you have to dereference it before applying the subscript operator:
(*mary)[5][5] = 777;
The parentheses are required because the subscript has higher precedence than the dereference.
Vectors store their elements on the heap, anyway. There's no point in allocating the vector object itself on the heap, since it is very small (typically 12 bytes on a 32-bit machine).
In plain C, arrays and pointers are similar (not the same!), which leads to your confusion. In plain C, if you have the following declarations:
int array1[100];
int *array2 = (int *)malloc(100*sizeof(int));
you can use array1 and array2 in exactly the same way.
However, if you write this in C:
int (*array3)[100];
This is something completely different. Array3 is now a pointer to an array, not a pointer to the elements of the array anymore, and if you want to access an element, you have to write this:
(*array3)[5] = 123;
In C++, you are actually doing something similar, the second 'mary' is a pointer to the vector, not a pointer to the elements in the vector. Therefore, you have to write this:
(*mary)[5][5] = 777;