The short answer

ftell() reports where you are in a file: it returns the current position as a byte offset from the start. fseek() moves you: it sets the position indicator to a chosen spot, measured from the start, the current point, or the end. So ftell reads the position, while fseek changes it, and together they give C programs random access to files.

The C standard library uses a position indicator to track where the next read or write will happen in a file. The ftell() and fseek() functions let you read and move that indicator, which unlocks random access instead of plain start-to-end reading.

In short, this guide explains what each function does, shows their syntax and a working example, lists the whence constants, compares them in a table, and covers common use cases.

They build on C file handling, so it also helps to know malloc vs calloc for the memory side.

What is ftell()?

Specifically, ftell() returns the current value of the file position indicator for a stream. Indeed, the value is a byte offset measured from the beginning of the file. Its signature is simple:

long ftell(FILE *stream);

So you pass it an open FILE *, and it gives back a long. On success, that is the current offset; on error, it returns -1L. Because ftell only reports the position, it never changes where you are or alters the file. For example, it is handy for remembering a spot or working out a file’s size.

What is fseek()?

By contrast, fseek() moves the file position indicator to a new location. You give it the stream, an offset in bytes, and a whence reference point. Its signature is:

int fseek(FILE *stream, long offset, int whence);

So the offset is added to the position named by whence. As a result, fseek can jump forward, jump backward, or move to an absolute spot. Then it returns 0 on success and a non-zero value on failure. Unlike ftell, fseek actively changes where the next read or write will land.

The whence Constants

Specifically, the third argument to fseek, whence, picks the reference point for the offset. In total, there are three standard constants:

  • SEEK_SET: the offset is measured from the beginning of the file.
  • SEEK_CUR: the offset is measured from the current position.
  • SEEK_END: the offset is measured from the end of the file.

For example, fseek(fp, 0, SEEK_END) jumps to the end, while fseek(fp, 0, SEEK_SET) returns to the start. In fact, that last call is exactly what rewind(fp) does.

Code Example: File Size with fseek and ftell

Infographic of a file byte stream showing fseek reference points SEEK_SET at the start, SEEK_CUR at the current position, and SEEK_END at the end
fseek measures its offset from SEEK_SET, SEEK_CUR, or SEEK_END.

For instance, a classic use pairs both functions to find a file’s size. You seek to the end, ask where you are, then rewind:

#include <stdio.h>

int main() {
    FILE *fp = fopen("data.txt", "rb");
    if (fp == NULL) return 1;

    fseek(fp, 0, SEEK_END);   /* jump to the end of the file */
    long size = ftell(fp);    /* current position = size in bytes */
    rewind(fp);               /* back to the start, like fseek(fp, 0, SEEK_SET) */

    printf("File size: %ld bytes\n", size);
    fclose(fp);
    return 0;
}

Here fseek moves to the end, ftell reads the offset there (which equals the byte count), and rewind sends the indicator back so you can read the file normally.

ftell() vs fseek(): Comparison Table

Comparison infographic listing purpose, parameters, whether the position changes, and common use for ftell versus fseek
ftell() vs fseek() at a glance.
Aspectftell()fseek()
PurposeReports the current positionSets the position
Signaturelong ftell(FILE *stream)int fseek(FILE *stream, long offset, int whence)
ParametersJust the streamStream, offset, and whence
Return valueCurrent offset, or -1L on error0 on success, non-zero on error
Changes position?No (read-only)Yes
whence constantsNot usedSEEK_SET, SEEK_CUR, SEEK_END
DirectionTells you where you areMoves you where you want
Effect on fileNever modifies itLets you reposition to modify
Common useFile size, save a checkpointRandom access, skip, rewind
Often paired withUsed after an fseekUsed before a read or write
Related helperSize = fseek(SEEK_END) then ftellrewind(fp) = fseek(fp, 0, SEEK_SET)
Access typeRead-only queryRead-write positioning

Common Use Cases

As a result, ftell and fseek give files a flexible, random-access toolkit. So here are the cases where they shine.

  • Random access within files: firstly, jump straight to any byte instead of reading from start to end, which is vital for large files.
  • File position management: use ftell to remember a spot or measure size, and fseek to return there later.
  • File modification: seek to a position, then overwrite or update that part without rewriting the whole file.
  • Parsing structured data: in a large CSV or binary record file, seek to the row or record you need, then read just that part.
  • Seekable streams: similarly, let users rewind or skip sections, which improves media and log viewers.
  • Error recovery: mark checkpoints with ftell, then fseek back to the last good point if processing fails.

Frequently Asked Questions

ftell() reports the current position in a file as a byte offset, and it does not change anything. fseek() moves the position indicator to a new location, set by an offset and a whence reference point. So ftell reads the position, while fseek changes it, and together they enable random file access.

They are the three whence constants for fseek. SEEK_SET measures the offset from the start of the file, SEEK_CUR from the current position, and SEEK_END from the end. For example, fseek(fp, 0, SEEK_END) moves to the end, which is useful for finding a file’s size.

First, call fseek(fp, 0, SEEK_END) to move to the end of the file. Then call ftell(fp), which returns the current offset, and that value equals the file size in bytes. Finally, use rewind(fp) or fseek(fp, 0, SEEK_SET) to return to the start before reading.

fseek() returns 0 when it succeeds and a non-zero value when it fails, for instance on a non-seekable stream. By contrast, ftell() returns the current offset as a long, or -1L on error. So you should check these return values before trusting the position.

rewind(fp) simply moves the position back to the start of the file, and it also clears the error indicator. It is basically a shortcut for fseek(fp, 0, SEEK_SET). However, fseek is more general, since it can move to any offset from the start, the current point, or the end.

Wrapping Up

ftell() and fseek() turn plain sequential files into random-access ones. ftell tells you the current byte offset, while fseek moves the indicator using an offset and a whence reference point.

So remember the pair: ftell reads the position, and fseek sets it. With SEEK_SET, SEEK_CUR, and SEEK_END, you can find a file’s size, jump to any record, and recover from errors with ease.

Related reading on DiffStudy:


Whatsapp-color Created with Sketch.

By Arun Kumar

Full Stack Developer with a BE in Computer Science, working with React, Next.js, Node.js, MongoDB, and AI/ML tools. Founder of DiffStudy — built to help CS students ace GATE and university exams, and keep developers up to date across AI, cloud, system design, web development, and every field of computer science. Every article is written from real hands-on experience, not just theory.

Leave a Reply

Your email address will not be published. Required fields are marked *


You cannot copy content of this page