I want to have a function that initializes simple Grid (2d array) with Columns and Rows, each position (cell) is then the size of struct.
I found a solution that accomplishes this in main function but when done in any other function, after running half-way through it crashes with segmentation fault before it prints the Grid (unlike in the last paragraph).
However, if printing the Grid is added directly behind the initializing part, the code works normally afterwards and all faults disappear.
I suspect that main does not now that Position array was initialized but I am passing it as pointer so, what am I doing wrong?
The following code is divided to two parts. First has the segmentation fault, second does not. The only difference is that in the second part, the for-cycles for printing out the grid are inside function that initializes the 2d array.
//SEGMENTATION FAULT
void CreateMap (struct GameGrid *Position, int &Dim_x, int &Dim_y)
{
cout << "Lets create the game map." << endl;
cout << "Enter number of Columns: ";
cin >> Dim_x;
cout << "Enter number of Rows: ";
cin >> Dim_y;
Position = new GameGrid[Dim_x * Dim_y];
}
int main()
{
struct GameGrid *Position = NULL;
int Dim_x;
int Dim_y;
CreateMap(Position, Dim_x, Dim_y);
for (int y=0; y < Dim_y; y++)
{
cout << setw (20);
for (int x=0; x < Dim_x; x++)
{
cout << Position[x*Dim_y + y].Element;
cout << char(32);
}
cout << endl;
}
delete[] Position;
return 0;
}
//NO FAULTS
void CreateMap (struct GameGrid *Position, int &Dim_x, int &Dim_y)
{
cout << "Lets create the game map." << endl;
cout << "Enter number of Columns: ";
cin >> Dim_x;
cout << "Enter number of Rows: ";
cin >> Dim_y;
Position = new GameGrid[Dim_x * Dim_y]
for (int y=0; y < Dim_y; y++)
{
cout << setw (20);
for (int x=0; x < Dim_x; x++)
{
cout << Position[x*Dim_y + y].Element;
cout << char(32);
}
cout << endl;
}
}
int main()
{
struct GameGrid *Position = NULL;
int Dim_x;
int Dim_y;
CreateMap(Position, Dim_x, Dim_y);
delete[] Position;
return 0;
}
The Grid should look something like this for dimensions Dim_x=6 and Dim_y=6 (chosen by end-user).
A A A A A A
A A A A A A
A A A A A A
A A A A A A
A A A A A A
A A A A A A
Also when the printing the grid is done two times (once in the function CreateMap and once in main), it prints them both times, then freezes for 10 secs and dies.
In your CreateMap function:
void CreateMap (struct GameGrid *Position, int &Dim_x, int &Dim_y)
{
// ...
Position = new GameGrid[Dim_x * Dim_y];
}
This modifies the Position local variable only, it does not alter the caller's value supplied to that argument.
What you need is to re-work this:
GameGrid *CreateMap(const int Dim_x, const int Dim_y)
{
// ...
return new GameGrid[Dim_x * Dim_y];
}
Where that returns a value you can capture:
int main()
{
int x, y;
cout << "Lets create the game map." << endl;
cout << "Enter number of Columns: ";
cin >> x;
cout << "Enter number of Rows: ";
cin >> y;
GameGrid *Position = CreateMap(x, y);
// ...
}
Do all your input/output outside of these functions. Remember your SOLID Principles, give that function one job and one job only. Input and allocation are two jobs.
Even better: Make a constructor instead of these CreateX functions. This is C++ and you can take full advantage of that.
As always:
Whenever you're having strange behaviour, step through your code in a debugger to see what the values of various variables are as it executes.
Although you're using a pointer as a parameter, you are still passing-by-value.
When trying to pass-by-reference the pointer itself is not changed but the object at the address it points to is updated.
So to update the pointer you need a pointer to the pointer or a reference to a pointer. Otherwise, often as has been answered, the return is used to return an updated pointer.
Related
I am getting error from cin >> theGift.m_wrap[i].m_pattern; part. I am new to C++. How do I store the patterns that the user enters? For example:
Enter wrapping pattern #1: Spots
Enter wrapping pattern #2: Stripes
Enter wrapping pattern #3: Zigzags
also, how would I access these?
struct Wrapping {
char m_pattern[MAX_WRAP];
};
struct Gift {
char m_description[MAX_DESC + 1];
double m_price;
int m_units;
int m_wrapLayers = 0;
Wrapping* m_wrap = new Wrapping[m_wrapLayers];
};
bool wrap(Gift& theGift){
if (theGift.m_wrapLayers == 0) {
cout << "Wrapping gifts..." << endl;
do {
cout << "Enter the number of wrapping layers for the Gift: ";
cin >> theGift.m_wrapLayers;
}while ((theGift.m_wrapLayers <= 0) && cout << "Layers at minimum must be 1, try again." << endl);
for (int i = 0; i < theGift.m_wrapLayers; i++) {
cout << "Enter wrapping pattern #" << i + 1 << ": ";
cin >> theGift.m_wrap[i].m_pattern;
}
return true;
}else {
cout << "Gift is already wrapped!" << endl;
return false;
}
}
Wrapping* m_wrap = new Wrapping[m_wrapLayers];
This line heap-allocates an array of zero elements because m_wrapLayers is zero at the moment this allocation happens. You never reallocate the array, so attempting to access any element of this array is undefined behavior since no elements exist.
You should be using std::vector which is a dynamically-sized container that does all of the following for you:
Makes a memory allocation to hold elements.
Reallocates when attempting to add an element to a full vector, copying over the old values.
Copies itself properly.
Deallocates memory when it's destroyed.
Right now you only do the first step, and you make an allocation that can't hold anything.
Vectors also know how many elements they hold, so you don't need to track that separately.
Additionally, you should use std::string instead of character arrays for strings. std::string is much like a vector of chars; it will grow as necessary.
I would redefine your types like this:
struct Wrapping {
std::string m_pattern;
};
struct Gift {
std::string m_description;
double m_price;
int m_units;
std::vector<Wrapping> m_wrap;
};
Then your code to populate the vector goes like this:
int layers;
do {
cout << "Enter the number of wrapping layers for the Gift: ";
} while ((!(cin >> layers) || layers <= 0) && cout << "Layers at minimum must be 1, try again." << endl);
for (int i = 0; i < layers; i++) {
cout << "Enter wrapping pattern #" << (i + 1) << ": ";
theGift.m_wrap.emplace_back();
cin >> theGift.m_wrap.back().m_pattern;
}
I have a structure sportist
struct sportist{
string name;
string surname;
int goals;
string tim;
}
Here is the function that should read the values.
void read(sportist x[],int n)
{
int i;
for(i=0;i<n;i++)
{
cout<<"************************************************"<<endl;
cout<<"Name:";
cin>>x[i].name;
cout<<endl<<"Surname:";
cin>>x[i].surname;
cout<<endl<<"Goals :";
cin>>x[i].goals;
cout<<endl<<"Name of the team:";
cin>>x[i].tim;
}
My question is how can I use pointers, because I need to? My attempt:
void read(sportist* x,int n)
{
int i;
for(i=0;i<n;i++)
{
cout<<"************************************************"<<endl;
cout<<"Name:";
cin>>x->name;
cout<<endl<<"Surname:";
cin>>x->surname;
cout<<endl<<"Goals :";
cin>>x->goals;
cout<<endl<<"Name of the team:";
cin>>x->tim;
}
}
What I want is to sort the sequence of athletes and teams by the number of goals and print them on the screen to sort them in a popup order. But it shows me errors when I debug.
you should pay attention to one point when you are using array x[i] with i increasing ,you are traversing the array ,but with pointer you should move pointer so it would point to next elements of array.You should use x++;.
look:
void read(sportist* x, int n)
{
int i;
for (i = 0; i < n; i++)
{
cout << "************************************************" << endl;
cout << "Name:";
cin >> x->name;
cout << endl << "Surname:";
cin >> x->surname;
cout << endl << "Goals :";
cin >> x->goals;
cout << endl << "Name of the team:";
cin >> x->tim;
x++;
}
}
if you miss x++; each time you will write entered data in first element of array.
Also note in function you are declaring this array of sportist , if you declare sportist* x instead of sportist x[num] ,you have to allocate memory for it too.
I would like to pass dynamic arrays to functions and receive user input. Currently I'm using the following code:
#include <iostream>
using namespace std;
struct make
{
int part;
int graph;
int like;
};
int z;
int *p = new int [z];
void inpart( make x[],int *fig)
{
cout << "Input part\n";
cin >> x[*fig].part;
}
void ingraph(make x[],int *tig)
{
cout << "Input graph\n";
cin >> x[*tig].graph;
}
void inlike(make x[],int *gig)
{
cout << "Input like\n";
cin >> x[*gig].like;
}
int main()
{
cout << "Input array count\n";
cin >> z;
make p[z];
for (int i=0; i < z; i++)
{
inpart(p,&z);
ingraph(p,&z);
inlike(p,&z);
}
for (int i=0; i < z; i++)
{
cout << "the result is\n";
cout << p[z].part << ", ";
cout << p[z].graph << ", ";
cout << p[z].like << "\n";
}
}
My input 1,1,1 for all the structure objects should output 1,1,1. However, the answer I receive is 1,0,2. Why?
Firstly, you shouldn't trying to initialize a static buildin array in run-time:
Your implementation is wrong here:
cout<< "Input array count\n";
cin>>z;//initialized in run-time
make p[z]; // wrong, need to be allocated with new
make* example = new make[z]; // Ok!
Secondly, you're trying to read and write out of bounds of the created array. It's Undefined behaviour. When you're creating an array with size N, chunk of the memory will be allocated to which you can have access by index. In your case from 0 to z or [0,z), excluding z. To sum up, your cycle should look like this:
for (int i = 0; i < z; i++) {
inpart(p,&i);
ingraph(p,&i);
inlike(p,&i);
}
Actually u've made a lot of mistakes in your code, but I feel like you will understand this later when continue learning.
So, I have a hero structure that contains name, health, and attack. I'm allowing the user to enter how many heroes they want to create and create an array of that many heroes (I also had problems allowing the user to determine the array size, so the problem could be there). When trying to set the attributes using a loop of the array, I get an error: IntelliSense: no operator "[]" matches these operands. operand types are: Hero [ int ]
My question is, how do I loop through an array of a structures to set their attributes and if so, would displaying the hero's information be similar with a display function?
struct Hero
{
private:
string hName;
int hHealth;
int hAttack;
public:
void displayHeroData();
void setName(string);
void setHealth(int);
void setAttack(int);
};
void Hero::displayHeroData()
{
cout << "\n\n\n\nHERO INFO:\n" << endl;
cout << "Name: " << hName << endl;
cout << "Health: " << hHealth << endl;
cout << "Attack: " << hAttack << endl;
};
void Hero::setName(string name)
{
hName = name;
}
void Hero::setHealth(int health)
{
if(health > 0)
hHealth = health;
else
hHealth = 100;
}
void Hero::setAttack(int attack)
{
if(attack > 0)
hAttack = attack;
else
hAttack = 100;
}
int main()
{
string name;
int health;
int attack;
int num;
Hero *heroList; //declaring array
//getting size of array
cout << "How many hero's do you want to create? (greater than 0)" <<endl;
cin >> num;
heroList = new Hero[num]; //this is the array of Heroes
//looping through the array
for(int x = 0; x < num; ++x){
//creating a new hero, I think???
Hero heroList[x];
//setting hero's name
cout << "What is hero" << x <<"'s name?" << endl;
cin >> name;
heroList[x].setName(name);
//display the character after attributes have been set
heroList[x].displayCharacterData();
}//end of for loop
return 0;
}
Hero heroList[x];
Remove this line for good. no need for it.
The only problem that you will encounter after removing the line proposed (Hero heroList[x]) is that all the hero objects created aren't initialized (when you called new Hero[num] you only allocated the array and created the default implicit constructor for each one).
In order to init all of them, you must either use all your 'setters', or write a non-default constructor and then only allocate an array of Hero* ptrs, and when looping through it init each ptr to a new Hero(.....) with the parameters you wish.
Hope that helps clarify things.
In the loop just do the following
//looping through the array
for(int x = 0; x < num; ++x)
{
cout << "What is hero" << x <<"'s name?" << endl;
cin >> name;
heroList[x].setName(name);
}
for(int x = 0; x < num; ++x)
{
heroList[x].displayHeroData();
}
#include <iostream>
#include <string>
using namespace std;
struct FriendInfo
{
string name;
int last_day;
};
FriendInfo GrowArray(FriendInfo friend_list,int sizing);
int main()
{
int initial_friends;
cout << "How many friends would you like to add--> ";
cin >> initial_friends;
FriendInfo friends[initial_friends];
for (int i = 0; i < initial_friends;i++)
{
cout << "What is your friend's name?--> ";
cin >> friends[i].name;
cout << "When was the last time you talked to " << friends[i].name << " ?--> ";
cin >> friends[i].last_day;
}
for (int i = 0; i < initial_friends;i++)
cout << friends[i].name << " " << friends[i].last_day << "\n";
cout << "What would you like to do now?\n1. Add another friend?\n2. Update one of yourfriends?\n3. Sort friends by day?4. Quit.\n--> ";
int option;
cin >> option;
while (option != 4)
{
if (option == 1)
{
friends = GrowArray(friends,initial_friends);
cout << "What is your new friend's name?--> ";
cin >> friends[initial_friends].name;
cout << "When was the last time you talked to " << friends[initial_friends].name << " ?--> ";
cin >> friends[initial_friends].last_day;
}
}
}
FriendInfo GrowArray(FriendInfo friend_list, int sizing)
{
FriendInfo new_list[sizing + 1];
for (int i = 0;i < sizing;i++)
{
new_list[i].name = friend_list[i].name;
new_list[i].last_day = friend_list.last_day;
}
return new_list;
}
This program put structures into an array that hold a friend's name, and the last day they talked to them. One of the options later on is to add another friend. The function GrowArray takes the initial array with the friends and the days, makes another array with an extra spot and copies the original array into the new one. But when I use the function I get this error --> error: could not convert '(FriendInfo*)(& friends)' from 'FriendInfo*' to 'FriendInfo'. What's wrong?
You can't reassign friends like that since it's not a pointer, it's an array.
Even if you could, what you're doing isn't safe since GrowArray just creates a new array on the stack which will be destroyed when the function returns.
You should either use new and delete to create and destroy the arrays (you can then then pass them around as pointers), or preferably, use std::vector which handles all this stuff for you.