Displaying element from pointer struct - c++

I have run onto a little problem and I have looked everywhere but I believe I am looking in the wrong direction. I created an account here in hopes of solving a slight issue I have. I am in the middle of programming an RPG and when I attempt to display one characters "magic spells", I can only display [3]. [0] [1] [2] crashes my game. Game is in C++.
Example of my code below:
Create my struct:
struct Fighter {
int HP; //max 999
int maxHP;
int MP; //max 999
int maxMP;
int STR; //max 255
int CON; //max 255
int AGL; //max 100
bool dead;
const char* Magic[];
};
Fighter * player = new Fighter[5];
Initializing and assigning elements with these parameters for 4 party members:
void InitPlayer(int pClass, int p)
{
if(pClass == 0) //Knight
{
player[p].maxHP = 750;
player[p].HP = player[p].maxHP;
player[p].maxMP = 0;
player[p].MP = player[p].maxMP;
player[p].STR = 200;
player[p].CON = 0;
player[p].AGL = 35;
}
else if(pClass == 1) //Ninja
{
player[p].maxHP = 675;
player[p].HP = player[p].maxHP;
player[p].maxMP = 0;
player[p].MP = player[p].maxMP;
player[p].STR = 175;
player[p].CON = 0;
player[p].AGL = 80;
player[p].Magic[0] = "Cure";
player[p].Magic[1] = "Haste";
player[p].Magic[2] = "Sleep";
}
//... More Character code
}
Here I draw/print "Magic" to the screen:
Printf_xy(123,223,player[0].Magic[0]); //Crash
Printf_xy(123,233,player[1].Magic[0]); //Crash
Printf_xy(123,243,player[2].Magic[0]); //Crash
Printf_xy(123,253,player[3].Magic[0]); //Prints "Cure" does not crash
As you can see, it will work but only if I display player[3]. I am sure I am forgetting to do something or initializing something incorrectly. Any help would be greatly appreciated.

Magic is a zero length array - when you assign anything into it, or even try to access Magic[0] you are accessing outside of the array boundaries.
If you know the maximum number of magic entries you need, use that as your array size, something like:
const int MagicLimit = 10
...
const char* Magic[MagicLimit];
Better still, if you are using c++, use a std::vector to hold the magic strings (also use std::string), that way you can easily tell the length of the list.
For example:
std::vector<std::string> Magic;

Related

C++, Overloading, Creating functions in the class that receive an array and the size of the array as input, and find the smallest value

I am currently learning C++. I run into troubles when I work on an Overloading problem. The function in the class supposed to receive the array and size of the array as input and output the smallest value. There are three arrays in total including int, float, and char. My code works only under int. I can't understand why I have attached my code below. Can anyone tell my mistake?
I know there must be a better method than mine, I really wanna to figure out why my code doesn't work for float and char case. Any help will be greatly appreicated.
For the int case, it can correctly output the smallest value which is 2. However for the float condition, it keeps giving me 0 instead a number from the float list.
Main function
int main()
{
Compare c;
int arrayInt[5] = {65,43,2,898,678};
float arrayInF[4] = {4.5,4.9,4.3,6.5};
char arrayInC[6] = {'w','z','t','h','e','c'};
std::cout<<c.findSmaller(arrayInt, 5)<<" is the smallest of the input array\n";
std::cout<<c.findSmaller(arrayInF, 4)<<" is the smallest of the input array\n";
std::cout<<c.findSmaller(arrayInC, 6)<<" is the smallest of the input array\n";
return 0;
}
Class
class Compare
{
public:
int findSmaller(int input1[],int input2);
float findSmaller(float input1[],int input2);
};
int Compare::findSmaller(int input1[], int input2)
{
int small;
for(int i=0;i<input2;i++)
{
if(input1[i]<input1[i+1])
{
small = input1[i];
input1[i+1] = small;
}
else
{
small = input1[i+1];
input1[i+1] = small;
}
}
return small;
}
float Compare::findSmaller(float input1[], int input2)
{
float small;
for(int i=0;i<input2;i++)
{
if(input1[i]<input1[i+1])
{
small = input1[i];
input1[i+1] = small;
}
else
{
small = input1[i+1];
input1[i+1] = small;
}
}
return small;
}
char Compare::findSmaller(char input1[], int input2)
{
char small;
for(int i=0;i<input2;i++)
{
if(input1[i]<input1[i+1])
{
small = input1[i];
input1[i+1] = small;
}
else
{
small = input1[i+1];
input1[i+1] = small;
}
}
return small;
}
The reason the code does not work as you expect is two fold
because your algorithm is destructive
because you are overstepping array bounds
your code snippet:
if(input1[i]<input1[i+1]) // <-- 2) over step array when i = (input2 - 1)
{
small = input1[i];
input1[i+1] = small; // <-- 1) this will overwrite the NEXT value
}
else
{
small = input1[i+1];
input1[i+1] = small;
}
if you walk through this with your arrayInt input
int arrayInt[5] = {65,43,2,898,678};
the data becomes {65, 43, 2, 2, 2} as it executes, destroying the original data.
c and c++ use 0 base indexing, meaning a 4 element array is indexed 0, 1, 2, 3, etc so when you are iterating "i < input2" where input2 = 5 the first iteration i will equal 0 and the last iteration i will equal 4. When your code then makes reference to input1[i+1] that would then be input1[5] which is out of bounds but not necessarily undefined nor 0. You see, the compiler will try to allocate an array in a continuous block of memory like so:
| item 0 | item 1 | item 2 | item 3 | item 4 | etc.
referencing input1[5] will simply return the next block of memory interpreted as the expected data type, an integer in the case of arrayInt.
Since the 3 arrays are declared together, the compiler allocated their space together, this means that arrayInt is adjacent to arrayInf in physical memory, which also means that arrayInt[5] would be the same as (int)arrayInf[0]. 4.5 float is a large integer and will engage the destructive nature of your algorithm, meaning that when iterating over the arrayInt you actually overwrote the 4.5 float with an integer 2 and that's going to be interpreted as a really small float, so you've clobbered the first element of the arrayInf array.
#Bo-r gives an example of a better algorithm for doing what you want.
float arrayInF[4] = {4.5, 4.9, 4.3, 6.5};
has 4 values (use whitespace in your code, it makes reading it much easier)
You pass in an input2 (use more descriptive variable names, too) of 4 which means that
for(int i=0;i<input2;i++)
i goes up to 3.
You then access array indices 3 and 3+1=4 here (and other places as well):
if(input1[i]<input1[i+1])
When you only have valid indices up to 3, which completely breaks your program. Once you read/write invalid memory locations, the behavior of your program becomes undefined. It may still look like it's working sometimes, but that's just sheer luck.
This problem is not limited to just the float implementation.
Seems you haven't declare and implemented the method char Compare::findSmaller(char *input1, int input2).
A example of such an implementation would be:
char Compare::findSmaller(char input1[], int input2) {
assert(input2 >0);
char small = input1[0];
for (int i = 1; i < input2; i++)
if (input1[i] < small)
small = input1[i];
return small;
}

Create Dynamically Allocated Array C++

I'm trying to create a dynamically allocated array of type unsigned char* in C++. However, when I this I get back a string instead of a bracket enclosed ({}) array which is what I want.
unsigned char* arr = new unsigned char[arrLen];
Code Picture
Picture showing the difference between the two
You see how the latter doesn't just go to nothing after the first character? That's what I want.
How might I go about remedying this?
Thank you for your time.
First, de debugger assumes by default that char represents an ascii character rather than a number. It will display char as such.
arr2 has type const char[3] so the debugger knows there are 3 elements to display.
arr has type const char*. The debugger can't know if it's only one elements or an array with a certain number of elements.
If you are using visual studio for instance, you can hint the debugger to display three char by adding a “variable watch” with the syntax arr,3 in the watch menu.
I'm not sure if this is what you are looking for, but have you tried using a std::vector? It can handle the dynamic assignment you are looking for at least, and shouldn't treat a NULL character as the end of a string.
#include <vector>
std::vector<char> arr = { 0x5A, 0x00, 0x2B };
If you want a list of chars(array) that grows dynamically, what you need is a list of pointers where the list of each segment is a large number-say 1000. A vector container class sacrifices memory usage for the ability to grow.
vector container class allows for dynamic growth but uses a lot of memory
Also, dynamic growth one data element at a time is not recommended for a large list of data. If you want dynamic growth for a large list, create a list in chunks such as the following. Use a large list segment- of say 1000 units. I created 1000 lists in the following example. I do this by creating an array of 1000 pointers. This will create the 1 million chars you are looking for and can grow dynamically. The following example shows how you would do this.
.
void main() {
unsigned char* listsegment[1000];
int chrn=0;
int x, y = 0;
for (int x = 0; x < 1000; x++) {
listsegment[x] = new unsigned char[1000];
for (y = 0; y < 1000; y++) {
*(listsegment[x] + y) = chrn;
if (chrn >=255) chrn=0;
else chrn++;
}
}
}
Completing the program- What if more than 1000 segments need to be dynamically allocated?
Then create a list of Segment Sets. It can either be in a linked list or a in a container class.
Since the single set creates a 1000 segments of 1000 characters, a collection of these sets needs probably not be larger than 1000. A thousands sets would equal (1000*1000)*1000 which would equal one billion. Therefore, the collection would only need to be 1000 or less, which can be quickly iterated through-which makes random access for the collection not necessary.
Here is the program redone to support an infinite amount of sets through an infinitely large collection of sets. This also is a good example of segmented dynamic memory allocation in general.
#include <iostream>
#include<queue>
using namespace std;
struct listSegmentSetType {
unsigned char* listSegment[1000];
int count=0;
};
void main() {
listSegmentSetType listSegmentSet;
queue<listSegmentSetType> listSegmentSetCollection;
int numberOfListSegmentSets = 0;
int chrn = 0;
int x, y = 0;
listSegmentSet.count = 0;
for (int x = 0; x < 1000; x++) {
listSegmentSet.listSegment[x] = new unsigned char[1000];
for (y = 0; y < 1000; y++) {
*(listSegmentSet.listSegment[x] + y) = chrn;
if (chrn >= 255) chrn = 0;
else chrn++;
}
listSegmentSet.count++;
}
// add just completely filled out first list segment set to que
listSegmentSetCollection.push(listSegmentSet);
numberOfListSegmentSets++;
// now fill in second set of list segments-
listSegmentSet.count = 0;
for (int x = 0; x < 1000; x++) {
listSegmentSet.listSegment[x] = new unsigned char[1000];
for (y = 0; y < 1000; y++) {
*(listSegmentSet.listSegment[x] + y) = chrn;
if (chrn >= 255) chrn = 0;
else chrn++;
}
listSegmentSet.count++;
}
listSegmentSetCollection.push(listSegmentSet);
numberOfListSegmentSets++;
// now fill out any more sets of list segments and add to collection
// only when count listSegmentSet.count is no
// longer less than 1000.
}

How to initialize an array of pointers (or do I need to do so at all)?

It's for my college exam, so don't ask why I'm not using advanced stuff in C++.
This is a console app. The problem to solve is to write missing functions inside defined structures. It is simulation of entrance exam so there's this question struct that has its attributes as follows:
char* _txtOfQuestion;
char* _answers[10]; //max 10 answers
int _correct; //location of the correct answer
int _points; //no. of points
Now, I need to implement the function Create() of this struct, which is responsible for initialising all the structure attributes.
I thought the parameters should be:
Create(char* text, char* answers[], int posOfCorrect, int points){
_txtOfQuestion = new char[strlen(text)+1];
strcpy_s(_txtOfQuestion , strlen(text), text);
// now this _question[10] attribute seems to be the toughest here
// as it happens to be an array
// how to initialize it here or if init. is not necessary, then
// how to assign it to this parameter answers, to that it fits?
// code here....
_correct = posOfCorrect;
_points = points;
}
Why don't you try something like this:
for (int i = 0; i < 10; ++i)
{
if (answers[i] != nullptr)
{
_answers[i] = malloc(strlen(answers[i])+1);
strcpy(_answers[i], answers[i]);
}
else
break;
}
of course you can omit nullptr check.
Is that helpful?

Getting garbage value after assigning value to a variable, can't see why

I'm creating a new object of my class 'Dynamic' (not shown), which inheritates from 'Organic', which inheritates from 'Being' certain parameters such as id, biomeRow, etc.
Organic has: features_ (a struct), max_spawn_, total_spawn_, age_dur_ (an array) and current_age_.
The problem: Upon creating a Dynamic object, all values are set just right except max_spawn_. I've done my printfs both before creating Dynamic, in the creation of Dynamic and in the creation of Organic for the input value, and all of them are correct.
Features struct is right, total_spawn_ is right, age_dur_ array and current_age_ are both also right.
All of them are what I asked except for max_spawn_. maxSpawn is the value I'm passing (20), max_spawn_ should then be 20, but it isn't. All my printfs and debugging console show it is something around -858993460. I'm guessing that's just garbage, but I don't know how is it possible when all I'm doing is:
max_spawn_ = maxSpawn;
So, this is my function:
Organic::Organic(int id, int biomeRow, int biomeColumn, int biomeType, int beingType,
int object, Features features, int maxSpawn, int totalSpawn,
int age_dur[5], int current_age)
: Being(id, biomeRow, biomeColumn, biomeType, beingType, object)
{
features_ = features;
max_spawn_ = maxSpawn;
total_spawn_ = totalSpawn;
age_ = current_age;
for (int i = 0; i <= 5; i++)
age_dur_[i] = age_dur[i];
printf("\n%d\n", max_spawn_);
}
age_dur (and presumably age_dur_) are int [5] arrays. Copying like this:
for (int i = 0; i <= 5; i++)
age_dur_[i] = age_dur[i];
will overwrite something near age_dur_ with something. If max_spawn_ is adjacent to age_dur_, it's probably being overwritten with garbage.
Change the loop to:
for (int i = 0; i < 5; i++)
age_dur_[i] = age_dur[i];

How can I convert from a class with a 2D vector of chars to a 2D vector of another obj with a char variable?

I'm still new to this so my apologies in advance if I provide too much or not enough information for my problem.
The Run Down
This question isn't a rogue like game related question, but for a little background of what my program does.. is to be similar to a rogue like game.
Ok, so I had a class that had a member 2D char vector (the chars were manipulated to represent a "dungeon"). Everything worked seamlessly. I wanted to expand what my program could do so I decided to create a new class to replace the 2D vector of chars so that the char is just the visual representation of the new class and other variables can be stored along with that char.
For simplistic sake, I tried to remove what isn't necessary for this question. This new class is called Tile - which represents a space being used for the dungeon level. Tile has:
a char variable called displayChar.. defaults to ' ' changes to represent what it contains
(other variables..)
The Problems / My Poor guesses
I'm not the best at completely understanding some concepts of programming syntax/implementation, so please don't judge.
The way I filled the vector of chars, I resized it to the width of the game board, and set everything to ' ' since all the values were chars
I think I need to fill it with new, Tile objects and push them to the
2D Tile vector?
My other methods that manipulated the char values are giving errors.
I think I should change the methods to take a pointer to the Tile
object and use the setDisplayChar(' ') method to change its
value?
My at(int, int) method used to return the char at that location
I thought I could change it to "return m_vvTiles[y][x].getDisplayChar()" but I get an error
I'm bad at changing how something works and I usually end up making a mess out of my code. I'll post the code that is relevant for this. I'd greatly appreciate any help you can offer. And please let me know if I need to add more. (I'll try to keep the code minimized to only related methods). Thanks!
DungeonLevel.h
#include "Tile.h"
#include <vector>
#include <random>
class DungeonLevel {
public:
DungeonLevel(int iWidth, int iHeight, std::mt19937 & mt);
~DungeonLevel(void);
void dump();
char at(int x, int y);
int getWidth();
int getHeight();
private:
std::vector<std::vector<Tile>> m_vvTiles; //Tile was char
};
DungeonLevel.cpp
#include <iostream>
#include <random>
#include "DungeonLevel.h"
using namespace std;
DungeonLevel::DungeonLevel(int iWidth, int iHeight, std::mt19937 & mt){
// Initialize the blank vector
m_vvTiles.resize(iHeight);
for(auto it = m_vvTiles.begin(); it != m_vvTiles.end(); it++ ){
// Tile tempTile = new;?
(*it).resize(iWidth,' ');
}
// divide the level into 4x2 chunks
int iChunkWidth = iWidth / 4;
int iChunkHeight = iHeight / 2;
// Taking the easy way out, and generating
// a loop of tunnels first to drop rooms on to
for( int x = (iChunkWidth/2); x <= ((3 * iChunkWidth) + (iChunkWidth/2)$
m_vvTiles[iChunkHeight/2][x] = '#';
m_vvTiles[iChunkHeight + (iChunkHeight/2)][x] = '#';
}
for( int y = (iChunkHeight/2); y <= (iChunkHeight + (iChunkHeight/2)); $
m_vvTiles[y][iChunkWidth/2] = '#';
m_vvTiles[y][(3 * iChunkWidth) + (iChunkWidth/2)] = '#';
}
void DungeonLevel::dump(){
for( auto itOuter = m_vvTiles.begin(); itOuter != m_vvTiles.end(); itOu$
for( auto itInner = (*itOuter).begin(); itInner != (*itOuter).e$
cout << *itInner.getDisplayChar(); ///Updated:: CAUSING ERROR//
}
cout << endl;
}
}
//SEVERAL IRRELEVANT LINES FOR THIS PROBLEM..
}
char DungeonLevel::at(int x, int y){
return m_vvTiles[y][x].getDisplayChar();
//return m_vvTiles[y][x]; WORKED BEFORE
}
Tile.h
#include "Entity.h"
#include <vector>
class Tile : public Entity {
public:
Tile(void);
virtual ~Tile(void);
//void setEntity(Entity * entityToSet); BOTH IRRELEVANT
//Entity * getEntity();
void setDisplayChar(char displayCharToSet);
char getDisplayChar();
//virtual void dumpObjectData(); IRRELEVANT AT THIS TIME
private:
char displayChar;
//Entity * theEntity; IRRELEVANT AT THIS TIME
};
Tile.cpp
#include "Tile.h"
#include "Entity.h"
using namespace std;
Tile::Tile(void){
displayChar = '.';
//theEntity = NULL;
}
Tile::~Tile(void){
}
void Tile::setDisplayChar(char displayCharToSet){
displayChar = displayCharToSet;
}
char Tile::getDisplayChar(){
return displayChar;
}
*Heres my existing error: *
For the method dump() in DungeonLevel.cpp,
Some of your questions with my answers
I think I need to fill it with new, Tile objects and push them to the 2D Tile vector?
No you need to resize it and fill it with Tile objects. Pretty much like you did when it was a char array. new doesn't come into it.
I think I should change the methods to take a pointer to the Tile object and use the setDisplayChar(' ') method to change its value?
I would use a reference.
I thought I could change it to return m_vvTiles[y][x].getDisplayChar() but I get an error.
That sounds right to me, what error did you get?
Everything about your redesign sounds well motivated to me. Good idea to make a back up before going on a major reorganization however.