Dataslope logoDataslope

Strings

C strings, null-termination, string literals, and the `<string.h>` toolkit

A C string is not a type. It is a convention: a contiguous sequence of char ending in a zero byte ('\0'). Every function in <string.h> relies on that single byte to know where the string stops.

Null-terminated character arrays

The character '\0' is the byte 0, not the digit '0' (which is 0x30 in ASCII). Until the runtime finds it, every byte is still "part of the string."

Code Block
C 17 (201710L)

printf("%s", s) walks s starting at the address you pass, printing characters until it hits '\0'. If the terminator is missing, it will happily keep walking into unrelated memory.

String literals

"hello" in C is a string literal — an anonymous array of char with an automatically appended '\0'. The compiler usually places literals in read-only memory.

FormWhat it isMutable?
char s[] = "hi";A copy of the literal in a local arrayyes
char *s = "hi";A pointer to the literal in read-only memoryno — writing through it is UB
const char *s = "hi";The right way to spell the second formn/a

Do not write through a string literal pointer

char *s = "hi"; s[0] = 'H'; compiles but is undefined behavior — on many platforms it crashes because the literal lives in read-only memory. Use const char * for literal pointers, or char s[] = "hi"; when you need to modify the contents.

Code Block
C 17 (201710L)

The <string.h> toolkit

FunctionPurposeNotes
strlen(s)Number of bytes before '\0'O(n)
strcpy(dst, src)Copy null-terminated src to dstNo length check — unsafe
strncpy(dst, src, n)Copy at most n bytesMay not null-terminate; see below
strcat(dst, src)Append src to dstNo length check — unsafe
strcmp(a, b)Compare two stringsnegative / 0 / positive
strncmp(a, b, n)Compare first n bytes
strchr(s, c)First occurrence of cReturns pointer or NULL
strstr(haystack, needle)First occurrence of substring
memcpy(dst, src, n)Copy n bytes (no terminator)Buffers must not overlap
memmove(dst, src, n)Like memcpy but overlap-safe
memset(dst, b, n)Fill n bytes with byte b

The "unsafe" functions are unsafe because they have no way to know how big dst is. You are responsible for that.

Code Block
C 17 (201710L)

The strncpy footgun

strncpy(dst, src, n) looks like a "safer strcpy." It is not.

  1. If src is shorter than n bytes, it pads dst with extra '\0's out to n bytes.
  2. If src is longer than n bytes, it copies exactly n bytes and does not null-terminate dst.

That second case is the bug factory. Many codebases now use snprintf(dst, sizeof dst, "%s", src) or platform-specific strlcpy instead.

Code Block
C 17 (201710L)

Counting your own strlen

Writing string functions by hand is a great way to internalize null-termination.

Code Block
C 17 (201710L)

The idiomatic version uses a moving pointer:

Code Block
C 17 (201710L)

Buffer sizes are the API

Every C string function is part of a contract: "I will read until I find a '\0'," or "I will write at most n bytes." Whenever you write a new function that takes a string, document and enforce the buffer size.

Code Block
C 17 (201710L)

Note the (unsigned char) cast before passing to toupper. The <ctype.h> functions are only defined for non-negative ints, and plain char is signed on some platforms.

Practice: implement strcmp

Challenge
C 17 (201710L)
Implement your own strcmp

Implement int my_strcmp(const char *a, const char *b) that returns a negative value if a < b, zero if equal, and positive if a > b — using byte-wise comparison. The provided main prints <, =, or > for a few pairs.

Practice: reverse a string in place

Challenge
C 17 (201710L)
Reverse a C string in place

Implement void reverse_str(char *s) so that the string s is reversed without using any helper buffer. The provided main calls it on "systems" and prints the result on one line.

Test your understanding

QuestionSelect one

What is the length of the C string literal "hello" in memory (in bytes)?

4 bytes

5 bytes

6 bytes (5 characters + the trailing '\0')

It depends on the encoding; cannot be determined.

QuestionSelect one

Why is the function char *s = "hello"; s[0] = 'H'; dangerous?

It overflows the buffer.

It always crashes the program in a controlled way.

String literals may live in read-only memory; writing through a non-const pointer to a literal is undefined behavior.

It corrupts the system clock.

QuestionSelect one

Which is the safest way to copy a string into a fixed-size buffer?

strcpy(dst, src);

strncpy(dst, src, sizeof dst);

snprintf(dst, sizeof dst, "%s", src);

memcpy(dst, src, strlen(src));

On this page