Is this kosher?

  • Follow


Folks,

I just wrote a little function to find the end of a line:

char *eol(char *pt)
{ while(*pt != '\r' && *pt != '\n' && *pt != '\0')  // run along to the line 
terminator character
      pt++;
    return pt;   // and return a pointer to it
}

I use it thus:

main()  // I know, I know!
{ char text_line[260], *t_pt;

   /* [ get a file path into text_line]  */

   t_pt = eol(text_line);
   *t_pt = '\0';   // this knocks off a '\n', which stops chdir() from 
working

   chdir(text_line);
}

This works fine, but just for the experiment, I replaced the two lines 
containing t_pt with

   *eol(text_line) = '\0';

.... and it worked.  Is this a syntactical thing to do?  Is it portable?  I'd 
appreciate your educated comment on this.

Thanks a heap,

MikeC.


-- 
Mental decryption required to bamboozle spam robots:

mike_best$ntlworld*com
$ = @
* = dot 


0
Reply My_address (24) 11/10/2006 10:01:49 PM

MikeC said:

<snip>
> 
> This works fine, but just for the experiment, I replaced the two lines
> containing t_pt with
> 
>    *eol(text_line) = '\0';
> 
> ... and it worked.  Is this a syntactical thing to do?  Is it portable?

Yes, it's fine, provided you are absolutely 100% certain that the pointer 
that eol() returns is guaranteed to be to a writeable character. In your 
case, it is, provided that you only give writeable strings to eol().

Only give genuine null-terminated strings to eol() - an array of char 
doesn't /necessarily/ contain a string: char foo[3] = "foo"; being an 
example of one that does not. And if you plan to do your *eol() thing, 
don't give eol() a string literal to feed on:

*eol("oh deary deary me\n") = '\0'; /* asking for trouble */

char *p = "oh deary deary me\n";
*eol(p) = '\0'; /* still asking for the same trouble */

char arr[] = "but this is okay\n");
*eol(arr) = '\0'; /* no sweat */

-- 
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: normal service will be restored as soon as possible. Please do not 
adjust your email clients.
0
Reply invalid171 (6559) 11/10/2006 10:10:47 PM




"MikeC" <My_address@end.of.post> wrote in message 
news:hF65h.3491$bC3.2937@newsfe7-win.ntli.net...
> Folks,
>
> I just wrote a little function to find the end of a line:
>
> char *eol(char *pt)
> { while(*pt != '\r' && *pt != '\n' && *pt != '\0')  // run along to the 
> line terminator character
>      pt++;
>    return pt;   // and return a pointer to it
> }
>
> I use it thus:
>
> main()  // I know, I know!
> { char text_line[260], *t_pt;
>
>   /* [ get a file path into text_line]  */
>
>   t_pt = eol(text_line);
>   *t_pt = '\0';   // this knocks off a '\n', which stops chdir() from 
> working
>
>   chdir(text_line);
> }
>
> This works fine, but just for the experiment, I replaced the two lines 
> containing t_pt with
>
>   *eol(text_line) = '\0';
>
> ... and it worked.  Is this a syntactical thing to do?  Is it portable? 
> I'd appreciate your educated comment on this.
>
I'd like to see

char *end = eol(text|_line);

*end = 0;

simply because it looks a bit funny to dereference the function return value 
directly.

The function itself is unexceptional C. There is an issue about returning 
pointers to input parameters, but it is problem deep and inherent in the C 
language itself, and there is no point avoiding it if you choose to use C at 
all.
-- 
www.personal.leeds.ac.uk/~bgy1mm
freeware games to download.



0
Reply regniztar (3128) 11/10/2006 10:42:50 PM

Malcolm said:

> 
> 
> 
> "MikeC" <My_address@end.of.post> wrote in message
> news:hF65h.3491$bC3.2937@newsfe7-win.ntli.net...
>> Folks,
>>
>> I just wrote a little function to find the end of a line:
>>
>> char *eol(char *pt)
>> { while(*pt != '\r' && *pt != '\n' && *pt != '\0')  // run along to the
>> line terminator character
>>      pt++;
>>    return pt;   // and return a pointer to it
>> }
>>
>> I use it thus:
>>
>> main()  // I know, I know!
>> { char text_line[260], *t_pt;
>>
>>   /* [ get a file path into text_line]  */
>>
>>   t_pt = eol(text_line);
>>   *t_pt = '\0';   // this knocks off a '\n', which stops chdir() from
>> working
>>
>>   chdir(text_line);
>> }
>>
>> This works fine, but just for the experiment, I replaced the two lines
>> containing t_pt with
>>
>>   *eol(text_line) = '\0';
>>
>> ... and it worked.  Is this a syntactical thing to do?  Is it portable?
>> I'd appreciate your educated comment on this.
>>
> I'd like to see
> 
> char *end = eol(text|_line);

Why |?

> *end = 0;
> 
> simply because it looks a bit funny to dereference the function return
> value directly.

To you, maybe. It's quite common, though, in some people's code, and it's an 
idiom worth being aware of, albeit a minor one.


> The function itself is unexceptional C. There is an issue about returning
> pointers to input parameters,

He isn't doing that, though.

> but it is problem deep and inherent in the C
> language itself,

No, not really. Parameters are local objects which disappear when the 
function that they parameterise has completed execution. That isn't a 
problem, any more than it's a problem that soup disappears from your plate 
when you lift a spoonful to your mouth. It's just the way the world works, 
that's all. And there's no point in returning a pointer to something that 
no longer exists. But he isn't returning a pointer to an input parameter. 
He's returning a pointer to a character that he tracked down using an input 
parameter as a starting point. Not the same thing at all.

> and there is no point avoiding it if you choose to use C at all.

No point avoiding what? He isn't doing what you claim he's doing.

-- 
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: normal service will be restored as soon as possible. Please do not 
adjust your email clients.
0
Reply invalid171 (6559) 11/10/2006 10:52:23 PM


MikeC wrote On 11/10/06 17:01,:
> Folks,
> 
> I just wrote a little function to find the end of a line:
> 
> char *eol(char *pt)
> { while(*pt != '\r' && *pt != '\n' && *pt != '\0')  // run along to the line 
> terminator character
>       pt++;
>     return pt;   // and return a pointer to it
> }
> 
> I use it thus:
> 
> main()  // I know, I know!

    Interesting that the disclaimer takes nineteen or more
keystrokes, whereas inserting both `int ' and `void' would
take eight, and `int ' alone only four.  Perversity for
perversity's sake?

> { char text_line[260], *t_pt;
> 
>    /* [ get a file path into text_line]  */
> 
>    t_pt = eol(text_line);
>    *t_pt = '\0';   // this knocks off a '\n', which stops chdir() from 
> working
> 
>    chdir(text_line);
> }
> 
> This works fine, but just for the experiment, I replaced the two lines 
> containing t_pt with
> 
>    *eol(text_line) = '\0';
> 
> ... and it worked.  Is this a syntactical thing to do?  Is it portable?  I'd 
> appreciate your educated comment on this.

    As others have noted, it's fine.  But in the spirit of
the Seventh Commandment, let me point out that the Standard
library already has a function that makes eol() unnecessary:

	text_line[ strcspn(text_line, "\r\n") ] = '\0';

-- 
Eric.Sosman@sun.com

0
Reply Eric.Sosman (4228) 11/10/2006 10:59:34 PM

Folks,

My thanks to one and all!
Now I'm a little wiser.

Best regards,

MikeC.

"MikeC" <My_address@end.of.post> wrote in message 
news:hF65h.3491$bC3.2937@newsfe7-win.ntli.net...
> Folks,
>
> I just wrote a little function to find the end of a line:
>
> char *eol(char *pt)
> { while(*pt != '\r' && *pt != '\n' && *pt != '\0')  // run along to the 
> line terminator character
>      pt++;
>    return pt;   // and return a pointer to it
> }
>
> I use it thus:
>
> main()  // I know, I know!
> { char text_line[260], *t_pt;
>
>   /* [ get a file path into text_line]  */
>
>   t_pt = eol(text_line);
>   *t_pt = '\0';   // this knocks off a '\n', which stops chdir() from 
> working
>
>   chdir(text_line);
> }
>
> This works fine, but just for the experiment, I replaced the two lines 
> containing t_pt with
>
>   *eol(text_line) = '\0';
>
> ... and it worked.  Is this a syntactical thing to do?  Is it portable? 
> I'd appreciate your educated comment on this.
>
> Thanks a heap,
>
> MikeC.
>
>
> -- 
> Mental decryption required to bamboozle spam robots:
>
> mike_best$ntlworld*com
> $ = @
> * = dot
> 


0
Reply My_address (24) 11/11/2006 12:17:23 AM

"Richard Heathfield" <invalid@invalid.invalid> wrote in message
> Malcolm said:
>
>> "MikeC" <My_address@end.of.post> wrote in message
>> news:hF65h.3491$bC3.2937@newsfe7-win.ntli.net...
>>> Folks,
>>>
>>> I just wrote a little function to find the end of a line:
>>>
>>> char *eol(char *pt)
>>> { while(*pt != '\r' && *pt != '\n' && *pt != '\0')  // run along to the
>>> line terminator character
>>>      pt++;
>>>    return pt;   // and return a pointer to it
>>> }
>>>
>>> I use it thus:
>>>
>>> main()  // I know, I know!
>>> { char text_line[260], *t_pt;
>>>
>>>   /* [ get a file path into text_line]  */
>>>
>>>   t_pt = eol(text_line);
>>>   *t_pt = '\0';   // this knocks off a '\n', which stops chdir() from
>>> working
>>>
>>>   chdir(text_line);
>>> }
>>>
>>> This works fine, but just for the experiment, I replaced the two lines
>>> containing t_pt with
>>>
>>>   *eol(text_line) = '\0';
>>>
>>> ... and it worked.  Is this a syntactical thing to do?  Is it portable?
>>> I'd appreciate your educated comment on this.
>>>
>> I'd like to see
>>
>> char *end = eol(text|_line);
>
> Why |?
>
>> *end = 0;
>>
>> simply because it looks a bit funny to dereference the function return
>> value directly.
>
> To you, maybe. It's quite common, though, in some people's code, and it's 
> an
> idiom worth being aware of, albeit a minor one.
>
>
>> The function itself is unexceptional C. There is an issue about returning
>> pointers to input parameters,
>
> He isn't doing that, though.
>
>> but it is problem deep and inherent in the C
>> language itself,
>
> No, not really. Parameters are local objects which disappear when the
> function that they parameterise has completed execution. That isn't a
> problem, any more than it's a problem that soup disappears from your plate
> when you lift a spoonful to your mouth. It's just the way the world works,
> that's all. And there's no point in returning a pointer to something that
> no longer exists. But he isn't returning a pointer to an input parameter.
> He's returning a pointer to a character that he tracked down using an 
> input
> parameter as a starting point. Not the same thing at all.
>
OK, substitute aonther term to refer to the data accessible to the function 
by reason of its pointer parameters. "Argument" won't do since that refers 
to the parameters as they exist in the caller.
>> and there is no point avoiding it if you choose to use C at all.
>
> No point avoiding what? He isn't doing what you claim he's doing.
>
char *makeanalias(char *str)
{
  return str;
}

Causes all sorts of subtle programming problems. There is a strong case for 
designing a language which avoids it. However that language isn't C.
-- 
www.personal.leeds.ac.uk/~bgy1mm
freeware games to download.



0
Reply regniztar (3128) 11/11/2006 8:52:59 AM

Malcolm said:

<snip>

> char *makeanalias(char *str)
> {
>   return str;
> }
> 
> Causes all sorts of subtle programming problems.

No more so than:

char *p = q;

-- 
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: normal service will be restored as soon as possible. Please do not 
adjust your email clients.
0
Reply invalid171 (6559) 11/11/2006 9:02:51 AM



"Richard Heathfield" <invalid@invalid.invalid> wrote in message 
news:DqmdnUKUv6P7DMjYnZ2dnUVZ8sCdnZ2d@bt.com...
> Malcolm said:
>
> <snip>
>
>> char *makeanalias(char *str)
>> {
>>   return str;
>> }
>>
>> Causes all sorts of subtle programming problems.
>
> No more so than:
>
> char *p = q;
>
The difference is that
char *p = q

as it stands, simply creates a named alias. A decent compiler will optimise 
it to a no-op.

However real code is unlikely to leave things at that - since q is already 
in scope, why not simply replace p by q? p will be incremented, or set to a 
different value on an conditional. So you've got a potentially nasty 
situation.

When you further start messing about with the scope of the variables, you 
soon get into a potential huge mess. In fact you could say that the code 
become garbage which needs collecting.
-- 
www.personal.leeds.ac.uk/~bgy1mm
freeware games to download.



0
Reply regniztar (3128) 11/11/2006 10:02:17 PM

Malcolm said:

> 
> 
> 
> "Richard Heathfield" <invalid@invalid.invalid> wrote in message
> news:DqmdnUKUv6P7DMjYnZ2dnUVZ8sCdnZ2d@bt.com...
>> Malcolm said:
>>
>> <snip>
>>
>>> char *makeanalias(char *str)
>>> {
>>>   return str;
>>> }
>>>
>>> Causes all sorts of subtle programming problems.
>>
>> No more so than:
>>
>> char *p = q;
>>
> The difference is that
> char *p = q
> 
> as it stands, simply creates a named alias. A decent compiler will
> optimise it to a no-op.

char *p = makeanalias(q); is no different. It assigns the value of q to p. 
If that were all there is to it, a decent compiler will, as you say, 
optimise it to a no-op. But of course that isn't all there is to it.

> However real code is unlikely to leave things at that - since q is already
> in scope, why not simply replace p by q? p will be incremented, or set to
> a different value on an conditional. So you've got a potentially nasty
> situation.

No, not really. You've just got an ordinary pointer assignment. I see no 
reason to struggle with this. C programmers do it all the time. Witness 
some code taken at random from my source base:

    unsigned char *Iterator = wnn_String->Start + wnn_Start;
    unsigned char *Stop = wnn_String->Start;
    if(wnn_Stop > len)
    {
      wnn_Stop = len;
    }
    Stop += wnn_Stop;
    while(Iterator < Stop)
    {
      *Iterator = toupper(*Iterator);
      ++Iterator;
    }

Bog-standard pointer manipulation. Really, I'm struggling to see why this 
would be difficult to follow or maintain.

-- 
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: normal service will be restored as soon as possible. Please do not 
adjust your email clients.
0
Reply invalid171 (6559) 11/11/2006 11:16:12 PM

Malcolm wrote:
> "Richard Heathfield" <invalid@invalid.invalid> wrote in message
> news:DqmdnUKUv6P7DMjYnZ2dnUVZ8sCdnZ2d@bt.com...
> > Malcolm said:
> >
> > <snip>
> >
> >> char *makeanalias(char *str)
> >> {
> >>   return str;
> >> }
> >>
> >> Causes all sorts of subtle programming problems.
> >
> > No more so than:
> >
> > char *p = q;
> >
> The difference is that
> char *p = q
>
> as it stands, simply creates a named alias. A decent compiler will optimise
> it to a no-op.
>

I don't follow.  Before the assignment p is indeterminate.  After the
assignment p is equal in value to q.  So the operation is not a no_op.
Also, if you increment p you do not increment q.

Do you mean something like

char q[1] = 'a'
char *p;

p = q;
*q = 'b';
*p = *q;

The last is truly a no_op, and if you increment *q, you also increment
*p.

I don't see what this has to do with function calls.

                                               - William Hughes





> However real code is unlikely to leave things at that - since q is already
> in scope, why not simply replace p by q? p will be incremented, or set to a
> different value on an conditional. So you've got a potentially nasty
> situation.
>
> When you further start messing about with the scope of the variables, you
> soon get into a potential huge mess. In fact you could say that the code
> become garbage which needs collecting.
> -- 
> www.personal.leeds.ac.uk/~bgy1mm
> freeware games to download.

0
Reply wpihughes (390) 11/12/2006 4:33:32 AM

William Hughes said:

> Malcolm wrote:
>> "Richard Heathfield" <invalid@invalid.invalid> wrote...
>> > Malcolm said:
>> >
>> The difference is that
>> char *p = q
>>
>> as it stands, simply creates a named alias. A decent compiler will
>> optimise it to a no-op.
>>
> 
> I don't follow.  Before the assignment p is indeterminate.  After the
> assignment p is equal in value to q.  So the operation is not a no_op.

When I was replying to the same thing, I presumed he meant that it was 
semantically equivalent to a no-op if p's value is not used thereafter. 
What that has to do with the price of cheese is, however, unclear.

> I don't see what this has to do with function calls.

Nor I. And I certainly don't see why it's bad for a function to return a 
pointer whose value is based, however loosely, on a pointer value that was 
handed to it as a parameter.

-- 
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: normal service will be restored as soon as possible. Please do not 
adjust your email clients.
0
Reply invalid171 (6559) 11/12/2006 7:13:06 AM

Richard Heathfield wrote:
> 
.... snip ...
> 
> Nor I. And I certainly don't see why it's bad for a function to
> return a pointer whose value is based, however loosely, on a
> pointer value that was handed to it as a parameter.

For one, consider a hypothetical revstring function:

   char *revstring(char *s) {
      /* code to reverse the string in place */
      return s;
   }

Now there is an unholy temptation to use it in a printf function:

   printf("orig: %s\nrev: %s\n", str, revstring(s));

which will output two identical strings (whether or not reversed is
unknown).  If the prototype is:

   size_t revstring(char *s);

returning, say, the string length, there is no such temptation.

-- 
Chuck F (cbfalconer at maineline dot net)
   Available for consulting/temporary embedded and systems.
   <http://cbfalconer.home.att.net>

0
Reply cbfalconer (19183) 11/12/2006 9:36:27 AM

"William Hughes" <wpihughes@hotmail.com> wrote in message
>
> Malcolm wrote:
>> "Richard Heathfield" <invalid@invalid.invalid> wrote in message
>> news:DqmdnUKUv6P7DMjYnZ2dnUVZ8sCdnZ2d@bt.com...
>> > Malcolm said:
>> >
>> > <snip>
>> >
>> >> char *makeanalias(char *str)
>> >> {
>> >>   return str;
>> >> }
>> >>
>> >> Causes all sorts of subtle programming problems.
>> >
>> > No more so than:
>> >
>> > char *p = q;
>> >
>> The difference is that
>> char *p = q
>>
>> as it stands, simply creates a named alias. A decent compiler will 
>> optimise
>> it to a no-op.
>>
>
> I don't follow.  Before the assignment p is indeterminate.  After the
> assignment p is equal in value to q.  So the operation is not a no_op.
> Also, if you increment p you do not increment q.
>
> Do you mean something like
>
> char q[1] = 'a'
> char *p;
>
> p = q;
> *q = 'b';
> *p = *q;
>
> The last is truly a no_op, and if you increment *q, you also increment
> *p.
>
> I don't see what this has to do with function calls.
>
>                                               - William Hughes

char q[1024];

gets(q); /* troll alert *

if(q[0] = '*')
{
   char *p = q;

   myasteriskroutine(p);
}

This is legitimate code, if p has some meaning for an asterisk-started 
string. It makes the code easier to read.

However a decent compiler will say q, p - same value. Therefore we just 
store them in the same location in memory.
-- 
www.personal.leeds.ac.uk/~bgy1mm
freeware games to download.



0
Reply regniztar (3128) 11/12/2006 10:22:34 AM

CBFalconer wrote:
> Richard Heathfield wrote:
> ... snip ...
>> Nor I. And I certainly don't see why it's bad for a function to
>> return a pointer whose value is based, however loosely, on a
>> pointer value that was handed to it as a parameter.
> 
> For one, consider a hypothetical revstring function:
> 
>    char *revstring(char *s) {
>       /* code to reverse the string in place */
>       return s;
>    }
> 
> Now there is an unholy temptation to use it in a printf function:
> 
>    printf("orig: %s\nrev: %s\n", str, revstring(s));
> 
> which will output two identical strings (whether or not reversed is
> unknown).

Surely it is guaranteed that if revstring does what the name suggest the 
printed strings will be reversed? After all, which ever order the 
parameters are evaluated in there is a sequence point between their 
evaluation and printf being executed and also one on return from 
revstring so there are two reasons why revstring must have completed 
before the string is printed.

 > If the prototype is:
> 
>    size_t revstring(char *s);
> 
> returning, say, the string length, there is no such temptation.

I agree.
-- 
Flash Gordon
0
Reply spam331 (4024) 11/12/2006 11:02:54 AM

Flash Gordon wrote:
> CBFalconer wrote:
>> Richard Heathfield wrote:
>> ... snip ...
>>> Nor I. And I certainly don't see why it's bad for a function to
>>> return a pointer whose value is based, however loosely, on a
>>> pointer value that was handed to it as a parameter.
>>
>> For one, consider a hypothetical revstring function:
>>
>>    char *revstring(char *s) {
>>       /* code to reverse the string in place */
>>       return s;
>>    }
>>
>> Now there is an unholy temptation to use it in a printf function:
>
>>    printf("orig: %s\nrev: %s\n", str, revstring(s));
>>
>> which will output two identical strings (whether or not reversed is
>> unknown).
> 
> Surely it is guaranteed that if revstring does what the name suggest
> the printed strings will be reversed? After all, which ever order
> the parameters are evaluated in there is a sequence point between
> their evaluation and printf being executed and also one on return
> from revstring so there are two reasons why revstring must have
> completed before the string is printed.

Yes, but what are the actual parameters sent to printf?  I concede
that the two outputs (in this case) are probably of the reversed
string.  At any rate, the output is not that desired.  The purpose
was to illustrate the trap involved in returning the input string.

-- 
Chuck F (cbfalconer at maineline dot net)
   Available for consulting/temporary embedded and systems.
   <http://cbfalconer.home.att.net>


0
Reply cbfalconer (19183) 11/12/2006 12:45:24 PM

Malcolm wrote:
> "William Hughes" <wpihughes@hotmail.com> wrote in message
> >
> > Malcolm wrote:
> >> "Richard Heathfield" <invalid@invalid.invalid> wrote in message
> >> news:DqmdnUKUv6P7DMjYnZ2dnUVZ8sCdnZ2d@bt.com...
> >> > Malcolm said:
> >> >
> >> > <snip>
> >> >
> >> >> char *makeanalias(char *str)
> >> >> {
> >> >>   return str;
> >> >> }
> >> >>
> >> >> Causes all sorts of subtle programming problems.
> >> >
> >> > No more so than:
> >> >
> >> > char *p = q;
> >> >
> >> The difference is that
> >> char *p = q
> >>
> >> as it stands, simply creates a named alias. A decent compiler will
> >> optimise
> >> it to a no-op.
> >>
> >
> > I don't follow.  Before the assignment p is indeterminate.  After the
> > assignment p is equal in value to q.  So the operation is not a no_op.
> > Also, if you increment p you do not increment q.
> >
> > Do you mean something like
> >
> > char q[1] = 'a'
> > char *p;
> >
> > p = q;
> > *q = 'b';
> > *p = *q;
> >
> > The last is truly a no_op, and if you increment *q, you also increment
> > *p.
> >
> > I don't see what this has to do with function calls.
> >
> >                                               - William Hughes
>
> char q[1024];
>
> gets(q); /* troll alert *
>
> if(q[0] = '*')
> {
>    char *p = q;

At this point p has the same value as q.  If at any time the
complier can determine that this is true, it is free to use
the value of q rather than the value of p.  If the compiler
can determine that this will always be true then the
compiler can ignore p  and use q whenever it
sees p.

However, if the value of p or q can change (e.g.
by incrementng one of them) the compiler cannot and
must not make this optimization.

So there is no trap for the programmer or maintainer.
If the code is changed so that the values of p and
q are no longer the same, the optimization will no
longer be done.  In particular, if the code is changed
so that p is incremented, q will not be incremented.

>
>    myasteriskroutine(p);
> }
>
> This is legitimate code, if p has some meaning for an asterisk-started
> string. It makes the code easier to read.
>
> However a decent compiler will say q, p - same value. Therefore we just
> store them in the same location in memory.

Yes, but this is just using the as if rule.  The compiler can only do
this if there is no way to determine that it has done this.

                                            - William Hughes

0
Reply wpihughes (390) 11/12/2006 1:36:54 PM

CBFalconer wrote:
> Richard Heathfield wrote:
> >
> ... snip ...
> >
> > Nor I. And I certainly don't see why it's bad for a function to
> > return a pointer whose value is based, however loosely, on a
> > pointer value that was handed to it as a parameter.
>
> For one, consider a hypothetical revstring function:
>
>    char *revstring(char *s) {
>       /* code to reverse the string in place */
>       return s;
>    }
>
> Now there is an unholy temptation to use it in a printf function:
>
>    printf("orig: %s\nrev: %s\n", str, revstring(s));
>
> which will output two identical strings (whether or not reversed is
> unknown).  If the prototype is:
>
>    size_t revstring(char *s);
>
> returning, say, the string length, there is no such temptation.
>

Yes, but all you are saying is that a function of the form

                   do_something_to_object(object)

should not return an object  (in C an object is a pointer).

Enforcing this absolutely mean that a new idiom is needed for

                   new_object = copy_object(object)

It is not clear that this is even "good style".  Yes it avoids
the ambiguity of

                   print obj, do_something_to_object(object)

but it also disallows

                  print  make_object_printer_friendly(object)


                                           - William Hughes

0
Reply wpihughes (390) 11/12/2006 2:16:53 PM

CBFalconer said:

> Richard Heathfield wrote:
>> 
> ... snip ...
>> 
>> Nor I. And I certainly don't see why it's bad for a function to
>> return a pointer whose value is based, however loosely, on a
>> pointer value that was handed to it as a parameter.
> 
> For one, consider a hypothetical revstring function:
> 
>    char *revstring(char *s) {
>       /* code to reverse the string in place */
>       return s;
>    }
> 
> Now there is an unholy temptation to use it in a printf function:
> 
>    printf("orig: %s\nrev: %s\n", str, revstring(s));
> 
> which will output two identical strings (whether or not reversed is
> unknown).

Well, it would if you'd said revstring(str)! :-)  Seriously, though, it's 
true that making this particular mistake is a *possibility*, but it isn't 
one that I would consider all that significant. After all, I would only 
have to run the program once and examine its output to realise I've done 
something stupid that needs fixing, and it's not as if it would take a long 
time to fix, either:

printf("orig: %s\n", str);
revstring(str);
printf("rev: %s\n", str);

Just because it's possible to misuse a technique, that doesn't make the 
technique bad per se.

-- 
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: normal service will be restored as soon as possible. Please do not 
adjust your email clients.
0
Reply invalid171 (6559) 11/12/2006 2:33:50 PM

CBFalconer wrote:
> Flash Gordon wrote:
>> CBFalconer wrote:
>>> Richard Heathfield wrote:
>>> ... snip ...
>>>> Nor I. And I certainly don't see why it's bad for a function to
>>>> return a pointer whose value is based, however loosely, on a
>>>> pointer value that was handed to it as a parameter.
>>> For one, consider a hypothetical revstring function:
>>>
>>>    char *revstring(char *s) {
>>>       /* code to reverse the string in place */
>>>       return s;
>>>    }
>>>
>>> Now there is an unholy temptation to use it in a printf function:
>>>    printf("orig: %s\nrev: %s\n", str, revstring(s));
>>>
>>> which will output two identical strings (whether or not reversed is
>>> unknown).
>> Surely it is guaranteed that if revstring does what the name suggest
>> the printed strings will be reversed? After all, which ever order
>> the parameters are evaluated in there is a sequence point between
>> their evaluation and printf being executed and also one on return
>> from revstring so there are two reasons why revstring must have
>> completed before the string is printed.
> 
> Yes, but what are the actual parameters sent to printf?

For both what is passed is a pointer to a string, not the string itself.

 >  I concede
> that the two outputs (in this case) are probably of the reversed
> string.

They are guaranteed to be the reversed string for the reasons given 
above. No probably about it.

 > At any rate, the output is not that desired.  The purpose
> was to illustrate the trap involved in returning the input string.

That I agree with :-)
-- 
Flash Gordon
0
Reply spam331 (4024) 11/12/2006 2:48:16 PM

"William Hughes" <wpihughes@hotmail.com> writes:
[...]
> Yes, but all you are saying is that a function of the form
>
>                    do_something_to_object(object)
>
> should not return an object  (in C an object is a pointer).
[...]

In C, an object is a "region of data storage in the execution
environment, the contents of which can represent values" (C99 3.14).
A pointer variable, or a variable of any type, is an object; a pointer
value is not.  I'm not sure what you meant by "object", but you might
consider choosing a different term.

<OT>BTW, C++ uses a very similar definition of "object", one that's
not related to "object-oriented" programming.</OT>

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
San Diego Supercomputer Center             <*>  <http://users.sdsc.edu/~kst>
We must do something.  This is something.  Therefore, we must do this.
0
Reply kst-u (21474) 11/12/2006 9:10:15 PM

"Keith Thompson" <kst-u@mib.org> wrote in message 
news:lnr6w84big.fsf@nuthaus.mib.org...
> "William Hughes" <wpihughes@hotmail.com> writes:
> [...]
>> Yes, but all you are saying is that a function of the form
>>
>>                    do_something_to_object(object)
>>
>> should not return an object  (in C an object is a pointer).
> [...]
>
> In C, an object is a "region of data storage in the execution
> environment, the contents of which can represent values" (C99 3.14).
> A pointer variable, or a variable of any type, is an object; a pointer
> value is not.  I'm not sure what you meant by "object", but you might
> consider choosing a different term.
>
> <OT>BTW, C++ uses a very similar definition of "object", one that's
> not related to "object-oriented" programming.</OT>
>
What is meant is the C idiom

typedef struct
{
  char *ascii;
  char **somepointers;
  int moredata;
} ROPE;

We keep this as an opaque pointer, and only code in rope.c is allowed to 
access the data directly.

Now
/* reverses a rope */
void reverserope(ROPE *rope);
is OK
so too is
/* returns reversed rope, input unchanged */
ROPE *reverserope(ROPE *rope)

but

/* reverses the rope, returns pointer to reversed object */
ROPE *reverserope(ROPE *rope)

is asking for trouble.

-- 
www.personal.leeds.ac.uk/~bgy1mm
freeware games to download.



0
Reply regniztar (3128) 11/12/2006 10:15:21 PM

Malcolm wrote:
> "Keith Thompson" <kst-u@mib.org> wrote in message
> news:lnr6w84big.fsf@nuthaus.mib.org...
> > "William Hughes" <wpihughes@hotmail.com> writes:
> > [...]
> >> Yes, but all you are saying is that a function of the form
> >>
> >>                    do_something_to_object(object)
> >>
> >> should not return an object  (in C an object is a pointer).
> > [...]
> >
> > In C, an object is a "region of data storage in the execution
> > environment, the contents of which can represent values" (C99 3.14).
> > A pointer variable, or a variable of any type, is an object; a pointer
> > value is not.  I'm not sure what you meant by "object", but you might
> > consider choosing a different term.
> >
> > <OT>BTW, C++ uses a very similar definition of "object", one that's
> > not related to "object-oriented" programming.</OT>
> >
> What is meant is the C idiom
>
> typedef struct
> {
>   char *ascii;
>   char **somepointers;
>   int moredata;
> } ROPE;
>
> We keep this as an opaque pointer, and only code in rope.c is allowed to
> access the data directly.
>
> Now
> /* reverses a rope */
> void reverserope(ROPE *rope);
> is OK
> so too is
> /* returns reversed rope, input unchanged */
> ROPE *reverserope(ROPE *rope)
>
> but
>
> /* reverses the rope, returns pointer to reversed object */
> ROPE *reverserope(ROPE *rope)
>
> is asking for trouble.
>

Hardly.  It is required if you want to do things like

                skip_with(reverserope(rope))

without forcing a copy operation.


[In C you could do something like

  void reverserope(ROPE *rope);
  void skip_wth(ROPE *rope);


               skip_with((reverserope(rope),rope))

(I think), but even if the compiler can keep the comma expression
and the arguments straight, the programmer can't.]

You have to live with the fact that a function that is passed
an ADT might do something with that ADT. (Though it
may make sense to put some restrictions on which functions
are allowed do this).  Given this, restricting the return types
of the functions buys you very little.

                                     - William Hughes

0
Reply wpihughes (390) 11/12/2006 10:53:14 PM

Malcolm wrote:
> What is meant is the C idiom
> 
> typedef struct
> {
>   char *ascii;
>   char **somepointers;
>   int moredata;
> } ROPE;
> 
> We keep this as an opaque pointer, and only code in rope.c is allowed to 
> access the data directly.
> 
> Now
> /* reverses a rope */
> void reverserope(ROPE *rope);
> is OK
> so too is
> /* returns reversed rope, input unchanged */
> ROPE *reverserope(ROPE *rope)

It's not really OK. The parameter ought to be a pointer to const ROPE. 
That would make it clear to the function's user that the function does 
not modify its argument. The returned value should be a separate ROPE 
(either a pointer to a static object or a newly malloced one). The 
function's documentation should specify which, and also specify if there 
are any error cases that could cause it to return NULL.

> but
> 
> /* reverses the rope, returns pointer to reversed object */
> ROPE *reverserope(ROPE *rope)
> 
> is asking for trouble.

It provides some syntactic convenience but can also cause some 
confusion. Is it necessary to check the return value of this function? 
If the function succeeds, it will return the same pointer value as that 
passed in. If the function fails, it may return NULL. I would prefer to 
simply return a bool or an int containing a status code.

-- 
Simon.
0
Reply news195 (400) 11/13/2006 1:59:45 AM

Malcolm wrote:
> char q[1024];
> 
> gets(q); /* troll alert *

Your comment is missing a slash. I won't comment on the gets for fear of 
being called a troll.

> if(q[0] = '*')
> {
>    char *p = q;
> 
>    myasteriskroutine(p);
> }
> 
> This is legitimate code, if p has some meaning for an asterisk-started 
> string.

The code replaces the first character of q with an asterisk. Since the 
value of an asterisk character is never zero, it will always call 
myasteriskroutine. I think you meant to use the == operator.

> It makes the code easier to read.

How does it make the code easier to read? I would find it easier to read 
had you simply written:

if(q[0] == '*')
{
   myasteriskroutine(q);
}

> However a decent compiler will say q, p - same value. Therefore we just 
> store them in the same location in memory.

Indeed.

-- 
Simon.
0
Reply news195 (400) 11/13/2006 2:09:04 AM

24 Replies
35 Views

(page loaded in 0.234 seconds)


Reply: