newbie question: whats wrong with my code?

E

ericunfuk

I'm trying to copying a file to another file using the follwoing code,
but it's not working properly, some data is missing so I can't finally
recover the file.

#include <stdio.h>


void main(){
FILE *file, *file1;
file = fopen("title.jpg","rb");
if(file == NULL) perror("Error open file:");

char buf[100];

file1 = fopen("title1.jpg","wb");

while(fgetc(file)!=EOF){
fread(buf,sizeof(buf),sizeof(buf[0]),file);
fwrite(buf,sizeof(buf),sizeof(buf[0]),file1);

}

fclose(file);
fclose(file1);

}

Can you plz tell me where is wrong?
 
C

Christopher Benson-Manica

ericunfuk said:
I'm trying to copying a file to another file using the follwoing code,
but it's not working properly, some data is missing so I can't finally
recover the file.

Well, at least you tried before posting code. That said, there are a
lot of problems.
#include <stdio.h>
void main(){

int main(void) { /* If your textbook uses void main(), it's wrong. */
FILE *file, *file1;
file = fopen("title.jpg","rb");
if(file == NULL) perror("Error open file:");

What's the good of printing an error message and then going blithely
on with your NULL file pointer? You'll really want to just exit the
program.
char buf[100];
file1 = fopen("title1.jpg","wb");

Hadn't you better check file1 against NULL as well?
while(fgetc(file)!=EOF){

What are you doing with all those characters that fgetc() is returning
to you? They're certainly not being written to your output file.
Sounds like a problem to me.
fread(buf,sizeof(buf),sizeof(buf[0]),file);

You've mixed up the parameter order:

fread(buf,1,sizeof(buf),file);

Also, the return value of fread is rather important...
fwrite(buf,sizeof(buf),sizeof(buf[0]),file1);

....because there's no guarantee that you actually read sizeof(buf)
bytes from file. (You also mixed up the parameter order again.)
fclose(file);
fclose(file1);

return 0;
 
E

ericunfuk

ericunfuk said:
I'm trying to copying a file to another file using the follwoing code,
but it's not working properly, some data is missing so I can't finally
recover the file.

Well, at least you tried before posting code. That said, there are a
lot of problems.
#include <stdio.h>
void main(){

int main(void) { /* If your textbook uses void main(), it's wrong. */
FILE *file, *file1;
file = fopen("title.jpg","rb");
if(file == NULL) perror("Error open file:");

What's the good of printing an error message and then going blithely
on with your NULL file pointer? You'll really want to just exit the
program.
char buf[100];
file1 = fopen("title1.jpg","wb");

Hadn't you better check file1 against NULL as well?
while(fgetc(file)!=EOF){

What are you doing with all those characters that fgetc() is returning
to you? They're certainly not being written to your output file.
Sounds like a problem to me.
fread(buf,sizeof(buf),sizeof(buf[0]),file);

You've mixed up the parameter order:

fread(buf,1,sizeof(buf),file);

Also, the return value of fread is rather important...
fwrite(buf,sizeof(buf),sizeof(buf[0]),file1);

...because there's no guarantee that you actually read sizeof(buf)
bytes from file. (You also mixed up the parameter order again.)
fclose(file);
fclose(file1);

return 0;
while(fgetc(file)!=EOF){

What are you doing with all those characters that fgetc() is returning
to you? They're certainly not being written to your output file.
Sounds like a problem to me.

I wanted to check EOF, would you plz tell me the right and better way
of doing this?
 
E

Eric Sosman

ericunfuk said:
I'm trying to copying a file to another file using the follwoing code,
but it's not working properly, some data is missing so I can't finally
recover the file.

I'll point out a few other problems as well.
#include <stdio.h>


void main(){

int main(void)
FILE *file, *file1;
file = fopen("title.jpg","rb");
if(file == NULL) perror("Error open file:");

... but after the error message, the program plows
ahead and tries to use the NULL pointer anyhow. perror()
just outputs a message; it does not also stop the program.
char buf[100];

file1 = fopen("title1.jpg","wb");

And if this fopen() returns NULL ...?
while(fgetc(file)!=EOF){

Here's your biggest problem: fgetc() reads and returns
the next character from the input stream. The subsequent
fread() will start from the character after the one fgetc()
has already consumed; since you didn't save that character
anyplace there is no way you can write it to the output.
fread(buf,sizeof(buf),sizeof(buf[0]),file);
fwrite(buf,sizeof(buf),sizeof(buf[0]),file1);

}

fclose(file);
fclose(file1);
}

Can you plz tell me where is wrong?

See above. The suggested fix is to pay attention to the
value that fread() returns: it will return the number of
elements that were read, or it will return EOF if the stream
is already exhausted. Get rid of the bogus fgetc() and let
fread() itself tell you when you're finished.

Note also that fread() may read less data than you asked
for: For example, if you're twenty characters from the end of
the input and try to read a hundred, you clearly won't get a
full hundred characters! This means that when you call fwrite()
you shouldn't try to write the whole buffer, but only the part
that contains data that's been read.

Finally, a little error-checking wouldn't hurt. One easy
way to add it would be to use ferror() on file and file1 at
the end of the loop, and to check the values returned by
fclose(). (Yes, Virginia, fclose() can fail. I once made a
plane trip to St. Louis to pacify a customer who'd lost a whole
lot of work because an fclose() failure wasn't detected.)
 
K

Kenneth Brody

ericunfuk said:
I'm trying to copying a file to another file using the follwoing code,
but it's not working properly, some data is missing so I can't finally
recover the file.

#include <stdio.h>

void main(){
FILE *file, *file1;
file = fopen("title.jpg","rb");
if(file == NULL) perror("Error open file:");

char buf[100];

file1 = fopen("title1.jpg","wb");

while(fgetc(file)!=EOF){

Here you read a character and throw it away.
fread(buf,sizeof(buf),sizeof(buf[0]),file);

Here, you don't check the return value of fread() to see how
much was actually read.
fwrite(buf,sizeof(buf),sizeof(buf[0]),file1);

Here, you write 100 characters, even if fread() returned less.
}

fclose(file);
fclose(file1);

}

Can you plz tell me where is wrong?

Data is missing because you read a character with fgetc() and then
discard it.

Read your documentation on fread(). You will see that it returns
how much it read. Use it. Also, note what it returns on EOF.

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
C

Christopher Benson-Manica

(I've fixed the attribution of the above comment, please do try to be
careful about how you quote relevant text.)
I wanted to check EOF, would you plz tell me the right and better way
of doing this?

char mychar;
/* ... */

while( (mychar=fgetc(file)) != EOF ) {
/* do things with mychar */
}
 
E

Eric Sosman

Christopher said:
(I've fixed the attribution of the above comment, please do try to be
careful about how you quote relevant text.)


char mychar;

int mychar;

You've been around long enough to have read the FAQ,
haven't you? This misteak is the subject of Question 12.1.
 
E

ericunfuk

Thank you all your help. I have more questions:
Following is my corrected version, it's still not as good as you
expect, I need to ask few more questions before I could improve it
further.


#include <stdio.h>


int main(void){
FILE *file, *file1;
file = fopen("title.jpg","rb");
if(file == NULL) perror("Error open file:"); //<--bad

char buf[100];

file1 = fopen("title1.jpg","wb");
if(file1 == NULL) perror("Error open file:");//<--bad

int n;
while(!feof(file)){ //<--highly likely to be bad
n = fread(buf,sizeof(buf[0]),sizeof(buf),file);
fwrite(buf,sizeof(buf[0]),n,file1);

}

fclose(file);
fclose(file1);


return 1;
}


Q1. I used perror, becuase I almost know nothing about exit(),
especially exit status of my platform(if it's platform dependent, I
dont know)


Q2. I'm really not confident about the feof() function I used in the
while loop, I've seen people say you generally don't use feof, anyone
please tell me somewhat best way to test for EOF?I also would
appreciate if anyone could explain further the following code segment
from Chris's reply, I thought it would be really complicated if you
use fgetc, because you need to write it to the file you are writing to
separately?

char mychar;
/* ... */

while( (mychar=fgetc(file)) != EOF ) {
/* do things with mychar */

}

Again, thank you for your help.
Eric
 
R

Robert Gamble

I'm trying to copying a file to another file using the follwoing code,
but it's not working properly, some data is missing so I can't finally
recover the file.

#include <stdio.h>

void main(){

int main (void) {
FILE *file, *file1;
file = fopen("title.jpg","rb");
if(file == NULL) perror("Error open file:");

You should also exit the program instead of just printing an error and
then continuing to try to use the null pointer.
Also, perror prints a colon after your message, no need to add your
own.
char buf[100];

This is fine in C99 but in C89 the declarations need to come before
the code.
file1 = fopen("title1.jpg","wb");

This call to fopen can fail too...
while(fgetc(file)!=EOF){

The character that you read here with fgetc() is now gone, it won't be
read by the next call to fread(), this is where you are losing data.
fread(buf,sizeof(buf),sizeof(buf[0]),file);
fwrite(buf,sizeof(buf),sizeof(buf[0]),file1);

You are trying to write out 100 bytes of data even if fread() didn't
read that much. It looks like you might have started out with a
program that reads and writes one byte at a time with fgetc() and
fputc() and then tried to convert it to one that read multiple bytes
at a time. Below is a cleaned up version with the required changes.

#include <stdio.h>
#include <stdlib.h>

int main (void) {
FILE *file, *file1;
char buf[100];
size_t bytes_read;

file = fopen("title.jpg","rb");
file1 = fopen("title1.jpg","wb");
if (file == NULL || file1 == NULL) {
perror("Error open file");
exit(EXIT_FAILURE);
}

while (( bytes_read = fread(buf, 1, sizeof(buf), file)) != 0) {
if (fwrite(buf, 1, bytes_read, file1) != bytes_read) {
perror("Error writing file");
exit(EXIT_FAILURE);
}
}

fclose(file);
fclose(file1);
return 0;
}

fread() returns the number of elements read which will be 0 when there
is no data left to read either because eof or an error has occured.
We need to store the number of bytes read so that we know how much to
write out in case the size of the file isn't a multiple of 100.
Notice the change in the order of the arguments in fread(), we are
saying "read 100 elements of size 1" instead of "1 element of size
100" so that we can keep track of the number of bytes that need to be
written when it is less than 100. When the while loop ends you can
use ferror(file) to determine if there was an error reading the file
if you'd like.

Robert Gamble
 
C

Christopher Benson-Manica

Eric Sosman said:
int mychar;
You've been around long enough to have read the FAQ,
haven't you? This misteak is the subject of Question 12.1.

It's been a long enough week that I just blew it. I appreciate the
correction. (It's also been a long enough week that I can't tell
whether there is an implied smiley included with "misteak" or whether
you're ready for a weekend as well.)
 
M

Martin Ambuhl

ericunfuk said:
I'm trying to copying a file to another file using the follwoing code,
but it's not working properly, some data is missing so I can't finally
recover the file.

#include <stdio.h>


void main(){
^^^^
You lose. Start over from page 1 or a decent C text.
 
C

CBFalconer

Eric said:
.... snip ...

You've been around long enough to have read the FAQ,
haven't you? This misteak is the subject of Question 12.1.

FAQ 12.1 seems to deal with neither wood nor meat :)
 
K

Keith Thompson

ericunfuk said:
Thank you all your help. I have more questions:
Following is my corrected version, it's still not as good as you
expect, I need to ask few more questions before I could improve it
further.


#include <stdio.h>


int main(void){
FILE *file, *file1;
file = fopen("title.jpg","rb");
if(file == NULL) perror("Error open file:"); //<--bad

char buf[100];

file1 = fopen("title1.jpg","wb");
if(file1 == NULL) perror("Error open file:");//<--bad

int n;
while(!feof(file)){ //<--highly likely to be bad
n = fread(buf,sizeof(buf[0]),sizeof(buf),file);
fwrite(buf,sizeof(buf[0]),n,file1);

}

fclose(file);
fclose(file1);


return 1;
}

Your code is showing up with no indentation, which makes it difficult
to read. I don't know whether you wrote it that way. If you used tab
characters for indentation, some news software will ignore them. If
you can, try to use only spaces for indentation.
Q1. I used perror, becuase I almost know nothing about exit(),
especially exit status of my platform(if it's platform dependent, I
dont know)

Use exit(EXIT_SUCCESS) or exit(EXIT_FAILURE) to terminate your
program and indicate whether it succeeded or failed. You'll need a
"#include <stdlib.h>", both for exit() and for the EXIT_* macros.
exit(0) is equivalent to exit(EXIT_SUCCESS). All of this is portable;
other arguments to exit() can be used in system-specific code.
Q2. I'm really not confident about the feof() function I used in the
while loop, I've seen people say you generally don't use feof, anyone
please tell me somewhat best way to test for EOF?
[...]

Your lack of confidence in feof() is admirable. :cool:}

In your original program, you used both fgetc() and fread(), which was
a large part of your problem. Both functions read input; you should
use just one or the other.

The feof() function is rarely useful. You want to detect when you've
run out of input. The way to do that is to look at the result
returned by whichever input function you're using. The fgetc() and
fread() functions do this differently.

fgetc() returns the next character from the input file (interpreted as
an unsigned char and converted to int). If there is no next
character, it returns the value EOF, which is guaranteed to be
negative and therefore unequal to any unsigned char value. (On some
exotic systems, char and int can be the same size, so EOF could also
be a valid character value; you almost certainly don't need to worry
about that possibility.)

fread() returns the number of items successfully read (note that this
isn't the number of characters unless the size argument happens to be
1). If there are no more items to read, it returns 0; if there are
some items to read, but fewer than you asked for, it returns a value
smaller than what you asked for.

With either function, you can use the result to determine whether it
ran out of data to read. *After* that happens, you can, if you wish,
call feof() and/or ferror() to find out whether this happened because
you reached end-of-file or because of some error.

If you haven't already done so, read section 12 of the comp.lang.c
FAQ, <http://www.c-faq.com/stdio/>.
 
D

Doug

...and to check the values returned by
fclose(). (Yes, Virginia, fclose() can fail. I once made a
plane trip to St. Louis to pacify a customer who'd lost a whole
lot of work because an fclose() failure wasn't detected.)

Hi Eric,

Just for laughs, can you tell us more about that episode?

And just for my education, can you tell me more about failures to
check the retcode from fclose()? If I detect a bad retcode what
should I do, etc.? Pointers to the FAQ humbly received.

Thanks,
Doug
 
R

Richard Tobin

Doug said:
And just for my education, can you tell me more about failures to
check the retcode from fclose()?

You open the old file, copy it to the new file, add the extra line,
delete the old file, but whoops! the disk was full and now you don't
have either file.

You might expect that you would have got errors from fwrite() or
whatever in this case, but the disk may not fill up until the last
block is flushed, or a network disk protocol may not give synchronous
errors. Even fclose() doesn't guarantee that the data has been
written to the disk (rather than, say, buffered in the OS), but it's
the best you can do in standard C.
If I detect a bad retcode what should I do, etc.?

Not delete the old file :)

-- Richard
 
D

Daniel Rudy

At about the time of 3/23/2007 11:17 AM, ericunfuk stated the following:
I'm trying to copying a file to another file using the follwoing code,
but it's not working properly, some data is missing so I can't finally
recover the file.

#include <stdio.h>


void main(){
int main(void)

If your book/instructor says otherwise, then it's time to find another
book/instructor.
FILE *file, *file1;
file = fopen("title.jpg","rb");
if(file == NULL) perror("Error open file:");
You probably should exit the program here if file == NULL.
char buf[100];
This should probably be up with your other variables.
file1 = fopen("title1.jpg","wb");
You need to check for errors here too.
while(fgetc(file)!=EOF){
I think you want feof here...fgetc returns 1 character from the file
stream and you are throwing it away.
fread(buf,sizeof(buf),sizeof(buf[0]),file);
fwrite(buf,sizeof(buf),sizeof(buf[0]),file1);

You need to do something like this:

readsize = fread(buf, 1, sizeof(buf), file);
if (readsize < sizeof(buf))
{
if (ferror) /* see if short read was caused by an error */
{
perror("error reading file")
fclose(file);
fpurge(file1);
fclose(file1);
remove("title1.jpg");
exit(1);
}
}
writesize = fwrite(buf, 1, readsize, file1);
if (writesize < readsize)
{
perror("error writing file");
fclose(file);
fpurge(file1);
fclose(file1);
remove("title1.jpg");
exit(1);
}

fread and fwrite param 2 is the record size, which should be 1, and
param 3 is the number of records to read/write. Doing it this way
allows you to specify the number of bytes to read/write directly. Also,
you need to be looking at the return value for fread. That way when you
get a short read, you do a short write and then exit the loop. The
values returned are of type size_t.
}

fclose(file);

Not required, but you can do fflush(file1); here before you close the
file1 stream. This forces a write of the buffer to disk. (At least it
forces a call to the underlying write function which is usually a system
call to the operating system.)
fclose(file1);

}

Can you plz tell me where is wrong?



--
Daniel Rudy

Email address has been base64 encoded to reduce spam
Decode email address using b64decode or uudecode -m

Why geeks like computers: look chat date touch grep make unzip
strip view finger mount fcsk more fcsk yes spray umount sleep
 
D

Daniel Rudy

At about the time of 3/24/2007 3:23 AM, Daniel Rudy stated the following:
At about the time of 3/23/2007 11:17 AM, ericunfuk stated the following:

This is a complete version of what you are trying to do. As for the
regulars, critiques are welcome. :)



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>


#define BUFFSIZE 65536 /* buffer size */
#define FILENAMESIZE 1024 /* max size of filenames */


int main(int argc, char **argv)
{
size_t readsize; /* size of data read */
size_t writesize; /* size of data written */
int eof_flag; /* flag if eof encountered */
FILE *infile; /* file pointer for input file */
FILE *outfile; /* file pointer for output file */
void *buffer; /* pointer to buffer space */
char infilename[FILENAMESIZE]; /* input filename */
char outfilename[FILENAMESIZE]; /* output filename */



/* get filenames */
if (argc != 3)
{
printf("Enter path/filename to copy -->");
fgets(infilename, sizeof(infilename), stdin);
printf("Enter destination path/filename -->");
fgets(outfilename, sizeof(outfilename), stdin);
}
else
{
if (strlen(argv[1]) > sizeof(infilename) - 2)
{
printf("error: input filename too long\n");
exit(EXIT_FAILURE);
}
if (strlen(argv[2]) > sizeof(outfilename) - 2)
{
printf("error: output filename too long\n");
exit(EXIT_FAILURE);
}
strncpy(infilename, argv[1], sizeof(infilename) - 2);
infilename[sizeof(infilename) - 1] = '\0';
strncpy(outfilename, argv[2], sizeof(outfilename) - 2);
outfilename[sizeof(outfilename) - 1] = '\0';
}

/* allocate buffer space */
buffer = malloc(BUFFSIZE);
if (buffer == NULL)
{
printf("error: unable to allocate buffer space: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}

/* open input and output files */
infile = fopen(infilename, "rb");
if (infile == NULL)
{
printf("error: unable to open input file %s: %s\n", infilename, strerror(errno));
free(buffer);
exit(EXIT_FAILURE);
}
outfile = fopen(outfilename, "wb");
if (outfile == NULL)
{
printf("error: unable to open output file %s: %s\n", outfilename, strerror(errno));
free(buffer);
fclose(infile);
exit(EXIT_FAILURE);
}

/* copy input file to output file in a loop */
eof_flag = 0;
while (eof_flag == 0)
{

/* read input file into buffer */
readsize = fread(buffer, 1, BUFFSIZE, infile);
if (readsize < BUFFSIZE) /* can only be caused by a eof or error */
{
if (feof != 0) eof_flag = 1;
else
{
printf("error: error reading file: %s\n", strerror(errno));
fpurge(outfile);
fclose(infile);
fclose(outfile);
remove(outfilename);
free(buffer);
exit(EXIT_FAILURE);
}
}

/* write contents of buffer to output file */
writesize = fwrite(buffer, 1, readsize, outfile);
if (writesize < readsize) /* can only be caused by an error */
{
printf("error: error writing to file: %s\n", strerror(errno));
fpurge(outfile);
fclose(infile);
fclose(outfile);
remove(outfilename);
free(buffer);
exit(EXIT_FAILURE);
}
}

/* clean up */
free(buffer);
fflush(outfile);
fclose(infile);
if (fclose(outfile) == EOF)
{
printf("error: problem closing output file: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}


/* return to operating system */
exit(EXIT_SUCCESS);
}


As you can see, about half the code is dealing with errors. I
didn't use perror though like you did.

--
Daniel Rudy

Email address has been base64 encoded to reduce spam
Decode email address using b64decode or uudecode -m

Why geeks like computers: look chat date touch grep make unzip
strip view finger mount fcsk more fcsk yes spray umount sleep
 
D

Doug

You open the old file, copy it to the new file, add the extra line,
delete the old file, but whoops! the disk was full and now you don't
have either file.

Ah, good one. I see what you mean.

When I write code like that, I usually use fflush() and fsync(), do
error handling for them, then basically ignore the fclose() retcode.
(Well, I trace/log it, but effectively ignore it.) Does that sound
silly?

Doug
 
B

Bill Pursell

At about the time of 3/24/2007 3:23 AM, Daniel Rudy stated the following:


This is a complete version of what you are trying to do. As for the
regulars, critiques are welcome. :)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define BUFFSIZE 65536 /* buffer size */

Why not just use BUFSIZ from stdio.h?
#define FILENAMESIZE 1024 /* max size of filenames */

int main(int argc, char **argv)
{
size_t readsize; /* size of data read */
size_t writesize; /* size of data written */
int eof_flag; /* flag if eof encountered */
FILE *infile; /* file pointer for input file */
FILE *outfile; /* file pointer for output file */
void *buffer; /* pointer to buffer space */

Hmmm, why not declare buffer as a char * or unsigned char *?
char infilename[FILENAMESIZE]; /* input filename */
char outfilename[FILENAMESIZE]; /* output filename */

/* get filenames */
if (argc != 3)
{
printf("Enter path/filename to copy -->");
fgets(infilename, sizeof(infilename), stdin);
printf("Enter destination path/filename -->");
fgets(outfilename, sizeof(outfilename), stdin);
}
else
{
if (strlen(argv[1]) > sizeof(infilename) - 2)
{
printf("error: input filename too long\n");

This is an error message. It should probably go to stderr rather
than stdout.
exit(EXIT_FAILURE);
}
if (strlen(argv[2]) > sizeof(outfilename) - 2)
{
printf("error: output filename too long\n");
exit(EXIT_FAILURE);
}
strncpy(infilename, argv[1], sizeof(infilename) - 2);

Why make copies of the filenames? Why not just declare infilename
as a char * and have "infilename = argv[1];" Also, since
you've already checked the lengths of the filenames, you know
that strncpy is going to write the null at the end, so
there's no need to do it.
infilename[sizeof(infilename) - 1] = '\0';
strncpy(outfilename, argv[2], sizeof(outfilename) - 2);
outfilename[sizeof(outfilename) - 1] = '\0';
}

/* allocate buffer space */
buffer = malloc(BUFFSIZE);
if (buffer == NULL)
{
printf("error: unable to allocate buffer space: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}

/* open input and output files */
infile = fopen(infilename, "rb");
if (infile == NULL)
{
printf("error: unable to open input file %s: %s\n", infilename, strerror(errno));
free(buffer);
exit(EXIT_FAILURE);
}
outfile = fopen(outfilename, "wb");
if (outfile == NULL)
{
printf("error: unable to open output file %s: %s\n", outfilename, strerror(errno));
free(buffer);
fclose(infile);
exit(EXIT_FAILURE);
}

/* copy input file to output file in a loop */
eof_flag = 0;
while (eof_flag == 0)
{

/* read input file into buffer */
readsize = fread(buffer, 1, BUFFSIZE, infile);

Just a style point, I prefer
fread(buffer, sizeof *buffer, ...), which won't work since you
declared buffer as a void *.
if (readsize < BUFFSIZE) /* can only be caused by a eof or error */
{
if (feof != 0) eof_flag = 1;

feof shuould probably be called. eg feof(infile)
else
{
printf("error: error reading file: %s\n", strerror(errno));
fpurge(outfile);
fclose(infile);
fclose(outfile);
remove(outfilename);
free(buffer);
exit(EXIT_FAILURE);
}
}

/* write contents of buffer to output file */
writesize = fwrite(buffer, 1, readsize, outfile);
if (writesize < readsize) /* can only be caused by an error */
{
printf("error: error writing to file: %s\n", strerror(errno));
fpurge(outfile);
fclose(infile);
fclose(outfile);
remove(outfilename);
free(buffer);
exit(EXIT_FAILURE);
}
}

/* clean up */
free(buffer);
fflush(outfile);
fclose(infile);
if (fclose(outfile) == EOF)
{
printf("error: problem closing output file: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}

/* return to operating system */
exit(EXIT_SUCCESS);
}

As you can see, about half the code is dealing with errors. I
didn't use perror though like you did.

Overall, the main function is way too long, and I don't like
seeing the error checking stuff strewn throughout. It's hard
to see the flow of the program. Here's my attempt, and I'm
not sure I completely like it. Rather than checking for
read errors immediately, I handle a read error by storing
errno, calling fwrite with a zero count, and then giving
a warning about the read error later (I'm not convinced
that I like that technique, but it makes the processing
loop very readable.)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

struct args {
FILE *in;
FILE *out;
char *in_name;
char *out_name;
};

int clean_up( int readerr, struct args *A );
void parse_args( struct args *A, int argc, char **argv );


int
main( int argc, char **argv )
{
struct args A;
size_t rc; /* Read count. */
int re; /* Read error. */
size_t wc; /* Write count. */
unsigned char buf[ BUFSIZ ];

parse_args( &A, argc, argv );
do {
rc = fread( buf, sizeof *buf, BUFSIZ, A.in );
re = errno;
wc = fwrite( buf, sizeof *buf, rc, A.out );
} while( rc == wc && rc == BUFSIZ );

return clean_up( re, &A );
}

int
clean_up( int readerr, struct args *A )
{
int status = EXIT_SUCCESS;

if( ferror( A->out )) {
status = EXIT_FAILURE;
perror( A->out_name );
}

if( ferror( A->in )) {
status = EXIT_FAILURE;
fprintf( stderr, "%s: %s", A->in_name,
strerror( readerr ));
}

if( fclose( A->in )) {
status = EXIT_FAILURE;
perror( A->in_name );
}

if( fclose( A->out )) {
status = EXIT_FAILURE;
perror( A->out_name );
}

return status;
}


void
parse_args( struct args *A, int argc, char **argv )
{
A->in = stdin;
A->out = stdout;
A->in_name = "stdin";
A->out_name = "stdout";

if( argc > 1 ) {
A->in_name = argv[1];
A->in = fopen( A->in_name, "rb" );
if( A->in == NULL ) {
perror( A->in_name );
exit( EXIT_FAILURE );
}
}

if( argc > 2 ) {
A->out_name = argv[2];
A->out = fopen( A->out_name, "wb" );
if( A->out == NULL ) {
perror( A->out_name );
if( fclose( A->in ))
perror( A->in_name );
exit( EXIT_FAILURE );
}
}
}
 
A

Army1987

Daniel Rudy said:
#define BUFFSIZE 65536 /* buffer size */
What if INT_MAX were 32767?
Decimal constants are interpreted as int before being cast to anything else
(size_t in this case).
Maybe you could use (size_t)65536L...
/* get filenames */
if (argc != 3)
{
printf("Enter path/filename to copy -->");
fgets(infilename, sizeof(infilename), stdin);
printf("Enter destination path/filename -->");
fgets(outfilename, sizeof(outfilename), stdin);
}
On entering only one filename as a command-line parameter, I'd expect being
told which the syntax is, or being asked only for the output filename.
printf("error: input filename too long\n");
If for some insane reason I've redirected the output to a file, I won't see
the error message 'till I open the output file.
I'd use fputs("error: input filename too long\n", stderr);
printf("error: unable to allocate buffer space: %s\n",
strerror(errno));
Why don't you like perror("error: unable to allocate buffer space");?
if (feof != 0) eof_flag = 1;
You meant feof(infile)?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

error 28
code 34
fread/fwrite 2 18
Whats wrong with my stream ? 4
question 33
Can not read VCD file in Linux 8
file bug 28
bsearch problem in my code 8

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top