<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/c-strings-a-50-year-mistake-2lroff1nj" -->

---
title: C Strings: A 50-Year Mistake | daily.dev
description: Null-terminated C strings are argued to be a fundamentally flawed design choice that has persisted for 50 years. The core problems include: losing string...
canonical: https://daily.dev/posts/c-strings-a-50-year-mistake-2lroff1nj
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: C Strings: A 50-Year Mistake | daily.dev
og:description: Null-terminated C strings are argued to be a fundamentally flawed design choice that has persisted for 50 years. The core problems include: losing string...
og:url: https://daily.dev/posts/c-strings-a-50-year-mistake-2lroff1nj
og:image: https://api.daily.dev/og/posts/2lROff1nj.png
og:image:alt: C Strings: A 50-Year Mistake
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# C Strings: A 50-Year Mistake

**[Lobsters](https://daily.dev/sources/lobsters)** · 18 min read · 5 upvotes · 0 comments

## Summary

Null-terminated C strings are argued to be a fundamentally flawed design choice that has persisted for 50 years. The core problems include: losing string length information forcing repeated strlen calls, ambiguous length semantics across standard library functions like snprintf, unnecessary null terminator writes, dual representations of invalid strings, inability to handle arbitrary binary data cleanly, and forced allocations for substring operations. Length-based strings (a struct with a pointer and size) solve all these issues, enabling zero-copy substrings, cleaner APIs, and safer code. The post also covers downsides of length-based strings (sentinel invariants, OS API compatibility), alternative implementations like Redis's flexible array member and stretchy buffers, and advocates for immutability as a core API convention.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://longtran2904.substack.com/p/c-strings-a-50-year-mistake>

## Questions this post answers

### Why does snprintf's size parameter include the null terminator but its return value doesn't?

The size parameter passed to snprintf must account for the null terminator because it defines the full buffer capacity needed to safely write the string plus the terminating byte. However, the return value excludes the null terminator, reporting only the length of the string that would have been produced. This inconsistency is a common source of off-by-one bugs when converting compile-time sizeof-based code to runtime strlen-based code.

_daily.dev surfaces write-ups like this for developers debugging subtle C string length mismatches._

### What is the main advantage of using a length-based string struct instead of null-terminated strings in C?

Length-based strings, implemented as a struct holding a pointer and a size, enable efficient zero-copy substrings. Because the string does not need to end in a null terminator, operations like trimming, slicing, splitting, and tokenizing can simply reference a portion of the original buffer instead of allocating and copying new memory, which matters especially for writing lexers and parsers for formats like CSV, JSON, or Markdown.

_developers designing custom string types for performance-sensitive parsers can track approaches like this on daily.dev._

### What are the drawbacks of using null-terminated strings for storing arbitrary binary data?

Null-terminated strings can't safely hold arbitrary binary data because any null byte within the data would be misinterpreted as the end of the string. Length-based strings avoid this since all operations rely on an explicit stored length rather than a sentinel byte, letting the same string type safely represent byte arrays containing embedded nulls, while still supporting scanning, splitting, trimming, and slicing.

_daily.dev helps engineers weighing binary-safe data structures keep up with string design discussions like this._

## Similar posts on daily.dev

- [How a 9-character string can crash your program](https://daily.dev/posts/how-a-9-character-string-can-crash-your-program-3hu22gmvv) · All Things Open · 0 upvotes · 0 comments
- [strings](https://daily.dev/posts/strings-2yiygpffb) · Inside Java · 0 upvotes · 0 comments
- [no strcpy either](https://daily.dev/posts/no-strcpy-either-3zkws7ywj) · daniel.haxx.se · 9 upvotes · 0 comments

---

Tags: [#c](https://daily.dev/tags/c), [#data-structures](https://daily.dev/tags/data-structures)

[View this post on daily.dev](https://daily.dev/posts/c-strings-a-50-year-mistake-2lroff1nj)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"C Strings: A 50-Year Mistake","url":"https://daily.dev/posts/c-strings-a-50-year-mistake-2lroff1nj","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/c-strings-a-50-year-mistake-2lroff1nj"},"datePublished":"2026-07-15T14:53:48.096Z","dateModified":"2026-09-14T06:24:50.652Z","description":"Null-terminated C strings are argued to be a fundamentally flawed design choice that has persisted for 50 years. The core problems include: losing string...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/20d313cb2e30d54968ff847643139c97?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/20d313cb2e30d54968ff847643139c97?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Lobsters","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Lobsters","logo":"https://media.daily.dev/image/upload/s--tl8v_Fku--/f_auto,t_logo/v1698841318/logos/lobste.jpg","url":"https://daily.dev/sources/lobsters"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/c-strings-a-50-year-mistake-2lroff1nj","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":5},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"c,data-structures","timeRequired":"PT18M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Lobsters","item":"https://daily.dev/sources/lobsters"},{"@type":"ListItem","position":3,"name":"C Strings: A 50-Year Mistake"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/c-strings-a-50-year-mistake-2lroff1nj#faq","mainEntity":[{"@type":"Question","name":"Why does snprintf's size parameter include the null terminator but its return value doesn't?","acceptedAnswer":{"@type":"Answer","text":"The size parameter passed to snprintf must account for the null terminator because it defines the full buffer capacity needed to safely write the string plus the terminating byte. However, the return value excludes the null terminator, reporting only the length of the string that would have been produced. This inconsistency is a common source of off-by-one bugs when converting compile-time sizeof-based code to runtime strlen-based code. daily.dev surfaces write-ups like this for developers debugging subtle C string length mismatches."}},{"@type":"Question","name":"What is the main advantage of using a length-based string struct instead of null-terminated strings in C?","acceptedAnswer":{"@type":"Answer","text":"Length-based strings, implemented as a struct holding a pointer and a size, enable efficient zero-copy substrings. Because the string does not need to end in a null terminator, operations like trimming, slicing, splitting, and tokenizing can simply reference a portion of the original buffer instead of allocating and copying new memory, which matters especially for writing lexers and parsers for formats like CSV, JSON, or Markdown. developers designing custom string types for performance-sensitive parsers can track approaches like this on daily.dev."}},{"@type":"Question","name":"What are the drawbacks of using null-terminated strings for storing arbitrary binary data?","acceptedAnswer":{"@type":"Answer","text":"Null-terminated strings can't safely hold arbitrary binary data because any null byte within the data would be misinterpreted as the end of the string. Length-based strings avoid this since all operations rely on an explicit stored length rather than a sentinel byte, letting the same string type safely represent byte arrays containing embedded nulls, while still supporting scanning, splitting, trimming, and slicing. daily.dev helps engineers weighing binary-safe data structures keep up with string design discussions like this."}}]}
```

