How to Convert a Zero-Terminated Byte Array to a String in Go

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: When Bytes Are Silent and the String Won't Form



Imagine: you wrote a Go server that receives data from a C library. Or you're parsing a binary protocol where strings are stored in the good old C style — with a terminating null byte (\\0). You try to simply do string(byteArray) and get… garbage. Or, even worse, hidden bugs that will surface a month later in production.



Sound familiar? This question on Stack Overflow has gathered thousands of views for a reason. The problem of converting a zero-terminated byte array to a string is one that trips up even experienced Go developers. In this article, we'll break it down from start to finish: from a simple solution to pitfalls with performance, memory, and Unicode.



If you write Go and work with byte arrays, CGO, or network protocols — this article is for you. Let's go!



What is a Zero-Terminated Byte Array and Why Is It a Problem in Go?



A zero-terminated byte array (or null-terminated string) is an array of bytes whose end is marked by a null byte (0x00). This is a legacy from the C language, where strings are exactly this: an array of char ending with \\0.



In Go, strings are immutable sequences of bytes of arbitrary length. A null byte inside a string is a regular character; it does not signify the end. Therefore, a direct cast string([]byte{104, 101, 108, 108, 111, 0, 119, 111, 114, 108, 100}) will give you the string "hello\\x00world", not "hello".



This is where the main trap lies: if you simply copy the bytes, the null character remains inside the string. This can lead to:

  • Incorrect display in logs and UI
  • Errors during serialization (JSON, XML)
  • Problems with hashing and string comparison
  • Data leaks if the string contains confidential information after the null


Solution #1: The Classic Way with bytes.IndexByte



The simplest and most understandable way is to find the position of the first null byte and truncate the array up to it. The bytes.IndexByte function from the standard library is perfect for this.



package main

import ( "bytes" "fmt")

func zeroTerminatedToString(data []byte) string { // Find the index of the first null byte idx := bytes.IndexByte(data, 0) if idx == -1 { // If there is no null byte — return everything as is return string(data) } // Truncate the array up to the found index return string(data[:idx])}

func main() { // Example: C-string "hello" with a null terminator cArray := []byte{'h', 'e', 'l', 'l', 'o', 0, 'e', 'x', 't', 'r', 'a'} result := zeroTerminatedToString(cArray) fmt.Printf("Result: %q", result) // "hello" fmt.Printf("Length: %d", len(result)) // 5}


This code is fast, easy to read, and covers 80% of scenarios. But there is a nuance: bytes.IndexByte does a full pass through the array until the first null. If the array is huge and the null byte is at the very end — this is an O(n) operation.



When is this solution not suitable?

  • If the array is guaranteed to contain a null byte at the beginning (empty string) — it needs to be handled separately
  • If performance is critical and you call this function millions of times
  • If the data contains multiple null bytes (e.g., an array of C-strings)


Solution #2: Using CGO and C Functions (For the Brave)



If you work directly with C code via CGO, you can call the standard C function strlen. This is elegant but adds a dependency on CGO and the overhead of a function call.



// #include <string.h>import "C"import "unsafe"

func cStringToString(cArray []byte) string { if len(

Blogs

Book Recommendations