Part of Code 1:-
while(1)
{
ch=fgetc(pt);
if(c==EOF)
{
break;
}
if(c==' ')
{
fputc('z',pt);
}
}
Part of Code 2:-
while(1)
{
ch=fgetc(pt);
if(c==EOF)
{
break;
}
if(c==' ')
{
fseek(pt,0,SEEK_CUR);
fputc('z',pt);
fseek(pt,0,SEEK_CUR);
}
}
I want to replace next character after every space in a file. That file is pointed by the pointer pt.
Both the code shows no error and runs fine, but when I externally opens the .txt file, first code did nothing whereas the second code replaces the next character after space successfully.
Clearly fseek(pt,0,SEEK_CUR); is making the difference.
So I am unable to understand that what it is doing in the second code?
The use of fseek() here - The C standard requires a positioning operation between a read and a write operation on an update stream, or between a write and a read. This is a positioning operation between a write and a read. It is not a no-op; it places the stream into a mode which allows the next fgetc() to work correctly, reliably, across platforms, as required by the C standard.
EDIT:
2 fseek() calls are required because the first one acts as the "no-op" call between an fgetc() and a subsequent fputc() call. After the fputc(), the second one acts as the "no-op" between the fputc() and the subsequent fgetc() call. (since a loop is running)
Related
In this related question How to use feof and ferror for fgets (minishell in C), the answers aren't really clear for my problem.
What I'm trying to do is: I want to read all of the characters from a plain text file on my disk. It's not a link, devicefile, socket etc. just a regular text file. Once I've read all the characters I want to see if everything succeeded. What I'm seeing now is, in my Debug builds everything goes successfully, but in my Release builds ferror() always indicates there is a an error. While the Debug build returns the 0 in the end. In both cases I can see that the content of the file has been obtained in a debugger.
my_function(File* f) {
int c;
while ((c = fgetc(f)) != EOF) {
char character = (char) c;
// store character in a dynamic growing buffer
}
// append '0' byte to buffer (to terminate the string).
if (ferror(f)) {
// return error
return 1;
}
return 0; // no error.
}
Rationale of having a already opened file as function argument, is to make it relatively easy to read from a file, without the need to bother with a platform dependent encoding. This is inside a private part of my library, the public functions handle the case that f == NULL.
Do I need to call clearerr(file) first, because the error bit is not initialized in a Release builds?
it is always printing an extra character at the end. here is the code:
#include <stdio.h>
int main ()
{
char bit;
FILE *fp_read,*fp_write;
fp_read = fopen("test.txt","r");
if(fp_read==NULL) {
printf("Error!! Unable to open the file!!");
return 1;
}
while(!feof(fp_read)) {
fscanf(fp_read,"%c",&bit);
printf("%c",bit);
}
fclose(fp_read);
return 0;
}
if test.txt contains 010101 it prints 0101011 . if 00110 it prints 001100. if it contains abc it prints abcc . that means it always repeats the last character.
What is the problem ? can anybody explain ?
I am not able to reproduce the error.
Refer to David Bowling's first comment in the original post for a neat explanation.
The cppreference page for feof has a shorter version.
The eof function only reports the stream state as reported by the most recent I/O operation, it does not examine the associated data source. For example, if the most recent I/O was a fgetc, which returned the last byte of a file, feof returns zero. The next fgetc fails and changes the stream state to end-of-file. Only then feof returns non-zero.
In typical usage, input stream processing stops on any error; feof and ferror are then used to distinguish between different error conditions.
This means that the use of feof in the while loop may not be appropriate. The last character from the file may be junk and will be different in different systems.
Try doing this instead.
while(fscanf(fp_read,"%c",&bit) != EOF) {
printf("%c",bit);
}
The mod_rewrite documentation states that it is a strict requirement to disable in(out)put buffering in a rewrite program.
Keeping that in mind I've written a simple program (I do know that it lacks the EOF check but this is not an issue and it saves one condition check per loop):
#include <stdio.h>
#include <stdlib.h>
int main ( void )
{
setvbuf(stdin,NULL,_IONBF,0);
setvbuf(stdout,NULL,_IONBF,0);
int character;
while ( 42 )
{
character = getchar();
if ( character == '-' )
{
character = '_';
}
putchar(character);
}
return 0;
}
After making some measurements I was shocked - it was over 9,000 times slower than the demo Perl script provided by the documentation:
#!/usr/bin/perl
$| = 1; # Turn off I/O buffering
while (<STDIN>) {
s/-/_/g; # Replace dashes with underscores
print $_;
}
Now I have two related questions:
Question 1. I believe that the streams may be line buffered since Apache sends a new line after each path. Am I correct? Switching my program to
setvbuf(stdin,NULL,_IOLBF,4200);
setvbuf(stdout,NULL,_IOLBF,4200);
makes it twice as fast as Perl one. This should not hit Apache's performance, should it?
Question 2. How can one write a program in C which will use unbuffered streams (like Perl one) and will perform as fast as Perl one?
Question 1: You would have to look at the code. It could be line buffered, it could be using fflush at the end of each request (or block of requests), or it could be using write calls with a larger buffer. In any case, it won't be doing per-character I/O which is what your program is doing.
Question 2: I suspect the main issue is on output. If you were to assemble the entire result in a buffer and write that out as one call, then you would be faster. However, that just means you are doing the line buffering instead of having the library take care of it for you. The key is that with no buffering, each output call results in a system call - that is very high overhead. In theory, the same concept holds true on input but I'm not sure the implementation wouldn't notice the available characters and buffer them in any case. Same workaround though - read a larger buffer and then take it apart yourself.
Personally, I'd avoid all the setvbuf stuff and just do an fflush at the end of each request.
When writing to a terminal, stdout is flushed after every line. This way you can always see the output right away. When writing to a file or, as in your case a pipe, this automatic flush is disabled. Usually in those cases performance is more important.
This causes problems when processes have to interact with each other. One program writes something. It's not sent instantly but stored in a buffer. Second program waits for that data. First program waits for more data from second program resulting in a deadlock.
To avoid this, you need to flush all the output before waiting for additional input. Simple fflusuh(stdout) before every read operation should be enough. This is actually what $|=1 does in Perl. Nothing needs to be done with stdin.
If performance is critical and you need to operate only on single bytes. Read and write data in big chunks using unbuffered read/write. For example:
#include <unistd.h>
int main() {
char buf[1024];
while(1) {
int len = read(0,buf,sizeof(buf));
for(int i=0;i<len;i++) {
if ( buf[i] == '-' ) {
buf[i] = '_';
}
}
write(1,buf,len);
}
}
I am pretty new to C and have a very simple function for displaying file contents here. It works fine, except the last line of my file prints twice...I know that it has to do w/EOF but I can't figure out how to get the function to recognize EOF as the last line and not run once more. I know there are a billion places on the internet with similar issues, but lots were for C++ and since I am new I thought it would be best to just use my own code. Here is the code:
{
int count=0, fileEnd=0;
FILE* rockPtr=fopen("rockact.txt", "r");
printf("\n%8s%8s%8s%8s%8s\n", "BANDID", "NAME", "SIZE", "CREW", "TRANS");
do
{
fileEnd=fscanf(rockPtr, "%d%s%d%d%s", &(tempBand.rockid), tempBand.bandname, &(tempBand.bandsize), &(tempBand.crewsize), tempBand.transport);
if (fileEnd !=EOF); //checks EOF has not been reached
{
printf("\n%8d%8s%8d%8d%8s", tempBand.rockid, tempBand.bandname, tempBand.bandsize, tempBand.crewsize, tempBand.transport);
count++;
}
}
while (fileEnd !=EOF);
fclose(rockPtr);
printf("\n The total amount of rock acts on file is %d\n", count);
}
Your if condition doesn't want the semi-colon:
if (fileEnd !=EOF); // This semicolon is wrong!
The semicolon is a null statement and is the body of the if.
I'd rather see the whole loop cast as a while loop:
while (fscanf(rockPtr, "%d%s%d%d%s", &tempBand.rockid, tempBand.bandname,
&tempBand.bandsize, &tempBand.crewsize, tempBand.transport)) == 5)
{
printf("\n%8d%8s%8d%8d%8s", tempBand.rockid, tempBand.bandname,
tempBand.bandsize, tempBand.crewsize, tempBand.transport);
count++;
}
If you want to worry about it, you can spot the difference between EOF, read error and format error after the loop. Note that the check is that all values were converted OK.
you have ; after if - remove it
also, check manual for fscanf
If a reading error happens or the end-of-file is reached while
reading, the proper indicator is set (feof or ferror). And, if either
happens before any data could be successfully read, EOF is returned.
This mean that you can read at least partial data from file, reach EOF or error, but fscanf will not return it.
You should use feof function to check whether end of file is reached
so your logic should be:
read from file
if anything is read - display it, here I mean you should compare returned number with count of arguments, not with EOF
check for feof
UPDATE: during opening/reading from file you should always check ferror, as EOF is not the only problem
fwrite(&studentg,sizeof(studentg),1,p);
while(!feof(p))
{
printf("flag");
fread(&studentg,sizeof(studentg),1,p);
printf("%s\t%s\t%s\t%s\t%s\t%s\t\n",studentg.name,studentg.add,studentg.tel,studentg.pc,studentg.qq,studentg.email);
}
Why I put only one object in file,but it output two same line?
And if I put two objects in file,it output one object correct,but another repeated.
I try show feof(p)'s return value,it show me that after fread ,feof(p)'s return value is still 0.Can anyone explain how it happens?
You won't get an end of file until you try to read beyond the file. This means that you have to check eof before the print:
fwrite(&studentg,sizeof(studentg),1,p);
finish = 0;
while(!finish)
{
printf("flag");
fread(&studentg,sizeof(studentg),1,p);
finish = feof(p);
if (!finish)
{
printf("%s\t%s\t%s\t%s\t%s\t%s\t\n",studentg.name,studentg.add,studentg.tel,studentg.pc,studentg.qq,studentg.email);
}
}
or
fwrite(&studentg,sizeof(studentg),1,p);
while(1)
{
printf("flag");
fread(&studentg,sizeof(studentg),1,p);
if (feof(p)) break;
printf("%s\t%s\t%s\t%s\t%s\t%s\t\n",studentg.name,studentg.add,studentg.tel,studentg.pc,studentg.qq,studentg.email);
}
From http://www.cplusplus.com/reference/cstdio/feof/:
"This indicator is generally set by a previous operation on the stream that attempted to read at or past the end-of-file."
This means that end of file is usually detected after an operation.
To fix your code, you may for example replace the condition in while loop with 1 or true and break execution when eof is reached (run feof inside loop).
Use of feof is one of the biggest misconception among beginners in File I/O. Everybody at some point has done the same mistake once or twice.
The way you have used it is Pascal's way but C way is different. The difference is::
Pascal's function returns true if the next read will fail because of end of file.
C's function returns true if the last function failed.
Thats why your code prints the last line twice because after the last line is read in and printed out, feof() will still return 0 (false) and the loop will continue. The next fgets() fails and so the line variable holding the contents of the last line is not changed and is printed out again. After this, feof() will return true (since fgets() failed) and the loop ends.
The correct way to use it is::
while( 1 ) {
fgets(line, sizeof(line), fp);
if ( feof(fp) ) /* check for EOF right after fgets() */
break;
fputs(line, stdout);
}
Still better way::
while( fgets(line, sizeof(line), fp) != NULL )
fputs(line, stdout);
First of all you should include a complete, reproducing, example to what you want to do, not a combined fragment of the code, which is hard to reproduce. Otherwise, note that using fwrite()/fread() on struct contents directly is not portable (see the free online book Porting UNIX Software), and is prone to errors. But you didn't provide enough context for us to understand what went wrong.