Flushing and Seeking Functions in C

Question: What are Flushing and Seeking Functions in C and What are they Used for in a Program

Answer: Let’s recall that whenever we need to perform read and write operations with files in C programs we must open a stream for file and access that stream to perform desired operations with file. These streams are mostly ‘Fully Buffered’ meaning that they are flushed i.e. physically written to a file when it gets full or when newline character is encountered. Note hare that output strems are fulushed to file and effects of flushing input streams is undefined.

Now question is, why do we need to flush the output stream? One significant reason is whenever we are required output stream to be physically written immediately. For ex. while debugging a program we would like the debugging information to be flushed immidiately until hold it for later time. For ex.,

int main(void)
{
    FILE *in_out;
 
    int shots = 12;
    int *pi = &shots;
    char ch = 'A';
    char *pc = ch;
 
    in_out = fopen("hello.txt", "a+");
 
    fprintf(in_out, "value at location %p is %d\n",
             pi + 1, *(pi + 1));
 
    fflush(in_out);
 
    fprintf(in_out, "value at location %p is %c\n",
             pc, *pc);
 
    /* other code */
 
    return 0;
}

Notice that fflush() caused strean ‘in_out’ to be flushed immediately; writing physically ‘message’ before it to the file while ‘message’ after it is not written. Program gives ‘seg fault’ because of mistakenly initializing pointer-to-char ‘pc’ with value of character ‘ch’.

    char *pc = ch;

and accessing value of ‘ch’ by dereferencing ‘pc’.

advertisement
advertisement

Secondly, when we open stream bidirectionally i.e. open it in update mode so that we could read from and write to the file. Then, after each time we have written to the file, flush output stream just before next successive reading from it, so that all the contents in the stream are physially writen to file. Let’s see, just relevent, fragment of code in C,

    FILE *in_out;
    char buffer[TEXTSIZE] = "cpp is very ineresting!";
 
    in_out = fopen("hello.txt", "a+"); /* a+ refers update mode */
    /* verify if stream opened successfully */
 
    /* now write to the file */
    fpritf(in_out, "%s", buffer);
 
    /*
     * now call fflush() to flush the stream before next
     * read from stream
     */
    fflush(in_out);
 
    /* now we can read from stream */

Prototype for fflush() function is as follows

    int fflush(FILE *stream);

Writing to file is done sequentially which means data written later appears in the file after any data written earlier. C also supports random access I/O meaning that file can be accessed randomly in any order. Therefore, writing to file at specific location is accomplished by seeking to desired location in the file. This is done by calling a pair of functions which are prototyped below,

Sanfoundry Certification Contest of the Month is Live. 100+ Subjects. Participate Now!
    long ftell(FILE *stream);
    int fseek(FILE *stream, long offset, int from);

Notice that ftell() returns current position from the beginning in the file. That is, it returns offset from the beginning in the file at which next read or write would begin. This function allows us to save the offset and return to it later when required. In binary files, it returns no. of bytes from the beginning but in text files it returns the current position from the beginning and not no. of characters from the beginning. Actually, this is because of end-of-line character translations by other systems. For ex. Linux, Unix terminates lines by newline character, MS-DOS uses character pair combination “carriage return/newline” while MAC uses “carriage return” to terminate lines. However, this offset from the begining can always be used with fseek() function.

fseek() function seeks on the stream for specified location. This operation changes the position at which next read/write will occur. Standard defined three diferent modes which fseek() can use to set the position where from read/write would take place.

1. If from in fseek is SEEK_SET, offset bytes from the beginning of the stream. Offset must be non-negative. It’s an error to attempt to seek before the beginning of file. On text streams, offset must be a value previously returned by call to ftell().

advertisement

2. If from in fseek() is SEEK_CUR, offset bytes from the current loaction in the stream. Offset may be both positive and negative. On text streams, offset must be zero.

3. If from in fseek() is SEEK_END, offset bytes from the end of the file. Offset may be both positive or negative. Seeking beyond the ‘EOF’ and writing to the file extends the file while seeking beyond the ‘EOF’ and reading causes ‘EOF’ indication to be returned.

On binary streams, seeking from SEEK_END may not be supported and therefore should be avoided.

There are three side-effects of changing streams’ position with fseek(). Firstly, it clears ‘EOF’ indication; secondly, the character that is returned on the stream using ungetc() prior to fseek() is forgotten because after the seek it’s no longer the next character. And thirdly, seeking let’s you switch from reading to writing and back on the stream opened for update. Let’s consider a simple C program that uses ftell() and fseek() functions. We write below, just relevent code,

 /* open text file in update mode */
    text_in_out = fopen("tf_name", "a+");
    if (text_in_out == NULL) {
        perror("File Open");
        exit(EXIT_FAILURE);
    }
 
    /* write floats to text file named "tf_name" */
    for (i = 0; i < SIZE; i++)
        fprintf(text_in_out, "%f\n", fvalues[i]);
 
    /* let's check current position in text file */
    current = ftell(text_in_out);
    printf("Next read or write will occur at offset:%ld from the "
           "beginning.\n", current);
 
    /* call fseek() to set to read from beginning */
    fseek(text_in_out, -current, SEEK_END);
 
    /* changed position in text file */
    changed = ftell(text_in_out);
    printf("Next read or write will occur at offset:%ld from the "
           "beginning.\n", changed);
 
    /* before attempt to read from the file, flush text_in_out stream */
    fflush(text_in_out);
 
    /* perform reading from the file */
    /* attempt to read floating values form the file back to program */
    printf("\nfloat values:\n");
    for (i = 0; i < SIZE; i++) {
        fscanf(text_in_out, "%f", &fval);
        printf("%f\n", fval);
    }

Notice that in the above program, we write floats to a file then set position to beginning in the file using ftell() and fseek() and read floats back to the program.

advertisement

Sanfoundry Global Education & Learning Series – 1000 C Tutorials.

If you wish to look at all C Tutorials, go to C Tutorials.

advertisement
advertisement
Subscribe to our Newsletters (Subject-wise). Participate in the Sanfoundry Certification contest to get free Certificate of Merit. Join our social networks below and stay updated with latest contests, videos, internships and jobs!

Youtube | Telegram | LinkedIn | Instagram | Facebook | Twitter | Pinterest
Manish Bhojasia - Founder & CTO at Sanfoundry
Manish Bhojasia, a technology veteran with 20+ years @ Cisco & Wipro, is Founder and CTO at Sanfoundry. He lives in Bangalore, and focuses on development of Linux Kernel, SAN Technologies, Advanced C, Data Structures & Alogrithms. Stay connected with him at LinkedIn.

Subscribe to his free Masterclasses at Youtube & discussions at Telegram SanfoundryClasses.