Writing Multiline Strings in C: A Simple Guide


3 min read

Writing Multiline Strings in C: A Simple Guide

Welcome to this quick and easy tutorial! Today, we're going to explore how to handle multiline strings in C. Now, let's dive into the world of strings, specifically multiline strings.

Understanding Multiline Strings

In C, dealing with long strings that span multiple lines can seem like a jigsaw puzzle. Imagine you're writing a letter but you need to put each line on a new piece of paper. Sounds tricky, right? Well, in C, it's a bit like that, but we have some neat tricks to make it seamless.

Method 1: The Continuation Character

// 👇 first approach
char *str1 = "line 1\n \
line 2";

Here's our first method. Notice the backslash (\) at the end of the first line? That's like saying, "Hey, there's more to come on the next line!" It's a way of telling the C program that our string isn't finished yet.

Method 2: Split and Conquer

// 👇 second approach
char *str2 = "line 1\n"
             "line 2";

This is my favorite method, and it's like using building blocks. You write each line as a separate string and C magically glues them together. This method is cleaner and easier to read, much like a well-organized bookshelf.

Practical Example: Redis Source Code

Now, let's see this concept in action with a real-world example from Redis, a popular in-memory database.

/* taken from: https://github.com/antirez/redis/blob/3.2/src/server.c#L3651-L3666 */
void usage(void) {
    fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf] [options]\n");
    fprintf(stderr,"       ./redis-server - (read config from stdin)\n");
    fprintf(stderr,"       ./redis-server -v or --version\n");
    fprintf(stderr,"       ./redis-server -h or --help\n");
    fprintf(stderr,"       ./redis-server --test-memory <megabytes>\n\n");
    fprintf(stderr,"       ./redis-server (run the server with default conf)\n");
    fprintf(stderr,"       ./redis-server /etc/redis/6379.conf\n");
    fprintf(stderr,"       ./redis-server --port 7777\n");
    fprintf(stderr,"       ./redis-server --port 7777 --slaveof 8888\n");
    fprintf(stderr,"       ./redis-server /etc/myredis.conf --loglevel verbose\n\n");
    fprintf(stderr,"Sentinel mode:\n");
    fprintf(stderr,"       ./redis-server /etc/sentinel.conf --sentinel\n");

In the original Redis code, each line of the message is printed separately. It's like sending a text message word by word – effective, but a bit cumbersome.

/* Alternative version of https://github.com/antirez/redis/blob/3.2/src/server.c#L3651-L3666 */
void usage(void) {
    "Usage: ./redis-server [/path/to/redis.conf] [options]\n"
    "       ./redis-server - (read config from stdin)\n"
    "       ./redis-server -v or --version\n"
    "       ./redis-server -h or --help\n"
    "       ./redis-server --test-memory <megabytes>\n\n"
    "       ./redis-server (run the server with default conf)\n"
    "       ./redis-server /etc/redis/6379.conf\n"
    "       ./redis-server --port 7777\n"
    "       ./redis-server --port 7777 --slaveof 8888\n"
    "       ./redis-server /etc/myredis.conf --loglevel verbose\n\n"
    "Sentinel mode:\n"
    "       ./redis-server /etc/sentinel.conf --sentinel\n");

Here, we use our second method. It's like sending the whole text message in one go. Less typing, more clarity, and easier maintenance.

Conclusion: Why It Matters

Writing code is not just about getting the job done; it's about doing it elegantly. By choosing the right way to handle multiline strings, we make our code more readable and easier to maintain. It's like choosing the right tool for a job - it makes everything smoother.

Remember, great code is not just functional; it's also a joy to read and work with.