Creating a array of structs #2 - c++

I am writing this post in reference to my recent one - Create a array of structs
So, where I've got now is this code:
struct MacroMas
{
int x;
int y;
int Delay;
int SemiAutoDelay;
int ammo;
void Cords(int x, int y, int Delay)
{
this->x = x;
this->y = y;
this->Delay = Delay;
}
};
MacroMas* temp()
{
MacroMas _ret;
MacroMas* macroMasArray = new MacroMas[107];
for (int index = 0; index <107 ; ++index)
macroMasArray[index] = MacroMas();
macroMasArray[0].Cords(-3, 4, 16);
macroMasArray[1].Cords(-3, 4, 17);
// Some more code
return macroMasArray;
Thanks to John, who got me on the right way, but unfortunately, I can't accept this answer, because this eliminates only "randomization" bug. Now here's a stable problem - In array, only the first (macroMasArray[0]) is properly stored, other array's elements get the same value, as the first one. For example. mascroMasArray[10] should be 1,5,17, but is -3,4,16. Same as 0th element

You're simply misunderstanding the debugger. You are always looking at element zero. The other elements have the correct values, but you are not looking at them.
Because you've declared macroMasArray as a pointer to MacroMas the debugger presumes it's intended only to point to a single object.
You need to specifically type in the watch window which element you want, e.g.
macroMasArray[1]
or make sure you highlight the entire element, including the index.

Related

Unexpected errors regarding structs and arrays

So I'm following a certain tutorial series and trying to use that knowledge to put my own spin on something kindof both similar but also different to the series itself. In one section, to tackle a certain inconvenience which is not important for the scope of my issue, a possible solution was to store certain chunk of data into members of a struct and then call that struct onto a function that later output the data precisely the way we wanted - as an array.
All was well and good, until the function for some reason refused to take in values of the array, claiming there was an overload of information in the array arguments (I will specify the errors later), and that the entity I am returning does not match the function's return type.
Here's my code:
struct TriCoord
{
float Position[3];
int Label[2];
};
std::array<TriCoord, 3> Implement(float x, float y, float z, int j) //2
{
float size = 1.0f;
TriCoord f0;
f0.Position = { x, y, z }; //1
f0.Label = { j, 1 }; //1
TriCoord f1;
f1.Position = { x + 0.5, y + 0.5, z };
f1.Label = { j, 2 };
TriCoord f2;
f2.Position = { x + 0.5, y, z };
f2.Label = { j, 3 };
return { f0, f1, f2 }; //2
};
int main()
{
int X;
float A[3] = Implement(3, 4, 5, 1); //3
std::cout << A[0] << ", " << A[1] << ", " << A[2] << std::endl;
std::cout << "Press Enter key to return" << std::endl;
std::cin >> X;
return 0;
}
I've put comments locating specifically where the errors are.
1) The compiler says that f0 is "not a modifiable lvalue". I see no reason why it shouldn't be. In the array argument at specifically the second element of the array (in this case y), the compiler says that I am adding "too many initializer values". Again, makes no sense. I specified the Position array to have 3 elements and am plugging 3 elements of matching type (float).
These two errors extend to f0.Label, as well as the other TriCoords.
2) The compiler says that the function "returns incomplete type 'std::array'". Furthermore, in the return line, "list-initialization of an object type 'std::array' is not allowed because the type is incomplete".
Technically what I am returning is an std array whose elements are TriCoords and of amount 3, so I don't see the problem once again. I did work around this issue by changing the function's return type to float, but in its stead the return line generates the same error for the second element (in this case f1) as in problem 1.
3) "Initialization with '{...}' expected for aggregate object" I have no idea what this means. I get this error regardless of which return type I specify for my function.
I must emphasise that both me and the series I'm following are using Visual Studios and no such errors popped up in the video I was following. I even copy-pasted the entirety of the video's code line by line and the errors still persisted, leading me to the conclusion that there is something wrong in the way Visual Studios is configured on my end, possibly due to version differences (the video was uploaded this year so it's not running on too old of a version). All my dependencies are correct as well and are present in their respective project-based directories, I have double checked those.
Lastly, the code I used above was a separate testing code I redid on a new project in an attempt to isolate the error. Needless to say, I got the same error in both cases indicating there's nothing inherently wrong with the custom-defined headers and libraries of my original project.
1) You cannot assign into arrays like this once they are initialized.
int arr[3] = {1, 2, 3}; //valid
int arr2[3];
arr2 = {1, 2, 3}; //invalid
In your case, what you could do is instead of: -
TriCoord f0;
f0.Position = { x, y, z };
f0.Label = { j, 1 };
write: -
float tempFloat[3] = { x, y, z };
int tempInt[2] = { j, 1 };
TriCoord f0;
for (int i = 0; i < 3; ++i)
f0.Position[i] = tempFloat[i];
for (int i = 0; i < 2; ++i)
f0.Label[i] = tempInt[i];
2) Solve 1 to solve 2...
3) You are trying to assign std::array<TriCoord, 3> to a float array which is certainly not possible...
At this point, I would strongly advise you to use std::array everywhere.

while every value in array is different than specific int value

I have an array of values e.g. 1, 4, 7, 2.
I also have another array of values and I want to add its values to this first array, but only when they all are different from all values that are already in this array. How can I check it? I've tried many types of loops, but I always ended with an iteration problem.
Could you please tell me how to solve this problem? I code in c++.
int array1[7] = {2,3,7,1,0};
int val1 = rand() % 10;
int val2 = rand() % 10;
int array2[2] = {val1, val2};
and I am trying to put every value from array2 into array1. I tried loop
for (int x:array2)
{
while((val1 && val2) == x)
{
val1 = rand() % 10;
val2 = rand() % 10;
}
}
and many more, but still cannot figure it out. I have this problem because I may have various number of elements for array2. So it makes this "&&" solution infinite.
It is just a sample to show it more clearly, my code has much more lines.
Okay, you have a few problems here. If I understand the problem, here's what you want:
A. You have array1 already populated with several values but with space at the end.
1. How do you identify the number of entries in the array already versus the extras?
B. You have a second array you made from two random values. No problem.
You want to append the values from B to A.
2. If initial length of A plus initial length of B is greater than total space allocated for A, you have a new problem.
Now, other people will tell you to use the standard template library, but if you're having problems at this level, you should know how to do this yourself without the extra help from a confusing library. So this is one solution.
class MyArray {
public:
int * data;
int count;
int allocated;
MyArray() : data(nullptr), count(0), allocated(0) {}
~MyArray() { if (data != nullptr) free(data); }
// Appends value to the list, making more space if necessary
void add(int value) {
if (count >= allocated) {
// Not enough space, so make some.
allocated += 10;
data = (data == nullptr) malloc(allocated * sizeof(int))
: realloc)data, allocated * sizeof(int));
}
data[count++] = value;
}
// Adds value only if not already present.
void addUnique(int value) {
if (indexOf(value) < 0) {
add(value);
}
}
// Returns the index of the value, if found, else -1
int indexOf(int value) {
for (int index = 0; index < count; ++index) {
if (data[index] == value) {
return index;
}
}
return -1;
}
}
This class provides you a dynamic array of integers. It's REALLY basic, but it teaches you the basics. It helps you understand about allocation / reallocating space using old-style C-style malloc/realloc/free. It's the sort of code I was writing back in the 80s.
Now, your main code:
MyArray array;
array.add(2);
array.add(3);
array.add(7);
// etc. Yes, you could write a better initializer, but this is easy to understand
MyArray newValues;
newValues.add(rand() % 10);
newValues.add(rand() % 10);
for (int index = 0; index < newValues.count; ++index) {
array.addUnique(newValues.data[index]);
}
Done.
The key part of this is the addUnique function, which simply checks first whether the value you're adding already is in the array. If not, it appends the value to the array and keeps track of the new count.
Ultimately, when using integer arrays like this instead of the fancier classes available in C++, you HAVE TO keep track of the size of the array yourself. There is no magic .length method on int[]. You can use some magic value that indicates the end of the list, if you want. Or you can do what I did and keep two values, one that holds the current length and one that holds the amount of space you've allocated.
With programming, there are always multiple ways to do this.
Now, this is a lot of code. Using standard libraries, you can reduce all of this to about 4 or 5 lines of code. But you're not ready for that, and you need to understand what's going on under the hood. Don't use the fancy libraries until you can do it manually. That's my belief.

Allocating the correct size of struct variable with sub-structs

So I am trying to allocate the correct size for a variable. Then copy another variable to this new one and later access the new variable's data.
Structs:
struct Validations {
int validationId;
int count; // total queries
char queries[];
};
struct Query {
struct Column {
enum Op : int { Equal, NotEqual };
int column;
int value;
Op op;
};
int relationId;
int columnCount; // total columns
Column columns[];
};
Code:
// function that creates the new val
void function1(Validations* val){
int size = sizeof(Validations) + val->count;
Validations *new_val = (Validations*)malloc(size);
memcpy(new_val, val, size);
// I store this val in a global list
}
void function2(){
// I pop the val here
// I am casting here in order to get the values that i want
const char* reader = popped_val->queries;
for (...){
// casting again
const Query* q = (Query*)reader;
// operations....
// SIGSEGV here after reader is incremented and q is casted again
// done with operations, go to next
reader += sizeof(Query)+(sizeof(Query::Column)*q->columnCount);
}
}
The problem is that the new_val size that I am allocating in the first function is probably not the right one because I get a segmentation fault after the second cast of the function2 after trying to access the data.
What I tried:
1) size = 1000; Tried that for testing and it worked so the problem is surely the size.
2) size = sizeof(Validations) + val->count * sizeof(Query) * sizeof(Query::Column) * q->columnCount;. This one looks like the correct one to me but it does not work.
The correct expression should be more like this:
size = val->count * (sizeof(Validations) + sizeof(Query) + (sizeof(Query::Column) * q->columnCount));
But note that you probably have to add up the column counts for each individual Query if they can vary.

How to speed up a function that returns a pointer to object in c++?

I am a mechanical engineer so please understand I am not trained in proper coding. I have a finite element code that uses grids to make elements which make a model. The element is not important to this question so I have left it out. The elements and grids are read in from a file and that part works.
class Grid
{
private:
int id;
double x;
double y;
double z;
public:
Grid();
Grid(int, double, double, double);
int get_id() { return id;};
};
Grid::Grid() {};
Grid::Grid(int t_id, double t_x, double t_y double t_z)
{
id = t_id; x = t_x; y = t_y; z = t_z;
}
class SurfaceModel
{
private:
Grid** grids;
Element** elements;
int grid_count;
int elem_count;
public:
SurfaceModel();
SurfaceModel(int, int);
~SurfaceModel();
void read_grid(std::string);
int get_grid_count() { return grid_count; };
Grid* get_grid(int);
};
SurfaceModel::SurfaceModel()
{
grids = NULL;
elements = NULL;
}
SurfaceModel::SurfaceModel(int g, int e)
{
grids = new Grid*[g];
for (int i = 0; i < g; i++)
grids[i] = NULL;
elements = new Element*[e];
for (int i = 0; i < e; i++)
elements[i] = NULL;
}
void SurfaceModel::read_grid(std::string line)
{
... blah blah ...
grids[index] = new Grid(n_id, n_x, n_y, n_z);
... blah blah ....
}
Grid* SurfaceModel::get_grid(int i)
{
if (i < grid_count)
return grids[i];
else
return NULL;
}
When I need to actually use the grid I use the get_grid maybe something like this:
SurfaceModel model(...);
.... blah blah .....
for (int i = 0; i < model.get_grid_count(); i++)
{
Grid *cur_grid = model.get_grid(i);
int cur_id = cur_grid->get_id();
}
My problem is that the call to get_grid seems to be taking more time than I think it should to simply return my object. I have run the gprof on the code and found that get_grid gets called about 4 billion times when going through a very large simulation and another operation using the x, y, z occurs about the same. The operation does some multiplication. What I found is that the get_grid and math take about the same amount of time (~40 seconds). This seems like I have done something wrong. Is there a faster way to get that object out of there?
I think you're forgetting to set grid_count and elem_count.
This means, they will have uninitialized (indeterminate) values. If you loop for those values, you can easily end up looping a lot of iterations.
SurfaceModel::SurfaceModel()
: grid_count(0),
grids(NULL),
elem_count(0),
elements(NULL)
{
}
SurfaceModel::SurfaceModel(int g, int e)
: grid_count(g),
elem_count(e)
{
grids = new Grid*[g];
for (int i = 0; i < g; i++)
grids[i] = NULL;
elements = new Element*[e];
for (int i = 0; i < e; i++)
elements[i] = NULL;
}
Howeverm, I suggest you would want to get rid of each instance of new in this program (and use a vector for the grid)
On a modern CPU accessing memory often takes longer than doing multiplication. Getting good performance on modern systems can often mean focusing more on optimizing memory accesses than optimizing computation. Because you are storing your grid objects as an array of dynamically allocated pointers the grid objects themselves will be stored non-contiguously in memory and you will likely get many cache misses when trying to access them. In this example you would probably see a significant speedup by storing your grid objects directly in an array or vector since you will be accessing contiguous memory in your loop and so get good cache utilization and effective hardware prefetching.
4 billion times a microsecond (which is a pretty acceptable time in many cases) gives 4 000 seconds. And since you only get about 40 s (if I get it right), I doubt there's something seriously wrong here. If it's still slow for the task, I'd consider the use of parallel computing.

c++ type error message from compiler, what does it mean?

I'm using g++ on fedora linux 13.
I'm just practicing some exercises from my c++ textbook
and can't get this one program to compile. Here is the code:
double *MovieData::calcMed() {
double medianValue;
double *medValPtr = &medianValue;
*medValPtr = (sortArray[numStudents-1] / 2);
return medValPtr;
}
Here is the class declaration:
class MovieData
{
private:
int *students; // students points to int, will be dynamically allocated an array of integers.
int **sortArray; // A pointer that is pointing to an array of pointers.
double average; // Average movies seen by students.
double *median; // Median value of movies seen by students.
int *mode; // Mode value, or most frequent number of movies seen by students.
int numStudents; // Number of students in sample.
int totalMovies; // Total number of movies seen by all students in the sample.
double calcAvg(); // Method which calculates the average number of movies seen.
double *calcMed(); // Method that calculates the mean value of data.
int *calcMode(); // Method that calculates the mode of the data.
int calcTotalMovies(); // Method that calculates the total amount of movies seen.
void selectSort(); // Sort the Data using selection sort algorithm.
public:
MovieData(int num, int movies[]); // constructor
~MovieData(); // destructor
double getAvg() { return average; } // returns the average
double *getMed() { return median; } // returns the mean
int *getMode() { return mode; } // returns the mode
int getNumStudents() { return numStudents; } // returns the number of students in sample
};
Here is my constructor and destructor and selectSort():
MovieData::MovieData(int num, int movies[]) {
numStudents = num;
// Now I will allocate memory for student and sortArray:
if(num > 0) {
students = new int[num];
sortArray = new int*[num];
// The arrays will now be initialized:
for(int index = 0;index < numStudents;index++) {
students[index] = movies[index];
sortArray[index] = &students[index];
}
selectSort(); // sort the elements of sortArray[] that point to the elements of students.
totalMovies = calcTotalMovies();
average = calcAvg();
median = calcMed();
mode = calcMode();
}
}
// Destructor:
// Delete the memory allocated in the constructor.
MovieData::~MovieData() {
if(numStudents > 0) {
delete [] students;
students = 0;
delete [] sortArray;
sortArray = 0;
}
}
// selectSort()
// performs selection sort algorithm on sortArray[],
// an array of pointers. Sorted on the values its
// elements point to.
void MovieData::selectSort() {
int scan, minIndex;
int *minElement;
for(scan = 0;scan < (numStudents - 1);scan++) {
minIndex = scan;
minElement = sortArray[scan];
for(int index = 0;index < numStudents;index++) {
if(*(sortArray[index]) < *minElement) {
minElement = sortArray[index];
minIndex = index;
}
}
sortArray[minIndex] = sortArray[scan];
sortArray[scan] = minElement;
}
}
The compiler is giving this error:
moviedata.cpp: In memberfunction
'double * MovieData::calcMed()':
moviedata.cpp:82: error: invalid
operands of types 'int*' and 'double'
to binary 'operator/'
I'm not sure what to make of this error, i've tried static casting the types with no luck, what does this error message mean?
you are trying to divide a pointer by a double, which the compiler is saying it does not know how todo.
sortArray is probably defined by
int ** sortArray;
its also worth noting you are returning a pointer to a stack variable, who's value will be undefined as soon as you return out of the function.
sortArray[numStudents - 1] is a pointer to int, which can't be on the left side of a division (when you remember pointers are addresses, this makes sense). If you post more of your code, we can help you correct it.
Perhaps you want something like:
int *MovieData::calcMed() {
return sortArray[(numStudents - 1) / 2];
}
This returns the middle element in your array, which should be a pointer to the middle student. I'm not clear why you're sorting lists of pointers (not the actual values), or why you're returning a pointer here. The return value + 1 will be a pointer to the next value in students, which is not the next greater value numerically. So you might as well return the actual student (int from students). If you do this, you can also average the two middle elements when the count is even (this rule is part of the typical median algorithm).
Note that I changed the return type to int *, the type of sortArray's elements. Also, your comment is incorrect. This is the median, not the mean.
Also, your selection sort is wrong. The inner loop should start at scan + 1.
Your code shows a lack of understanding of pointers. You need to do more reading and practice on simpler examples.
More specifically:
double medianValue; creates a double variable. What for? You're apparently going to return a double * and returning a pointer to a local variable is always wrong, because local variables are "recycled" when their function ends.
double *medValPtr = &medianValue; creates a pointer called medValPtr and sets it to the location of medianValue. Well.
Due to the current contents of medValPtr, *medValPtr = (sortArray[numStudents-1] / 2); has the same effect as typing medianValue = (sortArray[numStudents-1] / 2); (supposing it were to compile at all).
Which it doesn't because sortArray[numStudents-1] is, at a guess, the last item in the array sortArray but happens to be a pointer to something else. You can't divide a pointer (numerically you can, but C++ disallows it's always wrong).
Finally you return medValPtr; which is wrong because medValPtr is pointing to a local variable.
You probably want something like:
int *MovieData::calcMed() {
return sortArray[numStudents/2];
}