By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,597 Members | 1,672 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,597 IT Pros & Developers. It's quick & easy.

Is this kosher?

P: n/a
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
Nov 10 '06 #1
Share this Question
Share on Google+
24 Replies


P: n/a
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.
Nov 10 '06 #2

P: n/a

"MikeC" <My********@end.of.postwrote in message
news:hF*****************@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.

Nov 10 '06 #3

P: n/a
Malcolm said:
>
"MikeC" <My********@end.of.postwrote in message
news:hF*****************@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.
Nov 10 '06 #4

P: n/a


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';

--
Er*********@sun.com

Nov 10 '06 #5

P: n/a
Folks,

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

Best regards,

MikeC.

"MikeC" <My********@end.of.postwrote in message
news:hF*****************@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

Nov 10 '06 #6

P: n/a
"Richard Heathfield" <in*****@invalid.invalidwrote in message
Malcolm said:
>"MikeC" <My********@end.of.postwrote in message
news:hF*****************@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.

Nov 11 '06 #7

P: n/a
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.
Nov 11 '06 #8

P: n/a

"Richard Heathfield" <in*****@invalid.invalidwrote in message
news:Dq******************************@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.

Nov 11 '06 #9

P: n/a
Malcolm said:
>
"Richard Heathfield" <in*****@invalid.invalidwrote in message
news:Dq******************************@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.
Nov 11 '06 #10

P: n/a

Malcolm wrote:
"Richard Heathfield" <in*****@invalid.invalidwrote in message
news:Dq******************************@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.
Nov 12 '06 #11

P: n/a
William Hughes said:
Malcolm wrote:
>"Richard Heathfield" <in*****@invalid.invalidwrote...
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.
Nov 12 '06 #12

P: n/a
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>

Nov 12 '06 #13

P: n/a
"William Hughes" <wp*******@hotmail.comwrote in message
>
Malcolm wrote:
>"Richard Heathfield" <in*****@invalid.invalidwrote in message
news:Dq******************************@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.

Nov 12 '06 #14

P: n/a
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
Nov 12 '06 #15

P: n/a
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>
Nov 12 '06 #16

P: n/a

Malcolm wrote:
"William Hughes" <wp*******@hotmail.comwrote in message

Malcolm wrote:
"Richard Heathfield" <in*****@invalid.invalidwrote in message
news:Dq******************************@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

Nov 12 '06 #17

P: n/a

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

Nov 12 '06 #18

P: n/a
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.
Nov 12 '06 #19

P: n/a
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
Nov 12 '06 #20

P: n/a
"William Hughes" <wp*******@hotmail.comwrites:
[...]
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) ks***@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.
Nov 12 '06 #21

P: n/a

"Keith Thompson" <ks***@mib.orgwrote in message
news:ln************@nuthaus.mib.org...
"William Hughes" <wp*******@hotmail.comwrites:
[...]
>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.

Nov 12 '06 #22

P: n/a

Malcolm wrote:
"Keith Thompson" <ks***@mib.orgwrote in message
news:ln************@nuthaus.mib.org...
"William Hughes" <wp*******@hotmail.comwrites:
[...]
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

Nov 12 '06 #23

P: n/a
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.
Nov 13 '06 #24

P: n/a
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.
Nov 13 '06 #25

This discussion thread is closed

Replies have been disabled for this discussion.