Returning Arrays from functions in C++ - c++

Good day :) I am working on a code for obtaining pitch, yaw and roll angles from an Accelerometer and a Gyroscope. To create a cleaner looking code that is easy to follow, I resorted to creating two different functions. One for the gyroscope that calculates the Pitch Yaw and Roll, and another for the accelerometer which also does the same thing.
float *readGyro(){
/*get data from sensor here*/
float gyroAngles[4]={gyroPitch,gyroRoll,gyroYaw};
float* gyroPRY=gyroAngles;
return gyroPRY;
}
float *readAccel(){
/*get data from sensor here*/
float accelAngles[4]={accelPitch,accelRoll,accelYaw};
float* accelPRY=accelAngles;
return accelPRY;
}
As you can see above, I stored the outputs of the functions into an array to be passed onto the main function. Basically the pointer is passed. However upon accessing the values from the pointer passed, constant junk values (not changing as I move the IMU) were printed instead (eg. 2.38221e-44 and -3.84146e-06). I checked the output of the functions for the gyro and the accelerometer by printing the values within those functions and they were fine.
int main(void){
float *accelData;
float *gyroData;
while(1){
accelData=readGyro();
gyroData=readAccel();
float accelPitch=*(accelData);
float accelRoll=*(accelData+1);
float accelYaw=*(accelData+2);
float gyroPitch=*(gyroData);
float gyroRoll=*(gyroData+1);
float gyroYaw=*(gyroData+2);
cout << "AccelPitch=" << accelPitch <<endl;
cout << "AccelRoll=" << accelRoll <<endl;
cout << "AccelYaw=" << accelYaw <<endl;
cout << "GyroPitch=" << gyroPitch <<endl;
cout << "GyroRoll=" << gyroRoll <<endl;
cout << "GyroYaw=" << gyroYaw <<endl;
}
}
I could not find what I did wrong with my code. Prior to this I consulted many references. However I still couldn't solve it. Your help would be very appreciated :)

C++'s built-in arrays are inherited from C, and don't necessarily work the way most people expect. Let's say you have a function like this:
float* get_vec() {
float vec[3] = { 1.0f, 2.0f, 3.0f };
return vec;
}
what this actually does is return the address of the stack-allocated variable vec; unfortunately vec will go out of scope when the function ends, and the returned address will be meaningless.
The way round this is to wrap the array up in a struct, which can be returned by value. You can either define your own, or use std::array from the C++ standard library, like so:
std::array<float, 3> get_vec() {
std::array<float, 3> vec = { 1.0f, 2.0f, 3.0f };
return vec;
}

What you are doing is returning the address of the array that is local to the function which gets destroyed when the function exits.
If you want an array for indexing reasons then I would recommend using std::array.
std::array<float, 3> readGyro() {
/*get data from sensor here*/
return {gyroPitch, gyroRoll, gyroYaw};
}
But better would be to use a struct like this.
struct angles
{
float pitch;
float roll;
float yaw;
};
angles readGyro() {
/*get data from sensor here*/
return {gyroPitch, gyroRoll, gyroYaw};
}

What you are doing will never work, as you are returning a pointer onto the stack of readGyro and readAccel. When those functions exit, that part of the stack is reclaimed and you are left with undefined behaviour.
One way would be to allocate the array and return it, but then you burden yourself with having to delete that allocation as well.
You could create 2 structs for the required parameters and pass them into your functions. That way the functions can write somewhere that will persist after they return.
e.g.
#include <iostream>
using std::cout;
using std::endl;
struct gyro_data_t
{
float pitch;
float roll;
float yaw;
};
struct accel_data_t
{
float pitch;
float roll;
float yaw;
};
void readGyro(gyro_data_t* gd)
{
/*get data from sensor here*/
gd->pitch = 1.0f;
gd->roll = 1.1f;
gd->yaw = 1.2f;
}
void readAccel(accel_data_t* ad)
{
/*get data from sensor here*/
ad->pitch = 1.0f;
ad->roll = 1.1f;
ad->yaw = 1.2f;
}
int main(void)
{
accel_data_t accelData;
gyro_data_t gyroData;
while(1)
{
readGyro(&gyroData);
readAccel(&accelData);
cout << "AccelPitch=" << accelData.pitch << endl;
cout << "AccelRoll=" << accelData.roll << endl;
cout << "AccelYaw=" << accelData.yaw << endl;
cout << "GyroPitch=" << gyroData.pitch << endl;
cout << "GyroRoll=" << gyroData.roll << endl;
cout << "GyroYaw=" << gyroData.yaw << endl;
}
}
Note how this is also more readable than your example as it names each variable explicitly, rather than expressing them as offsets from the returned value. The assignment to new variables to allow you to comprehend what the values mean is no longer required.
The two structs are actually identical and so could be condensed into one general struct if required.

Wrap array as a struct to return by value
While copying the array as data-member, the array elements will be copied one by one instead of copying the decayed pointer. This avoids returning the address of local variable.
struct float3{
float fs[3];
};
float3 readGyro(){
float3 f3 = {};
f3.fs[0] = gyroPitch;
f3.fs[1] = gyroRoll;
f3.fs[2] = gyroYaw;
return f3;
}
But using the std::array<float, 3> as other answers said is much appropriate. You don't need to invent another wheel.
Get the result via pass by reference
If you like get result through parameters, use reference instead of pointer to avoid lost the size information (decayed to pointer). This also ensures only type float[3] is passed.
void readGyro(float (&fs)[3])
{
fs[0] = gyroPitch;
fs[1] = gyroRoll;
fs[2] = gyroYaw;
}

Related

I wrote a class. And when I specified the function, it failed

class equation
{
public :
int k;
int l;
int t;
float x1_value;
float x2_value;
float b1 = sqrt(l^2 -4*k*t);
float equation1;
equation();
~equation();
};
float void equation::equation1() {
if (b1 == 0)
{
float x1_value = -l/2*k;
cout << " joongen. " <<x1_value <<endl;
}
else if (b1 > 0)
{
float x1_value = ((-l + sqrt(b1) / (2*k));
float x2_value = ((-l - sqrt(b1) / (2*k));
cout << "x is 2"<< x1_value < " x 2 is "<< x2_value <<endl;
}
else
{
cout <<"imagine number ."<<endl;
}
return (0);
};
The code produces this error:
error: two or more data types in declaration of 'equation1'
float void equation::equation1() {
^
I can make out two problems.
First you define equation1 as a member variable with type float. You might want to change that into a function declaration.
// ...
float equation1();
// ...
The second problem is pointed out in the comments. If you implement your function, you should only use one return type. As I can only guess, what return type you would really want, I take float, since it is in your faulty function declaration.
// ...
float equation::equation1() {
// ...
}
// ...
One extra thing, that disturbs me every time I see someone who is new with C++. Please, please, please, don't use using namespace std;. I assume you do so, because of the missing std::. You open up an fastly huge namespace. You may end up defining a function, with the same name and parameters and encounter a very cryptic error, which is nearly impossible to figure out.

Pointers with cout in C++

I am in the process of learning C++ and SDL, and when I tried to print the content of an array I ran into some confusion. I have an array with two values in it, 2 and 3. When I want to print the values like this:
int* test = myApp.countDivisions(5);
std::cout << "Horizontal: " << *test<< std::endl;
std::cout << "Vertical: " << *(test+1) << std::endl;
I get:
Horizontal: -858993460
Vertical: -858993460
But when I write:
int* test = countDivisions(5);
int foo = *(test);
int boo = *(test+1);
std::cout << "Horizontal: " << foo << std::endl;
std::cout << "Vertical: " << boo << std::endl;
I get:
Horizontal: 2
Vertical: 3
I am confused as to why this happens. If anyone could explain why this behaviour happens, it would be great! I am aware that I should not be using C arrays in C++, but I am still interested in understanding what is happenning here!.
Edit: I modified a typo in the first example.
Also I got asked what my countDivisions(int) function does so here is the entire code:
#include <iostream>
#include <SDL.h>
class SDLApplication {
private:
//This is the window of the application:
SDL_Window* AppWindow;
//This is the surface displayed by the window:
SDL_Surface* WindowSurface;
SDL_Renderer* Renderer;
//This is the name of the App:
std::string AppName;
//These are the dimensions of the window displaying the App
int WindowWidth;
int WindowHeight;
public:
SDLApplication(std::string name) {
AppWindow = NULL;
WindowSurface = NULL;
AppName = name;
WindowHeight = 0;
WindowWidth = 0;
Renderer = NULL;
}
int* countDivisions(int divisions) {
//This helper functions takes as input the number of divisions on the screen and returns an array that tells
//us how many horizontal and vertical divisions we have, assuming we divide linearly starting from the right corner.
int horizontal = 0;
int vertical = 0;
int i = 0;
int divTemp = pow(2,i);
int divCount = divTemp;
int temp;
while (divCount < divisions) {
if (i % 2 == 0) {
//Our power of two is pair, so we are adding horizontal divisions
horizontal += divTemp;
}
else {
//Our power of two is odd, so we are adding vertical divisions
vertical += divTemp;
}
++i;
divTemp = pow(2,i);
temp = divCount + divTemp;
if ( temp> divisions) {
if (i % 2 == 0) {
//Our power of two is pair, so we are adding horizontal divisions
horizontal += divisions-divCount;
}
else {
//Our power of two is odd, so we are adding vertical divisions
vertical += divisions-divCount;
}
}
divCount =temp;
}
int result[] = { horizontal, vertical };
return result;
}
}
int main(int argc, char* argv[])
{
SDLApplication myApp("SDL_Test");
int* test = myApp.countDivisions(5);
std::cout << "Horizontal: " << *test << std::endl;
std::cout << "Vertical: " << *(test + 1) << std::endl;
return 0;
}
I think printing *int is undefined behaviour - it is kind of meaningless. This expression is a type. Its a bit like saying "where is human" rather then "where is the human called bob" (ok, bit of a rubbish analogy), a type does not have an address on its own.
Your second example int* test is a variable named test which has a type of int* (pointer to an integer). You set the value of the pointer test to something (whatever myApp.countDivisions(5); returns - you should tell us what that returns).
Then:
int foo = *(test);
int boo = *(test+1);
foo is an integer variable that you set to the value of what test points to - and not the address itself. boo is set to the contents of the next address (address of test + 1).
If you want to print the address of the pointers you should do:
std::cout << "Horizontal: " << test << std::endl;
If you want to print the value of what the pointer is pointing to you should do:
std::cout << "Horizontal: " << *test << std::endl;
This is called dereferencing. See this little example: https://godbolt.org/z/CzHbq6
update: updated as per question update
You are returning a pointer to a local variable called result. That variable is destroyed at the end of your countDevisions() function, which will lead to undefined behaviour (which you are seeing) meaning anything can happen!. See here for an example of that with the warnings printed out: https://godbolt.org/z/gW2XS4
"A" fix for that is to change the scope of result by making its lifetime the entire life of the program, this can be done by making it static. Note I do this for demonstration only - this is not a good solution, but see it here working: https://godbolt.org/z/goQJzx
Perhaps a better solution would be to return a container from the standard template library (STL) like std::vector (something like an array): https://godbolt.org/z/3DOyhq
Or perhaps (after reading your code properly) you don't really even want an array, it seems you just want two values: vertical and horizontal. So you could define your own struct and use that - this seems more optimal: https://godbolt.org/z/RmUM39. This also makes more sense to the user of your function by being able to reference horizontal/vertical by name and not by some array index.
TLDR: "turn on warnings" and search for "c++ return multiple values"
You need to include iostream and define three classes, and fix two additional typos.
#include <iostream>
typedef int SDL_Window;
typedef int SDL_Surface;
typedef int SDL_Renderer;
This results in code that gives a useful warning message, which tells you that SDLApplication::countDivisions returns the address of a local variable or temporary. As you later attempt to use that temporary object which has gone out of scope, the result is, not surprisingly, undefined behavior.
Your function returns multiple values. You could have created an std::tuple object, but I would just define a struct so you can return one value, with named members.
struct Divisions {
int horizontal;
int vertical;
};
class SDLApplication {
...
Divisions countDivisions(int divisions) {
...
return Divisions{ horizontal, vertical };
}
};
see also
Return multiple values to a method caller
Returning multiple values from a C++ function

Initialization of a vector inside a struct

struct geopoint {
double x;
double y;
const char * description;
};
struct georectangle {
double left_x;
double bottom_y;
double right_x;
double top_y;
const char * description;
};
struct geomap {
vector < geopoint * > geopointList;
vector < georectangle * > georectangleList;
};
struct geomap * geomap_new() {
struct geomap * newGeoMap = (struct geomap * ) malloc(sizeof(struct geomap));
return newGeoMap;
}
void geomap_delete(struct geomap * m) {
printf("%lu\n", m->geopointList.size());
for (int i = 0; i < m->geopointList.size(); i++) {
free(m->geopointList[i]);
}
printf("%lu\n", m->georectangleList.size());
for (int i = 0; i < m->georectangleList.size(); i++) {
free(m->georectangleList[i]);
}
free(m);
}
int main () {
struct geomap * m = geomap_new();
assert(m);
geomap_delete(m);
}
I'm new to C++ and I'm super confused about object initialization in this language... In Java you always use the new keyword when you initialize an object not of a primitive type. In C++, it looks to me that sometimes the default constructor is automatically executed and sometimes it isn't.
In the above snippet of code through the geomap_new() function I create an instance of struct geomap which contains two vectors of pointers.
My questions are the following:
How do I initialize these two vectors to be fresh new empty vectors? In Java I would use the new keyword... Is there such thing also in C++?
I'm asking this question because if I don't initialize them in any way, when I printf the size of these two vectors in the geomap_delete function, the size of the geopointList is 0, as it should be, but the size of the georectangleList is a big random number. It looks like to me that only the first vector is being initialized.
Another question...
If a start adding a lot of stuff in the vectors, these vectors will start growing up. Is it possible that their size will become bigger than the size of the struct itself? Is the struct going to realloc?
You could simplify your code to
#include <iostream>
#include <string>
#include <vector>
struct geopoint {
double x;
double y;
std::string description;
};
struct georectangle {
double left_x;
double bottom_y;
double right_x;
double top_y;
std::string description;
};
struct geomap {
std::vector<geopoint> geopointList;
std::vector<georectangle> georectangleList;
};
int main () {
geomap m;
std::cout << "m.geopointList.size(): " << m.geopointList.size() << '\n';
std::cout << "m.georectangleList.size(): " << m.georectangleList.size() << '\n';
m.geopointList.push_back({1, 2, "Description"});
m.georectangleList.push_back({1, 2, 3, 4, "Description"});
std::cout << "m.geopointList.size(): " << m.geopointList.size() << '\n';
std::cout << "m.georectangleList.size(): " << m.georectangleList.size() << '\n';
}
to avoid such problems. Avoid dynamic memory allocation and deallocation. Don't use malloc, free, new and delete.
"How do I initialize these two vectors to be fresh new empty vectors?" The default constructor does this for you.
"Is it possible that their size will become bigger than the size of the struct itself? Is the struct going to ```realloc``" The struct has a fixed size and contains two vectors. Both vectors contain a reference/pointer to dynamic memory outside of the struct. The struct and both vectors are created on the stack (in my example code) and the dynamic memory of the vectors is on the heap.

Through what to call the method, if I already created constructor with initialization of array of structures?

I'm trying to call the method displayChoices, member of the class MachineManager through the object of the class. But I already have a constructor with initializing of the array of structures. How I understood when we create an object of the class compiler implicitly create a default constructor of the class.
Question: How to call method displayChoices?
#include "MachineManager.h"
using namespace std;
int main()
{
MachineManager mjp;
mjp.displayChoices();
return 0;
}
struct BrewInfo {
string* DrinkName;
double* Cost;
int* Number;
};
class MachineManager {
static const int Num_Drinks = 3; /// why it works only with static?!!!
BrewInfo* BrewArr[Num_Drinks];
public:
MachineManager()
{
*BrewArr[0]->Cost = 1.25;
*BrewArr[0]->Number = 20;
*BrewArr[1]->DrinkName = "pepsi";
*BrewArr[1]->Cost = 1.15;
*BrewArr[1]->Number = 17;
*BrewArr[2]->DrinkName = "Aloe";
*BrewArr[2]->Cost = 2.00;
*BrewArr[2]->Number = 15;
};
int displayChoices();
}
int MachineManager::displayChoices() // (which displays a menu of drink names and prices)
{
cout << 1;
int choice;
cout << "|1." << *BrewArr[0]->DrinkName << " |2." << *BrewArr[1]->DrinkName << " |3." << *BrewArr[2]->DrinkName << " |" << endl;
cin >> choice;
if (!choice || choice == 0) {
system("slc");
displayChoices();
}
else
return choice;
}
displayChoices has to print a menu in console.
You have a majo bug in your source code. You do not yet understand, how pointer work.
You are defining an array of pointer with BrewInfo* BrewArr[Num_Drinks];.
But these pointers are not initialized. They point to somewhere. Then you are dereferencing those pointers (pointing to somewhere) and assigning a value to somewhere in the memory.
This is a major bug.
The array dimensions for C-Sytle arrays must be a compile time constant.
You cannot write
int x=3;
unt array[x];
This is C99 code (called VLA, Variable length array), but not C++.
Solution for you problem:
Do never use C-Style arrays, like int array[5]. Use STL container like std::vector instead.
Do not use pointers.
This is your major problem. Define your array with BrewInfo BrewArr[Num_Drinks];. Please remove also the pointer from
struct BrewInfo {
string* DrinkName;
double* Cost;
int* Number;
};

Initializing a dynamic memory array in a class

I am new to c++ programming, and this is probably a trivial problem, but I need to construct a variable sized array in a class and transfer text file data into it, see below. Here HISTORYFile >> ClusterCoord[i]; seems to take in the information fine, however when I try to get access to the info in the main program via,
cout << CoordClassExample.ClusterCoord[1] << "\n";
I get a bus error. Please help if you can!
class CoordClass{
public:
int Entries;
double * ClusterCoord;
void set_valuesCoord(ifstream &HISTORYFile,int MolAtomNum, int MolNum);
};
void CoordClass::set_valuesCoord(ifstream& HISTORYFile,int MolAtomNum, int MolNum) {
Entries=MolAtomNum*MolNum;
double *ClusterCoord = new double [Entries];
for (int i=0;i<Entries;i++) {
HISTORYFile.ignore(1000,'\n');
HISTORYFile >> ClusterCoord[i];
cout << ClusterCoord[i] << "\n";
HISTORYFile.ignore(1000,'\n');
}
}
You have a leak in the set_valuesCoord() function if you call the function twice, unless you somewhere release the resources. That's not the problem but it's a problem. Use a std::vector<>.
class CoordClass {
// ...
std::vector<double> ClusterCoord; // instead of double *ClusterCoord
// ...
};
What might be the problem is that you don't check whether the double parsed properly. If it didn't then you're accessing uninitialized memory, and that leads to undefined behaviour.
void CoordClass::set_valuesCoord(...)
{
// ...
double cluster_coord = 0;
if( HISTORYFile >> cluster_coord )
ClusterCoord.push_back(cluster_coord);
else
std::cerr << "Error parsing cluster coord.\n";
// ...
}
As an exercise showing the vector way that won't leak among other things:
Further changes would be to remove Entries and use ClusterCoord.size().
class CoordClass{
public:
int Entries;
std::vector<double> ClusterCoord;
void set_valuesCoord(ifstream &HISTORYFile,int MolAtomNum, int MolNum);
};
void CoordClass::set_valuesCoord(ifstream& HISTORYFile,int MolAtomNum, int MolNum) {
Entries=MolAtomNum*MolNum;
ClusterCoord.resize(Entries);
for (int i=0;i<Entries;i++) {
HISTORYFile.ignore(1000,'\n');
HISTORYFile >> ClusterCoord[i];
cout << ClusterCoord[i] << "\n";
HISTORYFile.ignore(1000,'\n');
}
}