Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

AppGameKit Classic Chat / T2 reading strings

Author
Message
The Zoq2
14
Years of Service
User Offline
Joined: 4th Nov 2009
Location: Linköping, Sweden
Posted: 8th Dec 2012 16:30
Well, here is another thread about my adventures of going from T1 to T2

This time im trying to read some data from a file, however I have encounterd a few problems

The first thing is that the agk::ReadString() dosn't behave like it does in T1. Im trying to read a file looking like this:



And this is the code reading the data.



This is the code displaying the data:


And the code prints the following:

MikeMax
AGK Academic Backer
12
Years of Service
User Offline
Joined: 13th Dec 2011
Location: Paris
Posted: 8th Dec 2012 17:02
Maybe you have to convert sectors[0].asteroidAmount to string before being able to display it ?
The Zoq2
14
Years of Service
User Offline
Joined: 4th Nov 2009
Location: Linköping, Sweden
Posted: 8th Dec 2012 17:05 Edited at: 8th Dec 2012 17:19
That could be the problem, but does it explain the numbers that im not printing?

Also, this is what the documentation says about the read string command. Does that have anything to do with it
Quote: "Reads a null terminated string from the given file, which must have been opened for reading. If you use this command in tier 2 you must delete the returned string when you are finsihed with it."


Edit, it turns out that part of the soulution to my problem was using the ReadLine command and not the ReadString command.
MikeMax
AGK Academic Backer
12
Years of Service
User Offline
Joined: 13th Dec 2011
Location: Paris
Posted: 8th Dec 2012 17:21 Edited at: 8th Dec 2012 17:23
I think the problem is elsewhere

ReadLine instead of ReadInteger no ?

ReadLine return a string (so OK to print it).. ReadInteger return an integer .. It's only a conversion miss i think
The Zoq2
14
Years of Service
User Offline
Joined: 4th Nov 2009
Location: Linköping, Sweden
Posted: 8th Dec 2012 17:30
I noticed that to, and solved it by reading everything as a line, then converting that to the apropriate datatype
Ancient Lady
Valued Member
20
Years of Service
User Offline
Joined: 17th Mar 2004
Location: Anchorage, Alaska, USA
Posted: 8th Dec 2012 17:37
The Zoq2, based on the data file you showed, you need to use ReadLine for all the reads and then convert the strings to integers:
int i = agk::Val(agk::ReadLine(1));

Cheers,
Ancient Lady
AGK Community Tester and AppGameKit Master
The Zoq2
14
Years of Service
User Offline
Joined: 4th Nov 2009
Location: Linköping, Sweden
Posted: 8th Dec 2012 18:26
Yep, I figgured that out eventually

I got suspicious when the read integer returned 35000
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 8th Dec 2012 22:24
This has brought up something interesting. It looks like all strings (char*) returned by agk functions in T2 must be deleted at some point.

Taking AL's example (I know it's just for a demo/explanation, not saying there's anything wrong with your programming ): int i = agk::Val(agk::ReadLine(1));

This will cause a memory leak because the newly created string doesn't get stored in a pointer and so the reference to the start of that chunk of memory is lost and can't be freed.

So you'd have to do something like this:
char *p = agk::ReadLine(1);
int i = agk::Val(p);
delete[] p;

Just thought I'd point that out.

JimHawkins
14
Years of Service
User Offline
Joined: 26th Jul 2009
Location: Hull - UK
Posted: 8th Dec 2012 22:59
That's a useful point, well raised. Who actually "owns" the memory allocated for this string?

I prefer to use the Object Pascal versions rather than AGK's string functions because I know exactly what's happening. Referenced-counted strings will always be destroyed when they have reference-count zero and go out of scope.

-- Jim DO IT FASTER, EASIER AND BETTER WITH AppGameKit FOR PASCAL
erebusman
12
Years of Service
User Offline
Joined: 23rd Jul 2011
Location: Sacramento, CA
Posted: 8th Dec 2012 23:45
Quote: "This has brought up something interesting. It looks like all strings (char*) returned by agk functions in T2 must be deleted at some point.

Taking AL's example (I know it's just for a demo/explanation, not saying there's anything wrong with your programming ): int i = agk::Val(agk::ReadLine(1));

This will cause a memory leak because the newly created string doesn't get stored in a pointer and so the reference to the start of that chunk of memory is lost and can't be freed.
"


I had a memory leak I knew had to do w/ text but couldnt quite figure out. This might actually be it thanks for the tip Hodgey!

The Zoq2
14
Years of Service
User Offline
Joined: 4th Nov 2009
Location: Linköping, Sweden
Posted: 9th Dec 2012 00:04 Edited at: 9th Dec 2012 00:06
So, even if I don't create an object with the string, I have to delete it in some way?

If I do this for example
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 9th Dec 2012 00:31 Edited at: 9th Dec 2012 00:31
Quote: "So, even if I don't create an object with the string, I have to delete it in some way?"

Yes, you even quoted the documentation yourself.
Quote: "Quote: "Reads a null terminated string from the given file, which must have been opened for reading. If you use this command in tier 2 you must delete the returned string when you are finsihed with it.""

I'm assuming ReadLine() creates a new chunk of memory, fills it with a string (read from the file) and then returns a pointer to the start of that chunk of memory. This means that you get control of the string but it also means you're responsible for it. The joys of C++.

[/quote]
Quote: "I had a memory leak I knew had to do w/ text but couldnt quite figure out. This might actually be it thanks for the tip Hodgey!"

You're welcome. I hope you find and fix the leak!

Ancient Lady
Valued Member
20
Years of Service
User Offline
Joined: 17th Mar 2004
Location: Anchorage, Alaska, USA
Posted: 9th Dec 2012 04:21
Hodgey, you are correct about the memory leak. I was only thinking about the quick fix and not the overall picture. (My file class does clean up the string.)

Cheers,
Ancient Lady
AGK Community Tester and AppGameKit Master
The Zoq2
14
Years of Service
User Offline
Joined: 4th Nov 2009
Location: Linköping, Sweden
Posted: 12th Dec 2012 22:31
Quote: "I'm assuming ReadLine() creates a new chunk of memory, fills it with a string (read from the file) and then returns a pointer to the start of that chunk of memory. This means that you get control of the string but it also means you're responsible for it. The joys of C++.
"


How would I remove the string from the memory, do I have to create an object from it and then remove that object? Or is there a way to remove the string in another way?
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 12th Dec 2012 23:12
Like this:
char* p = agk::ReadLine(1);
// do stuff with string
...
// delete string from memory
delete[] p;

Remember not to offset the pointer returned from the agk functions e.g p++; This might cause trouble when you try to delete it.

Happy programming!

The Zoq2
14
Years of Service
User Offline
Joined: 4th Nov 2009
Location: Linköping, Sweden
Posted: 12th Dec 2012 23:33
Sounds resonable

Can I reuse the char pointer for multiple strings without causing any problems
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 13th Dec 2012 00:09
Quote: "Can I reuse the char pointer for multiple strings without causing any problems"

Depends on what you mean by reuse. If you try something like this:


That will cause a memory leak. But this should be fine:


XanthorXIII
AGK Gold Backer
12
Years of Service
User Offline
Joined: 13th May 2011
Location:
Posted: 13th Dec 2012 07:45
Why mess around with Char Pointers and not use C++ Strings?
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 13th Dec 2012 09:06
Quote: "Why mess around with Char Pointers and not use C++ Strings?"

I personally find char pointers pretty straight forward but one could use strings as well (thanks for providing a demo ).

After including <string>
std::string s = agk::Str(1);

It'll get deleted when it goes out of scope (unless you've used the new keyword). When wanting to access the string itself, you'll need to use s.data(). e.g agk::Len(s.data());

Ancient Lady
Valued Member
20
Years of Service
User Offline
Joined: 17th Mar 2004
Location: Anchorage, Alaska, USA
Posted: 13th Dec 2012 16:42
Using the 'delete[]' is unnecessary (and might not work quite right in all platforms) for deleting a char* variable. You only actually need to do 'delete varname' (assuming varname defined as 'char* varname;').

Cheers,
Ancient Lady
AGK Community Tester and AppGameKit Master
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 13th Dec 2012 21:25
Quote: "Using the 'delete[]' is unnecessary (and might not work quite right in all platforms)"

I'm afraid I disagree. The way I interpret the documentation is that the agk string functions return a pointer to the start of an array of characters in memory, hence I'm using delete[]. I could be mistaken however and happy to admit defeat if I'm wrong.

Why won't delete[] work on all platforms?

Ancient Lady
Valued Member
20
Years of Service
User Offline
Joined: 17th Mar 2004
Location: Anchorage, Alaska, USA
Posted: 13th Dec 2012 21:55 Edited at: 13th Dec 2012 22:05
I just did some research on deleting char* variables. And it comes down to how they are created. If they are created as 'char* var = new char[10]', then 'delete[]' is the correct way.

It appears that I am not cleaning up properly!

Thank you for making me look at this again.

EDIT: And it looks like I only had four places to fix this up in.

I did say 'might not work', because if the char* is created some other way, it might not be an array. I try to avoid using absolute terms when discussing code stuff, because I know that I am not always correct.

Cheers,
Ancient Lady
AGK Community Tester and AppGameKit Master
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 13th Dec 2012 22:13
You're welcome. I hope it's not too much work to fix your app.

Maybe we should take Xanthor's route and just use string objects as (if created on the stack) they will clean themselves up and the string when they go out of scope.

The Zoq2
14
Years of Service
User Offline
Joined: 4th Nov 2009
Location: Linköping, Sweden
Posted: 13th Dec 2012 22:43
Does the memory leak unless the object is deleted apply for GetNetworkMessageString aswell, I don't see any indication of that in the documentation
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 13th Dec 2012 23:13 Edited at: 13th Dec 2012 23:13
Quote: "I did say 'might not work', because if the char* is created some other way, it might not be an array. I try to avoid using absolute terms when discussing code stuff, because I know that I am not always correct."

I did think about that but then thought it would be easier for everyone if the agk functions just did something like char *p = new char[ i ] where i >= 1. That way it'll still be an array but with only one element. I'm only assuming this so I could easily be wrong.

Quote: "Maybe we should take Xanthor's route and just use string objects as (if created on the stack) they will clean themselves up and the string when they go out of scope."

Scratch this, I think the string object makes a copy of the string/char* assigned to it (which makes sense). So you still have to store (and delete) the char pointer returned by agk string functions.

Quote: "Does the memory leak unless the object is deleted apply for GetNetworkMessageString aswell, I don't see any indication of that in the documentation"

I would assume so.

JimHawkins
14
Years of Service
User Offline
Joined: 26th Jul 2009
Location: Hull - UK
Posted: 13th Dec 2012 23:25
As Ancient Lady says, this is actually quite a difficult issue. To get it right we do need some more information.

I assume that this string is not reference-counted, as it would be in Delphi, so we can't assume that it will free memory if we simply assign it an empty string. In a sense, AppGameKit is a kind of operating system running inside a host, and as hosts we have no idea what this little beast is doing unless methods are exposed.

Good questions are:

* Does this automatically get freed when it goes out of scope?
* If we nil the pointer, is the memory still on the heap?
* Can we have a SafeAGKKillString(mystringpointer) function?

I suspect that's (No, Yes, No)

There are times when I would like TGC to expose at least a few of the internal code elements to make it easier for us to deal with the issues. This is one of those. If we simply get a char * it is not sufficient information to say "free it" - we need "This is how to free it."

-- Jim DO IT FASTER, EASIER AND BETTER WITH AppGameKit FOR PASCAL
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 13th Dec 2012 23:44
I agree, all of this (ok my) 'assuming' is dangerous.

Quote: "If we simply get a char * it is not sufficient information to say "free it" - we need "This is how to free it.""

I second this.

Paul Johnston
TGC Developer
21
Years of Service
User Offline
Joined: 16th Nov 2002
Location: United Kingdom
Posted: 14th Dec 2012 00:12
All AppGameKit functions that return a char* should be deleted with delete[], there are some alternatives for tier 2 that use the AppGameKit uString class which wraps up the memory handling and will delete itself when it goes out of scope.

In my experience Windows handles "delete" and "delete[]" mix ups pretty well and will still clean up all the memory originally assigned (whether it will correctly call the destructors for an array of objects though is another question). iOS on the other hand does require the correct version of delete to be used.
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 14th Dec 2012 00:43
Thanks Paul!

I've added this to the wiki, feel free to add to it, update it etc.
http://appgamekit.wikispaces.com/CplusplusStrings

Quote: "there are some alternatives for tier 2 that use the AppGameKit uString class which wraps up the memory handling and will delete itself when it goes out of scope."

I noticed the uString class there, I might make use of it for generic strings. When creating a uString with a char pointer, does it make a copy of the string?

Paul Johnston
TGC Developer
21
Years of Service
User Offline
Joined: 16th Nov 2002
Location: United Kingdom
Posted: 14th Dec 2012 00:45
uString makes a copy of any char* used to create or modify it
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 14th Dec 2012 00:47
Thanks Paul, I just needed to be sure.

Ancient Lady
Valued Member
20
Years of Service
User Offline
Joined: 17th Mar 2004
Location: Anchorage, Alaska, USA
Posted: 14th Dec 2012 17:12
Thank you, Paul, for clearing it up for us. It is a great help to know and now we can make sure that we don't have memory leaks happening.

Cheers,
Ancient Lady
AGK Community Tester and AppGameKit Master
The Zoq2
14
Years of Service
User Offline
Joined: 4th Nov 2009
Location: Linköping, Sweden
Posted: 14th Dec 2012 23:12 Edited at: 14th Dec 2012 23:51
Just so im sure that im not getting any memory leaks from these things.



Edit: I just found something that I think may cause a problem for me...

Since I send some strings on the network, I create some char*'s but when I delete them, I get some werid erros. Now that I think about it, it makes sense, but it dosn't seem like im doing things correctly. Basicaly if I do this:


I get the correct strings, but if I have understood these things correctly, this will cause a memory leak. So in order to fix this, I added the delete[p] command after every loading, but now I get some weird strings. I realise that I delete the strings from the memory when doing delete[], but this would mean that I would have to have 1 char* / string I want to save in my program. Which would be a bit anoying. Have I understood things correctly or am I doing it wrong?
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 15th Dec 2012 01:26
Your first code snippet is fine.

Quote: "sectors[0].name = p;"

This bit is a problem. sectors[0].name and p both point to the exact same memory address so if you delete[] p, sectors[0].name is consequently pointing to freed memory. If you want sectors[0].name to be independent from p then make it a string type. When assigning a char pointer to a string type, the string will make a copy of the character array char* points to. Then you'll be able to delete p without it affecting other strings.

#include <string>
class Sectors {
public:
std::string name;
};

Dar13
15
Years of Service
User Offline
Joined: 12th May 2008
Location: Microsoft VisualStudio 2010 Professional
Posted: 15th Dec 2012 16:32
Or if he really wants to keep the char pointer, he can do something like this:
sectors[0].name = p; p = NULL;
(deletion of a null pointer does nothing)

or this:
class Sectors
{
public:
char name[40];
};
memcpy(sectors[0].name,p,strlen(p)+1);
(basically does what std::string would do but keeps the char pointer)

It's basically the programmer's choice though.

JimHawkins
14
Years of Service
User Offline
Joined: 26th Jul 2009
Location: Hull - UK
Posted: 15th Dec 2012 22:58
Doesn't all this strike you as semantically rather dirty?

What is the scope of the string object? It's plainly not just a few bytes of memory. If there is a string constructor should there not also be a destructor?

What happens when you manipulate this string by changing it?

-- Jim DO IT FASTER, EASIER AND BETTER WITH AppGameKit FOR PASCAL
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 15th Dec 2012 23:40 Edited at: 15th Dec 2012 23:40
Quote: "What is the scope of the string object?"

The scope of any variable in C++ is defined by the block (between the two { } ) it's created in.

For example:


That probably wasn't a very good explanation but I hope it conveys the right idea.

Quote: "
If there is a string constructor should there not also be a destructor?"

There is a destructor and it's called upon either delete, delete[] or, if stack based, when it goes out of scope.

Quote: "What happens when you manipulate this string by changing it?"

It's the same as changing any other variable I guess. If you're talking about the String class; string objects create a copy of the char* their given in the constructor. They're also operator overloaded to do the same thing upon the = operator. So manipulating the string won't affect the source.

JimHawkins
14
Years of Service
User Offline
Joined: 26th Jul 2009
Location: Hull - UK
Posted: 15th Dec 2012 23:53
Hodgey - I understand that, but I was asking what is the difference from calling an AppGameKit string and a generic C++ string. If any! If there's no difference, why call AppGameKit at all?

-- Jim DO IT FASTER, EASIER AND BETTER WITH AppGameKit FOR PASCAL
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 16th Dec 2012 00:01
Quote: "I understand that"

I was wondering why you were asking such a basic question.

Quote: "what is the difference from calling an AppGameKit string and a generic C++ string. "

So std::string vs uString? There may not be many technical differences (I haven't really looked into it) but using uString means I don't have to include <string> and I don't have to worry about calling the namespace std as well. Also, uString has been integrated into AppGameKit so it's likely to be more compatible.

JimHawkins
14
Years of Service
User Offline
Joined: 26th Jul 2009
Location: Hull - UK
Posted: 16th Dec 2012 00:05
Thanks, Hodgey - so I think you're agree that this needs to be disambiguated!

-- Jim DO IT FASTER, EASIER AND BETTER WITH AppGameKit FOR PASCAL
Hodgey
14
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 16th Dec 2012 00:23
Quote: "so I think you're agree that this needs to be disambiguated!"

We could use some more documentation on this, at least some definitions. When someone refers to a string in C++, it can mean a char pointer to an array of characters, or an object of the C++ string class or a uString.

The Zoq2
14
Years of Service
User Offline
Joined: 4th Nov 2009
Location: Linköping, Sweden
Posted: 25th Dec 2012 23:15 Edited at: 25th Dec 2012 23:48
And once again I have some questions regarding this

If I put a char* in a class and then use the delete command in the constructor, will the char get removed from memory once the class is removed. And what if I edit the value?
Dar13
15
Years of Service
User Offline
Joined: 12th May 2008
Location: Microsoft VisualStudio 2010 Professional
Posted: 26th Dec 2012 00:28
The memory pointed to by the char pointer will be deleted, and any other equivalent pointers will become invalid.

Editing it would be like any other variable, but you have to remember that you're dealing with pointers, not values.

Here's a quick example to show how this can get a bit tricky with char pointers:


While with std::strings it can look like this:


Ancient Lady
Valued Member
20
Years of Service
User Offline
Joined: 17th Mar 2004
Location: Anchorage, Alaska, USA
Posted: 2nd Jan 2013 16:33
If you use a char* variable in a class and assign it something, you need to make sure to delete the assigned value (using 'delete[] varnam') or you run the risk of memory leaks.

While the pointer itself becomes invalid when the class object is deleted, it does NOT automatically release the memory that was assigned when you created a string for the char* variable.

Cheers,
Ancient Lady
AGK Community Tester and AppGameKit Master
The Zoq2
14
Years of Service
User Offline
Joined: 4th Nov 2009
Location: Linköping, Sweden
Posted: 10th Feb 2013 21:10
I got thinking about this again. In my current project, im mostly using uStrings for storing strings. But sometimes I find that I have to use the .getString function. Does this return a char*, and if so, will I have to delete that.
Ancient Lady
Valued Member
20
Years of Service
User Offline
Joined: 17th Mar 2004
Location: Anchorage, Alaska, USA
Posted: 10th Feb 2013 22:04
I don't know. I can't find something that shows me the function call for uStrings for getString.

If it returns a 'const char*', then you don't have to delete it.

If it is 'char *', you probably do.

Cheers,
Ancient Lady
AGK Community Tester and AppGameKit Master
fog
20
Years of Service
User Offline
Joined: 5th Oct 2003
Location: Newcastle, England
Posted: 10th Feb 2013 22:35
Quote: "I don't know. I can't find something that shows me the function call for uStrings for getString.

If it returns a 'const char*', then you don't have to delete it.

If it is 'char *', you probably do."

The actual method is .GetStr() and yes, it returns 'const char*'

The Zoq2
14
Years of Service
User Offline
Joined: 4th Nov 2009
Location: Linköping, Sweden
Posted: 10th Feb 2013 22:38
So then I don't have to delete it, that will make things easier
Paul Johnston
TGC Developer
21
Years of Service
User Offline
Joined: 16th Nov 2002
Location: United Kingdom
Posted: 13th Feb 2013 17:59 Edited at: 13th Feb 2013 18:00
Quote: "So then I don't have to delete it"

Correct

Quote: "If it returns a 'const char*', then you don't have to delete it.

If it is 'char *', you do."

AGK follows this rule

Login to post a reply

Server time is: 2024-05-08 01:31:13
Your offset time is: 2024-05-08 01:31:13