Author Topic: Pointer trouble  (Read 8189 times)

0 Members and 1 Guest are viewing this topic.

Offline TC01

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 344
  • Rating: +9/-0
    • View Profile
Pointer trouble
« on: August 03, 2010, 07:45:23 pm »
A note- this is 68k C (GCC4TI), not Nspire C. Shouldn't really be a difference except for the nature of my error...

I've mostly finished making z89 (that's my z80 Basic editor for 68k calcs) read in the list of tokens from a token file, then build them into an array of tokenInfo structures. The code to do this is rather complicated and probably poorly written- I'm not the best C programmer. I only started programming in C recently. However, it works.

Or, at least, it would work if not for the Address Error I get when I try to free allocated memory at the end of the process. I have four pointers to strings being dynamically allocated- the text of the token file, a "working" string (for storing end-of-line characters and other things necessary in procedures like strcpsn()), a line string (for storing each line of the text file), and a "tokenstr" string, for storing token information (first the name, then the first token in hex).

I had had problems with this before. Specifically, originally I was using realloc() to shrink and decrease the line string on each pass through the while loop. But that was causing an Address Error. I "solved" it by allocating enough memory to store the entire file to the line string- I'm not entirely sure why that solved the problem, though.

The GCC4TI docs offer the definition of an address error below, but I'm not sure how trying to free the pointers would cause that.

Quote from: GCC4TI docs
Q: What kind of error in my program usually causes an "Address Error"?

A: Well, writing over the boundaries of an array can usually cause all sorts of errors, since it usually destroys code or the return address of the function. However, an "Address Error" actually means that a short or long value is read or written at an odd address. So if you get an "Address Error" while you are dealing with pointers, check that you do not cast an odd address to a pointer to a short or long integer. 

Here is my long and probably over-complex initTokens() function, which is where the array of token infos is built. It assumes the text file is formatted as follows (name\byte1\byte2, with byte2=0 if the token is one byte):

Code: [Select]
:BoxPlot\0x05\0
:ClrHome\0xE1\0

Code: [Select]
void initTokens(tokenInfo *tokens, char *tokenfile)
{
    int length;
    int bool;
    int newlength;
    int span = 0;
    int i = 0;
    char newchar;
    char endline = '\r';
    unsigned long rawhex;
    unsigned short size = 0;
    unsigned char hex = '0';

    char *tokentext = NULL;
    char *working = NULL;
    char *line = NULL;
    char *tokenstr = NULL;

    tokenInfo token;
    SYM_ENTRY *sym;
   
    if ((working = (char *)calloc(2, sizeof(char))) == NULL)
    {
        DlgMessage("DMA Failure", "Unable to allocate space for working string", BT_OK, BT_NONE);
        return;
    }
    if ((line = (char *)calloc(10, sizeof(char))) == NULL)
    {
        DlgMessage("DMA Failure", "Unable to allocate space for line string", BT_OK, BT_NONE);
        free(working);
        return;
    }
    if ((tokenstr = (char *)calloc(16, sizeof(char))) == NULL)
    {
        DlgMessage("DMA Failure", "Unable to allocate space for token working string", BT_OK, BT_NONE);
        free(working);
        free(line);
        return;
    }
   
    //Get the size of the token file and allocate memory accordingly
    sym = SymFindPtr(SYMSTR(tokenfile), 0);
    size = ((MULTI_EXPR*)HeapDeref(sym->handle))->Size + 2;
    if ((tokentext = (char *)calloc(size, sizeof(char))) == NULL)
    {
        DlgMessage("DMA Failure", "Unable to allocate space for token file string", BT_OK, BT_NONE);
        free(working);
        free(line);
        free(tokenstr);
        return;
    }
   
    //Get input from file, set length and reallocate memory to troublesome pointers
    bool = getPrgmFromText(tokenfile, tokentext, size);
    if (bool == 0)
    {
        free(tokentext);
        free(working);
        free(line);
        return;
    }
    length = strlen(tokentext);
    line = (char *)realloc(line, (length + 2) * sizeof(char));
    tokenstr = (char *)realloc(tokenstr, (length + 2) * sizeof(char));

    //Loop until the length of the input string is zero
    while (length > 0)
    {
        //Maintain num token size!
        i += 1;
        if (i > NUM_TOKENS)
        {
            tokens = (tokenInfo *)realloc(tokens, i * sizeof(tokenInfo));
            NUM_TOKENS = i;
        }

        //Get the length of the line up to trailing character, reallocate memory
        memset(working, '\0', strlen(working));
        memset(line, '\0', strlen(line));   
        memset(tokenstr, '\0', strlen(tokenstr));           
        sprintf(working, "%c", endline);
        span = strcspn(tokentext, working);
       
        //Load the line into a string, and then remove it
        line = strncat(line, tokentext, span);
        tokentext = strpbrk(tokentext, working);
       
        //Then clear out the \r at the front of the string and clear the working string out
        newchar = tokentext[2];
        sprintf(working, "%c", newchar);
        tokentext = strpbrk(tokentext, working);
        length = strlen(tokentext);
       
        //Init the token
        token = tokens[i];
        token.twoByteToken = 0;

        //Seperate the name component from the line and set it (and it's length!)
        memset(working, '\0', strlen(working));
        sprintf(working, "%c", '\\');
        newlength = strcspn(line, working);
        tokenstr = strncat(tokenstr, line, newlength);
        line += (newlength + 1);
        token.chars = newlength;
        token.name = tokenstr;
       
        //Seperate the hex component from the line and set it
        memset(tokenstr, '\0', strlen(tokenstr));
        tokenstr = strncat(tokenstr, line, 4);
        rawhex = strtol(tokenstr, NULL, 0);
        hex = (unsigned char)rawhex;
        token.hex[0] = hex;
        line += 5;

        //Then check if what's left of the string is the second byte of a two-byte token and deal with it
        if (line[0] != '0')
        {
            rawhex = strtol(tokenstr, NULL, 0);
            ngetchx();
            hex = (unsigned char)rawhex;
            token.hex[1] = hex;
            token.twoByteToken = 1;
        }

        //Update the token
        tokens[i] = token;
    }
   
    //Free memory
    free(working);
    free(tokenstr);
    free(line);
    free(tokentext);
}



The userbars in my sig are links embedded links.

And in addition to calculator (and Python!) stuff, I mod Civilization 4 (frequently with Python).

Offline Lionel Debroux

  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2135
  • Rating: +290/-45
    • View Profile
    • TI-Chess Team
Re: Pointer trouble
« Reply #1 on: August 04, 2010, 08:26:30 am »
Stylistically speaking, DMA usually stands for "Direct Memory Access" instead of "Dynamic Memory Allocation" :)

It's often hard to debug a program with just one function, could you upload the source somewhere so that we can 1) look at the full source, 2) compile it and 3) execute it?
Member of the TI-Chess Team.
Co-maintainer of GCC4TI (GCC4TI online documentation), TILP and TIEmu.
Co-admin of TI-Planet.

Offline TC01

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 344
  • Rating: +9/-0
    • View Profile
Re: Pointer trouble
« Reply #2 on: August 04, 2010, 10:20:42 am »
Stylistically speaking, DMA usually stands for "Direct Memory Access" instead of "Dynamic Memory Allocation" :)

Oh, okay. (I based it on the Technoplaza tutorials, which use an error message similar to that).

Quote
It's often hard to debug a program with just one function, could you upload the source somewhere so that we can 1) look at the full source, 2) compile it and 3) execute it?

Okay, I've attached it (with the compiled 89z, 9xz, and v2z files included).



The userbars in my sig are links embedded links.

And in addition to calculator (and Python!) stuff, I mod Civilization 4 (frequently with Python).

Offline Lionel Debroux

  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2135
  • Rating: +290/-45
    • View Profile
    • TI-Chess Team
Re: Pointer trouble
« Reply #3 on: August 05, 2010, 05:46:00 am »
I'll try to look at that, but don't let that prevent you from proceeding further :)

Note about "Solar": there's a "Solar Striker" game, http://www.yaronet.com/t3/?id=8 .
Member of the TI-Chess Team.
Co-maintainer of GCC4TI (GCC4TI online documentation), TILP and TIEmu.
Co-admin of TI-Planet.

Offline TC01

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 344
  • Rating: +9/-0
    • View Profile
Re: Pointer trouble
« Reply #4 on: August 05, 2010, 09:52:17 am »
Thanks Lionel. And yes, I'll continue to work on it myself at the same time.

I did notice an older version of that game when I searched the ticalc.org archives for Solar to see if anything used the name Solar89, but wasn't actually called Solar89 so I decided it was okay.



The userbars in my sig are links embedded links.

And in addition to calculator (and Python!) stuff, I mod Civilization 4 (frequently with Python).

Offline TC01

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 344
  • Rating: +9/-0
    • View Profile
Re: Pointer trouble
« Reply #5 on: August 06, 2010, 01:10:55 pm »
Okay, well I guess I've figured it out but I don't know what to do about it.

You can't free a pointer after you've changed it. And in that code, all pointers are either being memset (to reinitialize them to point to nothing) or changed (for instance, the line pointer is incremented).

The advice given in the GCC4TI docs is "preserve the original pointer and pass it to free". How would I do this? Make a function and pass the code where I'm manipulating the pointer there?
« Last Edit: August 06, 2010, 01:12:37 pm by TC01 »



The userbars in my sig are links embedded links.

And in addition to calculator (and Python!) stuff, I mod Civilization 4 (frequently with Python).

Offline Lionel Debroux

  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2135
  • Rating: +290/-45
    • View Profile
    • TI-Chess Team
Re: Pointer trouble
« Reply #6 on: August 07, 2010, 05:04:37 am »
Quote
The advice given in the GCC4TI docs is "preserve the original pointer and pass it to free". How would I do this? Make a function and pass the code where I'm manipulating the pointer there?
That's one of the ways to do it. But without creating a function, you can just use a temporary pointer:
Code: [Select]
type * orig_ptr = malloc/calloc(size);
type * ptr = orig_ptr;
<do something with ptr, leave orig_ptr alone>
free(orig_ptr);
Member of the TI-Chess Team.
Co-maintainer of GCC4TI (GCC4TI online documentation), TILP and TIEmu.
Co-admin of TI-Planet.