I have a structure which includes a string field. I create an array of those structures and then I want to pass them to a function (by reference). Everything works perfectly fine when I comment out the string field, but if I don't the program crashes. I can't find an answer to this anywhere..
Here's the code (I reduced it to only show the issue):
struct student {
int a;
int b;
string name[20];
char status;
};
void operation(student the_arr[1],int number_of_students) {
delete[] the_arr;
the_arr = new student[3];
for(int i = 0; i<3; i++) {
the_arr[i].a = i+5;
the_arr[i].b = i+4;
}
}
int main() {
student *abc;
abc = new student[0];
operation(abc, 0);
system("pause");
return 0;
}
I need the array to be dynamic so I can change its' size when I need to.
Assuming you can't use std::vector instead of dynamically allocated arrays follow the answer below. In any other case you should use the containers provided by the standard library.
Note: Your program doesn't crash. The only things the compiler will complain about it the allocating zero elements part, but will let you compile and run this program.
Your function is completely wrong. When using dynamic allocation you can simply pass a pointer like this:
void operation(student* the_arr, int number_of_students) {
Then inside your function you are dynamically allocating memory which is stored inside the the_arr pointer which is not passed by reference therefore leading to the creation of a local pointer variable that will lose the pointer after its execution:
void operation(student*& the_arr [...]
I suggest you to avoid the below solution though and return the new pointer instead:
student* operation(student* the_arr, int number_of_students) {
delete[] the_arr;
the_arr = new student[3];
[...]
return the_arr; // <----
}
Allocating abc = new student[0]; doesn't make any sense. You are trying to allocate an array of 0 elements. Maybe you meant abc = new student[1];?
You should just use the vector or other sequence objects. Though I'm not sure what you are trying to do with your code. Here's a quick example:
// Vector represent a sequence which can change in size
vector<Student*> students;
// Create your student, I just filled in a bunch of crap for the
// sake of creating an example
Student * newStudent = new Student;
newStudent->a = 1;
newStudent->b = 2;
newStudent->name = "Guy McWhoever";
newStudent->status = 'A';
// and I pushed the student onto the vector
students.push_back( newStudent );
students.push_back( newStudent );
students.push_back( newStudent );
students.push_back( newStudent );
Related
I try to make simple program that will display students names from array of objects called "Student", I know that it can be easily done using vectors but I would like to do that using dynamic array. My code:
class Student {
public:
string name;
Student(string name){
this->name = name;
}
};
void DisplayStudentsNames(Student array[],int length) {
for(int i=0;i<length;i++){
cout << array[i].name << endl;
}
}
int main(int argc, char** argv) {
Student ** array = new Student *[3];
array[0] = new Student("Michael");
array[1] = new Student("Tom");
array[2] = new Student("Timmy");
DisplayStudentsNames(*array,3);
return 0;
}
I am not sure why it does not work, it does compile but program just "stops responding" after displaying first student name. I wonder what is the issue, I have read here that if Class does not have any zero argument constructor you cannot create an array of dynamic objects dynamically, I wonder why is that? I'm just assigining new objects to pointers (in C# that's the normal way creating a class).
Your issue is here
DisplayStudentsNames(*array,3);
What you are actually passing to DisplayStudentNames() here is the first element is the array array. The issue is that array[0] is not an array, it is a pointer to a single object. Therefore when you try and iterate it you get undefined behaviour, an exception would be the best case scienorio here (as you saw with your infinite loop).
You can fix this by changing
DisplayStudentsNames(*array,3);
to
DisplayStudentsNames(array,3);
and DisplayStudentsNames to take Student**
Also this wont work:
cout << array[i].name << endl;
Each element in array is a pointer to a Student object and in C++ accessing an object through a pointer requires using the -> operator (so array[i]->name instead).
Side note:
Student(string name){
this->name = name;
}
This is bad C++, use initaliser lists for setting members on creation instead, as it allows compiler optimisations and is easier to read
//in header file(in User class):
int howManyOpponents =0;
User** userArray; //(which is initialized to userArray = new User*[5] in the constructor)
//in class file:
void User::addWin(User* aUser)
{
userArray[howManyOpponents] =aUser;
howManyOpponents++;
}
//in main file
int maximumUser = 20;
User* userList[maximumUser];
(*userList[i]).addWin(userList[j]);
codeclocks stops working, I've traced the problem to the User::addWin and tried many different referencing or pointing settings but couldn't handle it. There may be a simple bug.
Thank you.
User* userList[maximumUser];
Creates an array of maximumUser User pointers. No actual instances of User are constructed.
You then try to call a method with one of these uninitialised pointers, causing the crash:
(*userList[i]).addWin(userList[j]);
To fix, create an array of actual User instances (assuming User's constructor does not require arguments):
User userList[maximumUser];
userList[i].addWin(userList[j]);
Consider passing argument by reference instead of passing them by pointers. Try to avoid using raw poiters in your code. If you really need pointers, think about using smart pointers.
Here's a example about how to use arrays of pointers:
size_t maxUsers = 5;
size_t maxUserLen = 48;
char** UserList = 0;
// First, allocates a array of pointers
UserList = new char*[maxUsers];
// Second, allocates each pointers in the array of pointers
for(size_t i=0; i<maxUsers; i++)
{
UserList[i] = new char[maxUserLen];
memset(UserList[i], 0, maxUserLen);
}
// Add user
const char* user1 = "Mike";
const char* user2 = "James";
strcpy(UserList[0], user1); // First element in the list
strcpy(UserList[1], user2); // Second element in the list, etc...
I'm new to C++ and programming in general and am trying to learn by creating a sort of game as I go along. I can't find any information on how to achieve what I need to do.
I have created the following code, which I believe creates new objects of class Player off the heap, and creates pointers to these objects in an array.
int playerObjects(int n, int gameMode)
{
Player* playerArray = new Player[n];
for (int i = 0; i < n; i++)
{
playerArray[i].balance = 50;
playerArray[i].score = 0;
playerArray[i].playerNum = (i+1);
int m = (i+1);
playerArray[i].playerName = playerArray[i].playerN(m);
string playerNam = playerArray[i].playerName;
playerArray[i].playerAge = playerArray[i].playerA(playerNam);
playerArray[i].teamNum = 0;
}
}
where n is the number of players (from 1-4).
The class Player I have created myself:
What I now want to do is return to the calling function, main(), and still be able to access and modify these objects. I cannot figure out how. I have attempted to create pointers to each element of the array, like so:
Player** pOne = playerArray[0];
Player** pTwo = playerArray[1];
Player** pThree = playerArray[2];
player** pFour = playerArray[3];
which I think declares pOne to be a pointer to a pointer to an object of class Player (the array element), however, this throws the error:
cannot convert 'Player' to 'Player**' in initialization
doing it like this throws the same error, but in assignment rather than initialization (obviously):
Player** pOne;
pOne = playerArray[0];
How do I do it?
And, once I have done it, how do I then pass this from main() to other functions that also need to have access to these?
Would it be better to declare the array globally?
Thanks
The easiest way is probably to just return the pointer.
Player* playerObjects(int n, int gameMode)
{
Player* playerArray = new Player[n];
...
return playerArray;
}
Alternatively if you want to keep the return value as an int, you can pass a pointer to a pointer to the function. You can then create the array in the specified pointer.
int playerObjects(int n, int gameMode, Player** playerArray)
{
*playerArray = new Player[n];
for (int i = 0; i < n; i++)
{
*playerArray[i].balance = 50;
*playerArray[i].score = 0;
...
}
}
You can call this function by doing:
Player* playerArray;
playerObjects(n, gameMode, &playerArray)
And then access the items of playerArray as usual:
playerArray[0].xyz;
Don't forget that after you've allocated memory with with new[], you need to delete it with delete[] when you're finished with it.
The function musts to return (either as the return value or as a referenced parameter) the pointer to the first element of the created array. Thus in main you can use the pointer with the subscript operator.
Or more better approach is to use standard container std::vector<Player> and return it from the function.
playerArray[0] will return object of type Player, so typecast operation you are doing is incorrect.
If you want to use this array in main() then you can return playerArray from function playerObjects().
I'm trying to assign a node to a pointer along an array of pointers but it keeps telling me that my array was not declared in the scope. I'm totally confused on how or why so any help would be greatly beneficial! Thanks for taking the time to respond!
#include <iostream>
#include "book.h"
using namespace std;
class bookstore
{
private:
int amount = 5;
int counting = 0;
public:
bookstore()
{
bookstore *store;
store = new book*[amount];
for(int i = 0; i < amount; i++)
{
store[i] = NULL;
}
}
~bookstore(){ delete[] store; }
void addbook(string a,string b, string c, string d, string e)
{
if (counting == amount)
{
cout<<"Full House!"<<endl;
return;
}
store[counting] = new book(a,b,c,d,e);
counting++;
}
void print()
{
for(int i = 0; i < amount; i++)
{
cout<<store[i]->name<<" "<<store[i]->publisher<<" "<<store[i]->year<<" "<<store[i]->price<<" "<<store[i]->category<<endl;
}
}
};
Your pointer store is local to the default constructor. It looks like you're after a data member. Furthermore, you seem to be after an array of pointers. If so, you need bookstore needs to be a pointer to pointer:
class bookstore
{
private:
bookstore** store; // or bookstore* store
int amount = 5;
int counting = 0;
and fix the constructor to use that:
bookstore()
{
store = new book*[amount]; // or store = new book[amount]
....
Note that your class is attempting to manage dynamically allocated resources, so you will need to take care of the copy constructor and assignment operators (either make the class non-copyable and non-assignable, or implement them. The defaults are not acceptable. See the rule of three.) If you are really using an array of dynamically allocated pointers, then you need to fix your destructor too. Currently, it only deletes the array, but not the objects pointed at by the pointers in it.
The better solution would be to use a class that manages the resources for you and has the desired semantics. It is easier to have each class handle a single responsibility.
If I declare an array on the heap, how can I get information about the array?
Here is my code:
class Wheel
{
public:
Wheel() : pressure(32)
{
ptrSize = new int(30);
}
Wheel(int s, int p) : pressure(p)
{
ptrSize = new int(s);
}
~Wheel()
{
delete ptrSize;
}
void pump(int amount)
{
pressure += amount;
}
int getSize()
{
return *ptrSize;
}
int getPressure()
{
return pressure;
}
private:
int *ptrSize;
int pressure;
};
If I have the following:
Wheel *carWheels[4];
*carWheels = new Wheel[4];
cout << carWheels[0].getPressure();
How can I get call the .getPressure() method on any instance in the array when it is on the heap?
Also, if I want to create an array of Wheel on the heap, yet use this constructor when creating the array on the heap:
Wheel(int s, int p)
How do I do this?
Wheel *carWheels[4];
is an array of pointers to Wheel, so you need to initialize it with new:
for ( int i = 0; i < sizeof(carWheels)/sizeof(carWheels[0]); ++i)
carWheels[i]=new Wheel(); // or any other c-tor like Wheel(int s, int p)
later you can access it like that:
carWheels[0]->getPressure();
size of array can be retrieved like above:
sizeof(carWheels)/sizeof(carWheels[0])
[edit - some more details]
If you want to stick to array you will need to pass its size on function call because arrays decays to pointers then. You might want to stay with following syntax:
void func (Wheel* (arr&)[4]){}
which I hope is correct, because I never use it, but better switch to std::vector.
Also with bare pointers in arrays you must remember to delete them at some point, also arrays does not protect you against exceptions - if any will happen you will stay with memory leaks.
Simple, replace
Wheel *carWheels[4];
with
std::vector<Wheel*> carWheels(4);
for ( int i = 0 ; i < 4 ; i++ )
carWheels[i] = new Wheel(4);
You seem to be confusing () and [], I suggest you look into that.
You do know that ptrSize = new int(30); doesn't create an array, right?
Like C, you will need to lug the array's element count around with your allocation.
This information is actually stored by the implementation in some cases, but not in a way which is accessible to you.
In C++, we favor types such as std::vector and std::array.
Other notes:
ptrSize = new int(30); << creates one int with a value of 30
How do I do this?
Wheel(int s, int p)
Typically, you would just use assignment if you have an existing element:
wheelsArray[0] = Wheel(1, 2);
because you will face difficulty creating an array with a non-default constructor.
and while we're at it:
std::vector<Wheel> wheels(4, Wheel(1, 2));
is all that is needed to create 4 Wheels if you use vector -- no new required. no delete required. plus, vector knows its size.