#include <stdio.h>
bool file_copy(const char * const & newfilename,
const char * const & oldfilename)
{
FILE *fpnew = fopen(newfilename, "wb");
FILE *fpold = fopen(oldfilename, "rb");
bool worked = false;
if (fpnew && fpold)
{
int ch;
for (ch = fgetc(fpold); !feof(fpold); ch = fgetc(fpold))
fputc(ch, fpnew);
if (!(ferror(fpnew) || ferror(fpold)))
worked = true;
}
if (!fpnew) fclose(fpold);
if (!fpold) fclose(fpnew);
return worked;
}
The key part above is the loop:
for (ch = fgetc(fpold); !feof(fpold); ch = fgetc(fpold))
fputc(ch, fpnew);
I have a personal rule against repeating code like this. So, I
can write it this way:
while (ch = fgetc(fpold), !feof(fpold))
fputc(ch, fpnew);
But now I'm using the comma operator. *I* feel the second is a
bit clearer than the first. Any opinions? I could also do this:
do
{
ch = fgetc(fpold);
if (!feof(fpold))
fputc(ch, fpnew);
}
while (!feof(fpold));
But now I'm repeating code again. Or I could do this:
do
{
ch = fgetc(fpold);
if (feof(fpold))
break;
}
while (1);
But now I'm breaking the rules of structured programming. So
I either repeat code, write unstructured code, or write code
with a comma operator. What do I do to avoid all of these?
I did not see an answer in the FAQ.
> #include <stdio.h>
> bool file_copy(const char * const & newfilename,
> const char * const & oldfilename)
Damn. I thought it was in the common subset of C99 and C++,
but it's not ;-) Pretend those &s aren't there :-)
How about:
while((ch = fgetc(fpold)) != EOF)
{
fputc(ch, fpnew);
}
possibly followed by feof()/ferror()?
Gergo
--
Out of the mouths of babes does often come cereal.
>The key part above is the loop:
>
> for (ch = fgetc(fpold); !feof(fpold); ch = fgetc(fpold))
> fputc(ch, fpnew);
>
[snip other approaches]
>
>So I either repeat code, write unstructured code, or write code
>with a comma operator. What do I do to avoid all of these?
while ((ch = fgetc(fpold)) != EOF)
fputc(ch, fpnew);
If you must use feof rather than EOF, I don't think it can be done. If you
unroll the procedure, you have
statement1 ch = fgetc(fpold)
condition !feof(fpold)
statement2 fputc(ch, fpnew)
statement1
condition
statement2
statement1
condition
statement2
...
C lets you place the terminating condition either at the beginning (for, while)
or the end (do ... while) of the loop. This loop starts "in the middle" and so
can't be expressed without using one of the forbidden methods. :)
-- Mat.
I have a personal rule against repeating code like this.
>So, I
>can write it this way:
> while (ch = fgetc(fpold), !feof(fpold))
> fputc(ch, fpnew);
So, what's wrong with:
while (ch = fgetc(fpold) != EOF)
{
fputc(ch, fpnew);
}
>I did not see an answer in the FAQ.
Mmm... what did the FAQ say about feof()?
--
-hs- Tabs out, spaces in.
CLC-FAQ: http://www.eskimo.com/~scs/C-faq/top.html
ISO-C Library: http://www.dinkum.com/htm_cl
FAQ de FCLC : http://www.isty-info.uvsq.fr/~rumeau/fclc
>So, what's wrong with:
>
> while (ch = fgetc(fpold) != EOF)
> {
> fputc(ch, fpnew);
> }
You forgot some parentheses. That parses as
while (ch = (fgetc(fpold) != EOF))
{
fputc(ch, fpnew)
}
so assuming there's no I/O failure, you'll end up with a file of the correct
length, but filled with (unsigned char)1.
-- Mat.
Mine is: the above loop may run forever in the event of an input
error (e.g., trying to read a file on a bad floppy). :-)
(In this case fgetc() can return EOF and yet feof(fpold) can be 0,
because ferror(fpold) is nonzero.)
>... Or I could do this:
>
> do {
> ch = fgetc(fpold);
> if (feof(fpold))
> break;
> } while (1);
>
>But now I'm breaking the rules of structured programming.
Aside from it containing the same bug (i.e., feof() is only the
more usual case of "no more input available"), whether it breaks
"the" rules depends on whose rules you use. (I, for one, feel that
using a "break" statement to exit a loop in the middle is sufficiently
structured not to worry about it.)
>What do I do to avoid all of these?
Use the more usual:
while ((ch = fgetc(fpold)) != EOF)
form.
--
In-Real-Life: Chris Torek, Berkeley Software Design Inc
El Cerrito, CA, USA Domain: to...@bsdi.com +1 510 234 3167
http://claw.bsdi.com/torek/ (not always up) I report spam to abuse@.
nice try though. With a bit of fiddling around (ie. replace feof() with
some function of your own) you could probably come with a plausible use
for the comma-operator. Yes your code is pretty clear, if unfortunatly
wrong.
For the record when I'm faced with a termination mid-loop or
duplicating code ("I'd rather cut mi own arm off then write t'same code
twice") I use a "break", and damn the structured zealots. I think I
could find support from some distinguised computer scientist if I dug
around enough (Knuth?). I'm sure I've seen reasoning along the lines
that some problems pretty well force you to terminate a loop in the
middle and your choices are a flag or a "goto". I had an over-zealous
potty(*) training as a young programmer and am too psychologically
scarred to use a "goto", but "break" doesn't bother me. I've never seen
the point of "continue" though.
(*) I'm not sure if this the same word in USian. It's the thing you
encourage a small child to defecate in in preference to
nappy(1)/floor/furniture/parents/etc
(1) diaper in USian
--
Dan Pop: "When was the last time you've implemented a real life
application as a strictly conforming program?"
Richard Heathfield: "About 20 minutes ago. It was a new, heavily
optimised pig-launching routine, which gets us a 70% range increase on
previous porcine aeronautic programs."
Sent via Deja.com
http://www.deja.com/
In article <94hps0$r8s$1...@nnrp1.deja.com>
Nick Keighley <nikei...@my-deja.com> wrote:
>... your code is pretty clear, if unfortunatly wrong.
Eh? Are you sure you meant this as a reply to *me*?
(There is one case where testing the return value from fgetc -- as
stored in an ordinary "int" variable -- against EOF might fail.
That happens when sizeof(int) is 1 and UCHAR_MAX > INT_MAX. In
that case, though, the assignment:
ch = fgetc(fpold);
itself might fail, so we are already in trouble.)
>For the record when I'm faced with a termination mid-loop or
>duplicating code ("I'd rather cut mi own arm off then write t'same code
>twice") I use a "break", and damn the structured zealots.
(... which is what I said as well, in a bit I snipped.)
> >>Use the more usual:
> >> while ((ch = fgetc(fpold)) != EOF)
>
> In article <94hps0$r8s$1...@nnrp1.deja.com>
> Nick Keighley <nikei...@my-deja.com> wrote:
> >... your code is pretty clear, if unfortunatly wrong.
>
> Eh? Are you sure you meant this as a reply to *me*?
arg! no I didn't. I was referring to naisbodo's code. Why I replied to
your post rather than his I can't explain.
I've always found "continue" a helpful way (within a loop) to return
from error-handling code. Example: if while reading records from a
file I detect a flawed record, I typically want to return from the
error handling function and begin processing at the next record.
while (NULL != (fgets(buf, ...))
{
if (error_detected(buf))
{
handle_error(buf);
continue;
}
...
}
> Dan Pop: "When was the last time you've implemented a real life
> application as a strictly conforming program?"
>
> Richard Heathfield: "About 20 minutes ago. It was a new, heavily
> optimised pig-launching routine, which gets us a 70% range increase on
> previous porcine aeronautic programs."
Sounds like "embedded" systems programming at Hormel.
Bob