An Attempt at a C Standard Library

by Subhomoy Haldar

Making my own tools from scratch. Part 1: Strings

Introduction - The Lay of the Land

C has been the language of choice for me whenever I need to immerse myself in a mindful state and aim to write some good code. The main weakness of this language is again its greatest strength: its small footprint. The C language is small - in terms of both the language and the library. This is because back in the 1970s, it was tedious to write programs in assembly. Less code is better in situations where time is valuable and implementation is difficult.

That’s good news when you’re focussing on portability, that is supporting your language or program on different operating systems, architectures, and hardware. Unfortunately, the experience seems incomplete when you want to develop an actual program in C. There are not enough tools at your disposal to make applications quickly. This is the reason C falls out of favour nowadays: there is a paucity of sufficient built-in support. You can’t avail sufficient safety checks and are all alone when you try to establish something even remotely resembling an architecture in a metaphorical desert.

This lack of support does not deter the determined and seasoned developers though. They are like lone venturers seeking adventure in the land where great challenges lie ahead. They set up camps, weather the storms, face ferocious foes and help fellow travellers in need by acting as a guide through the challenging terrain. It is because of selfless people like these that innovations in software came about. Hackers (in the true sense of the word) find solutions by rephrasing questions, finding new angles and opening a world of new possibilities.

Two people on a hike with a scenic mountainside in the background
➣ Adventurers heading out - Photo by Nathan Dumlao on Unsplash

Now it begs the question: how do these adventurers power through their journey? I’ll make use of another analogy: blacksmithing. The people of this noble profession nurture a beautiful way of thinking. “If I need a tool and I don’t have it, I’ll make one!” This idea of making your tools from scratch seamlessly carries over to C programming. The tiny standard library is almost an invitation to the ambitious developer to have a crack at it. That’s exactly what I did.

The first tool - Strings for storing

It won’t be very convenient if our program can’t interact with the user or read and write information. This information is usually a stream or sequence of characters and that is why we need strings. The default way to deal with strings in C is to use a simple array of characters. And a valid string has a null character at the end to mark its end. This structure leads to a lot of errors and rather inefficient algorithms for string processing. So I made a string data type. I wrote the code while watching nybbles.io’s first video in the CKong series$^1$. So it shouldn’t be a surprise that it is almost identical to his implementation. Kudos to him!

My string implementation is length-prefixed, i.e. it includes the length first. Because of this, a lot of basic string operations are simplified by removing the need to check for the terminating null character completely. The source code is over at GitHub and can be used freely $^{2}$. Heres how to use the code.

Usage

Quick Notes

  1. A general rule of thumb for C Programming is to always pair an allocation with a de-allocation. The same goes for opening and closing files and streams. Therefore, it is necessary to free a string after it has fulfilled its purpose.
  2. Most of the methods make use of string pointers. 

Necessities

I recommend copying the entire standard library to the source directory. This is bacause the string library makes use of the panic library to report errors and gracefully finish execution.

Initialization

string_t *strA = convert_string("This is an example!");
string_t *strB = new_string(10);    // empty string of length 10
string_t *strC = copy_string(strA); // a deep copy/clone of strA

Deallocation

free_string(strA);
free_string(strB);
free_string(strC);

Extracting data

string_t *str; // We assume that it is initialized
size_t len = str->len;
char *raw_str = (char*) str->data;

Printing a string

string_t str;       // We assume that it is initialized
print_string(str);  // Outputs to stdout by default
fprintf_string(str, file_ptr);

String manipulation

string_t *source = convert_string("bandana");
string_t *band = left_string(source, 4);    // The 4 left characters
string_t *and1 = right_string(band, 3);     // The 3 right characters
string_t *and2 = substring(source, 1, 4);   // 1 inclusive, 4 exclusive

Other stuff

These are some functions I have implemented. More are on the way. I'll be adding functions as I need them. I'll also be adding proper documentation in the header files.

Conclusion

I hope that my attempt at this task inspires fellow developers to forget the stigma that reinventing the wheel is unacceptable. You should avoid it when you're short on time and have a massive team to work with, minimising the friction. However, it is essential when you intend to learn new things and are preferably going it alone. It'd also be great if others use my library and help me find the bugs if any.


  1. nybbles.io's first video in the CKong playlist: Introduction
  2. Source code for the string library: String by HungryBlueDev on GitHub.