Passing pointer problems
Roberto Abraham at IoA, Cambridge wrote on Aug 18, 1998
Hi -
I'm having some trouble passing a bunch of pointers to arrays from an
SPP subroutine to an SPP task, and I think I must be misunderstanding
something fundamental with regard to how pointers are passed in SPP
programs. Can anyone enlighten me?
In a nutshell, what I'm trying to do is pass a string to a subroutine,
which then finds all rows in an STSDAS table where a particular column
matches the string. I then extract a bunch of arrays from the table
and pass back pointers to these arrays. For example, say I have a
bunch of rows in the table with the string "B-V", "V-I", etc in one of
the columns. I call a subroutine to find the rows where that column
has "B-V" then return all the corresponding values in several other
columns as a bunch of arrays.
It sounds pretty trivial, and indeed my code seems to almost work.
The maddening thing is that my subroutine works fine the first time my
task calls it, but on subsequent calls the subroutine passes back
pointers to garbage instead of pointers to my arrays of numbers. More
specifically, even after the first call the subroutine seems to be
doing the right thing internally, since *inside* the subroutine the
arrays are extracted correctly from the STSDAS table and are properly
defined when pointers to them are dereferenced, but once I pass the
pointers back to the main routine they no longer have the same target
as inside the subroutine. It looks to me that somehow I'm managing to
to deallocate the memory accidentally (or else retargeting the pointer
to hyperspace) simply by the act of passing the pointer back to the
main routine, but after staring at the code for ages I don't see how
that's possible.
I'm going berserk trying to figure out what the heck is happening.
Does the behaviour I describe sound like a familiar and obvious
problem to somebody... in case it is an obvious thing and you want to
laugh out loud, I've attatched a copy of the source below, along with
a test run, which shows how it seems to work fine the first time, and
then continues to do the right thing INSIDE the subroutine for
subequent calls, but then the pointer targets vanish when they're
passed.
Any ideas?
Best regards,
Bob Abraham
IoA, Cambridge
==============================================================
# Here is the source of all my grief
task pixfit = t_pixfit
include <tbset.h>
define DEBUG true
procedure t_pixfit ()
# variables input by user via the CL
int ncolour # number of colours the user wants models for
pointer colour[10] # point to a bunch of strings with desired colours
# pointers to table
pointer ktp
# variables holding information extracted from the table. Each pointer below
# points to an array of numbers, ie. tau[1] points to an array corresponding
# to all values of tau in the model table with colour colour[1], then
# tau[2] points to the array of tau values for colour[2], etc.
pointer tau[10] # point to a bunch of reals
pointer ebv[10] # point to a bunch of reals
pointer name[10] # will point to a bunch of strings holding table column names
int nmodel # number of models in the table with the desired colours
int i,j
pointer tbtopn()
int clgeti()
begin
##### Allocate memory for the individual colour names
for (i=1;i<=10;i=i+1)
call malloc(colour[i], SZ_COLNAME, TY_CHAR)
##### Read CL parameters
ncolour = clgeti ("ncolour")
call clgstr ("colour1", Memc[colour[1]], SZ_COLNAME)
call clgstr ("colour2", Memc[colour[2]], SZ_COLNAME)
call clgstr ("colour3", Memc[colour[3]], SZ_COLNAME)
call clgstr ("colour4", Memc[colour[4]], SZ_COLNAME)
call clgstr ("colour5", Memc[colour[5]], SZ_COLNAME)
##### Open table (The hardcoded table "mtest_key.tab" for this test)
ktp = tbtopn ("mtest_key", READ_ONLY, NULL)
if (ktp == NULL){
call error(1,"Error opening model key file")
}
##### Get information from table
call printf("\nTHIS IS A TEST PROGRAM: I define an bunch of pointer arrays in the\n")
call printf("main routine, then populate these with calls to a subroutine.\n")
call printf("This seems to work the *first* time I call the subroutine, but then\n")
call printf("for some curious reason, the targets pointed to by the pointers\n")
call printf("disappear when they are dereferenced outside the subroutine.\n")
call printf("\n")
call printf("To investigate this I will derefence the pointers inside the subroutine and\n")
call printf("compare this to the dereferenced pointers after they've been passed.\n\n")
# read in parameters for the models in the model table from the model key table
for(i=1;i<=ncolour;i=i+1){
nmodel = 0
call model_info (ktp, Memc[colour[i]], tau[i], ebv[i], name[i], nmodel)
call printf("\nIn main routine. The model_info() routine found %d models for colour %s \n")
call pargi(nmodel)
call pargstr(Memc[colour[i]])
# report on what we've just been passed by the subroutine.
for(j=0;j<nmodel;j=j+1){
call printf("tau: %g ebv: %g name: %s \n")
call pargr(Memr[tau[i]+j])
call pargr(Memr[ebv[i]+j])
call pargstr(Memc[name[i] + SZ_COLNAME*j])
}
call printf("\n")
}
# I won't bother deallocating the memory for the test program,
# but in the real routine it's done here.
end
#####################################################################
# MODEL_INFO -- returns arrays giving the column numbers
# corresponding to models of a given colour, along with arrays
# holding the corresponding column names and values of tau and E(B-V).
#####################################################################
procedure model_info (ktp, colour, tau, ebv, name, nmodel)
pointer ktp
char colour[SZ_COLNAME]
pointer tau
pointer ebv
pointer name
int nmodel
char rowcolour[SZ_COLNAME]
pointer colour_cp
pointer tau_cp
pointer ebv_cp
pointer name_cp
int i,j
int tbpsta()
bool streq()
begin
call printf("Inside the model_info() subroutine... \n");
call tbcfnd (ktp, "Colour", colour_cp, 1)
call tbcfnd (ktp, "Tau", tau_cp, 1)
call tbcfnd (ktp, "E(B-V)", ebv_cp, 1)
call tbcfnd (ktp, "Column_Label", name_cp, 1)
if (colour_cp == NULL || tau_cp == NULL || ebv_cp == NULL ) {
call tbtclo (ktp)
call error (1, "a required column was not found")
}
# allocate maximum amount of memory we could possibly need. This is
# actually a bit wasteful -- I really only need nmodel/ncolour elements.
nmodel = tbpsta (ktp, TBL_NROWS)
call malloc(tau,nmodel,TY_REAL)
call malloc(ebv,nmodel,TY_REAL)
call calloc(name,nmodel*SZ_COLNAME,TY_CHAR)
j=0
for(i=0; i<nmodel; i=i+1){
call tbegtt(ktp,colour_cp,i+1,rowcolour,SZ_FNAME)
if (streq(rowcolour,colour)){
call tbegtr(ktp,tau_cp,i+1,Memr[tau+i])
call tbegtr(ktp,ebv_cp,i+1,Memr[ebv+i])
call tbegtt(ktp,name_cp,i+1,Memc[name + SZ_COLNAME*i],SZ_COLNAME)
j = j+1
# Print out the variables as seen *inside* the procedure
call printf("tau: %g ebv: %g name: %g \n")
call pargr(Memr[tau+i])
call pargr(Memr[ebv+i])
call pargstr(Memc[name+SZ_COLNAME*i])
}
}
nmodel = j
call printf("Looks ok. I'm now leaving the the model_info() subroutine... \n");
end
===============================================================
This is a tdump of the data table I've been using to experiment with:
ab> tdump mtest_key.tab
Model_Column I %3d None
Colour CH*10 %-10s ""
Tau R %15.7g Gyr
E(B-V) R %15.7g ""
Law CH*10 %-10s ""
Column_Label CH*32 %-32s ""
HISTORY t Created Fri 13:43:37 14-Aug-98
2 U-B 0.5 0.2 Calzetti
ub_tau_0.5
3 U-B 0.6 0.2 Calzetti
ub_tau_0.6
4 U-B 1. 0.2 Calzetti
ub_tau_1.
5 U-B 1.5 0.2 Calzetti
ub_tau_1.5
6 B-V 0.5 0.2 Calzetti
bv_tau_0.5
7 B-V 0.6 0.2 Calzetti
bv_tau_0.6
8 B-V 1. 0.2 Calzetti
bv_tau_1.
9 B-V 1.5 0.2 Calzetti
bv_tau_1.5
10 V-I 0.5 0.2 Calzetti
vi_tau_0.5
11 V-I 0.6 0.2 Calzetti
vi_tau_0.6
12 V-I 1. 0.2 Calzetti
vi_tau_1.
13 V-I 1.5 0.2 Calzetti
vi_tau_1.5
===============================================================
Here is a test run:
ab>pixfit
Number of colours to fit (2):
Table header keyword for first colour (U-B):
Table header keyword for second colour (B-V):
Table header keyword for third colour (NIL):
Table header keyword for fourth colour (NIL):
Table header keyword for fifth colour (NIL):
THIS IS A TEST PROGRAM: I define an bunch of pointer arrays in the
main routine, then populate these with calls to a subroutine.
This seems to work the *first* time I call the subroutine, but then
for some curious reason, the targets pointed to by the pointers
disappear when they are dereferenced outside the subroutine.
To investigate this I will derefence the pointers inside the subroutine and
compare this to the dereferenced pointers after they've been passed.
Inside the model_info() subroutine...
tau: 0.5 ebv: 0.2 name: ub_tau_0.5
tau: 0.6 ebv: 0.2 name: ub_tau_0.6
tau: 1. ebv: 0.2 name: ub_tau_1.
tau: 1.5 ebv: 0.2 name: ub_tau_1.5
Looks ok. I'm now leaving the the model_info() subroutine...
In main routine. The model_info() routine found 4 models for colour U-B
tau: 0.5 ebv: 0.2 name: ub_tau_0.5
tau: 0.6 ebv: 0.2 name: ub_tau_0.6
tau: 1. ebv: 0.2 name: ub_tau_1.
tau: 1.5 ebv: 0.2 name: ub_tau_1.5
Inside the model_info() subroutine...
tau: 0.5 ebv: 0.2 name: bv_tau_0.5
tau: 0.6 ebv: 0.2 name: bv_tau_0.6
tau: 1. ebv: 0.2 name: bv_tau_1.
tau: 1.5 ebv: 0.2 name: bv_tau_1.5
Looks ok. I'm now leaving the the model_info() subroutine...
In main routine. The model_info() routine found 4 models for colour B-V
tau: 0. ebv: 0. name:
tau: 0. ebv: 0. name:
tau: 0. ebv: 0. name:
tau: 0. ebv: 0. name:
ab>
---------------------------------------------------------------------------
Roberto Abraham | E-mail: abraham@ast.cam.ac.uk
Institute of Astronomy | Tel (direct) +44-(0)-1223-374970
Cambridge University | (secretary) +44-(0)-1223-337548
Madingley Road, Cambridge | FAX +44-(0)-1223-337523
CB3 OHA United Kingdom | Mobile 0467-371014
--------------------------------------------------------------------------
"What gets us into trouble is not what we don't know.
It's what we know for sure that just ain't so."
- Yogi Berra
--------------------------------------------------------------------------
Mike Fitzpatrick wrote on Aug 18, 1998
Bob,
The problem is that in your model_info routine you're populating
the arrays based on the number of models in the whole table, not just the
ones matching the current color. So, when you make the first pass it just
so happens that rows 1-4 match what you want and in the main routine you
print the first four elements. On the second pass the subroutine fills
array elements 5-8 but you're still printing 1-4. The error is in the use
of 'i' and 'j' in the subroutine, and the way you're incrementing 'j'.
Try instead (I've indicated the lines needing changes):
j=0
for(i=0; i<nmodel; i=i+1){
call tbegtt(ktp,colour_cp,i+1,rowcolour,SZ_FNAME)
if (streq(rowcolour,colour)){
call tbegtr(ktp,tau_cp,i+1,Memr[tau+j]) # <----
call tbegtr(ktp,ebv_cp,i+1,Memr[ebv+j]) # <----
call tbegtt(ktp,name_cp,i+1,Memc[name+SZ_COLNAME*j], # <----
SZ_COLNAME)
# Print out the variables as seen *inside* the procedure
call printf("tau: %g ebv: %g name: %g \n")
call pargr(Memr[tau+j]) # <---
call pargr(Memr[ebv+j]) # <---
call pargstr(Memc[name+SZ_COLNAME*j]) # <---
j = j+1 # <---
}
}
I'm willing to forgive my normal fee if you'll just learn to spell 'color'
correctly 8-)
Cheers,
-Mike
Last post on Aug 18, 1998