SITERAW

Strings in C

A string is just the proper programming term for... plain old text, really. A string is essentially a piece of text that you can store in memory using a variable. For instance, you could save a user's name.

As we mentioned earlier, a computer can only store numbers. Letters aren't part of the deal. So how on earth do programmers manage to work with text? Well, they're a clever bunch, as you'll see.

The char type

In this chapter, we're going to focus on the char type. If you recall, char lets us store numbers between -128 and 127 (or from 0 to 255 if you use unsigned).

Even though char can hold numbers, in C it's not really used for that. Generally, even for small numbers, we use int or long instead. Sure, they take up a bit more memory, but let's be honest — modern computers aren't exactly starving for RAM. You're not going to blow up your PC just because you're using int or long instead of char ;)

The char type was actually made to hold... a single letter! Yep, just one letter.

Since memory only understands numbers, we came up with a table that translates numbers into letters and vice versa. This table tells the computer, for example, that the number 80 stands for the letter P.

This should sound familiar — it's the same example we used in the chapter about pointers, when talking about Pokémon statuses.

The C language makes it super easy to go from a letter to its numeric equivalent. Just wrap the letter in single quotes, like 'A'. When you compile, 'A' gets replaced with its corresponding value (which is 65).

Let's try it out:

int main(int argc, char *argv[])
{
    char letter = 'A';

printf("%d\n", letter);

return 0; }

Output:

65

So now we know that the uppercase letter A is represented by the number 65. B is 66, C is 67, and so on. Try it with lowercase letters, and you'll see the values are different. That's because 'a' is not the same as 'A' — computers do differentiate between uppercase and lowercase. The letter 'a' is 97. Kind of weird that lowercase letters come after uppercase ones in the table, but hey, don't ask me why ^^

Most basic characters are encoded with values from 0 to 127.

Displaying a character

Our good old printf function, which just keeps surprising us, can also be used to display a single character. If you remember, we actually used this trick back in the pointer chapter at the start of part three.

To do it, we use %c (c for character):

int main(int argc, char *argv[])
{
    char letter = 'A';

printf("%c\n", letter);

return 0; }

Output:

A

Hooray! We can now display a letter :D

By the way, whether you write 'A' or 65, the compiler treats them the same. Here's proof:

int main(int argc, char *argv[])
{
    char letter_1 = 'A';
    char letter_2 = 65;

printf("%d = %c = %c = %d\n", letter_1, letter_1, letter_2, letter_2);

return 0; }

Output:

65 = A = A = 65

You can also ask the user to input a letter using %c in a scanf:

int main(int argc, char *argv[])
{
    char letter = 0;

scanf("%c", &letter); printf("%c\n", letter);

return 0; }

If I type the letter B, the result will be: B. However, keep in mind that if you type something like 6, only the first character — 6 — will be registered as input.

And that's pretty much everything you need to know about the char type. Sneaky little guy, huh? ;)

Key takeaways:

  • The char type stores numbers from -128 to 127, and unsigned char from 0 to 255.
  • There's a lookup table your computer uses to convert letters to numbers and back.
  • So, you can use char to store a single letter.
  • 'A' gets replaced at compile time by its corresponding number (65 in this case). Use single quotes to get the numeric value of a letter.

Strings Are Just Arrays of char!

Argh, I went and spoiled it right in the title — what else am I supposed to say now?

That's pretty much the whole story: a string is nothing more than an array of char. Just a plain old array, nothing fancy.

If we create an array like this:

char string[5];

...and then store the letter 'H' in string[0], 'e' in string[1], and so on... we can piece together a string of characters — that is, readable text :)

Here's an explanation of how this might be stored in memory. As you'd imagine, it's an array that takes up 5 memory slots to store the word "Hello" right? Nothing more?

C is actually very easy, right? WRONG!

A string must end with a special character called the null-terminator, written as '\0'.

Why does a string need to end with \0?

So the computer knows where it stops! The \0 character is like a little sign that says: "End of the line, nothing to see past this point!"

So, to store the word "Hello" (which is 5 letters), you don't need an array of 5 chars — you need an array of 6 chars. If you try and store it in a 5 chars array I will come out of the Internets and kick your ass. Don't do it!

Every time you create a string, you must remember to make room for the null-terminator. Always, always, always add an extra slot in your array to hold that final \0. It's absolutely essential. Forgetting to include \0 is one of the classic traps in C. Any function that reads the string one character at a time... how's it supposed to know when to stop? This kind of mistake can lead to memory issues, crashes, or worse.

Here's how the string "Hello" is properly stored in memory:

AddressValue
5000'H'
5001'e'
5002'l'
5003'l'
5004'o'
5005'\0'

As you can see, the string takes six characters, not five. Gotta get used to that ;) It ends with '\0', which tells the computer: "This is where the string ends."

You can actually think of \0 as a feature. Thanks to it, you don't have to remember the size of your array — it tells the computer where to stop reading :) You can pass a char array to a function without also sending a separate variable to indicate its size.

Just keep in mind: this only applies to strings (i.e., char* or char[]). For all other array types, you still need to track the size yourself.

Creating and Reading Strings

Creating and initializing a string

If you want to initialize a string with the text "Hello," you can go the old-school brute force route:

char string[6]; // Array of 6 chars to hold H-e-l-l-o + the \0

string[0] = 'H'; string[1] = 'e'; string[2] = 'l'; string[3] = 'l'; string[4] = 'o'; string[5] = '\0';

That totally works! And we can prove it with a little printf.

Oh right, I almost forgot — printf has yet another format symbol to remember ^^ This time it's %s (s for string).

Here's the full code to create a "Hello" string in memory and print it:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) { char string[6]; // Array of 6 chars to hold H-e-l-l-o + \0

// Manually writing each character into memory string[0] = 'H'; string[1] = 'e'; string[2] = 'l'; string[3] = 'l'; string[4] = 'o'; string[5] = '\0';

// Displaying the string using printf and %s printf("%s", string);

return 0; }

Output:

Hello

Phew ^^ All that just to store and print "Hello" from memory :D

Writing out every character one by one is a bit tiring, to be honest.

Luckily, there's a much simpler way to initialize a string:

int main(int argc, char *argv[])
{
    char string[] = "Hello"; // Array size is automatically calculated

printf("%s", string);

return 0; }

Output:

Hello

As you can see, I'm creating a char[] variable. I could've written char* instead — the result would be the same.

By putting the string in double quotes, the compiler automatically figures out the size it needs. It counts the letters and adds 1 for the \0. It then writes each character (plus the \0) into memory for you — exactly like we did manually earlier. Super handy :)

Couldn't you have just told us that from the beginning instead of making us type every letter by hand AND throw in that weird \0 thing???

Lol.

Well, there's a (tiny) catch: this trick only works at initialization! You can't use it later in the code like this:

string = "Hello";

So this technique is just for the initial setup. After that, if you want to modify the string, you'll have to go old-school and update it character by character ;)

Getting a string from the user with scanf

You can also get a string input from the user using scanf and, once again, the %s symbol.

There's just one problem: you don't know how many characters the user's going to type. Maybe their name is Joe (3 letters), or maybe it's Sir Henry-Bryson the IVth (a lot more letters).

There's no magic fix here. You'll have to create a char array big enough to handle any likely input. For example, we can create a char[100] to store a name. Sure, it might feel like you're wasting memory, but remember — memory is the least of your worries these days (and believe me, there are programs out there wasting way more than this :D)

int main(int argc, char *argv[])
{
    char name[100];

printf("What's your name, young Noob? "); scanf("%s", name); printf("Hi %s! Stay safe out there on this site.", name);

return 0; }

Output:

What's your name, young Noob? B-tch
Hi B-tch! Stay safe out there on this site.

And that's basically how you ask a user to input text :)

String Manipulation Functions

Strings are — unsurprisingly — used all the time. Every word, every bit of text you see on your screen is actually a char array in memory that works just like I explained earlier (you're not going to see your computer the same way again, huh? ^^)

To make working with strings easier, the string.h library provides us with a whole bunch of handy functions for string operations.

I can't go over all of them here — it'd take forever, and not all of them are essential anyway. So I'll just walk you through the key ones you'll definitely be using soon, which is already a pretty solid foundation. After this you'll be a pro of strings.

🔹 Don't forget to include string.h

Even if this seems obvious, I'll say it again just in case: since we'll be using a new library called string.h, you need to include it at the top of any .c file where you want to use string functions:

#include <string.h>

If you don't, your compiler won't recognize the functions I'm about to show you because it won't have access to their prototypes — and your code just won't compile. So yeah, every time you use string manipulation functions, remember to include this header :)

🔹 strlen: Get the length of a string

strlen is a function that calculates the length of a string (not counting the \0 character). You give it a single argument: your string! It returns the number of characters in the string.

Now that you know what a function prototype is, I'll start showing them to you. Think of it as the "user manual" for a function (though a bit of extra explanation never hurts :p):

size_t strlen(const char* string);

size_t is a special type that represents a size value. It's not a basic type like int, long, or char — it's a "made-up" one. We'll learn how to create our own variable types a few chapters from now.

For now, we'll just store the return value of strlen in an int variable (the computer will automatically convert from size_t to int). Technically, you should use size_t, but in practice int is good enough.

The function takes a const char* as its parameter. That const means the function promises not to modify your string. Whenever you see const, it means the value is only being read — not changed.

Let's test out strlen:

int main(int argc, char *argv[])
{
    char string[] = "SiteRaw";
    int stringLength = 0;

stringLength = strlen(string);

printf("The string %s is %d characters long", string, stringLength);

return 0; }

Output:

The string SiteRaw is 7 characters long

This function's actually easy to recreate. All you need is a loop that walks through the char array and stops when it hits \0.

Let me code a version of strlen myself. That way, you'll really understand how it works — and maybe spot something interesting:

int stringLength(const char* string);

int main(int argc, char *argv[])
{
    char string[] = "SiteRaw";
    int length = 0;

length = stringLength(string);

printf("The string %s is %d characters long", string, length);

return 0; }

int stringLength(const char* string) { int count = 0; char currentChar = 0;

do { currentChar = string[count]; count++; } while(currentChar != '\0');

count--; // Remove 1 to exclude the \0 from the count

return count; }

This stringLength function loops through the array string, grabs characters one at a time into currentChar, and stops when it hits the \0. Each time through the loop, we add 1 to our counter. At the end, we subtract 1 to avoid counting the null character. Then we return the total count — and that's it ;)

You see how important that \0 is now?

🔹 strcpy: Copy one string into another

The strcpy function (short for "string copy") copies the contents of one string into another.

Prototype:

char* strcpy(char* destination, const char* source);

This function takes 2 arguments:

  • destination: a char* (i.e., an array of characters) where the string will be copied.
  • source: another string to be copied into destination.

It returns a pointer to destination, which you usually don't need. Most of the time, we just ignore the return value.

Let's test it:

int main(int argc, char *argv[])
{
    char source[] = "SiteRaw", copy[100] = {0};

strcpy(copy, source);

printf("source is : %s\n", source); printf("copy is : %s\n", copy);

return 0; }

Output:

source is : SiteRaw
copy is   : SiteRaw

So, source is "SiteRaw" — as expected. What's cool is that copy, which was empty before, now holds the same content. It worked!

⚠️ Just make sure copy is big enough to hold the entire contents of source. If I had used copy[7] instead (which isn't enough room for the \0), strcpy would've overflowed memory — and probably crashed the program. Definitely something to avoid… unless you enjoy crashing your computer for fun :)

🔹 strcat: Concatenate two strings

This function appends one string to the end of another — called concatenation.

If I have:

  • string1 = "Welcome to "
  • string2 = "SiteRaw"

After concatenating string2 to string1, we'll get "Welcome to SiteRaw". string2 stays unchanged; only string1 gets modified.

Here's the prototype:

char* strcat(char* string1, const char* string2);

As you can see, string2 is constant, so it won't be modified.

Again, the function returns a pointer to string1, which we don't really need. So we can ignore that.

Let's give it a go:

int main(int argc, char *argv[])
{
    char string1[100] = "Welcome to ", string2[] = "SiteRaw";

strcat(string1, string2);

printf("string1 is now: %s\n", string1); printf("string2 is still: %s\n", string2);

return 0; }

Output:

string1 is now: Welcome to SiteRaw
string2 is still: SiteRaw

Again — make sure string1 is large enough to hold the new string. Otherwise, you'll get a memory overflow and a crash. (Did I already say that?)

That's why I used string1[100]. string2 doesn't need to be resized since it's not being changed.

Here's a quick breakdown of what happened: The contents of string2 were added right after string1's last character. The \0 at the end of string1 was replaced by the 'S' from "SiteRaw". Remember: you can't have a \0 in the middle of your string — it'll be treated as the end of the string! So the final \0 only comes after the full string is built.

🔹 strcmp: Compare two strings

This one compares two strings. Here's the prototype:

int strcmp(const char* string1, const char* string2);

Both strings are marked const, meaning they won't be modified.

It's important to check what this function returns:

  • 0 if the strings are identical
  • A positive or negative value if they're different

It would've made more sense for it to return 1 for "true" when the strings match (remember booleans?), but hey — I didn't write the function.

In all seriousness, strcmp compares each character one by one. If they all match, it returns 0. If string1 has greater characters than string2, it returns a positive number. Otherwise, it returns a negative number.

In practice, we mostly just use it to check if two strings are equal — simple as that ;)

Here's a quick example:

int main(int argc, char *argv[])
{
    char string1[] = "SiteRaw", string2[] = "Siteraw";

if (strcmp(string1, string2) == 0) { printf("Strings are identical\n"); } else { printf("Strings are different\n"); }

return 0; }

Can you guess the output? What did I say earlier about uppercase vs lowercase?

To get strcmp to return 0, the two strings must match exactly. So either both say "SiteRaw", or both say "Siteraw" — not one of each.

You could store the result in an int variable, but it's not required. You can call the function directly in your if statement like I did.

Nothing more to say — it's a simple function. Just don't forget: 0 means "equal", anything else means "different". That's where most people trip up.

🔹 strchr: Finding a Character

The strchr function searches for a specific character within a string.

char* strchr(const char* string, int charToFind);

This function takes two arguments:

  • string: the string you want to search through.
  • charToFind: the character you're looking for in the string.

You might notice that charToFind is of type int, not char. That's not really a problem — after all, a character is basically just a number ;) That said, in practice, we tend to store characters using the char type rather than int.

The function returns a pointer to the first occurrence of the character it finds, meaning it gives you the memory address of that character. If it doesn't find anything, it returns NULL.

In the example below, we store the result in a pointer called substring:

int main(int argc, char *argv[])
{
    char string[] = "Welcome to SiteRaw", *substring = NULL;

substring = strchr(string, 'a'); if (substring != NULL) // If something was found { printf("Here's the end of the string starting from the first 'a': %s", substring); }

return 0; }

Output:

Here's the end of the string starting from the first 'a': aw

Got a good grasp on what's going on here? It's a bit special.

Basically, substring is a pointer, just like string. The difference is that string points to the very beginning of the string (the capital 'S'), whereas substring points to the first 'a' found in string.

So when we print substring using printf, it makes total sense that we only see "aw". The printf function prints every character it sees ('a', then 'w') until it hits the \0, which tells it the string is over.

Variant version

There's also a function called strrchr which works exactly like strchr, except it returns a pointer to the last occurrence of the character instead of the first ;) In this case, it wouldn't change much, but try it with the character 'e' instead of 'a' to see the difference.

🔹 strpbrk: First Matching Character from a List

This function is pretty similar to strchr. The key difference? Instead of searching for just one character, strpbrk looks for the first match among a list of characters, provided as a string.

For instance, if you search for characters in the string "wxyz" inside "Hello SiteRaw", the function will return a pointer to the first character from "wxyz" that it finds in "Hello SiteRaw". In this case, it finds 'w' first, so strpbrk will point to that 'w'.

Here's the prototype:

char* strpbrk(const char* string, const char* charsToFind);

Let's try it out:

int main(int argc, char *argv[])
{
    char *substring;

substring = strpbrk("Welcome to SiteRaw", "rAw");

if (substring != NULL) { printf("Say %sut?", substring); }

return 0; }

Output:

Say wut?

In this example, I've passed the arguments to the function directly using quotes. You don't have to store everything in variables — you can absolutely pass strings inline like this.

Just remember the golden rule:

  • Use double quotes "" for strings.
  • Use single quotes '' for individual characters.

🔹 strstr: Searching for a String Inside Another String

This function searches for the first occurrence of a string within another string.

Here's the prototype:

char* strstr(const char* string, const char* substringToFind);

The prototype is pretty similar to strpbrk, but don't confuse the two: strpbrk looks for any one character from a list, while strstr looks for a whole string.

Example:

int main(int argc, char *argv[])
{
    char *substring;

substring = strstr("Aw aw aw, Welcome to SiteRaw", "aw"); if (substring != NULL) { printf("First instance: %s\n", substring); }

return 0; }

Output:

First instance: aw

The strstr function looks for the string "aw" in "Aw aw aw, Welcome to SiteRaw". As with the other functions, it returns a pointer when it finds what it's looking for. If it doesn't, it returns NULL.

⚠️ Important: Always check if your search functions returned NULL. If you don't, and you try to print a string that points to NULL, one of two things will happen: either the print function is smart enough to tell you the pointer is null… or your program will crash hard, with the OS stepping in because it tried to access memory it shouldn't have. Better safe than sorry — use a conditional check to handle this!

So far, we've just been printing the string starting at the pointer returned by the function. In real-world code, that's not always useful ;) You'd usually just check if the result is != NULL to know whether your search was successful, and then display something like: "The text you were looking for was found."

Of course, this depends on your specific program, but these string functions are foundational if you want to do any kind of text processing :)

🔹 sprintf: Writing into a String

This one's a bit different — it lives in stdio.h, not string.h like the others we've looked at.

The name might sound a little familiar ;)

sprintf works a lot like printf, except instead of printing to the screen, it writes to a string. That's actually where the s comes from: "string".

It's a super handy function for formatting strings. Here's a quick example:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) { char string[100]; int age = 17;

// We write "You are 17 years old!" into string sprintf(string, "You are %d years old!", age);

// We print string to make sure it worked: printf("%s", string);

return 0; }

Output:

You are 17 years old!

It works just like printf, except you give it the string buffer as the first argument — the destination for the text.

In the example above, I'm writing into string the phrase "You are %d years old!", where %d gets replaced by the value of age. All the usual printf rules apply — you can use %s to insert other strings, %f for floats, and so on :)

As always, make sure the string you're writing into is large enough to hold everything. If not, well… boom :-°

And that wraps up this chapter! Strings in C, let's be honest, are a bit tricky to handle.

I'll admit, even I don't know all the functions in string.h by heart — so I'm certainly not expecting you to memorize them all. But you do need to understand how strings work in C, with the \0 and all that good stuff ;)

Just remember: C is a pretty low-level language, meaning you're very close to how your computer actually works. And that's a good thing — it means you're learning how text is handled by the machine. What you're learning now will absolutely pay off later, I promise. Unlike someone programming in Java or Python who doesn't need to think about the nuts and bolts, you're starting to understand how things really work, and that's huge.

Of course, there's a downside — this chapter is a bit on the complex side. You've got to be careful with array sizes, remember to include the \0, and so on. Strings aren't exactly beginner-friendly in C... but with a bit of practice, they'll become second nature.

Learn C Programing for Beginners

Enjoyed this C / C++ course?

If you liked this lesson, you can find the book "Learn C Programing for Beginners" from the same authors, available on SiteRaw, in bookstores and in online libraries in either digital or paperback format. You will find a complete C / C++ workshop with many exclusive bonus chapters.

More information