I am brand new to SO, and it all looks very helpful.
My code is being used for cryengine, but this seems to be a good all around c++ problem. And lets face it, the official CE forums blow.
The trouble I'm having is accessing the const char* variable of a struct array outside of the scope I'm assigning the variable in.
BuildingManager.h
class CBuildingManager {
public:
struct SBuilding {
const char* name;
};
struct SBuilding buildings[999];
//string buildingName;
const char* buildingList[999];
};
BuildingManager.cpp
void CBuildingManager::LoadBuildingXML() {
int n = -1;
const char *name;
const char *value;
//XML iterator is long and not necessary for example. n++ per iteration.
//it just works
//last part of iterator
for (size_t j = 0; j < tags->getNumAttributes(); j++) {
//Get building name in XML. This works
tags->getAttributeByIndex(j, &name, &value);
//assign building name to name in struct
buildings[n].name = value;
CryLog("%s", buildings[n].name);
buildingList[n] = buildings[n].name;
}
}
}
}
}
void CBuildingManager::LogAction(int x) {
//x modified by input. also works
CryLog("%c", buildingList[x]); //this, however, does not
}
So basically, I can print the building name as a string inside of the iterator, and it prints the whole building name (ie. "House")
But when I call LogAction, the building name will only print as a char, and will only show a single random symbol.
How can I convert the name in the struct to a string or otherwise get it to print as a whole word outside of the iterator?
Please let me know if my question is vague or shaky, and I will do my best to clean it up.
-Moose
Related
I was given an assignment to create a hash table that contains 30 buckets (20 primary, and 10 overflow), with each bucket containing 3 slots (each slot containing 2 stings for key and data passed in), a counter integer and a pointer variable that points to the next overflow bucket. My last C++ class was over a year ago so I'm completely lost as to how I am supposed to create this table properly (with no help from my professor).
This is my class declaration below. It technically compiles, however it crashes immediately, and when it debugs, I get an "Access Violation Reading Location" error stating "this was nullptr" on my home computer (and it includes a specific memory location on the computer I used in class).
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
// Define Global Variables
#define MAXBUCKETs 30
#define MAXSLOTs 3
typedef char STR10[10 + 1];
typedef char STR20[20 + 1];
// Define Class
class hash{
public:
int primaryBuckets = 20;
int overflowBuckets = 10;
union bucket
{
int count;
bucket* nextOverflow;
struct slot {
string keyValue;
string dataValue;
};
slot* slots[2];
} HashTable[30];
hash(); // Initialize HashTable
int HashFunction(STR10 key, int buckets); // Hash key to index
void InsertIntoHT(STR10 key, STR20 data); // Add data to slot
void PrintItemsInIndex();
void InsertOverflow(STR10 key, STR20 data, int index);
void InsertPrimary(STR10 key, STR20 data, int index);
};
My constructor, from what I understand, initialized the array in the right order
::hash::hash()
{
for (int i = 0; i < MAXBUCKETs; i++)
{
HashTable[i].count = 0;
for (int j = 0; j < MAXSLOTs; j++)
{
HashTable[i].slots[j]->keyValue = "no_data";
HashTable[i].slots[j]->dataValue = "no_data";
}
}
}
I'm pretty desperate for help at this point. I'm almost certain it's a bad pointer, but I've never understood them well. All help will be greatly appreciated! (This is also my first post so hopefully I didn't do anything wrong)
Maybe I misunderstand this, but the union looks suspicious
union bucket
{
int count;
bucket* nextOverflow;
struct slot {
string keyValue;
string dataValue;
};
slot* slots[2];
} HashTable[30];
A union is supposed to hold only one of its members, in this case one of
count
nextOverflow
slots[2]
Maybe a struct bucket is more appropriate.
Specifically,
HashTable[i].count = 0;
sets count member to zero, and at the same time overwrites memory of slots, which holds a pointer to a slot entry
HashTable[i].slots[j]->keyValue = "no_data";
Here you must either use plain slot objects, which I recommend, e.g.
slot slots[MAXSLOTs];
or first initialize with new
for (int i = 0; i < MAXSLOTs; ++i)
slots[i] = new slot;
I have written a function in c++ which receives a struct as a input. The struct object received has two arrays. I need to use both the arrays for different purposes. The array names have been created in a certain format. How to retrieve array names in a string.
struct INFO
{
float fADataLHS[3] = {1,2,3};
float fADataRHS[3] = {4,5,6};
Struct INFO has been defined where two arrays have been defined an initialized. The function useStruct uses both the function for different purposes.
void useStruct(struct *INFO)
{
--------;
--------;
}
int main()
{
struct INFO info;
useStruct(info);
}
I want a method in which I can retrieve the name of the array as for ex. fAdataLHS and store it to a string. The idea is to find the sub-string LHS and RHS from the string names and process then accordingly.
PS: I am quite new to c++.
I will go simple as you're a begginer to C++.
If you want to use both of arrays for different purposes, just doit. For instance:
void use_array_for_different_purposes(INFO *info)
{
// Purpose one, printing values using fADataLHS.
for (int i = 0; i < 3; i++) {cout << info->fADataLHS[i] << endl;}
// Purpose two, computing total sum using fADataRHS.
int acum;
for (int i = 0; i < 3; i++) {acum += info->fADataRHS[i];}
}
As you can see, you don't need to get the arrays names as strings values.
If I understand corectly, your use case is this: you have two (or more) names and each has a float array associated with it. You want to get the array by name and process the data.
Consider this code:
class INFO
{
std::map<std::string, std::vector<float>> vectors;
public:
INFO() : vectors{}
{
vectors["fADataLHS"] = { 1, 2, 3 };
vectors["fADataRHS"] = { 4, 5, 6 };
}
const std::vector<float>& operator[](const std::string& key) const // access vector by key
{
return vectors.at(key);
}
};
void useStruct(const INFO& info) // pass instance by const reference
{
std::cout << info["fADataLHS"][0] << "\n"; // access element 0 from the fADataLHS array
// get the entire array:
const auto& arr = info["fADataRHS"];
// this will throw a std::out_of_bounds
const auto& arr = info["non-existent-key"];
}
EDIT: A few other notes:
in C++ try not to use float - use double instead
if you need to alter the vector contents from client code, add a non-const version of the operator[]
I am currently working on an dynamic memory container.
Basic idea of the class is that you should be able to get the iterator of an object if you really do not know it, without the use of a for loop throughout all the elements to boost performance. The issue I have is the following; when you pass your pointer address to the object you want to get the iterator of it type casts the object into the extended memory containers structures type. This type contains an extra element, an integer. (IteratorNum)
When following the code the integer within the function is set to correct value, as below would be 50. But when the returned value is set into the local integer used in the main function it is 200? I've been adding watches and cannot figure out how it is possible that the function returns 50 but value gets set to 200.
template <typename DataType> class MemoryContainer {
public:
struct LevelData : DataType
{
int element;
};
DataType &New()
{
elements++;
//Reallocate the size of the array
ld = (LevelData*)realloc(ld, sizeof(LevelData) * elements);
//Set the iteratorNumber
ld[elements - 1].element = elements - 1;
return ld[elements - 1];
}
DataType *reserve(int num)
{
return calloc(num, sizeof(DataType));
}
DataType &operator[](int i)
{
return ld[i];
}
bool inArray(DataType *type)
{
//Compare memory addresses and see if it's within.
return (type >= &ld[0]) && (type < &ld[elements - 1]);
}
static unsigned int getIterator(DataType *type)
{
// v this is 50, but in main says returns 200.
return ((LevelData*)type)->element;
}
MemoryContainer()
{
elements = 0;
}
~MemoryContainer()
{
free(data);
}
private:
unsigned int elements;
LevelData *ld;
};
struct Effective
{
//Set it to polymorphic classes
virtual void dummy()
{
}
char * testvar;
Effective(char * c)
{
testvar = c;
}
Effective(){}
};
MemoryContainer<Effective> myContainer;
int _tmain(int argc, _TCHAR* argv[])
{
//Create 200 elements in the array
for(int i = 0; i < 200; i++)
myContainer.New().testvar = "E";
//Add pointer for testing purposes to get the iterator.
Effective * pointer = &myContainer[50];
//Test setting it's value
pointer->testvar = "HEHEHE";
//Get iterator of our pointer in the array
unsigned int i = myContainer.getIterator(pointer);
printf(pointer->testvar);
system("PAUSE");
return 0;
}
I suspect it is the visual studio debugger getting confused between your two i variables. If you print out the value of i, it will print correctly. If you change the name of your variable to something else, the value shows as 50 in the debugger.
That said, your code is a mish-mash of c and c++ and won't work correctly with anything that requires a copy constructor. I would suggest at the very least using new [] rather than realloc.
Also, any user of this collection who tries to store a class with a member variable called element is going to get mighty confused.
The unsigned int i in the main function really has a value of 50, but the debugger is confusing it with the i declared in the for loop (I reproduced this with Visual Studio 2013). If you cout i it will be 50, and if you change the variable name it will show up as 50 in the debugger. I've never seen this problem before so I wonder if it might be due to your use of malloc/realloc/free with C++ objects.
I have a pretty standard class with some public member functions and private variables.
My problem originally stems from not being able to dynamically name object instances of my class so I created an array of pointers of the class type:
static CShape* shapeDB[dbSize];
I have some prompts to get info for the fields to be passed to the constructor (this seems to work):
shapeDB[CShape::openSlot] = new CShape(iParam1,sParam1,sParam2);
openSlot increments properly so if I were to create another CShape object, it would have the next pointer pointing to it. This next bit of code doesn't work and crashes consistently:
cout << shapeDB[2]->getName() << " has a surface area of: " << shapeDB[2]->getSA() << shapeDB[2]->getUnits() << endl;
The array of pointers is declared globally outside of main and the get() functions are public within the class returning strings or integers. I'm not sure what I'm doing wrong but something relating to the pointer set up I'm sure. I'm writing this code to try and learn more about classes/pointers and have gotten seriously stumped as I can't find anyone else trying to do this.
I'm also curious as to what the CShape new instances get named..? if there is any other way to dynamically create object instances and track the names so as to be able to access them for member functions, I'm all ears.
I've tried all sorts of permutations of pointer referencing/de-referencing but most are unable to compile. I can post larger chunks or all of the code if anyone thinks that will help.
class CShape {
int dim[maxFaces];
int faces;
string units;
string type;
string name;
bool initialized;
int slot;
public:
static int openSlot;
CShape();
CShape(int, string, string); // faces, units, name
~CShape();
void initialize(void);
// external assist functions
int getA(void) {
return 0;
}
int getSA(void) {
int tempSA = 0;
// initialize if not
if(initialized == false) {
initialize();
}
// if initialized, calculate SA
if(initialized == true) {
for(int i = 0; i < faces; i++)
{
tempSA += dim[i];
}
return(tempSA);
}
return 0;
}
string getUnits(void) {
return(units);
}
string getName(void) {
return(name);
}
// friend functions
friend int printDetails(string);
};
// constructor with values
CShape::CShape(int f, string u, string n) {
initialized = false;
faces = f;
units = u;
name = n;
slot = openSlot;
openSlot++;
}
My guess is you use the CShape constructor to increment CShape::openSlot?
You're probably changing the value before it's read, thus the pointer is stored in a different location.
Try replacing openSlot with a fixed value to rule out this CShape::option.
-- code was added --
I'm pretty sure this is the problem, the constructor is executed before the asignment, which means the lhs. will be evaluated after CShape::openSlot is incremented.
My code is already working, seen here: http://pastebin.com/mekKRQkG
Right now, my functions work but utilizing information that I've declared globally, I guess, and I want to convert them so that they are in the format as seen on lines 11-15, but I'm unsure of how to convert them to do so. Simply put, I'm trying to convert my function of
"void add_county_election_file"
to be in the format of
"void add_county_election_file(const string, const vector &, const vector &, const vector &, const vector &)"
and I have no idea where to begin or how to even start.
Could someone please help me out and show me how I'd do this for the first function, so I can implement it across the board?
Thanks guys!
Your function declaration should look something like this:
void add_county_election_file(const string, vector<int>&, vector<string>..);
Make sure that your argument list for the vector template is correct(that's the type you put between <>)
Then match the implementation of you function to the declaration:
void add_county_election_file(const string, vector<int>&, vector<string>..){...}
Now call your function with apppropriate arguemtns in main:
string s;
vector<int> arg;
vector<string> sv;
void someFunction (s, arg, sv ...);
I think you are doing correct as the function you have declared
void add_county_election_file(const string, vector<int>&, vector<int>&,..);
so you just have to call the above function with the required arguments, as right now you are not passing the argument and your current definition doesn't accepts any arguments.
And as a good practice, in your int main() function you can use switch rather than going for if else.
Store your variables and functions in a class, overload operators and create functions to access these variables.
Declare all variables in int main() and set parameters to be passed into each function e.g.
void print_results() is modified to become
void print_results(std::vector<int> vec, int nCount, etc..)
Similar to the first one, create a struct to hold all data members, then pass the struct(by ref) into each function.
struct CountryTracker
{
std::vector<int> ID;
std::string name;
//etc...
}
`void print_results(CountryTracker& Obj) //pass single struct into functions`
The OOP way to do this is to create a class called perhaps ElectionInfo, where:
These would be its member fields:
vector <string> countyNameVector;
vector <int> countyNCount;
vector <int> countyFCount;
vector <int> countyOCount;
int NCount;
int FCount;
int OCount;
int NTotal;
int FTotal;
int OTotal;
and these would be its member functions:
void add_county_election_file(const string);
void search_county(const string);
void print_results();
This way you don't have to pass the references to the vectors around at all, instead you can just do:
ElectionInfo an_elect_info;
char selection = get_menu_choice();
// some if-statements to decide which of the following to call:
an_elect_info.add_county_election_file(county_name);
an_elect_info.search_county(county_name);
an_elect_info.print_results();
But if you'd prefer to stay with the current functional approach:
Declare and initialize the following inside your main method:
vector <string> countyNameVector;
vector <int> countyNCount;
vector <int> countyFCount;
vector <int> countyOCount;
int NCount;
int FCount;
int OCount;
int NTotal;
int FTotal;
int OTotal;
The syntax for the commented out function declarations should be tweaked to look like this:
void add_county_election_file(const string, vector<string>&, vector<int>&, vector<int&, vector<int>&);
(Of course, the definition should follow suit)
You would invoke it like this:
add_county_election_file(countyname, countyNameVector, countyNCount, countyFCount, countyOCount);
Objects are automatically passed-by-reference.
The basic process of refactoring should at the first step involve only code grouping and placement and should only minimally involve writing new logic. Using this as a principle you can go about modifying the code in the following way at first.
string ReadInputString(const char* title)
{
string s
cout << title;
cin >> s;
}
void add_county_election_file(const std::string& filename
, std::vector<string>& countyNameVector
, std::vector<int>& countyNCount
, std::vector<int>& countyFCount
, std::vector<int>& countyOCount
)
{
int NCount = 0;
int FCount = 0;
int OCount = 0;
int NTotal = 0;
int FTotal = 0;
int OTotal = 0;
char vote;
std::ifstream input((filename).c_str());
string countyName;
if(input.is_open())
{
input >> countyName;
countyNameVector.push_back(countyName);
while(input >> vote)
{
if(vote == 'N' || vote == 'n')
{
NCount = NCount + 1;
}
else if(vote == 'F' || vote == 'f')
{
FCount = FCount + 1;
}
else
{
OCount = OCount + 1;
}
}
countyNCount.push_back(NCount);
countyFCount.push_back(FCount);
countyOCount.push_back(OCount);
}
cout << countyName << endl;
}
void add_county_election_file()
{
string fn = ReadInputString("Enter the county file to process: ");
add_county_election_file(fn,g_countyNameVector,g_countyNCount,g_countyFCount,g_countyOCount);
}
As you can see I have just extracted your code and moved them to individual functions and changed names to make some significance. Like in the function ReadInputString - the line "cin >> s" was originally "cin >> filename". The abstract name "s" is to signify that the ReadInputString has no knowledge or doesn't care what the semantic meaning of the string it is reading from console.
In order to not change your main function - I have added a overloaded add_county_election_file that calls one function followed by another. The idea is that you should keep something unchanged and change others (for good) and then alternate if need be.
And I have changed names of your global variable to differentiate them from the local variable using "g_" - the point is that "g_" should only be found at very few places in your code.