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)
|