Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2009-10

pointer arithmetic help required

7 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Graeme Geldenhuys

Hi,

Sorry, I suck at this pointers think. Currently I am reading one record in correctly and from there is all corrupted data. :-(

Seeing that the first block of data (pEntry^ below) is correct, it seems my problem is incrementing to the next block of data. Here are the various variables I am working with

_pContentsData = a generic Pointer type that points to a block of data (containing multiples of various structures). XXX bytes of information.

pEntry = this is a pointer to a specific starting structure type and will increment in blocks of data to point to the various structures stored in _pContentsData. Each pEntry has a Length property that says how many bytes of data is used for all it's information.

pEnd = the ending point of all the data held by _pContentsData. This variable is just a safety net, so pEntry doesn't move past the end of data block by accident.

I have the following code...

------------------------
  pEntry := _pContentsData;
     // below toclen is in bytes
  pEnd := _pContentsData + _pHeader^.toclen;

// START LOOP
[(a)...do various things with data pointed to by pEntry..] ....

  // now increment pEntry to point to next data structure
  // below, .Length is in bytes
  inc( pEntry, pEntry^.Length);
  // now repeat from (a) above until all data is processed
// END LOOP
------------------------

Question:
Am I incrementing the pEnd and pEntry in the correct way? They are pointers to structures, so I believe I don't need to dereference them, because I am working with the pointer at that stage and not the actual data.
Example:

  inc(pEntry, pEntry^.Length);
vs
  inc(pEntry, pEntry^.Length * sizeof(byte));

Luckily the above method is not the only way to read the data I am interrested in. There is also a redundant array of file offsets pointing to each pEntry I am interrested in. Using the array works fine, but using the incrementing method shown below, I am having problems. :-(
Purely for the purpose of learning I would like to be able to get both methods working - how else am I supposed to learn these things. :)

[I think I need to dig up my old college handbooks and relearn the basics of pointers and record structures with binary file data]

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/
Martin
to Graeme Geldenhuys
Graeme Geldenhuys wrote 9 lines
_pContentsData = a generic Pointer type that points to a block of data (containing multiples of various structures). XXX bytes of information. pEntry = this is a pointer to a specific starting structure type and will increment in blocks of data to point to the various structures stored in _pContentsData. Each pEntry has a Length property that says how many bytes of data is used for all it's information.

if pentry is
TEntry = record .. end;
pentry = ^ TEntry

Show quoted text 11 lines
pEnd = the ending point of all the data held by _pContentsData. This variable is just a safety net, so pEntry doesn't move past the end of data block by accident. I have the following code... ------------------------ pEntry := _pContentsData; // below toclen is in bytes pEnd := _pContentsData + _pHeader^.toclen;

is toclen, in bytes, or in units (eg number of records)

the above assumes bytes, if

_pContentsData = pointer; //not typed
Show quoted text 8 lines
// START LOOP [(a)...do various things with data pointed to by pEntry..] .... // now increment pEntry to point to next data structure // below, .Length is in bytes inc( pEntry, pEntry^.Length);

inc(PEntry, 1)

since it increments by the size of the type

Show quoted text 29 lines
// now repeat from (a) above until all data is processed // END LOOP ------------------------ Question: Am I incrementing the pEnd and pEntry in the correct way? They are pointers to structures, so I believe I don't need to dereference them, because I am working with the pointer at that stage and not the actual data. Example: inc(pEntry, pEntry^.Length); vs inc(pEntry, pEntry^.Length * sizeof(byte)); Luckily the above method is not the only way to read the data I am interrested in. There is also a redundant array of file offsets pointing to each pEntry I am interrested in. Using the array works fine, but using the incrementing method shown below, I am having problems. :-( Purely for the purpose of learning I would like to be able to get both methods working - how else am I supposed to learn these things. :) [I think I need to dig up my old college handbooks and relearn the basics of pointers and record structures with binary file data]
Graeme Geldenhuys
to Martin

By the way, I am reading in the Table of Contents data for an OS/2 INF file.

Martin wrote
> if pentry is TEntry = record .. end; pentry = ^ TEntry
Yes, pEntry is a pointer to a structured type.
  pEntry: pTTOCEntryStart;
The actual structure is as follows...
------------------------
Type
  TTOCEntryStart = packed record
    length: uint8;// length in bytes including this byte
    flags: uint8; // flag byte, description folows (MSB first)
                  // bit1 haschildren;
                  // bit1 hidden;
                  // bit1 extended;     // extended entry format
                  // bit1 stuff;        // ??
                  // int4 level;        // nesting level
    numSlots: uint8; // number of "slots" occupied by the text for
                     // this toc entry
  end;
  pTTOCEntryStart = ^TTOCEntryStart;
------------------------
Show quoted text 6 lines
> ------------------------ > pEntry := _pContentsData; > // below toclen is in bytes > pEnd := _pContentsData + _pHeader^.toclen; > is toclen, in bytes, or in units (eg number of records)

_pHeader^.toclen is in number of bytes of data that pContentData is pointing at.

the above assumes bytes, if _pContentsData = pointer; //not typed

Yes, pContentsData is not typed because it contains various structures, NOT just a repeat of one structure type.

So I assume I am incrementing pEnd correctly at that point.

Show quoted text 7 lines
> // now increment pEntry to point to next data structure > // below, .Length is in bytes > inc( pEntry, pEntry^.Length); > inc(PEntry, 1) since it increments by the size of the type

No, I don't think that is correct. The data pContentData is pointing at, holds various structures of differing sizes. pEntry^.Length says that all data relating to one TOC entry is XXX bytes in length. That means the TTOCEntryStart structure itself (only 3 bytes) and various other structures making up the difference.

eg: In the file I am trying to read, the first pEntry^.Length is 17 bytes. Meaning 3 bytes for TTOCEntryStart itself, and 14 bytes of other information.

Here is a graphical but very simplified representation.

In this example, pContentsData will point to the beginning of this data block, encapsulating all the information shown below. Each TOC entry (complete data) is grouped together. As you can see, no set length, each entry can have 0 or 1 "extended data" info and 1 or more "data slots" and the title.

pContentsData----v
-----------------------
TOCEntryStart
pEntry^.Length = 17 TOCExtendedInfo
Data Slot
Title
-----------------------
TOCEntryStart
pEntry^.Length = 10 Data Slot
Title
-----------------------
TOCEntryStart
pEntry^.Length = 30 TOCExtendedInfo
Data Slot
Data Slot
Data Slot
Title
-----------------------
pEnd--------^

Base of the above information: _pHeader^.toclen should equal 57.

Regards,
- Graeme -

Martin
to Graeme Geldenhuys
Graeme Geldenhuys wrote 20 lines
By the way, I am reading in the Table of Contents data for an OS/2 INF file. >> // now increment pEntry to point to next data structure >> // below, .Length is in bytes >> inc( pEntry, pEntry^.Length); >> >> > inc(PEntry, 1) > > since it increments by the size of the type > No, I don't think that is correct. The data pContentData is pointing at, holds various structures of differing sizes. pEntry^.Length says that all data relating to one TOC entry is XXX bytes in length. That means the TTOCEntryStart structure itself (only 3 bytes) and various other structures making up the difference.

If pentry differs in length, then use a byte pointer, (for which inc will work in bytes), and cast it onlt when you access the data.

I don't know if you can do it the other way round (eg trick inc to belive it's a byte pointer by casting):
inc(pbyte(pentry), pentry.length); // no idea if that will work, never tried

Martin

Graeme Geldenhuys
to Martin
Martin wrote 22 lines
Graeme Geldenhuys wrote: > By the way, I am reading in the Table of Contents data for an OS/2 INF file. > > > >>> // now increment pEntry to point to next data structure >>> // below, .Length is in bytes >>> inc( pEntry, pEntry^.Length); >>> >>> >> inc(PEntry, 1) >> >> since it increments by the size of the type >> > No, I don't think that is correct. The data pContentData is pointing at, > holds various structures of differing sizes. pEntry^.Length says that > all data relating to one TOC entry is XXX bytes in length. That means > the TTOCEntryStart structure itself (only 3 bytes) and various other > structures making up the difference. > If pentry differs in length, then use a byte pointer, (for which inc will work in bytes), and cast it onlt when you access the data.

Ah, I get it now! :-) Because pEntry is a pointer to a structure, inc() will increment pEntry by multiples of the structure size. Casting it to a PByte forces inc() to increment in bytes, which is what pEntry^.Length is indicating. There is light at the end of this long tunnel. Thanks for your help, Martin.

I changed the code at the end of the loop to the following. Now stepping through the code, it's pulling out the data correctly. :-)

    p := PByte(pEntry);
    inc(p, pEntry^.Length);
    pEntry := pTTOCentryStart(p);

Now I know why vendors of newer languages (Dephi, Java etc) are trying to hide pointers from programmers. They are very tricky to work with - and give errors without warning!

Regards,
- Graeme -

Vinzent Höfler
to Graeme Geldenhuys

Graeme Geldenhuys :

Now I know why vendors of newer languages (Dephi, Java etc) are trying to hide pointers from programmers. They are very tricky to work with - and give errors without warning!

Especially when compiler and programmer are both trying to outsmart each other. :D

Vinzent.

Jetzt kostenlos herunterladen: Internet Explorer 8 und Mozilla Firefox 3.5 - sicherer, schneller und einfacher! http://portal.gmx.net/de/go/chbrowser
Jürgen Hestermann
to Vinzent Höfler
> Now I know why vendors of newer languages (Dephi, Java etc) are trying > to hide pointers from programmers. They are very tricky to work with - > and give errors without warning! Especially when compiler and programmer are both trying to outsmart each other. :D

Yes. But I never needed pointer arithmetic in my programs even when using pointers heavily. I always use arrays (of pointers) or records (with pointers) where the pointers point to well defined data types. I an a bit astonished that pointer arithmetic is even possible in Pascal. Yet another C-style crept in.