How to assign a dynamic array of pointer returned from a function, to a variable? - c++

Please have a look at the following code
Vehicle ** damagedVehicles(Vehicle **vehicles, int size)
{
Vehicle **damaged = new Vehicle *[size];
for(int i=0;i<size;i++)
{
int d = vehicles[i]->damage;
if(d>=35)
{
damaged[i] = vehicles[i];
}
}
return damaged;
}
int main()
{
Vehicle **damagedVehicles = damagedVehicles(vManager->getList(), vManager->getCount());
}
As you can see, my attemt in the main is not working. How can I assign that array of pointers to a variable?

Rename the variable so it doesn't clash with the name of the function?
Vehicle **myDamagedVehicles = damagedVehicles(vManager->getList(), vManager->getCount());

Related

How to pass array of object pointers to function?

I am having trouble passing an array of object pointers from main() to a function from different class.
I created an array of object pointers listPin main() and I want to modify the array with a function editProduct in class Manager such as adding new or edit object.
Furthermore, I want to pass the whole listP array instead of listP[index]. How to achieve this or is there any better way? Sorry, I am very new to c++.
#include <iostream>
using namespace std;
class Product
{
protected:
string id, name;
float price;
public:
Product()
{
id = "";
name = "";
price = 0;
}
Product(string _id, string _name, float _price)
{
id = _id;
name = _name;
price = _price;
}
};
class Manager
{
protected:
string id, pass;
public:
Manager(string _id, string _pass)
{
id = _id;
pass = _pass;
}
string getId() const { return id; }
string getPass() const { return pass; }
void editProduct(/*array of listP*/ )
{
//i can edit array of listP here without copying
}
};
int main()
{
int numProduct = 5;
int numManager = 2;
Product* listP[numProduct];
Manager* listM[numManager] = { new Manager("1","alex"), new Manager("2", "Felix") };
bool exist = false;
int index = 0;
for (int i = 0; i < numProduct; i++) { //initialize to default value
listP[i] = new Product();
}
string ID, PASS;
cin >> ID;
cin >> PASS;
for (int i = 0; i < numManager; i++)
{
if (listM[i]->getId() == ID && listM[i]->getPass() == PASS) {
exist = true;
index = i;
}
}
if (exist == true)
listM[index]->editProduct(/*array of listP */);
return 0;
}
Since the listP is a pointer to an array of Product, you have the following two option to pass it to the function.
The editProduct can be changed to accept the pointer to an array of size N, where N is the size of the passed pointer to the array, which is known at compile time:
template<std::size_t N>
void editProduct(Product* (&listP)[N])
{
// Now the listP can be edited, here without copying
}
or it must accept a pointer to an object, so that it can refer the array
void editProduct(Product** listP)
{
// find the array size for iterating through the elements
}
In above both cases, you will call the function as
listM[index]->editProduct(listP);
That been said, your code has a few issues.
First, the array sizes numProduct and numManager must be compiled time constants, so that you don't end up creating a non-standard variable length array.
Memory leak at the end of main as you have not deleted what you have newed.
Also be aware Why is "using namespace std;" considered bad practice?
You could have simply used std::array, or std::vector depending on where the object should be allocated in memory. By which, you would have avoided all these issues of memory leak as well as pointer syntaxes.
For example, using std::vector, you could do simply
#include <vector>
// in Manager class
void editProduct(std::vector<Product>& listP)
{
// listP.size() for size of the array.
// pass by reference and edit the listP!
}
in main()
// 5 Product objects, and initialize to default value
std::vector<Product> listP(5);
std::vector<Manager> listM{ {"1","alex"}, {"2", "Felix"} };
// ... other codes
for (const Manager& mgr : listM)
{
if (mgr.getId() == ID && mgr.getPass() == PASS)
{
// ... code
}
}
if (exist == true) {
listM[index]->editProduct(listP);
}
You cannot have arrays as parameters in C++, you can only have pointers. Since your array is an array of pointers you can use a double pointer to access the array.
void editProduct(Product** listP){
and
listM[index]->editProduct(listP);
Of course none of these arrays of pointers are necessary. You could simplify your code a lot if you just used regular arrays.
Product listP[numProduct];
Manager listM[numManager] = { Manager("1","alex"), Manager("2", "Felix")};
...
for(int i = 0; i < numManager; i++ ){
if(listM[i].getId() == ID && listM[i].getPass() == PASS) {
exist = true;
index = i;
}
}
if(exist == true){
listM[index].editProduct(listP);
}

Can't modify a string in C++ array

Trying to learn datastructures, I made this class for a stack. It works just fine with integers but it throws a mysterious error with strings.
The class List is the API for my stack. Its meant to resize automatically when it reaches the limit. The whole code is just for the sake of learning but the error I get doesn't make any sense and it happens somewhere in some assembly code.
#include <iostream>
#include<string>
using namespace std;
class List {
private:
int N = 0;
string* list = new string[1];
void resize(int sz) {
max = sz;
string* oldlist = list;
string* list = new string[max];
for (int i = 0; i < N; i++) {
list[i] = oldlist[i];
}
}
int max = 1;
public:
void push(string str) {
if (N == max) {
resize(2 * N);
}
cout << max << endl;
list[N] = str;
N++;
}
void pop() {
cout << list[--N] << endl;
}
};
int main()
{
string in;
List list;
while (true) {
cin >> in;
if (in == "-") {
list.pop();
}
else {
list.push(in);
}
}
}
string* list = new string[max]; in the resize method defines a new variable named list that "shadows", replaces, the member variable list. The member list goes unchanged and the local variable list goes out of scope at the end of the function, losing all of the work.
To fix: Change
string* list = new string[max];
to
list = new string[max];
so that the function will use the member variable.
Don't forget to delete[] oldlist; when you're done with it to free up the storage it points at.

How to return an array in method decleration using C++?

I am trying to write C++ code suitable for object oriented programming.
I have two classes, namely, Student and Course. In the Student class, I have quiz_scores which is a 1-D array of 4 integers. I need both set and get methods, both are used in natural common way.
In the following, I implement setQuizScores method:
void Student :: setQuizScores(int* quizscores){
for(int i = 0; i<4; i++){
quiz_scores[i] = quizscores[i];
}
Where quizscores are my private members.
Now, next thing is that I want to return this quiz_scores array in the getQuizScores for each students of Student class.
However, the problem is that C++ does not allow us to return arrays directly. Instead, I want the structure of my code as following:
int Student :: getQuizScores(){
Do something;
return the elements of quiz_scores;
}
How can I do that efficiently?
I prefer not to use the Standard Template Library (STL), so I need to create my own arrays and access them according to the explanation above.
There are a few ways how you could return an array:
Pass in an array to copy to
void Student::getQuizScores(int* out) {
for(int i = 0; i < 4; i++)
out[i] = quiz_scores[i];
}
Student student;
int scores[4];
student.getQuizScores(scores);
// use scores[0], etc...
return a struct containing the array
struct Scores {
int values[4];
};
Scores Student::getQuizScores() {
Scores s;
for(int i = 0; i < 4; i++)
s.values[i] = quiz_scores[i];
return s;
}
Student student;
Scores s = student.getQuizScores();
// use s.values[0], etc...
return a reference to the quiz_scores array inside the class
using Scores = int[4];
Scores const& Student::getQuizScores() const {
return quiz_scores;
}
Student student;
Scores const& scores = student.getQuizScores();
// use scores[0], etc...
Just as setQuizScores() is able to take a pointer to an array, so too can getQuizScores() return a pointer to the quiz_scores member array, eg:
const int* Student::getQuizScores() const {
// do something...
return quiz_scores;
}
The caller can then access the array elements as needed, eg:
Student s;
...
const int *scores = s.getQuizScores();
for(int i = 0; i < 4; ++i){
cout << scores[i] << ' ';
}
Alternatively, since the array is fixed size, you can return a reference to the array instead, eg:
typedef int scoresArr[4];
scoresArr quiz_scores;
...
const scoresArr& Student::getQuizScores() const {
// do something...
return quiz_scores;
}
Student s;
...
const scoresArr &scores = s.getQuizScores();
for(int i = 0; i < 4; ++i){
cout << scores[i] << ' ';
}
You can return a pointer to the quiz_scores array through getQuizScores method as shown below:
Version 1: Using trailing return type
auto getQuizScores() -> int(*)[4]
{
//Do something;
return &quiz_scores;//NOTE THE & INFRONT OF quiz_scores
}
Now you can use this returned pointer to initialize other arrays. One possible example would be:
#include <iostream>
struct Student
{
int quiz_scores[4]= {1,2,3,4};
//getQuizScores returns a pointer to an array of size 4 with element of type int
auto getQuizScores() -> int(*)[4]
{
//Do something;
return &quiz_scores;//NOTE THE & INFRONT OF quiz_scores
}
void setQuizScores(int* quizscores)
{
for(int i = 0; i<4; i++)
{
quiz_scores[i] = quizscores[i];
}
}
};
int main()
{
Student s;
int arr[4];
for(int i = 0; i< 4; ++i)
{
arr[i] = (*s.getQuizScores())[i];
std::cout<<arr[i]<<std::endl;
}
return 0;
}
Version 2: Without using trailing return type
int (*getQuizScores())[4]
{
//Do something;
return &quiz_scores;//NOTE THE & INFRONT OF quiz_scores
}
Version 2 is the same as version 1 except that this time the getQuizScores method does not uses trialing return type.
There are other possibilities also like returning a reference to the quiz_scores array.

Segmentation Fault 11 in C++ when accessing second element in array

In short, I have a C++ program that consists of a Car class with subclasses SportsCar and SUV, as well as a CarInventory that stores the Car objects.
I think the problem is in the insert function
void CarInventory::insert(Car *car) {
for (int i = 0; i < inventorySize; i++) {
if (carArray[i]) {
i++;
}
When you find a car already in in your carArray you increment i, but then you increment i again in the for-loop. That way you will skip every other position in the array, and they will remain uninitialized.
You allocated an array of 10 cars. But you only initialized it with 4 cars.
So when your loop in displayVehichles gets around to accessing carArray[5] it will likely be accessing uninitialized memory.
This statement seems troublesome:
carArray = new Car *[maxStock];
It should probably be:
carArray = new Car *[maxStock];
for (int i = 0; i < maxStock; i++)
{
carArray[i] = NULL;
}
totalNumCars = 0;
That way, your insert method will behave correctly. But your insert method could be much simpler:
void CarInventory::insert(Car *car) {
if (totalNumCars < maxStock)
carArray[totalNumCars] = car;
totalNumCars++;
}
}
Further, while it's OK the way you have it the cars you have declared go out of scope BEFORE your CarInventory goes out of scope, it will be referencing Car objects that have already been deleted.
Use std::vector to hold your cars:
class CarInventory
{
std::vector<Car*> _cars;
public:
void displayVehicles()
{
for (auto i = _cars.begin(); i != _cars.end(); i++)
{
i->printInfo();
}
}
void insert(Car* car)
{
_cars.push_back(car);
}
};
Now that still doesn't solve the problem of your CarInventory class holding onto pointers of stack objects.
This is even better:
class CarInventory
{
std::vector<std::shared_ptr<Car>> _cars;
public:
void displayVehicles()
{
for (auto i = _cars.begin(); i != _cars.end(); i++)
{
i->printInfo();
}
}
void insert(std::shared_ptr<Car>& spCar)
{
_cars.push_back(spCar);
}
};
Then your code to use the class:
std::shared_ptr<Car*> createCar(const char* vin, const char* make, const char* color, int year)
{
Car* car = new Car(vin, make, color, year);
return std::shared_ptr<Car>(car);
}
int main(int argn, char *argv[])
{
CarInventory cars;
std::shared_ptr<Car*> toyota = createCar("2GCGC34M9F1152828", "Toyota", "Camry", "Green", 2012);
std::shared_ptr<Car*> honda = createCar("1C4BJWAG4DL602733", "Honda", "Civic", "Blue", 2015);
...
CarInventory cars;
cars.insert(toyota);
cars.insert(honda);
cout << "\n";
cars.displayVehicles();
}

Expand and add a new object to a array inside a function

I'm trying to expand and add a new object to a array inside a function and have that array be effected outside the function as well (the arrays pointer is sent as a parameter).
void addMedia(Media* medias[], int &nrOfMedias, string title, int publYear, string author, int nrOfPages)
{
Media** tempArray = new Media*[nrOfMedias +1];
for(int i = 0; i < nrOfMedias; i++)
{
tempArray[i] = medias[i];
}
delete [] medias;
medias = tempArray;
delete [] tempArray;
medias[nrOfMedias] = new Book(title, publYear, author, nrOfPages);
nrOfMedias++;
}
This code works great inside the function but when I get outside it the array is still empty. As i understand this it's because the pointer is changed inside the function but how can i expand the array without having it change the pointer?
(I can not change the return data type or the parameters, assignment requirements.)
Do change medias = tempArray; to *medias = tempArray;, make it compile, polish your memory management (consider, what really should be freed, what not).
Don't view medias as an array of pointers, view it as a pointer to an array. Working example (slightly simplified):
class Media
{
public:
Media () { m_strTitle = "unknown";}
string m_strTitle;
};
class Book : public Media
{
public:
Book(string strTitle) { m_strTitle = strTitle; }
};
void addMedia(Media* medias[], int &nrOfMedias)
{
Media * tempArray = new Media[nrOfMedias +1];
for(int i = 0; i < nrOfMedias; i++)
{
tempArray[i] = (*medias)[i];
}
delete [] *medias;
(*medias) = tempArray;
(*medias)[nrOfMedias] = Book("newTitle");
nrOfMedias++;
}
int main()
{
int numMedia = 10;
Media * myArray = new Media[numMedia];
addMedia(&myArray, numMedia);
for (int i = 0; i < numMedia; i++)
{
cout << i << ") " << myArray[i].m_strTitle << endl;
}
return 0;
}
You don't need delete [] tempArray; because tempArray actually points to the same memory block as medias does after medias = tempArray;
Your function will work well whithout that line but I assume that you know what you pass with Media* medias[]