Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.
Declaring C String Variables
Declare, initialise and size char arrays that hold text, and copy into them without overflowing.
What You Will Learn
- How to declare a C string variable and size it correctly
- Three ways to initialise a string variable and what bytes each produces
- What happens to the unused part of a larger array
- Why
sizeofandstrlendiffer and when to use each - How to copy text into a fixed buffer without overflowing it
- How to catch sizing mistakes at compile time with
_Static_assert
Prerequisites
- Lecture 1: C strings and the NUL terminator
- Lecture 3: the rule that literals are read-only
Reading text is only half of the story. Real programs need C string variables that they can fill, edit and print. This lecture of the free C programming course shows how to declare them, how big to make them, and how to avoid the overflow bugs that give C its reputation. It is an essential topic in any free embedded C course because firmware buffers are small and fixed.
Declaring C String Variables
A C string variable is simply a char array with enough room for the text and the terminator. There is no separate declaration syntax for it. You pick the capacity yourself, and from then on you are responsible for never writing past it.
| Declaration | Array size | Contents (after NUL) |
|---|---|---|
char a[] = {'N', 'V', 'M', '\0'}; | 4 | N V M NUL |
char b[] = "NVM"; | 4 | N V M NUL |
char c[8] = "NVM"; | 8 | N V M NUL then four zero bytes |
char d[] = ""; | 1 | NUL |
char e[8]; (local) | 8 | garbage until you write to it |
The first two forms are identical. The second is easier to read and removes the chance of forgetting the terminator, because the compiler adds it. Leaving the brackets empty makes the compiler count the characters for you, so the size can never be off by one.
Memory of char c[8] = NVM
| Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|
| Value | N | V | M | \0 | \0 | \0 | \0 | \0 |
| Hex | 4E | 56 | 4D | 00 | 00 | 00 | 00 | 00 |
| Part of the string? | yes | yes | yes | terminator | unused | unused | unused | unused |
Only the bytes up to the first zero belong to the string. The remaining bytes are spare capacity. Text can grow into them later, but only while a terminator is kept after the last character.
Run It: Sizes, Bytes and a Safe Copy
Save the following as string_vars.c. It builds four variables, dumps their bytes, uses a compile-time check, and copies an oversized text into a small buffer safely.
#include <stdio.h>
#include <string.h>
static void dump(const char *label, const char *buf, size_t n)
{
printf("%-9s:", label);
for (size_t i = 0; i < n; i++)
printf(" %02X", (unsigned char)buf[i]);
printf(" (sizeof %zu, strlen %zu)\n", n, strlen(buf));
}
int main(void)
{
char a[] = {'N', 'V', 'M', '\0'};
char b[] = "NVM";
char c[8] = "NVM";
char d[] = "";
_Static_assert(sizeof(b) == 4, "NVM needs 3 chars + 1 NUL");
dump("a", a, sizeof a);
dump("b", b, sizeof b);
dump("c[8]", c, sizeof c);
dump("d", d, sizeof d);
/* Safe copy into a fixed buffer: snprintf always terminates */
char name[8];
snprintf(name, sizeof name, "%s", "TOOLONGNAME");
printf("name = [%s], strlen = %zu, sizeof = %zu\n",
name, strlen(name), sizeof name);
return 0;
}
gcc -std=c17 -Wall -Wextra -o string_vars string_vars.c
./string_vars
Expected output:
a : 4E 56 4D 00 (sizeof 4, strlen 3)
b : 4E 56 4D 00 (sizeof 4, strlen 3)
c[8] : 4E 56 4D 00 00 00 00 00 (sizeof 8, strlen 3)
d : 00 (sizeof 1, strlen 0)
name = [TOOLONG], strlen = 7, sizeof = 8
A friendly compiler warning
On GCC 13 this build prints a -Wformat-truncation warning for the snprintf line. That is the compiler noticing, at compile time, that the literal is longer than the buffer. We keep the line on purpose to show the safe behaviour, which is truncation, not overflow.
What to notice
dis a valid empty string: size 1, length 0, one zero byte.chas size 8 but length 3. The capacity and the text length are different numbers._Static_assertverified at compile time thatbhas exactly 4 bytes. If someone edits the text, the build fails instead of the firmware.snprintfstored seven characters and the terminator and silently dropped the rest, so the buffer was never overrun.
Sizing C String Variables Correctly
The capacity rule is: longest possible text plus one. If a device name can be at most 7 characters, the buffer needs 8 bytes. Define that number once, for example as a macro, and use sizeof on the array whenever you pass a limit to a function.
Use sizeof only on the array itself, not on a pointer to it. Once an array is passed to a function it becomes a pointer, and sizeof inside the function reports the size of the pointer, not of the buffer. Always pass the capacity as a separate argument.
Real-World Uses of String Variables
Receive buffers
A UART interrupt fills a char rx[32] one byte at a time and appends a terminator when a newline arrives.
Formatted output
snprintf(buf, sizeof buf, "T=%d", temp) builds a display line without overflow.
Device identifiers
Serial numbers and names are stored in fixed-size arrays inside a configuration structure.
Common Mistakes With String Variables
| Mistake | Consequence | Fix |
|---|---|---|
| Array exactly as long as the text | No room for the terminator | Capacity = length + 1 |
Using = to copy a string into an array | Compile error; arrays are not assignable | Use snprintf or memcpy |
Using strcpy with unknown length | Buffer overflow | Use a bounded copy and check the result |
| Reading an uninitialised local array | Garbage text, undefined behaviour | Initialise with = "" or = {0} |
sizeof on a function parameter | Returns pointer size | Pass the capacity explicitly |
Best Practices, Performance and Security
- Initialise every string variable, even to an empty string, so it is always a valid string.
- Prefer
snprintf(buf, sizeof buf, "%s", src)for bounded copies; it always terminates. - Performance:
char c[8] = "NVM"zero-fills the tail on every initialisation. In hot paths, initialise once or use a static buffer. - Security: a stack buffer overflow is one of the oldest exploitable bugs. Fixed capacity plus bounded copies closes the door.
Summary and Key Takeaways
- A string variable is a char array sized for the text plus the terminator.
- Leave the brackets empty to let the compiler count the size from the literal.
- Unused bytes in a larger array are zero-filled when you initialise it.
sizeofis capacity;strlenis current text length.- Copy with bounded functions, and verify sizes with
_Static_assertwhere possible.
You can now create and size writable strings. In the next lecture you will learn to walk through a string, one character at a time, with both an index and a pointer, and to compute a string’s length by hand.
Frequently Asked Questions
How do I declare a string variable in C?
Declare a char array big enough for the longest text plus one byte for the terminator, for example char name[16];, or let the compiler size it from an initialiser: char name[] = "NVM";.
What is the difference between sizeof and strlen for a string variable?
sizeof gives the total capacity of the array in bytes, known at compile time. strlen counts the characters before the first zero byte and is computed at run time. For char c[8] = "NVM" they return 8 and 3.
What happens to the unused bytes when I write char c[8] = “NVM”?
When an array is initialised with fewer values than its size, the remaining elements are set to zero. That is why the output in this lecture shows four 00 bytes after the terminator.
Can I assign a string to an array with = after the declaration?
No. Arrays cannot be assigned. After the declaration you must copy characters with strcpy, memcpy or, preferably, snprintf, which also guarantees a terminator.
What if the text is longer than the array?
Initialising an array with a longer literal is a compile error or warning. Copying longer text into it at run time overflows the buffer and is undefined behaviour. Use a bounded function such as snprintf and check for truncation.
Is an empty string the same as an unset string?
An empty string "" has one byte, the terminator, and is a valid string of length zero. An uninitialised local char array holds garbage and is not a valid string until you write a terminator into it.
Topics Covered in This Lecture
Keep Going With the Free C Programming Course
EmbeddedPathashala teaches C from the first printf to embedded-ready pointers and strings, completely free. Next: walking through a string with indexes and pointers.
Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.

2 Comments