Newsletters Subscriptions Forums Media Kit About Us Contact Search Home

mgo
OS/400 Edition
Volume 3, Number 76 -- November 12, 2003

Returning a Pointer to a Data Structure from a Function


by Steven Gray

Working with pointers can be a challenge. As iSeries developers using RPG, we need challenges to keep our bragging rights, but most of our day-to-day decisions are based on real business needs and long-term practicality. And though we know RPG can do almost everything C++ can do, none of us wants some maintenance programmer to suffer with something we wrote years ago just to prove our manliness. Nor do we want to untangle something we ourselves wrote when we were youthful and adventurous.

Sometimes pointers are just a very effective way of passing data. A data structure, for example, is a good way to return a lot of data from a procedure as a single item. Creating a function that returns a data structure is efficient, but setting up the procedure interface can require some extra thought.

Here's a technique I use to simplify the call and to exploit the compiler's ability to do much of the work for me. I can use standard RPG technique and still get the thrill of calling a function that returns a pointer to a data structure.

First, I create a function that returns my data bundled in a string. The string actually contains the data structure that I load with whatever values I need. Bundling the inbound data in a string, and putting all outbound parameters as read-only, makes maintenance easier. It's also more readable. Then all that's left is to load my target data structure with the data in the string. This is a snap to do by using the %STR() built-in function. The function %STR() looks at the pointer that is returned and sees it as the first character of a string. It loads the first character onto the data structure and continues to unwind, loading the remaining characters onto the data structure until it comes to the end of the string. I will mark the end of the string with the standard hex"00".

One line of code calls the function and loads the data structure from the pointer. Here's what it looks like in the calling program:

FCustomer  IF   E           K DISK    rename(Customer:Cfmt)
* funct prototype
D getCustDS       PR
D  pCustNum                     05P 0 value
 *
D CustDS          DS
D   CustNum                     10S 0
D   Name                        40
D   Addr                        40
D   CityStZip                   40
D   CurBal                       9S 2
D   CredBal                      9S 2
 *
D  zCustNum       S             10S 0
 *
C                   Eval      zCustNum = 1001
 * call function and use %str() to load DS
C                   Eval      CustDS = %str( getCustDS(zCustNum) )
 * do other stuff here
C                   Eval      *inlr = *on

This method also simplifies the procedure interface. A pointer to a string is all that is returned by the function. Passed parameters are not returned, allowing the use of pass by VALUE. Using the keyword VALUE tells the compiler to create a copy of the data to be passed to the function and also to fix any data type differences it might find, which means less maintenance for me. (I intentionally created a type mismatch here to show how this feature works.)

Here's all that's needed to begin the procedure.

P getCustDS       B
D getCustDS       PI              *
D  zCustNum                     05P 0 value

The body of the function contains just regular RPG code. Here I do all the normal work to assemble data and load a local copy of the customer data structure.

D CustDS          DS
D   CustNum                     10S 0
D   Name                        40
D   Addr                        40
D   CityStZip                   40
D   CurBal                       9S 2
D   CredBal                      9S 2
 *
D ReturnStr       S            200    inz(*blanks)
 *
C     pCustNum      Chain     cfmt
C                   If        %found
 * load DS here
C            Eval      CustNum         = CustomerNo
C            Eval      Name            = %trim(FName) + ' ' +
C                                      %trim(MidInit) + ' ' +
C                                      %trim(LName) + ' '
C            Eval      Addr            = address1
C            Eval      CityStZip       = %trim(city)  + ', '
C                                      + %trim(state) + '  '
C                                      + %trim(zipcode)
C            Eval      CurBal          = Balance
C            Eval      CredBal         = Credit - Balance
C            Else
C            Eval      CustNum         = *zeros
C            Endif

When I have finished loading the local copy of the data structure, it needs to be converted to a string before passing it back to the calling program. There are a number of ways to do this, but to keep things simple here, I append a NULL to the data structure and copy it to a character variable. This fills the requirements for a string. The function returns with the address of the variable.

C                   Eval      ReturnStr =  ReturnDS + X'00'    
C                   Return    %addr( ReturnStr )  
P getCustDS       E                     

Again, when my function returns, the %STR() BIF will load my target data structure, starting from the first character and continuing to the first NULL it finds. The important thing to keep in mind is that the attributes of the local copy of the data structure in the function and the target data structure must match. Using an external data structure or a /COPY member could simplify this.

For this example, I have put the function at the end of the source member. For use in production, the function should be put in a service program. And, of course, put your prototype in a separate /COPY member. To test this example, I have included sample SQL statements you can use to create and load the CUSTOMER file.


Steven Gray is a consultant for Paradigm Business Solutions, a Lawson and Microsoft business partner. He has worked with the AS/400 and iSeries for over 16 years, starting with the S/38. E-mail: steven.gray@rcn.com


Sponsored By
ADVANCED SYSTEMS CONCEPTS


WHAT IF


Creating Queries, Reports and Downloads
was Easy, Fast and Convenient
for ALL Users?


- - - Make it happen with SEQUEL ! - - -

Get a Free Trial today.

Read More



THIS ISSUE
SPONSORED BY:

Advanced Systems Concepts
inFORM Decisions


BACK ISSUES

TABLE OF
CONTENTS

Returning a Pointer to a Data Structure from a Function

Get with the Times

Reader Feedback and Insights: Reader Prefers DDS



Editors
Howard Arner
Joe Hertvik
Ted Holt
David Morris

Managing Editor
Shannon Pastore

Publisher and
Advertising Director:

Jenny Thomas

Advertising Sales Representative
Kim Reed

Contact the Editors
Do you have a gripe, inside dope or an opinion?
Email the editors:
editors@itjungle.com

Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved.