Const Char* in Struct Array

#1
Hello!
I'm using a struct array to define my building types, and each struct has a const char* name

when I assign the building name from an xml to the according index and member in my struct array, it will return the whole name as long as I am logging in the XML iterator scope where I am assigning the values.
However, when I try to access the name in an index outside of the iterator, in another function, it will always give me some random symbol.

CODE BELOW

Code: Select all

BuildingManager.h class CBuildingManager : public CGameObjectExtensionHelper<CBuildingManager, ISimpleExtension> { public: struct SBuilding { float money = 0; float electricity = 0; float water = 0; const char *name; }; struct SBuilding buildings[999];

Code: Select all

BuildingManager.cpp void CBuildingManager::LoadBuildingXML() { //Thanks Uniflare <3 int n = -1; char * file_name = "Scripts/Buildings/BuildingList.xml"; XmlNodeRef rootNode = GetISystem()->LoadXmlFromFile(file_name); if (rootNode) { CryLog("%s found!", file_name); /*Iterate Nodes*/ for (size_t i = 0; i < rootNode->getChildCount(); i++) { XmlNodeRef child = rootNode->getChild(i); for (size_t y = 0; y < child->getChildCount(); y++) { const char *name; const char *value; n++; struct SBuilding tempBuilding; XmlNodeRef tags = child->getChild(y); CGameXmlParamReader reader(tags); for (size_t j = 0; j < tags->getNumAttributes(); j++) { tags->getAttributeByIndex(j, &name, &value); CryLog("%i", n); //Assign to temp struct tempBuilding.name = value; buildings[n] = tempBuilding; CryLog("%s", buildings[n].name); //This works! buildingList[n] = buildings[n].name; //Works. Ignore this } } } } } void CBuildingManager::LogAction(int x) { //gets x from input CryLog("%c", &buildingList[x]); //does not work with %s and logs a bunch of shit }
This sounds like a good all around c++ problem that you can google, but I can't find much on it.
Thanks for any answers or tips on how to fix this!
-Moose
ImageTwitterImage

Re: Const Char* in Struct Array

#2
When the program leaves the iterator scope, the strings related to returned "char *" strings are terminated. Because they are out of scope. If you want to use these strings out of that scope, you have to copy them. You can google how to copy char pointers.
But save yourself the headache and use "string" class. If you assign a char pointer to a string object, it will automatically copy it to your variable. If you ever need a c-style string, just call "c_str()" method on the string object.

Re: Const Char* in Struct Array

#3
That's some c looking code you got there xD.

My advice;

Code: Select all

struct SBuilding buildings[999];
This is allocating 999*32 bytes memory on the stack (31968 bytes).

I would prefer to use

Code: Select all

std::vector<SBuilding> buildings{}.
If you are really cautious for performance you could opt for a Cry Array variant.

as game_dev mentioned I would change the struct to this;

Code: Select all

struct SBuilding { float money = 0; float electricity = 0; float water = 0; string name = ""; SBuilding(float m, float e, float w, string n) : money(m), electricity(e), water(w), name(n)){} };
Added a default consutrctor so we can emplace_back with our vector.

Then rid yourself of the attribute iterator and simply use this;

Code: Select all

for (size_t y = 0; y < child->getChildCount(); y++, ++n) { XmlNodeRef tags = child->getChild(y); CGameXmlParamReader reader(tags); // Get our specific attributes and create a new building on the fly float money = 0.f; tags.getAttr("money", &money); float electricity = 0.f; tags.getAttr("electricity", &electricity); float water = 0.f; tags.getAttr("water", &water); buidlings.emplace_back( money, electricity, water, tags.getAttr("name")); }
..

At them moment it looks like you are mangling your buildings struct by looping each attribute. If you want dynamic attributes (more than water/electric etc) then you would need another vector to store those types/names. Though I don't really see a use-case for that particular feature.

good luck :)
Uniflare
CRYENGINE Technical Community Manager
Here to help the community and social channels grow and thrive.

My personal belongings;
Beginner Guides | My GitHub | Splash Plugin

Re: Const Char* in Struct Array

#4
Or you could go with the even easier option of using json and the serialization api:

Code: Select all

#include <CrySerialization/IArchive.h> #include <CrySerialization/STL.h> #include <CrySerialization/CryStrings.h> struct SBuilding { string name = ""; float money = 0; float electricity = 0; float water = 0; void Serialize(TSerArch &archive){ archive(name, "name", "name"); archive(money , "money ", "money "); archive(electricity , "electricity ", "electricity "); archive(water , "water ", "water "); };

Code: Select all

void CBuildingManager::SerializeFile(const char* filename) { Serialization::LoadJsonFile(*this, filename); } void CBuildingManager::Serialize(TSerArch &archive) { archive(m_buildingTypes, "Types", "Types"); }
JSON

Code: Select all

{ "Types":[ { "name":"Blaa", "money ":1.0, "electricity":3.4, "water":3.2 }, { "name":"lebuilding", "money ":3.0, "electricity":3.4, "water":3.2 } ] }

Re: Const Char* in Struct Array

#6
Its mainly the syntax and the updated serialization framework. Everything from now on is gonna use it (including entity properties for exampl) so it lends itself well. It also means you can easily map your data to a file without the need to manually cycle through xml nodes like you need to do with the old serialization stuff.
The new api also support a variety of different standard components that can be serialized without the need to do anything but call archive and specify the type.
And if you like xml syntax better somehow (or want the ability to add comments to you files <.<) then you can save to xml as well if i recall correctly.
It just saves a ton of work and json is used cause its a very easy format to handle and which is widely used at the moment.

Who is online

Users browsing this forum: No registered users and 2 guests