Jeremy Galvan
Jeremy Galvan

Reputation: 33

Simple question on dynamically allocating memory to a char pointer

I am studying for a Data Structures and Algorithms exam. One of the sample questions related to dynamic memory allocation requires you to create a function that passes a string, which takes it at copies it to a user defined char pointer. The question provides the struct body to start off. I did something like this:

typedef struct smart_string {
    char *word;
    int length;
} smart_string;

smart_string* create_smart_string(char *str)
{
    smart_string *s = (smart_string*)malloc(sizeof(smart_string));
    s->length = strlen(str);
    s->word = malloc(s->length);
    strcpy(s->word, str);
    return s;
}

But the answer was this

typedef struct smart_string {
    char *word;
    int length;
} smart_string;

smart_string *create_smart_string(char *str)
{
    smart_string *s = malloc(sizeof(smart_string));
    s->length = strlen(str);
    s->word = malloc(sizeof(char) * (s->length + 1));
    strcpy(s->word, str);
    return s;
}

I went on code:blocks and tested them both to see any major differences. As far as I'm aware, their outputs were the same.

I did my code the way it is because I figured if we were to allocate a specific block of memory to s->word, then it should be the same number of bytes as s ->length, because that's the string we want to copy.

However the correct answer below multiplies sizeof(char) (which is just 1 byte), with s->length + 1. Why the need to add 1 to s->length? What's the importance of multiplying s->length by sizeof(char)? What mistakes did I make in my answer that I should look out for?

Upvotes: 2

Views: 655

Answers (2)

Swordfish
Swordfish

Reputation: 13144

Your answer is incorrect because it doesn't account for the terminating '\0'-character. In C strings are terminated by 0. That's how their length can be determined. A typical implementation of strlen() would look like

size_t strlen(char const *str)
{
    for (char const *p = str; *p; ++p);  // as long as p doesn't point to 0 increment p
    return p - str;  // the length of the string is determined by the distance of
}                    // the '\0'-character to the beginning of the string.

But both "solutions" are fubar, though. Why would one allocate a structure consisting of an int and a pointer on the free-store ("heap")!? smart_string::length being an int is the other wtf.

#include <stddef.h>  // size_t

typedef struct smart_string_tag {  // *)
    char *word;
    size_t length;
} smart_string_t;

#include <assert.h>  // assert()
#include <string.h>  // strlen(), strcpy()
#include <stdlib.h>  // malloc()

smart_string_t create_smart_string(char const *str)
{
    assert(str);  // make sure str isn't NULL

    smart_string_t new_smart_string;
    new_smart_string.length = strlen(str);
    new_smart_string.word = calloc(new_smart_string.length + 1, sizeof *new_smart_string.word);

    if(!new_smart_string.word) {
        new_smart_string.length = 0;
        return new_smart_string;
    }

    strcpy(new_smart_string.word, str);
    return new_smart_string;
}

*) Understanding C Namespaces

Upvotes: 4

sizeof(char) == 1 by definition, so that doesn't matter.

You should not cast the result of malloc: Do I cast the result of malloc?

And your only real difference is that strlen returns the length of the string, not including the terminating NUL ('\0') character, so you need to add + 1 to the size of the buffer as in the solution.

If you copy there the string, the terminating character won't be copied (or worse, it will be copied on some other memory), and therefore, any function that deals with strings (unless you use special safety functions such as strscpy) will run through the buffer and past it since they won't find the end. At that point it is undefined behaviour and everything can happen, even working as expected, but can't rely on that.

The reason it is working as expected is because probably the memory just next to the buffer will be 0 and therefore it is being interpreted as the terminating character.

Upvotes: 4

Related Questions