LYH wrote:

> if mes is defined as:
> 
> typedef struct
> {
> char *username;
> char *title;
> char *content;
> } messageType;
> 
> How I can allocate memory for content?
> I do it this way, but it doesn't work.
> 
> MemHandle mesContentH;
> Char* mesContent, s;
> 
> mesContentH = MemHandleNew(sizeof(mes.content));

You just asked it to tell you the size of the pointer.
"content" is a "char *".  That's a pointer.

> mesContent = MemHandleLock(mesContentH);
> StrCopy(mesContent, s);

Now you are copying in a string into this storage, but
the size you have allocated is related to the size of
a pointer.  But you are writing a string there, so the
size needs to be the size of the STRING.

In C, a string is a sequence of bytes, and the last byte is
always a zero byte.  For example, if I define the string
"PalmSource", then it is this sequence of bytes:

        { 80,97,108,109,83,111,117,114,99,101,0 }

If I want to print PalmSource (on a regular computer with
standard C library), I could do this:

        const char *str = "PalmSource";
        printf ("%s\n", str);

But, I could also do this:

        const char str[] = { 80,97,108,109,83,111,117,114,99,101,0 };
        printf ("%s\n", str);

Either way, evaluating the expression "str" gives a pointer
to the first one of the integers, so the printf() function sees
exactly the same thing either way.  It just starts at the first
integer and moves forward until it sees a 0 integer.

So, if you want to know what argument to pass to MemPtrNew(),
you have to know the length of the string that mesContent is
going to POINT TO.  Notice that I didn't say "what string
content is going to contain", since mesContent is a pointer
and can never contain a string.

If I have a string, and if str points to that string, then
"1 + StrLen(str)" is the number of bytes needed to store
that string.  The "1" is for the null character at the end,
and the "StrLen(str)" is for all the other characters.

So, the answer (to the question of how to allocate storage
memory for content) is that you must know in advance what
string you want to store.

For example, you could do this:

        void SetMessageContent (messageType *message, const char *newcontent)
        {
            message->content = MemPtrNew (1 + StrLen(newcontent));
            if (message->content != NULL)
            {
                StrCopy (message->content, newcontent);
            }
        }

        void some_other_function()
        {
            messageType mymessage;
            SetMessageContent (& mymessage, "This is my message.");
        }

However, if you call SetMessageContent() twice in a row on the
same struct (without freeing the memory allocated the first time),
then the pointer to the allocated memory will be lost and you
will have a memory leak, so I recommend that you make a rule
that you will keep everywhere inside the program:  the rule is,
either content will point to some memory allocated with MemPtrNew(),
or it will always be NULL.  This type of rule, which is known as
invariant, will help you keep things straight, because it's
something you can count on at any point in your program.  For
example:

        void InitMessage (messageType *message)
        {
            message->username = NULL;
            message->title = NULL;
            message->content = NULL;
        }

        void FreeMessage (messageType *message)
        {
            if (message->username != NULL)
            {
                MemPtrFree (message->username);
                message->username = NULL;
            }

            if (message->title != NULL)
            {
                MemPtrFree (message->title);
                message->title = NULL;
            }

            if (message->content != NULL)
            {
                MemPtrFree (message->content);
                message->content = NULL;
            }
        }

        // watch this:  we always check if content is already
        // allocated before we overwrite it

        void SetMessageContent (messageType *message, const char *newcontent)
        {
            if (message->content != NULL)
            {
                MemPtrFree (message->content);
                message->content = NULL;
            }

            message->content = MemPtrNew (1 + StrLen (newcontent));
            if (message->content != NULL)
            {
                StrCopy (message->content, newcontent);
            }
        }

        // now, you can safely call SetContent() over and over:

        void some_other_function ()
        {
            messageType mymessage;

            // always initialize before you do anything else,
            // because initialization helps you follow the rule.
            InitMessage (& mymessage);

            SetMessageContent (& mymessage, "My message contents.");
            SetMessageContent (& mymessage, "I decided to change it.");
            SetMessageContent (& mymessage, "I changed it again.");

            if (mymessage.content != NULL)
            {
                FrmCustomAlert (SomeAlert,
                        "Message content is", mymessage.content, "");
            }

            FreeMessage (& mymessage);
        }

One more comment.  Up above, you have this line:

        Char* mesContent, s;

You should be aware that that is equivalent to this:

        Char* mesContent;
        Char s;

That is, the line will not make "s" a pointer to a character.
For that reason, many C programmers have a rule:  if you allocate
two pointers, always put them in a separate allocations:

        Char* mesContent;
        Char* s;

Or, another rule is, always put them on separate lines and group
the asterisks with the variable names:

        Char   *mesContent,
               *s;

You may think this is confusing, and I think you're right, but it's
a mistake they made when they invented the C language.  (Java, for
example, has tried to fix it:  in Java, you'd type "int x[];", but
in Java the preferred form is "int[] x;", although the other form
is accepted.)

Also, you should know that the problems you're having aren't Palm
issues.  They are C issues.  Based on what you've posted, I would
say you're not the strongest on the C language.  If you want to
succeed at Palm programming (in C), then I think you need to spend
some time and concentrate on the C language itself before you are
going to have much success on programming the Palm in C.

Good luck.

  - Logan

-- 
For information on using the Palm Developer Forums, or to unsubscribe, please 
see http://www.palmos.com/dev/support/forums/

Reply via email to