Accessing a structure array through a pointer - c++

I have a class with a structure for its position:
class thing
{
void setCoOrds(int, int, int);
string name;
struct location
{
int x;
int y;
int z;
} coOrd;
};
Then in a function I created an array of type thing.
int main()
{
thing * p_myThings = new thing[5];
// call array element here to use setCoOrds()
delete p_myThings;
return 0;
}
From the main function how would I access, lets say, thing element [3] so that I can use its .setCoOrds() function?

It should be:
p_myThings[3].setCoOrds
Also the
setCoOrds
is private by default which will not allow you to call the function.

int main()
{
thing * p_myThings = new thing[5];
p_myThings[3].setCoOrds(42,21,0);
delete[] p_myThings; // use delete[] for arrays btw
return 0;
}

I suppose that member function
void setCoOrds(int, int, int);
has public access control. In this case you can use the following constructions
p_myThings[3].setCoOrds( x, y, z );
or
( *( p_myThings + 3 ) ).setCoOrds( x, y, z );
or
( p_myThings + 3 )->setCoOrds( x, y, z );

You should use:
p_myThings[3].setCoOrds(x, y, z);
And for deleting pointer arrays you should use delete[] not delete

Related

Address of local variable returned--can ignore warning without detriment but what's the proper way?

I have a class Particle:
class Particle {
private:
float x, y, z;
// ...
public:
// ...
float* getPos() {
float p[3] = {x, y, z};
return p;
}
// ...
};
I would call this method like:
Particle a = Particle();
// ...
float* pos = a.getPos();
And then reference the position elements with pos[0] through pos[2].
g++ spouts warning message as stated in the title. But the functionality is exactly how I want it: returning an array. Why does the warning exist and is there a "proper" way to do it?
You can't return a C-array like that, return std::array instead:
std::array<float, 3> getPos() {
std::array<float, 3> p = {x, y, z};
return p;
}
You'll need to include <array> for that.
Personally, I'd skip std::array/std::vector here, because in your particular case, the position of each value imposes independent meaning. In general, sequence types have ordering, tuples have structure; if the element count is fixed (and often heterogeneous) and sorting (or otherwise reordering the values) is intrinsically nonsensical (e.g. in the case of a coordinate, swapping the x and y values changes the meaning), then a tuple makes more sense.
In this case, you could just declare:
std::tuple<float, float, float> getPos() {
// C++17 or higher allows list initialization
return {x, y, z};
// Pre-C++17 you use the std::make_tuple helper
return std::make_tuple(x, y, z);
}
The advantage here is that you can then unpack the result in the caller easily, either with std::tie:
float x, y, z;
std::tie(x, y, z) = a.getPos();
or on C++17 or higher with structured bindings, it's even nicer, since you can declare and initialize the variables with auto, rather than declaring with explicit types, then reassigning with tie:
auto [x, y, z] = a.getPos();
You can store the tuple itself and use std::get if you prefer, but unpacking to useful names rather than obscure std::get indices usually makes for much cleaner code.
You're not returning an array. It's impossible to return an array in C++. You're returning a pointer to an array which no longer exists. Hence the warning.
You could make the array a part of your class and return a pointer to that. In general I wouldn't call that good design
class Particle {
private:
float pos[3];
// ...
public:
// ...
float* getPos() {
return pos;
}
// ...
};
You could return a vector<float> instead. You could return an array<float,3> instead. You could ask yourself why you need this.
p[3] will be destroyed when it goes out of scope so you shouldn't return a pointer to it.
Either return a std::array<float, 3> by value or consider making a class for positions too, and return a Position object, or a reference to it. Example:
struct Position {
float x, y, z;
};
class Particle {
private:
Position m_pos;
// ...
public:
// ...
Position const& getPos() const { return m_pos; }
// ...
};
I'd suggest that you're function is indicative of poor design. Provide getter methods an allow the user of your class to access member variables:
class Particle {
private:
float x, y, z;
public:
float GetX() const { return x; }
float GetY() const { return y; }
float GetZ() const { return z; }
};
Given const Particle a this will let you initialize an array as follows: const float pos[] = { a.GetX(), a.GetY(), a.GetZ() }
Creating a Particle method to allow the user to populate a float[] will encourage the user toward one of the following bad practices:
float* Particle::GetPos() const { return new[3]{ x, y, z }; } creates dynamic memory without clearly informing the caller that the memory needs to be released
array<float, 3U> Particle::GetPos() const { return { x, y, z }; } requires the allocation and creation of a temporary to populate a float[]
void Particle::GetPos(float* param) const { param[0] = x; param[1] = y; param[2] = z; } misses the opportunity for constant arrays and incurs potential caller misuse, as it's not clear that param must have room for at least 3 floats

Pointer arguments in void function returning inconsistent values

This might be a stupid simple thing I'm overlooking, but I am setting values in the Data::Data(char *DataType...) function as they are being passed in, and as I hover over them, they are setting fine (the variables type, material, ID, unit, reading when hovered over are what they should be).
However, when the getData function is called below, when I hover over the pointer arguments(*type, *materials.. etc) they are set to random strings like directory names and file names. I'm not sure why this is happening, because when the variables are being set above they are right.
I've included the header and implementation files for the Data class, where all of these functions are defined, but If I need include where they are being called please let me know, the only reason I didn't is because the calls are short and files are filled with other irrelevant stuff. Thanks
Data.cpp
#include "Data.hpp"
Sensor::Sensor(char *DataType, char *Material, int ID, char *Sensor, double Min, double Max) {
strcpy(type, Type);
strcpy(material, Material);
ID = SIDs;
strcpy(unit, Units);
max = Maxs;
min = Mins;
}
Sensor::Sensor() {}
double Data::generateData() {
reading = min + (rand() % (int)(max - min + 1));
return reading;
}
void Data::getData(char *type, char *material, int *ID, char *unit, double *reading) {
return;
}
Data::~Data(){}
Data.hpp
#ifndef Data_hpp
#define Data_hpp
#include
#include
#include
using namespace std;
class Data
{
public:
Data();
Data(char *Type, char *Material, int ID, char *Unit, double Min, double Max);
~Data();
void getData(char *type, char *material, int *ID, char *unit, double *reading);
private:
char type[32];
char material[32];
int ID;
int reading;
char unit[32];
double min;
double max;
double generateData();
};
#endif
Your implementation of Sensor::getData does not do what you think it does.
Let's look at this class:
class Foo
{
void getX(int* x)
{
}
int* x;
};
Within getX, the parameter x hides the member x of the same name. This function does literally nothing: A user passes a pointer to an int, which gets the name x in this function. The member is not automatically copied into there (which would be surprising, since you could name the parameter anything else). If you want to do that, you must do it explicitly:
void getX(int* x)
{
*x = *this->x; // Pointed-to value is copied
//x = this->x; // Pointer is copied
}
If you do not set the function parameter to anything, the pointer will keep pointing to random garbage in memory, which is what you are seeing in your debugger.
The more common way to denote "this parameter will be changed/set by this function" is passing a reference:
class Foo
{
void get(char*& x, int*& y, double& z)
{
x = this->x; // Now both parameter and member point to the same location.
y = this->y; // Now both parameter and member point to the same location.
z = this->z;
}
char x[32];
int* y;
double z;
};
Or, if you don't want to copy the pointers but the pointed-to values:
void get(char* x, int* y, double& z)
{
strcopy(x, this->x);
*y = *this->y;
z = this->z;
}
(PS: I recommend using std::string instead of char arrays if your use case allows for it.)
You uninitialized arguments are set to random garbage no matter if you call getData() or not. Try to print them out without calling getData() and see.

creating arrays of objects that store arrays attributes

Shape.h
class Shape {
private:
string name;
public:
Shape(name);
string getName();
void setName(string);
};
Triangle.h
class Triangle: public Shape {
private:
int x;
int y;
public:
Triangle(name,int[3],int[3]);
int getX();
int getY();
void setX(int);
void setY(int);
};
Triangle.cpp
Triangle::Triangle(string name,int _x[],int_y[]):Shape(name) {
x[] = _x[];
y[] = _y[];
}
int Square::getX() {
return x
}
int Square::getY() {
return y;
}
void Square::setX(int _x) {
x = _x;
}
void Square::setY(int _y) {
y = _y;
}
i need to create triangle that takes in name and 3 points of (x,y). when i try to create an array of triangle on the main Triangle Tri[50]; i got the following errors
Triangle::Triangle(std::string,int*,int*)
candidates expects 3 arguments, 0 provided
Triangle::Triangle(const Triangle&)
candidates expects 1 argument, 0 provided
can pls help me check what is wrong with my constructor?? is it because i am creating an array of objects that store arrays of x and y? so i need to use references and pointers for it?
When you create
Triangle Tri[50];
it will try to call the default constructor to initialize those elements in your Tri array, however, you did not provide such a default constructor and you did not call the constructor with 3 parameters, therefore, compiler complains.
Meanwhile, you seems to try to directly initialize one array with another inside the constructor of Triangle:
Triangle::Triangle(string name,int _x[],int_y[]):Shape(name) {
x[] = _x[];//^^I don't understand how this will work in practice.
y[] = _y[];
}
There is no direct assignment on arrays in C++, though C++ std::array (since C++11) has overloaded operator=, but this is not true for regular array.

Create an array of an array of structs?

this question is regarding the syntax of an array of array of structs.
I have a struct that takes in two ints:
struct point
{
int x, y;
};
I have created another struct that takes in 8 of these structs:
//Creating an Array of Array of structs
struct Arraypoint
{
point variable[8];
};
//Not sure if this is the correct way to do it.
Now, in main, I want to declare an array variable of type Arraypoint with 8 indices, so effectively I will have 8 * 8 = 64 elements of struct point and 128 ints (64 x and 64 y).
Also, how would I access an individual element struct point from the array Arraypoint?
Okay after having declared in main lets say Arraypoint is 2.
Arraypoint arr[2];
How do I initialize the elements without having to type in arr[0].variable[0].x = ... or without using for loops.
Why can't I do the following, it doesn't seem to work.
Arraypoint arr[2] = { {(x,y),(x,y),(x,y),(x,y),(x,y),(x,y),(x,y),(x,y)},
{(x,y),(x,y),(x,y),(x,y),(x,y),(x,y),(x,y),(x,y)} }//xy are rand
I have used curly braces in my code, the error returned is missing braces around initializer for type point and too many initializers for type Arraypoint.
In C++, you'd just write:
Arraypoint arr[8];
An individual point could then be accessed via:
arr[i].variable[j];
More practically, though, you'd probably be better off using e.g.
std::vector<std::vector<point> >
or writing your own class with an overloaded operator(int i, int j). For example:
class PointMatrix
{
private:
std::vector<point> m_points;
public:
PointMatrix() : m_points(64) {}
point& operator()(int i, int j) { return m_points[8 * i + j]; }
const point& operator()(int i, int j) const { return m_points[8 * i + j]; }
};
PointMatrix mat;
m(3, 4).x = 23;
got it: ideone.com/ix3hC. Arraypoint::variable has to have it's own { } pair.
struct point
{
int x, y;
};
#define P {0, 0}
struct Arraypoint
{
point variable[8];
};
#define V { P, P, P, P, P, P, P, P}
#define AP { V } //this is the pair you missed
int main() {
Arraypoint arr[2] = { AP, AP };
}
struct Arraypoint arraypoints[8];
is what you're after, I think. To use them:
int firstx = arraypoints[0].variable[0].x;
This isn't so pretty though
struct point { int x, y; };
struct point[8][8] arraypoints;
Is probably better? Don't know what exactly you're after though.
To create an array of Arraypoints, you can do:
Arraypoint arr[8];
To access an element:
arr[i]
will return the i'th Arraypoint element
arr[i].variable[j]
will return the j'th point in the element
arr[i].variable[j].x
will return the x coordinate of that point.
So I realized why I couldn't declare my array as such,
Arraypoint arr[2] = { {(x,y),(x,y),(x,y),(x,y),(x,y),(x,y),(x,y),(x,y)},
{(x,y),(x,y),(x,y),(x,y),(x,y),(x,y),(x,y),(x,y)} }
//xy are randomn integer values
its because in my struct declaration of Arraypoint, it takes in 8 elements of type point. So
I have to create variables of type point to store(x,y) and then i could store this variable in Array point.
point point1 = {x,y}, ...;
Arraypoint arr[2] = { {point1,point2,point3,point4,point5,....} };
Just for anyone in the future who stumbles across the same problem.

a nicer way to create structs in a loop

I haven't coded in C++ in ages. And recently, I'm trying to work on something
involving structs. Like this
typedef struct{
int x;
int y;
} Point;
Then in a loop, I'm trying to create new structs and put pointers to them them in a list.
Point* p;
int i, j;
while (condition){
// compute values for i and j with some function...
p = new Point;
p* = {i, j}; //initialize my struct.
list.append(p); //append this pointer to my list.
}
Now, my question is it possible to simplify this? I mean, the pointer
variable *p outside of the loop and calling p = new Point inside the loop.
Isn't there a better/nicer syntax for this?
Sure:
Point * p = new Point;
You should probably also give your Point class a constructor:
struct Point { // note no need for typedef
int x;
int y;
Point( int ax, int ay ) : x( ax ), y( ay ) {}
};
so that you can say:
Point * p = new Point( i, j );
You may also want to make your list a list of Point values, rather than pointers, in which case you can avoid using dynamic allocation with new - always something to be avoided wherever possible in C++.
The struct can have a constructor like:
struct Point{
Point(int ax, int ay):x(ax), y(ay){}
int x;
int y;
};
and then the function can look like:
int i, j;
while (condition)
{
list.append(new Point(i,j));
}
As structs are classes with public members by default, you could even create a constructor within the struct and initialize your point object within the loop like this:
Point* p = new Point(i,j);
I would venture a guess that it is extremely unlikely you really need to allocate something like a Point dynamically.
Most likely you want to add a constructor and store them by value:
list<Point> list;
list.append(Point(x, y));
I recommend the Factory approach. Assuming that "Point" will be the base class of many objects, you can have a "Factory" that would return pointers.
Ex:
struct Point
{
Point(int mx, int my):x(mx),y(my) {}
int x;
int y;
};
// Circle, Polygon, etc.
class Factory
{
public:
static Point *getPoint(int mx, int my) { return new Point(mx, my); }
// Circle, Polygon, etc
};
Then in code someplace:
while(cond)
{
list.append(Factory::getPoint(i, j));
}