This project has been created as part of the 42 curriculum by damorim-.
get_next_line is a 42 School project that consists of writing a function
able to read a text file (or any file descriptor, including standard input
or a socket) and return it one line at a time, on each call, without
knowing in advance the size of the line or the file.
The goal of the project is to understand and practise:
- Static variables, to keep data alive between successive calls to the same function.
- Reading in fixed-size chunks, since a file cannot be read all at once in a real-world / memory-constrained scenario.
- Manual memory management in C (
malloc/free), avoiding leaks while building and shrinking dynamically-sized buffers.
The project exposes a single public function:
char *get_next_line(int fd);Each call returns the next line read from the file descriptor fd,
including the trailing \n if there is one, or NULL when there is
nothing left to read (end of file) or an error occurs.
The project is built with the provided Makefile, which compiles the
sources and archives them into a static library.
make # builds get_next_line (static library)
make clean # removes object files
make fclean # removes object files AND the compiled library
make re # fclean + allThe read buffer size is controlled at compile time through the
BUFFER_SIZE macro, defined in the Makefile (default: 42). It can be
overridden at build time, for example:
make CFLAGS="-Wall -Werror -Wextra -D BUFFER_SIZE=1"To use get_next_line in your own project:
- Copy
get_next_line.c,get_next_line_utils.c, andget_next_line.hinto your project. - Include the header and call the function in a loop until it returns
NULL:
#include "get_next_line.h"
#include <fcntl.h>
#include <stdio.h>
int main(void)
{
int fd;
char *line;
fd = open("some_file.txt", O_RDONLY);
if (fd < 0)
return (1);
while ((line = get_next_line(fd)) != NULL)
{
printf("%s", line);
free(line);
}
close(fd);
return (0);
}cc -Wall -Wextra -Werror -D BUFFER_SIZE=42 main.c get_next_line.c get_next_line_utils.c -o gnl_test
./gnl_testThere is no bundled test suite in this repository. Manual testing was done
by reading files of various sizes (empty files, files with and without a
trailing newline, files larger than BUFFER_SIZE) with several
BUFFER_SIZE values (1, 42, large values), and by reading from
multiple file descriptors in the same run to check that the static state
does not leak between them.
The core design decision of get_next_line is how to remember, between
two separate calls, the part of the file that was already read from disk
but not yet returned to the caller. The chosen approach is:
-
A
static char *stashbuffer. Because a static variable keeps its value across function calls and is scoped to the function (here shared by all calls for all file descriptors, since the subject's mandatory part only requires a singlefdto work correctly at a time), it is used to accumulate everything read fromfdthat hasn't been handed back to the caller yet. This avoids any global variable while still giving the "memory" needed between calls. -
Chunked reading with
read()into a fixedBUFFER_SIZEbuffer.fill_stashcallsreadrepeatedly,BUFFER_SIZEbytes at a time, and appends each chunk to the stash withft_strjoin, until either a\nis found in the stash orreadreturns0/-1(end of file or error). Reading in fixed chunks — rather than the whole file at once — is the whole point of the exercise: it keeps memory usage bounded regardless of file size and mirrors howread()is meant to be used on any file descriptor, including non-seekable ones like pipes or sockets. -
Three cooperating helper functions, one responsibility each:
fill_stash— grows the stash until it contains at least one full line (or the file is exhausted).extract_line— scans the stash and allocates/returns a fresh copy of just the first line (up to and including\n), leaving the stash itself untouched.next_stash— rebuilds the stash without the line that was just extracted, freeing the old buffer, so the next call starts exactly where this one left off.
Splitting the algorithm this way keeps each function under the 42 norm's line-count limit and makes it possible to reason about, and test, each step independently.
-
ft_strjoinreimplementation. A localft_strjoin(distinct from thelibftone) is used to concatenate the existing stash with each new chunk read from the file, freeing the old stash automatically. This keepsget_next_line.cself-contained and avoids alibftdependency for a project that is meant to be usable as a small, standalone unit. -
Time and space complexity. Each byte of the file is read exactly once and copied a bounded number of times (once into the stash, once when a line is extracted, once when the remainder is shifted into the next stash), giving overall O(n) time in the size of the file. Memory usage at any point in time is proportional to the length of the longest line encountered, not the size of the whole file.
Classic references used while working on the topic:
read(2)— Linux man page — reference forread()'s behaviour, return values, and short reads.open(2)— Linux man page — reference for opening files and file descriptor basics.- C Standard, static storage duration — cppreference — documentation on how
staticlocal variables retain their value across calls. - GeeksforGeeks.
- Youtube.
An AI assistant (Claude) was used strictly as a documentation and review aid, not to write or debug the C implementation itself:
- Drafting and structuring this
README.md(Description, Instructions, Technical Choices, and Resources sections) from the existing source code and Makefile. - Explaining, in the "Technical Choices" section above, the reasoning
behind design decisions (the
staticstash buffer, chunked reading, the split betweenfill_stash/extract_line/next_stash) that were already implemented in the code, so they could be documented clearly and accurately. - Testing.
All get_next_line logic — the static-state management, the buffered
reading loop, and the line-extraction logic — was designed, written, and
debugged manually, in line with the 42 evaluation requirement that the
code itself reflects the student's own understanding.