[comp.lang.c] Is this ok??

davis@pacific.mps.ohio-state.edu ("John E. Davis") (03/07/91)

Hi,

   The following code works on sun4 and ultrix but crashes on VMS.  Just when
I thought I understood pointers.....

#include <stdio.h>
void fm2(s)
char **s;
{
    *s = "Hello\n";
}

void fm1(s)
char **s;
{
    char *ss;
    fm2(&ss);
    *s = ss;
}

int main()
  {
      char *s;

      fm1(&s);
      (void) fputs(s,stdout);
      return(0);
  }

I expect to `hello' but I fail on VMS.  I get a `symbolic dump stack ...'.
What is wrong???

Thanks,
--
John

  bitnet: davis@ohstpy
internet: davis@pacific.mps.ohio-state.edu

scott@stl.stc.co.uk (Mike Scott) (03/07/91)

In the referenced article davis@pacific.mps.ohio-state.edu  (John E. Davis) writes:
>Hi,
>
>   The following code works on sun4 and ultrix but crashes on VMS.  Just when
>I thought I understood pointers.....
>
(code omitted)
>What is wrong???
>


Works fine for me (VAXC 3.0-031, VMS 5.1-1 and VAXC v2.2-015, VMS
4.6). It would help everybody if anyone saying "it doesn't work" would
give relevant version numbers......





--
Regards.    Mike Scott       STL, London Road, Harlow, Essex  CM17 9NA, UK
scott@stl.stc.co.uk <or> ...uunet!mcsun!ukc!stl!scott <or>
PSI%234237100122::SCOTT        phone +44-279-429531 xtn 3133.

tsm@genrad.UUCP (Thomas S. Morse) (03/07/91)

In article <DAVIS.91Mar6213546@pacific.mps.ohio-state.edu> davis@pacific.mps.ohio-state.edu  (John E. Davis) writes:
>Hi,
>
>   The following code works on sun4 and ultrix but crashes on VMS.  Just when
>I thought I understood pointers.....
>
   < deleted source >
>
>I expect to `hello' but I fail on VMS.  I get a `symbolic dump stack ...'.
>What is wrong???

I couldn't see anything wrong with your code so I ran it on my
VAX station 2000 and it worked fine.

Hope this helps,

Tom

henry@zoo.toronto.edu (Henry Spencer) (03/08/91)

In article <DAVIS.91Mar6213546@pacific.mps.ohio-state.edu> davis@pacific.mps.ohio-state.edu  (John E. Davis) writes:
>   The following code works on sun4 and ultrix but crashes on VMS.  Just when
>I thought I understood pointers.....
> ...
>int main()
>  {
> ...
>      return(0);
>  }

My tentative diagnosis is that you understand pointers but don't understand
VMS exit status!  0 is *not* "success" in VMS.  They're going to have to do
something about this to conform to ANSI C, but they may not have figured
that out yet.

The pointer part of your program looks fine.
-- 
"But this *is* the simplified version   | Henry Spencer @ U of Toronto Zoology
for the general public."     -S. Harris |  henry@zoo.toronto.edu  utzoo!henry

gould@theory.tn.cornell.edu (EWD) (03/08/91)

In article <DAVIS.91Mar6213546@pacific.mps.ohio-state.edu> davis@pacific.mps.ohio-state.edu  (John E. Davis) writes:
>Hi,
>
>   The following code works on sun4 and ultrix but crashes on VMS.  Just when
>I thought I understood pointers.....
>
...
>      return(0);
...
>
>I expect to `hello' but I fail on VMS.  I get a `symbolic dump stack ...'.
>What is wrong???

It's been a while, but I believe the bottom line is that any useful
C program on VMS must include a '$'. 

You need to #include some SYS$SYSDEF$DARKSIDEOFTHEFORCE file in some
VMS specific include systax, then you have to #define your exit statuses
in terms of the '$' infested constants therein, then you need to
#define corresponding exit statuses for other platforms...
But don't complain:  The discipline will put you in Mr. Portable
mode for the rest of your career.

On the brighter side, at least on VMS you can walk and chew gum
at the same time without the horrors of execles and sockets and
children and signals.  Give me a Unix with async io and endaction
routines...

Eliot W. Dudley                       edudley@rodan.acs.syr.edu
RD 1, Box 66
Cato, New York   13033                315 437 0215

rankin@eql.caltech.edu (Pat Rankin) (03/08/91)

>In article <DAVIS.91Mar6213546@pacific.mps.ohio-state.edu> davis@pacific.mps.ohio-state.edu  (John E. Davis) writes:
>    The following code works on sun4 and ultrix but crashes on VMS.
> Just when I thought I understood pointers.....

     Your pointer usage looks correct.  Are you using VAX C V3.0?
Its optimizer had some problems with inlining functions.  Try using
``cc/nooptimize'' or ``cc/opt=noinline'', or upgrade to V3.1 (which
was released more than a year ago).

     You should always retry with optimization suppressed when something
you're reasonably sure is correct gives the wrong results.

>In article <1991Mar7.173712.18201@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
> My tentative diagnosis is that you understand pointers but don't understand
> VMS exit status!  0 is *not* "success" in VMS.

     He would have hit that next.  Even ``return EXIT_SUCCESS;'' wouldn't
help unless he defined EXIT_SUCCESS manually, because the the VAX C
version of <stdlib.h> currently has the wrong value for VMS (it's 0, when
VMS really does need 1 for success; it has 2 for EXIT_FAILURE, which is
suitable but not optimal).

In article <PJT.91Mar7191135@dharma.cpac.washington.edu>, pjt@cpac.washington.edu (Larry Setlow) writes...
> I've redirected followups to comp.os.vms, since this line of
> discussion has become VMS-specific.

     The question was about pointers, not about VMS.  Exit status is a
red herring here.  Known compiler problems are appropriate for this group,
as are suggestions to use EXIT_xx macros instead of hard coded exit values.

		Pat Rankin, rankin@eql.caltech.edu

scs@adam.mit.edu (Steve Summit) (03/09/91)

In article <1991Mar08.191107.23161@pilikia.pegasus.com> art@pilikia.pegasus.com (Art Neilson) writes:
>In article <DAVIS.91Mar6213546@pacific.mps.ohio-state.edu> davis@pacific.mps.ohio-state.edu  (John E. Davis) writes:
...
>>void fm2(s)
>>char **s;
>      ^ here we go yet again, this parameter doesn't match
>        what you're trying to pass in from fm1().
>>{
>>    *s = "Hello\n";
>     ^ you can't do this.  s points nowhere.
>       besides, you need to do strcpy(s, "Hello"),
>       the way you are initializing *s is wrong.
...
>>      char *s;
>>      fm1(&s);
>           ^why are you passing "address of" s ?
>            s is already an address, remove the &.
>
>You should really read your textbook before posting something like this
>to the net.  Any book worth it's salt will teach you not to make the
>sort of mistakes you've made here.

Yes, it is important to make sure you understand what's going on
before you post.

The code posted by John Davis was correct, although it contained
several (perfectly legal) pointers to pointers which apparently
confused both a VMS compiler (thus John's original question) and
Arthur Neilson (thus these irrelevant criticisms).  The code
passes lint -hbxa with flying colors (i.e. no complaints about
argument mismatches) and runs correctly under any number of
compilers.

                                            Steve Summit
                                            scs@adam.mit.edu

art@pilikia.pegasus.com (Art Neilson) (03/09/91)

In article <DAVIS.91Mar6213546@pacific.mps.ohio-state.edu> davis@pacific.mps.ohio-state.edu  (John E. Davis) writes:
>Hi,
>
>   The following code works on sun4 and ultrix but crashes on VMS.  Just when
>I thought I understood pointers.....

After seeing lots of replies to John Davis I went back and examined the
program he posted again and realized I was wrong regarding his pointer
usage, I sorta jumped the gun when I saw the &'s and ** stuff, I was
wrong. I still don't think it's OK to assign the quoted string "Hello\n"
to *s in fm2() as shown below.  Where does *s point to ?  Where in storage
would "Hello\n" reside ?  Does the compiler assign some scratch storage or 
something for it ??

>#include <stdio.h>
>void fm2(s)
>char **s;
>{
>    *s = "Hello\n";
>}
-- 
Arthur W. Neilson III		| INET: art@pilikia.pegasus.com
Bank of Hawaii Tech Support	| UUCP: uunet!ucsd!nosc!pilikia!art

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/10/91)

In article <1991Mar09.092611.24821@pilikia.pegasus.com> art@pilikia.pegasus.com (Art Neilson) writes:
> I still don't think it's OK to assign the quoted string "Hello\n"
> to *s in fm2() as shown below.  Where does *s point to ?  Where in storage
> would "Hello\n" reside ?  Does the compiler assign some scratch storage or 
> something for it ??
  [ void fm2(s) char **s; { *s = "Hello\n"; } ]

"Hello\n" is a constant string. When the compiler sees it, it makes room
for it somewhere, and replaces "Hello\n" by a pointer to that location.
Under UNIX, for example, the string is either stored along with the
unwritable process text, or in the initialized data region, depending on
your compiler.

Now the string "Hello\n" has value <pointer to char,0x3753> if 0x3753 is
the location where the compiler put "Hello\n". In fm2, s has type
<pointer to pointer to char>. More precisely, say s has value
<pointer to pointer to char,0x87654>. This means that at location
0x87654 there's a <pointer to char>, say <pointer to char,0x14702>.

The assignment *s = "Hello\n" means ``Take s's value (a location in
memory), and store a pointer to "Hello\n" in that location.'' In this
case, that means to store <pointer to char,0x3753> at the location
<object,pointer to char,0x87654>. The old value of *s, namely 0x14702,
is replaced by a pointer to "Hello\n", namely 0x3753.

So the string "Hello\n" is never copied. ``*s'' refers to a
pointer-to-char object, and ``"Hello\n"'' has a pointer-to-char value.
The assignment just stores the value inside the object.

Chris will undoubtedly give a more comprehensible explanation.

---Dan

mla@enea.se (Mats L|fstr|m) (03/10/91)

In article <1991Mar08.191107.23161@pilikia.pegasus.com> art@pilikia.pegasus.com (Art Neilson) writes:

Lots of stuff deleted, I haven't time to comment on all of it, so I'll
concentrate on just one item. I think my point will be clear enough...

>>
>>int main()
>>  {
>>      char *s;
>>
>>      fm1(&s);
>           ^why are you passing "address of" s ?
>            s is already an address, remove the &.

s isn't an address, it's a pointer, i.e. a variable *containing* an
address. And the poor guy is trying to give the address of this
pointer as an argument to fm1(). Which is perfectly legal and very
usefull in some situations. As in this, for instance.

What he wants to do, is to give s a good value, i.e. set it to point
to a "string". In order to do so, he must give the address of the
pointer (s) as an argument to fm1(). fm1() then has a chance to change
the value of s.

Some more lines deleted.

>
>You should really read your textbook before posting something like this
>to the net.  Any book worth it's salt will teach you not to make the
>sort of mistakes you've made here.

Maybe you should buy yourself a new textbook. :-)

>-- 
>Arthur W. Neilson III		| INET: art@pilikia.pegasus.com
>Bank of Hawaii Tech Support	| UUCP: uunet!ucsd!nosc!pilikia!art


----------------------------------------------------------------------------
International:			Domestic:
Mats Lofstrom			Mats L|fstr|m
ENEA Data AB			ENEA Data AB
Nytorpsvagen 5b			Nytorpsv{gen 5b
Box 232				Box 232
S-183 23 TABY			183 23  T[BY
Phone: (+46) 8792 - 2500	Tel: 08 - 792 25 00

		e-mail: mla@enea.se
----------------------------------------------------------------------------

torek@elf.ee.lbl.gov (Chris Torek) (03/10/91)

In article <1991Mar09.092611.24821@pilikia.pegasus.com>
art@pilikia.pegasus.com (Art Neilson) writes:
>After seeing lots of replies to John Davis I went back and examined the
>program he posted again and realized I was wrong regarding his pointer
>usage, I sorta jumped the gun when I saw the &'s and ** stuff, I was
>wrong.

Indeed.  (Incidentally, the reason his program `failed' on VMS was that
he was testing a different program, an easy enough mistake to make; when
he tested the one he posted, it worked.)

>I still don't think it's OK to assign the quoted string "Hello\n"
>to *s in fm2() as shown below.  Where does *s point to ?  Where in storage
>would "Hello\n" reside ?  Does the compiler assign some scratch storage or 
>something for it ??

If you do not know the answer to the latter question, you should not
be posting definitive followups to comp.lang.c.

A double quoted string in C is, with one exception%, an anonymous
object of type `array N of char', where N is one more than the number
of characters enclosed in quotes (after escape interpolation).  The
value of an array object is of course determined by The Rule, hence in

>>#include <stdio.h>
>>void fm2(s)
>>char **s;
>>{
>>    *s = "Hello\n";
>>}

the object at `*s' (which will have to be an <object, pointer to char>
for the assignment to succeed) is made to point to the first character
of this anonymous array of (in this case) 7 characters.  That array
itself resides in some sort of system-allocated space which has static
storage duration; a typical system puts it in a code or initialized
data segment.  (There are atypical systems; a C compiler for Xerox
D-machines once kept the original strings in Mesa `string descriptor'
format and allocated the C versions on the heap.  Perhaps it still does,
although Xerox D-machines have largely been relegated to the Dustbin
of History....)

In the original example in question, `s' happened in this case to
point to a single `char *' object declared in fm1():

	fm1(ss) char **ss; { char *s; fm2(&s); *ss = s; }

(I may have some of the original names mixed up), so the clause `which
will have to be an <object, pointer to char> for the assignment to
succeed' is satisfied.  The object at fm2's `*s' is fm1's `s', so s is
made to point to the `H' in `Hello\n\0'.  Fm1 then sets the object at
`*ss' (which has the exact same restriction) to point to that `H' as
well, and fm1's *ss in the original example was main's `s', so
everything was fine, if overly convoluted.
-----
% The exception occurs when a double quoted string is used as an
  initializer for an object of type `array N of char' or `array N
  of const char', including when the size N is given as `the size
  of the initializer':

	char xyz[] = "abcd";

  makes xyz an <object, array 5 of char, `abcd\0'>, and need not
  leave a copy of the sequence `abcd\0' anywhere else.  (If it does
  leave a copy somewhere else, the compiler is wasting space, unless
  this copy exists for, e.g., debugging purposes.)
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab EE div (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov

art@pilikia.pegasus.com (Art Neilson) (03/10/91)

In article <1991Mar9.073231.1364@athena.mit.edu> scs@adam.mit.edu writes:
>In article <1991Mar08.191107.23161@pilikia.pegasus.com> art@pilikia.pegasus.com (Art Neilson) writes:
>>In article <DAVIS.91Mar6213546@pacific.mps.ohio-state.edu> davis@pacific.mps.ohio-state.edu  (John E. Davis) writes:
>The code posted by John Davis was correct, although it contained
>several (perfectly legal) pointers to pointers which apparently
>confused both a VMS compiler (thus John's original question) and
>Arthur Neilson (thus these irrelevant criticisms).  The code
>passes lint -hbxa with flying colors (i.e. no complaints about
>argument mismatches) and runs correctly under any number of
>compilers.

Guess I deserve a bit of public chastisement for my criticisms.
I still don't get why the string assignment

	*s = "Hello\n";

in fm2() is ok.  Raymond Chen sent me an email stating that storage for
"Hello\n" was allocated as static anonymous readonly by the compiler.
I had always thought that the rvalue in a pointer assignment had to be an
address.  The usual way I do assignments of this nature is to either
explicitly declare an array large enough to hold the string or malloc
the storage and move the data there, or assign the pointer globally
(outside of main) like:

char *s = "Hello\n";	/* aggregate initializations out here */

main()
{

John's program does compile and run on my system ;^) (sheepish grin) 
so it must be ok.  Since the assignment is ok, how large a string can be
assigned in this manner ?  Does the constant go in .data or .bss ??
-- 
Arthur W. Neilson III		| INET: art@pilikia.pegasus.com
Bank of Hawaii Tech Support	| UUCP: uunet!ucsd!nosc!pilikia!art

ark@alice.att.com (Andrew Koenig) (03/10/91)

John E. Davis asked a question about pointers in C.
Art Neilson reponded with a rather nasty criticism of
the question.

The trouble with this sort of criticism is that it
can be embarrassing if the criticism is mistaken.
Let's take a look at the original program and the
criticism with an eye towards sorting it all out.

In what follows, >> precedes comments by Davis
(article <DAVIS.91Mar6213546@pacific.mps.ohio-state.edu>)
and > precedes comments by Neilson
(article <1991Mar08.191107.23161@pilikia.pegasus.com>).

>> #include <stdio.h>

>> void fm2(s)
>> char **s;
>       ^ here we go yet again, this parameter doesn't match
>         what you're trying to pass in from fm1().
>> {
>>     *s = "Hello\n";
>      ^ you can't do this.  s points nowhere.
>        besides, you need to do strcpy(s, "Hello"),
>        the way you are initializing *s is wrong.
> 
>> }

Is it actually true that s points nowhere?  It's hard to say
without looking at the caller of fm2; we'll come to that presently.
If we assume that s points somewhere, though, there is nothing
wrong with saying

	*s = "Hello\n";

A string literal is essentially the "name" of an otherwise unnamed
initialized character array.  Thus the assignment above would make
the pointer addressed by s point to the initial character of this array.

That brings us back to the previous question: where does s point?
Let's look at fm2's caller:

>> void fm1(s)
>> char **s;
>       ^ this formal parameter to fm1 doesn't match what
>         you're passing it from main.
> 
>> {
>>     char *ss;
>>     fm2(&ss);
>          ^ here we go again.  the & is not necessary.
> 
>>     *s = ss;
>> }

Aha! fm2 is passed the address of the local variable "ss" in
function fm1.  That variable is of type "char *" so its address
is of type "char **", which matches the type of the formal
parameter of fm2.  Apparently that criticism is incorrect.

We are now in a position to understand the assignment to *s
in fm2; since s is the address of the variable ss in fm1,
*s is that variable itself.  Thus after executing this assignment,
variable ss in fm1 will point to the initial character of "Hello\n".

I see nothing wrong with that so far.  Indeed, the second criticism
in fm1 is also seen to be incorrect; the & is indeed necessary
(else the call would not be type-safe) and the call

	fm2(&ss);

has the same effect as

	ss = "Hello\n";

Now let's look at the first criticism in fm1, namely that the
formal parameter to fm1 doesn't match what's passed from main.
To check this, we need to look at main:

>> int main()
>>   {
>>       char *s;
>> 
>>       fm1(&s);
>            ^why are you passing "address of" s ?
>             s is already an address, remove the &.
> 
>>       (void) fputs(s,stdout);
>>       return(0);
>>   }

Variable s in main is of type "char *" so its address is of type
"char **".  That is the same type as the formal parameter to fm1,
so the criticism of fm1 is incorrect.  The criticism of "main"
answers its own question: if fm1 were passed s rather than &s,
the call would indeed be incorrect.

What happens inside fm1?  If we replace the call to fm2 by the
assignment having the same effect, we get this:

	char *ss;
	ss = "Hello\n";		/* the effect of the call to fm2 */
	*s = ss;

What is *s?  It's exactly the variable "s" in main.  Thus,
the effect of main should be as if its body were written:

	char *s;

	s = "Hello\n";		/* the effect of the call to fm1 */
	(void) fputs(s,stdout);
	return(0);

I don't see anything wrong with any of this, so I suspect a compiler bug.
-- 
				--Andrew Koenig
				  ark@europa.att.com

gwyn@smoke.brl.mil (Doug Gwyn) (03/11/91)

In article <1991Mar09.092611.24821@pilikia.pegasus.com>, art@pilikia.pegasus.com (Art Neilson) writes:
> Where does *s point to ?  Where in storage would "Hello\n" reside ?

The compiler must arrange for the string literal to be allotted some
storage having static storage duration.  There was nothing whatever
wrong with the posted example program, just with the VMS C implementation,
probably due to its failure to support 0 as a valid form for expressing
a "successful" exit status.

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (03/11/91)

In article <1991Mar08.191107.23161@pilikia.pegasus.com>,
 art@pilikia.pegasus.com (Art Neilson) set some kind of record for radically
incorrect advice about John E. Davis's program
    #include <stdio.h>
    void fm2(s) char **s; { *s = "Hello\n"; }
    void fm1(s) char **s; { char *ss; fm2(&ss); *s = ss; }
    int main() { char *s; fm1(&s); (void) fputs(s,stdout); return(0); }
Comrade Neilson ended by writing
> You should really read your textbook before posting something like this
> to the net.  Any book worth it's salt will teach you not to make the
> sort of mistakes you've made here.
It really is _fitting_ that in advice more appropriately directed at the
advisor the very common word "its" is spelled incorrectly.

The program works correctly under "gcc -ansi -pedantic" and PCC.  The
only system-specific thing in it is the "return 0;" in main().  VMS has
the convention that a program result signifies success (perhaps with a
warning) if it is odd, failure if it is even.  Recent versions of DCL
have been taught to shut up about the error code 0, precisely to cope
with sloppy C code, which may be why some people have reported that it
works in VMS.  Use EXIT_SUCCESS if you have it, if not

	#include <stdlib.h>
	#ifndef EXIT_SUCCESS
	#ifdef vms
	#define EXIT_SUCCESS 1
	#else /* not vms */
	#define EXIT_SUCCESS 0
	#endif /* vms */
	#endif /* EXIT_SUCCESS */

		exit(EXIT_SUCCESS);	/* instead of return 0; */

-- 
The purpose of advertising is to destroy the freedom of the market.

gwyn@smoke.brl.mil (Doug Gwyn) (03/12/91)

In article <4934@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:
>The only system-specific thing in it is the "return 0;" in main().

Even that is strictly conforming to the C standard.

jockc@hammer.idsila.com (PRIV Account) (03/12/91)

In article <1991Mar10.040429.29309@pilikia.pegasus.com> art@pilikia.pegasus.com (Art Neilson) writes:
>	..discussion deleted..
>Guess I deserve a bit of public chastisement for my criticisms.
>I still don't get why the string assignment
>
>        *s = "Hello\n";
>
>in fm2() is ok.  Raymond Chen sent me an email stating that storage for
>"Hello\n" was allocated as static anonymous readonly by the compiler.
>I had always thought that the rvalue in a pointer assignment had to be an
>address.  The usual way I do assignments of this nature is to either
>explicitly declare an array large enough to hold the string or malloc


Think of it like this:

main()
{
	int x=1;

	foo(x);
	printf("%d\n",x); /*prints 1*/
	bar(&x);
	printf("%d\n",x); /*prints 5*/
	return 0;
}
foo(val)
int val;
{
	val=5;
}
bar(val)
int *val;
{
	*val=5;
}

For a function to modify the varable I pass it, I have to pass it's
address.  The same goes for a char pointer.  I must pass the address
so that the called function can change its contents:

main()
{
	char *s="some chars";

	foo(s);
	printf("%s\n",s);  /* prints "some chars" */
	bar(&s);
	printf("%s\n",s);  /* prints "different chars" */
}
foo(str)
char *str;
{
	str="different chars";	/* this changes this function's copy 
				of the passed variable's value */
}
bar(str)
char **str;
{
	*str = "different chars"; 
}

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (03/12/91)

In article <15439@smoke.brl.mil>, gwyn@smoke.brl.mil (Doug Gwyn) writes:
> In article <4934@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:
> >The only system-specific thing in it is the "return 0;" in main().
> 
> Even that is strictly conforming to the C standard.

I didn't say it was *non-standard*, I said it was *system-specific*.
There are a lot of pre-ANSI C compilers out there, and I have met ones
where "return 0;" in the main program did not work at all.  I didn't
say that the VAX/VMS C compiler doesn't like it either.  My point was
simply that ANSI or not, one may run into compilers where it doesn't
work, so one might as well play safe and stick with exit().
-- 
The purpose of advertising is to destroy the freedom of the market.