2

There's a struct

struct Foo{
    int a, b, c;
    char* name;
};

with an initialization function

Foo_init(struct Foo* foo, const char* name){
    // ... stuff
}

When I create a struct Foo object, I pass in a const char*, to serve as the object's name. Example:

struct Foo foo1;
Foo_init(&foo1, "foo1");

The goal is to "store" the content of "foo1" into foo1's char* variable.

I'm currently doing it like:

Foo_init(struct Foo* foo, const char* name){
    foo->name = name;

    // ... other stuff
}

but I wonder if the correct way is:

Foo_init(struct Foo* foo, const char* name){
    int name_len = strlen(name) + 1;
    foo->name = malloc(name_len);
    memcpy(foo->name, name, name_len)

    // ... other stuff
}

(I suppose either way is fine, since in this example the argument "foo1" is a string literal.)

  1. Which way is correct?
  2. What if the argument const char* name is no longer a string literal, but an arbitrary array with length determined at runtime?
  3. What if the signature of Foo_init() is not Foo_init(struct Foo* foo, const char* name) but Foo_init(struct Foo* foo, char* name) (ie. the char* is no longer const)?
  4. More generally, when do I need to malloc()/memcpy() memory for an incoming argument that is a char* (or an int*, or anything that owns a bunch of elements in memory), assuming I want "store it" inside a struct?
7
  • 1
    You specifically do not have an array inside the struct. You have a pointer Commented Aug 17, 2017 at 21:35
  • 4
    The "correct" way depends on whether you want the struct to own the data or not. Commented Aug 17, 2017 at 21:39
  • 1
    Detail: Use size_t --> size_t name_len = strlen(name) + 1; Commented Aug 17, 2017 at 21:45
  • 1
    foo->name = name; should have warned about losing const. Certainly this is not correct code. Commented Aug 17, 2017 at 21:47
  • What's wrong with using strdup() to allocate and copy a string in one line of code that's easy to read? Commented Aug 18, 2017 at 1:01

1 Answer 1

3

Which way is correct?

It depends on usecase, but highly prefer second. If you would store a pointer to string literal to name and then tried to modify its content, it would lead to undefined behavior. If name was const, and you would just need to store this string without modification, you could use first.

A common technique is for string literals to be put in "read-only-data" section which gets mapped into the process space as read-only (which is why you can't change it). It does vary by platform.

What if the argument const char* name is no longer a string literal, but an arbitrary array with length determined at runtime?

Doesn't matter, it will be the same. If its string (null terminated sequence of characters), strlen will return number of characters and you can copy it to malloced memory on heap.

What if the signature of Foo_init() is not Foo_init(struct Foo* foo, const char* name) but Foo_init(struct Foo* foo, char* name) (ie. the char* is no longer const)?

It's no longer const. It allows you to modify content of an array. Since you dont need to modify it (it's init function), you should leave it const.

More generally, when do I need to malloc()/memcpy() memory for an incoming argument that is a char* (or an int*, or anything that owns a bunch of elements in memory), assuming I want "store it" inside a struct?

You need allocate memory with dynamic storage duration on heap when you dont know amount of input data and need to calculate it in runtime. Automatic arrays are safer & faster so if you dont have to use dynamic storage, dont.

Sign up to request clarification or add additional context in comments.

1 Comment

Very helpful! Thank you. In general I prefer zero-copy over nonzero-copy, but in this case I'm still trying to convince myself that not using the memcpy() approach is actually safe...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.