Question
I am writing a C program that opens a file, and I need to determine the file's size.
I want to know the size because I plan to read the file's contents into a dynamically allocated character buffer using malloc().
Using a fixed allocation such as the following seems like a poor approach:
char *buffer = malloc(10000 * sizeof(char));
How can I correctly find the size of a file in C before allocating memory for its contents?
Short Answer
By the end of this page, you will understand how to determine a file's size in C, why that matters before calling malloc(), and how to safely read a whole file into memory. You will also see common mistakes, practical patterns, and a complete mini project you can reuse.
Concept
In C, file size is often needed when you want to read an entire file into memory at once. A common beginner pattern is:
- Open the file
- Find its size
- Allocate enough memory with
malloc() - Read the file into the buffer
- Add a null terminator if you want to treat it as a C string
A common way to get the size of a regular file is to move the file position to the end using fseek(), then ask for the current position with ftell(). That position is typically the file size in bytes.
Basic idea:
fseek(file, 0, SEEK_END);
long size = ftell(file);
rewind(file);
Why this matters:
- It helps you allocate the correct amount of memory.
- It avoids hardcoded buffer sizes.
- It reduces the risk of buffer overflows or wasted memory.
- It makes file-reading code more reliable.
Important caveat: this approach works well for regular files, but not all streams behave the same way. For example, pipes, terminals, or some special devices may not support seeking. For normal disk files, it is a standard beginner-friendly solution.
Mental Model
Think of a file like a book with a bookmark.
fseek()moves the bookmark.ftell()tells you where the bookmark currently is.- If you move the bookmark to the end of the book, the bookmark's position tells you how many bytes are in the file.
- Then you move the bookmark back to the beginning and start reading.
So the process is:
- Jump to the end
- Check the position
- Jump back to the start
- Read exactly that many bytes
Syntax and Examples
The classic pattern in C uses fopen(), fseek(), ftell(), and rewind().
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *file = fopen("example.txt", "rb");
if (file == NULL) {
perror("fopen");
return 1;
}
if (fseek(file, 0, SEEK_END) != 0) {
perror("fseek");
fclose(file);
return 1;
}
long size = ftell(file);
if (size < 0) {
perror("ftell");
fclose(file);
return 1;
}
rewind(file);
char *buffer = malloc((size_t)size + 1);
if (buffer == NULL) {
perror();
fclose(file);
;
}
bytes_read = fread(buffer, , ()size, file);
(bytes_read != ()size) {
perror();
(buffer);
fclose(file);
;
}
buffer[size] = ;
(, size);
(, buffer);
(buffer);
fclose(file);
;
}
Step by Step Execution
Consider this file content:
Hi
That file contains 2 bytes if it is exactly H and i, or 3 bytes if it includes a newline. Suppose the file contains Hi only.
Now trace this code:
FILE *file = fopen("example.txt", "rb");
fseek(file, 0, SEEK_END);
long size = ftell(file);
rewind(file);
char *buffer = malloc((size_t)size + 1);
size_t bytes_read = fread(buffer, 1, (size_t)size, file);
buffer[size] = '\0';
Step by step:
-
fopen("example.txt", "rb")- Opens the file for reading.
- The file position starts at the beginning.
-
fseek(file, 0, SEEK_END)- Moves the file position to the end.
-
long size = ftell(file)
Real World Use Cases
Getting a file's size is useful in many practical programs:
-
Loading configuration files
- Read a JSON, text, or INI file into memory before parsing it.
-
Reading templates or static assets
- Server-side programs may load HTML templates or email bodies.
-
Processing small data files
- Import CSV or log files for parsing.
-
Copying file contents
- Allocate a buffer large enough for the whole file.
-
Testing and tooling
- Read fixture files in unit tests.
-
Binary file handling
- Load images, custom formats, or serialized data where exact byte count matters.
This pattern is most appropriate when the file is small enough to fit comfortably in memory. For very large files, developers usually read in chunks instead.
Real Codebase Usage
In real projects, developers usually wrap this logic in a helper function instead of repeating it everywhere.
Common patterns include:
Guard clauses
Return early if something fails:
if (file == NULL) return NULL;
if (fseek(file, 0, SEEK_END) != 0) return NULL;
This keeps code flatter and easier to read.
Validation before allocation
Check that ftell() did not fail before converting to size_t:
long size = ftell(file);
if (size < 0) {
fclose(file);
return NULL;
}
Reading whole files into a reusable utility
Many codebases use a helper like:
char *read_file(const char *path, long *out_size);
That helper can:
Common Mistakes
Here are common beginner mistakes when working with file sizes in C.
1. Forgetting to go back to the start before reading
Broken code:
fseek(file, 0, SEEK_END);
long size = ftell(file);
char *buffer = malloc((size_t)size + 1);
fread(buffer, 1, (size_t)size, file);
Problem:
- The file position is still at the end.
fread()reads zero bytes.
Fix:
rewind(file);
2. Not checking whether ftell() failed
Broken code:
long size = ftell(file);
char *buffer = malloc((size_t)size + 1);
Problem:
ftell()returns-1Lon error.- Converting that to
size_tcan create a huge number.
Fix:
Comparisons
| Approach | How it works | Good for | Limitations |
|---|---|---|---|
fseek() + ftell() | Move to end, ask for current position | Regular files, simple programs | Not suitable for all streams |
| Read in chunks | Repeatedly call fread() into a smaller buffer | Large files, streams, unknown sizes | Slightly more code |
| Fixed-size buffer | Allocate a guessed amount | Quick experiments only | Unsafe and unreliable |
rewind() vs fseek(file, 0, SEEK_SET)
| Function | Purpose |
|---|
Cheat Sheet
FILE *file = fopen("example.txt", "rb");
if (file == NULL) {
// handle error
}
if (fseek(file, 0, SEEK_END) != 0) {
// handle error
}
long size = ftell(file);
if (size < 0) {
// handle error
}
rewind(file);
char *buffer = malloc((size_t)size + 1);
if (buffer == NULL) {
// handle error
}
size_t bytes_read = fread(buffer, 1, (size_t)size, file);
if (bytes_read != (size_t)size) {
// handle error
}
buffer[size] = '\0';
Key rules
- Use
fseek(file, 0, SEEK_END)to move to the end. - Use
ftell(file)to get the position in bytes. - Check if
ftell()returned a negative value. - Use
rewind(file)before reading. - Allocate
size + 1if you need a C string. - Check the return values of , , , , and .
FAQ
How do I get a file's size in C?
A common method is to use fseek(file, 0, SEEK_END), then call ftell(file), and finally return to the beginning with rewind(file).
Why should I not use a fixed malloc(10000) buffer?
Because the file may be larger than 10,000 bytes or much smaller. Fixed guesses are unreliable and can waste memory or cause bugs.
Do I need to add 1 when allocating memory for a file?
Yes, if you want to treat the data as a C string. The extra byte stores the null terminator \0.
What happens if ftell() returns -1?
That means an error occurred. You should not pass that value to malloc().
Can I use this method for binary files?
Yes. The size still represents the number of bytes. But binary data should not automatically be treated as text.
Does this work for every kind of input stream?
No. Some streams, such as pipes or terminals, may not support seeking.
Is sizeof(char) necessary in malloc()?
No. sizeof(char) is always 1, so is enough for a character buffer.
Mini Project
Description
Build a small C program that reads an entire text file into memory and prints both its size and contents. This demonstrates the full workflow of opening a file, measuring it safely, allocating memory dynamically, reading data, and cleaning up resources properly.
Goal
Create a program that loads a file into a dynamically allocated buffer using the file's actual size.
Requirements
- Open a file from a path provided in the code.
- Determine the file size before allocation.
- Allocate enough memory for the file contents plus a null terminator.
- Read the entire file into memory.
- Print the file size and contents, then free the memory and close the file.
Keep learning
Related questions
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.
C Pointer to Array vs Array of Pointers: How to Read Complex Declarations
Learn the difference between pointer-to-array and array-of-pointers in C, plus a simple rule for reading complex declarations correctly.