Bug: Initial allocation not cleared to zero

Your initial allocation of sb->mem uses malloc instead of calloc, so its contents are uninitialized. If you then append a few characters and call sb_as_string(), you will get back a string that is not properly terminated. You should use calloc instead.

Minor bug

If your call to realloc fails, your buffer will be incorrect because it will no longer be null terminated (you just appended a character to the last spot). You should either rewrite a '\0' to the end of the buffer if realloc fails, or do the realloc before you append the character.

Argument check

When creating a string buffer, you should handle the case where init_cap is passed in as 0. You can set it to some default value in that case. Right now, an initial capacity of 0 will cause a crash down the line because your append function will append to a zero length buffer without ever reallocating.

Usability

I would much prefer an append function that took a string argument instead of a character argument. I'm not sure that I would ever need to append one character at a time.

Also, it might be nice to have a to_string type function that returns the string but also frees the stringbuilder. The way you currently have it, you can retrieve the string, but if you subsequently free the stringbuilder it will also free the string you just retrieved. That makes it difficult to use the string because its lifetime is tied to the lifetime of the stringbuilder.

Answer from JS1 on Stack Exchange
🌐
GitHub
github.com › cavaliercoder › c-stringbuilder
GitHub - cavaliercoder/c-stringbuilder: A simple StringBuilder in C · GitHub
A simple StringBuilder in C. Contribute to cavaliercoder/c-stringbuilder development by creating an account on GitHub.
Starred by 18 users
Forked by 2 users
Languages   C 93.2% | Makefile 6.8%
🌐
Reddit
reddit.com › r/c_programming › string builders in c
r/C_Programming on Reddit: String builders in C
June 3, 2023 -

I've written a bunch of code that prints values of various different types which works great but rather than printing to stdout I'd like to capture the result in a big string. In other languages this would be achieved by appending to a string builder or appending strings to an array and then concatenating them all. Is there an idiomatic way to do this in vanilla C? If not, what library would you recommend (M1/M2 Mac OS and Raspberry Pi)?

🌐
Microsoft Learn
learn.microsoft.com › en-us › dotnet › api › system.text.stringbuilder
StringBuilder Class (System.Text) | Microsoft Learn
Mutability means that once an instance of the class has been created, it can be modified by appending, removing, replacing, or inserting characters. ... Although the StringBuilder class generally offers better performance than the String class, you should not automatically replace String with ...
🌐
GitHub
github.com › YeGoRenji › C_StringBuilder
GitHub - YeGoRenji/C_StringBuilder: This is a simple stringbuilder for C
This is a simple implementation of a String Builder in C, designed to provide efficient string manipulation capabilities compared to using normal strings in C.
Author   YeGoRenji
🌐
Chilkat
chilkatsoft.com › refdoc › c_CkStringBuilderRef.html
StringBuilder C Reference Documentation
Loads the contents of a file. Returns TRUE for success, FALSE for failure. ... Load utf-8 Text File into a StringBuilderLoad Text File to String using any Code PageConvert a Text File from utf-8 to Windows-1252 top
🌐
Lua Ternary
nachtimwald.com › posts › efficient c string builder
Efficient C String Builder | John's Blog
February 27, 2017 - * * return str builder. */ str_builder_t *str_builder_create(void); /*! Destroy a str builder. * * param[in,out] sb Builder. */ void str_builder_destroy(str_builder_t *sb); /* - - - - */ /*! Add a string to the builder. * * param[in,out] sb Builder. * param[in] str String to add.
Top answer
1 of 3
7

Bug: Initial allocation not cleared to zero

Your initial allocation of sb->mem uses malloc instead of calloc, so its contents are uninitialized. If you then append a few characters and call sb_as_string(), you will get back a string that is not properly terminated. You should use calloc instead.

Minor bug

If your call to realloc fails, your buffer will be incorrect because it will no longer be null terminated (you just appended a character to the last spot). You should either rewrite a '\0' to the end of the buffer if realloc fails, or do the realloc before you append the character.

Argument check

When creating a string buffer, you should handle the case where init_cap is passed in as 0. You can set it to some default value in that case. Right now, an initial capacity of 0 will cause a crash down the line because your append function will append to a zero length buffer without ever reallocating.

Usability

I would much prefer an append function that took a string argument instead of a character argument. I'm not sure that I would ever need to append one character at a time.

Also, it might be nice to have a to_string type function that returns the string but also frees the stringbuilder. The way you currently have it, you can retrieve the string, but if you subsequently free the stringbuilder it will also free the string you just retrieved. That makes it difficult to use the string because its lifetime is tied to the lifetime of the stringbuilder.

2 of 3
3

To be more comprehensive, the line in sb_append():

memset(new_mem + to->cap, 0, to->cap);

should become:

memset(new_mem + to->cap, 0, (to->cap) * (LOAD_FACTOR - 1));

That matters when LOAD_FACTOR is set to something greater than 2.

thanks for sharing this code.

🌐
GitHub
github.com › draffensperger › golp › blob › master › stringbuilder.c
golp/stringbuilder.c at master · draffensperger/golp
* Stringbuilder - a library for working with C strings that can grow dynamically as they are appended
Author   draffensperger
Find elsewhere
🌐
GeeksforGeeks
geeksforgeeks.org › c# › stringbuilder-in-c-sharp
C# StringBuilder - GeeksforGeeks
November 17, 2025 - StringBuilder is a dynamic object used to handle mutable strings in C#. Unlike the immutable String class which creates a new object after every modification, StringBuilder updates the existing buffer and expands its memory as needed.
🌐
Tutorial Teacher
tutorialsteacher.com › csharp › csharp-stringbuilder
C# StringBuilder
This article explains stringbuilder in C#. StringBuilder is a dynamic object that allows you to expand the number of characters in the string. It doesn't create a new object in the memory but dynamically expands memory to accommodate the modified ...
🌐
Medium
engcfraposo.medium.com › exploring-stringbuilder-variables-in-c-basic-and-advanced-concepts-ec444f24db52
Exploring StringBuilder Variables in C#: Basic and Advanced Concepts | by Cláudio Rapôso | Medium
November 10, 2023 - String variables in C# are immutable, which means that when you modify a string, you’re actually creating a new string from the original. This can be inefficient when working with large amounts of text. This is where StringBuilder comes into play.
🌐
C# Corner
c-sharpcorner.com › article › stringbuilder-and-string-concatenation
StringBuilder and String Concatenation
February 9, 2023 - Append methods append a string or an object to an existing StringBuilder string. The space is allocated dynamically and expands when new strings are added to the StringBuilder. The following code snippet creates a StringBuilder and appends a string.
🌐
IronPDF
ironpdf.com › ironpdf blog › .net help › string builder c#
String Builder C# (How It Works For Developers)
April 22, 2026 - The StringBuilder class, which resides in the System.Text namespace, is a crucial tool for optimizing string manipulations in C#. It distinguishes itself from the traditional string class by being mutable, enabling dynamic modifications without ...
Top answer
1 of 13
117

A string instance is immutable. You cannot change it after it was created. Any operation that appears to change the string instead returns a new instance:

string foo = "Foo";
// returns a new string instance instead of changing the old one
string bar = foo.Replace('o', 'a');
string baz = foo + "bar"; // ditto here

Immutable objects have some nice properties, such as they can be used across threads without fearing synchronization problems or that you can simply hand out your private backing fields directly without fearing that someone changes objects they shouldn't be changing (see arrays or mutable lists, which often need to be copied before returning them if that's not desired). But when used carelessly they may create severe performance problems (as nearly anything – if you need an example from a language that prides itself on speed of execution then look at C's string manipulation functions).

When you need a mutable string, such as one you're contructing piece-wise or where you change lots of things, then you'll need a StringBuilder which is a buffer of characters that can be changed. This has, for the most part, performance implications. If you want a mutable string and instead do it with a normal string instance, then you'll end up with creating and destroying lots of objects unnecessarily, whereas a StringBuilder instance itself will change, negating the need for many new objects.

Simple example: The following will make many programmers cringe with pain:

string s = string.Empty;
for (i = 0; i < 1000; i++) {
  s += i.ToString() + " ";
}

You'll end up creating 2001 strings here, 2000 of which are thrown away. The same example using StringBuilder:

StringBuilder sb = new StringBuilder();
for (i = 0; i < 1000; i++) {
  sb.Append(i);
  sb.Append(' ');
}

This should place much less stress on the memory allocator :-)

It should be noted however, that the C# compiler is reasonably smart when it comes to strings. For example, the following line

string foo = "abc" + "def" + "efg" + "hij";

will be joined by the compiler, leaving only a single string at runtime. Similarly, lines such as

string foo = a + b + c + d + e + f;

will be rewritten to

string foo = string.Concat(a, b, c, d, e, f);

so you don't have to pay for five nonsensical concatenations which would be the naïve way of handling that. This won't save you in loops as above (unless the compiler unrolls the loop but I think only the JIT may actually do so and better don't bet on that).

2 of 13
14

String vs. StringBuilder

  • String

    • Under System namespace

    • Immutable (readonly) instance

    • Performance degrades when continuous change of value occurs

    • Thread-safe

  • StringBuilder (mutable string)

    1. Under System.Text namespace
    2. Mutable instance
    3. Shows better performance since new changes are made to an existing instance

For a descriptive article about this topic with a lot of examples using ObjectIDGenerator, follow this link.

Related Stack Overflow question: Mutability of string when string doesn't change in C#

🌐
C# Corner
c-sharpcorner.com › UploadFile › puranindia › Csharp-stringbuilder
C# StringBuilder Tutorial With Code Examples
February 10, 2023 - C# StringBuilder is useful for concatenating multiple strings. The code examples demonstrate how to use a StringBuilder in C#.
🌐
CodeGuru
codeguru.com › home › c#
Manipulating C# Strings with StringBuilder | CodeGuru.com
July 21, 2022 - In this C# programming tutorial, we will talk about the C# StringBuilder class, its methods, and properties. StringBuilder is a class in C# that you may use to perform repetitive operations on a string. Interested in learning C# in a classroom ...
🌐
LinkedIn
linkedin.com › pulse › string-vs-stringbuilder-performance-cnet-explained-andre-baltieri-5qeff
String vs StringBuilder: Performance in C#/.NET Explained
April 30, 2026 - This can result in a significant performance hit, especially when working with large loops or frequent concatenation operations. Enter StringBuilder, a mutable class designed for situations where frequent string modifications are required.