The Size Of Strings

It's quite common to find pieces of C code like the following:

void do_something()  
{
        const char foo[] = "This is foo";
        ...
        func(foo, sizeof(foo));
        ...
}

This is perfectly legal in C and, as you can try by yourself, sizeof(foo) returns exactly the amount of space allocated for the string plus the trailing \0 character. This works because foo is declared as an array.

Well, now you should be tempted to ask why the function func() needs to have the size of foo passed as a parameter. Shouldn't it be able to use sizeof by itself? The reason is that foo is always passed as a pointer, no matter how the parameters are declared. Look at the following example (and please note how the second parameter of print_sizes() is declared):

#include <stdio.h>
#include <string.h>

void print_sizes(const char * name, const char var[])  
{
    printf("strlen(%s) = %lu\n", name, strlen(var));
    printf("sizeof(%s) = %lu\n", name, sizeof(var));
}

int main(int argc, char const *argv[])  
{
    const char foo[] = "This is foo";
    const char *bar = "This is not foo";

    printf("strlen(foo) = %lu\n", strlen(foo));
    printf("sizeof(foo) = %lu\n", sizeof(foo));

    printf("strlen(bar) = %lu\n", strlen(bar));
    printf("sizeof(bar) = %lu\n", sizeof(bar));

    print_sizes("foo", foo);
    print_sizes("bar", bar);

    return 0;
}

This is the result on my 64-bit system:

strlen(foo) = 11  
sizeof(foo) = 12  
strlen(bar) = 15  
sizeof(bar) = 8  
strlen(foo) = 11  
sizeof(foo) = 8  
strlen(bar) = 15  
sizeof(bar) = 8  

Why You Should Avoid It

Since you know how (and when) it works, it should not be a problem to use the operator sizeof in this way, right?

Unfortunately, usually code changes many times in the lifetime of a project. Sometimes pieces of functions are copied and pasted elsewhere or something that was meant to be a constant can become a variable.

Do you get the point? If not, take a look on how the simple function on the top of this post may change:

void do_something(char foo[])  
{
        ...
        func(foo, sizeof(foo));
        ...
}

Now you see the problem. Our array foo has become a parameter of the function. And we have just introduced a bug - and what a sneaky one. If the size of foo passed to the function is less than the result of sizeof you may not even notice it. But if it's bigger, you'll end up with corrupted memory.

For this reason, I strongly suggest you to not use the operator sizeof for arrays (not only of chars) since the chance of introducing bugs is too much high.

Now, if you want to ask me "Other than sizeof(), what is the best way to ensure a safe implementation?", the answer is here!


Cover image by petur r taken from Flickr licensed under the Creative Commons Attribution-ShareAlike 2.0 Generic license.

Luca Sommacal

Luca Sommacal

Italian developer (mainly in C for embedded platforms), Linux learner, addicted to rock music, history, science and few other things. Follow me on Twitter

comments powered by Disqus